Merge changes from topic "b221419865" into tm-dev am: 4682c6576c am: 6b4f3a7474
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17592154
Change-Id: Ic6df49ce50e77501868750225667947ef7d6b85e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index 96bbf8e..cf4e6a6 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
+import android.text.TextUtils;
import com.android.internal.R;
@@ -44,6 +45,7 @@
*/
public class DreamActivity extends Activity {
static final String EXTRA_CALLBACK = "binder";
+ static final String EXTRA_DREAM_TITLE = "title";
public DreamActivity() {}
@@ -51,6 +53,11 @@
public void onCreate(@Nullable Bundle bundle) {
super.onCreate(bundle);
+ final String title = getIntent().getStringExtra(EXTRA_DREAM_TITLE);
+ if (!TextUtils.isEmpty(title)) {
+ setTitle(title);
+ }
+
DreamService.DreamServiceWrapper callback =
(DreamService.DreamServiceWrapper) getIntent().getIBinderExtra(EXTRA_CALLBACK);
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index d4f8a3b..95eae6c 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1280,6 +1280,9 @@
i.setPackage(getApplicationContext().getPackageName());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
+ final ServiceInfo serviceInfo = fetchServiceInfo(this,
+ new ComponentName(this, getClass()));
+ i.putExtra(DreamActivity.EXTRA_DREAM_TITLE, fetchDreamLabel(this, serviceInfo));
try {
if (!ActivityTaskManager.getService().startDreamActivity(i)) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 488fb180..12571b1 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -912,6 +912,12 @@
}
}
+ if (!st.hasPanelItems()) {
+ // Ensure that |st.decorView| has its actual content. Otherwise, an empty window can be
+ // created and cause ANR.
+ return;
+ }
+
st.isHandled = false;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 62fb840..ecdccd7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -34,6 +34,7 @@
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingWindowController;
+import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.unfold.UnfoldTransitionHandler;
@@ -131,6 +132,13 @@
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mTransitions.register(mShellTaskOrganizer);
mUnfoldTransitionHandler.ifPresent(UnfoldTransitionHandler::init);
+ if (mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
+ final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
+ mPipTouchHandlerOptional.get().getTransitionHandler(),
+ mSplitScreenOptional.get().getTransitionHandler());
+ // Added at end so that it has highest priority.
+ mTransitions.addHandler(mixedHandler);
+ }
}
// TODO(b/181599115): This should really be the pip controller, but until we can provide the
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b6635f3..6d0aad0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -295,6 +295,10 @@
displayController.addDisplayWindowListener(this);
}
+ public PipTransitionController getTransitionController() {
+ return mPipTransitionController;
+ }
+
public Rect getCurrentOrAnimatingBounds() {
PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getCurrentAnimator();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 48df28e..5d17f85b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -28,7 +28,6 @@
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
-import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
@@ -52,6 +51,7 @@
import android.os.IBinder;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
@@ -217,8 +217,9 @@
}
// Entering PIP.
- if (isEnteringPip(info, mCurrentPipTaskToken)) {
- return startEnterAnimation(info, startTransaction, finishTransaction, finishCallback);
+ if (isEnteringPip(info)) {
+ startEnterAnimation(info, startTransaction, finishTransaction, finishCallback);
+ return true;
}
// For transition that we don't animate, but contains the PIP leash, we need to update the
@@ -245,16 +246,9 @@
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (request.getType() == TRANSIT_PIP) {
+ if (requestHasPipEnter(request)) {
WindowContainerTransaction wct = new WindowContainerTransaction();
- if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- mRequestedEnterTransition = transition;
- mRequestedEnterTask = request.getTriggerTask().token;
- wct.setActivityWindowingMode(request.getTriggerTask().token,
- WINDOWING_MODE_UNDEFINED);
- final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
- wct.setBounds(request.getTriggerTask().token, destinationBounds);
- }
+ augmentRequest(transition, request, wct);
return wct;
} else {
return null;
@@ -262,6 +256,22 @@
}
@Override
+ public void augmentRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT) {
+ if (!requestHasPipEnter(request)) {
+ throw new IllegalStateException("Called PiP augmentRequest when request has no PiP");
+ }
+ if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ mRequestedEnterTransition = transition;
+ mRequestedEnterTask = request.getTriggerTask().token;
+ outWCT.setActivityWindowingMode(request.getTriggerTask().token,
+ WINDOWING_MODE_UNDEFINED);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+ outWCT.setBounds(request.getTriggerTask().token, destinationBounds);
+ }
+ }
+
+ @Override
public boolean handleRotateDisplay(int startRotation, int endRotation,
WindowContainerTransaction wct) {
if (mRequestedEnterTransition != null && mOneShotAnimationType == ANIM_TYPE_ALPHA) {
@@ -559,92 +569,94 @@
}
/** Whether we should handle the given {@link TransitionInfo} animation as entering PIP. */
- private static boolean isEnteringPip(@NonNull TransitionInfo info,
- @Nullable WindowContainerToken currentPipTaskToken) {
+ private boolean isEnteringPip(@NonNull TransitionInfo info) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() != null
- && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED
- && !change.getContainer().equals(currentPipTaskToken)) {
- // We support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
- // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
- if (info.getType() == TRANSIT_PIP || info.getType() == TRANSIT_OPEN) {
- return true;
- }
- // This can happen if the request to enter PIP happens when we are collecting for
- // another transition, such as TRANSIT_CHANGE (display rotation).
- if (info.getType() == TRANSIT_CHANGE) {
- return true;
- }
-
- // Please file a bug to handle the unexpected transition type.
- throw new IllegalStateException("Entering PIP with unexpected transition type="
- + transitTypeToString(info.getType()));
- }
+ if (isEnteringPip(change, info.getType())) return true;
}
return false;
}
- private boolean startEnterAnimation(@NonNull TransitionInfo info,
+ /** Whether a particular change is a window that is entering pip. */
+ @Override
+ public boolean isEnteringPip(@NonNull TransitionInfo.Change change,
+ @WindowManager.TransitionType int transitType) {
+ if (change.getTaskInfo() != null
+ && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED
+ && !change.getContainer().equals(mCurrentPipTaskToken)) {
+ // We support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
+ // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
+ if (transitType == TRANSIT_PIP || transitType == TRANSIT_OPEN) {
+ return true;
+ }
+ // This can happen if the request to enter PIP happens when we are collecting for
+ // another transition, such as TRANSIT_CHANGE (display rotation).
+ if (transitType == TRANSIT_CHANGE) {
+ return true;
+ }
+
+ // Please file a bug to handle the unexpected transition type.
+ throw new IllegalStateException("Entering PIP with unexpected transition type="
+ + transitTypeToString(transitType));
+ }
+ return false;
+ }
+
+ private void startEnterAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- // Search for an Enter PiP transition (along with a show wallpaper one)
+ // Search for an Enter PiP transition
TransitionInfo.Change enterPip = null;
- TransitionInfo.Change wallpaper = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getTaskInfo() != null
&& change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) {
enterPip = change;
- } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
- wallpaper = change;
}
}
if (enterPip == null) {
- return false;
- }
- // Keep track of the PIP task.
- mCurrentPipTaskToken = enterPip.getContainer();
- mHasFadeOut = false;
-
- if (mFinishCallback != null) {
- callFinishCallback(null /* wct */);
- mFinishTransaction = null;
- throw new RuntimeException("Previous callback not called, aborting entering PIP.");
+ throw new IllegalStateException("Trying to start PiP animation without a pip"
+ + "participant");
}
- // Show the wallpaper if there is a wallpaper change.
- if (wallpaper != null) {
- startTransaction.show(wallpaper.getLeash());
- startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
- }
// Make sure other open changes are visible as entering PIP. Some may be hidden in
// Transitions#setupStartState because the transition type is OPEN (such as auto-enter).
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (change == enterPip || change == wallpaper) {
- continue;
- }
+ if (change == enterPip) continue;
if (isOpeningType(change.getMode())) {
final SurfaceControl leash = change.getLeash();
startTransaction.show(leash).setAlpha(leash, 1.f);
}
}
+ startEnterAnimation(enterPip, startTransaction, finishTransaction, finishCallback);
+ }
+
+ @Override
+ public void startEnterAnimation(@NonNull final TransitionInfo.Change pipChange,
+ @NonNull final SurfaceControl.Transaction startTransaction,
+ @NonNull final SurfaceControl.Transaction finishTransaction,
+ @NonNull final Transitions.TransitionFinishCallback finishCallback) {
+ if (mFinishCallback != null) {
+ callFinishCallback(null /* wct */);
+ mFinishTransaction = null;
+ throw new RuntimeException("Previous callback not called, aborting entering PIP.");
+ }
+
+ // Keep track of the PIP task and animation.
+ mCurrentPipTaskToken = pipChange.getContainer();
+ mHasFadeOut = false;
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
mFinishTransaction = finishTransaction;
- final int endRotation = mInFixedRotation ? mEndFixedRotation : enterPip.getEndRotation();
- return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
- startTransaction, finishTransaction, enterPip.getStartRotation(),
- endRotation);
- }
- private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
- final SurfaceControl.Transaction startTransaction,
- final SurfaceControl.Transaction finishTransaction,
- final int startRotation, final int endRotation) {
+ final ActivityManager.RunningTaskInfo taskInfo = pipChange.getTaskInfo();
+ final SurfaceControl leash = pipChange.getLeash();
+ final int startRotation = pipChange.getStartRotation();
+ final int endRotation = mInFixedRotation ? mEndFixedRotation : pipChange.getEndRotation();
+
setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
taskInfo.topActivityInfo);
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
@@ -657,7 +669,6 @@
computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo,
destinationBounds, sourceHintRect);
}
- PipAnimationController.PipTransitionAnimator animator;
// Set corner radius for entering pip.
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destinationBounds)
@@ -694,7 +705,7 @@
null /* callback */, false /* withStartDelay */);
}
mPipTransitionState.setInSwipePipToHomeTransition(false);
- return true;
+ return;
}
if (rotationDelta != Surface.ROTATION_0) {
@@ -702,6 +713,12 @@
tmpTransform.postRotate(rotationDelta);
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
+ if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ startTransaction.setAlpha(leash, 0f);
+ }
+ startTransaction.apply();
+
+ PipAnimationController.PipTransitionAnimator animator;
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
@@ -712,7 +729,6 @@
animator.setUseContentOverlay(mContext);
}
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- startTransaction.setAlpha(leash, 0f);
animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
0f, 1f);
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -720,7 +736,6 @@
throw new RuntimeException("Unrecognized animation type: "
+ mOneShotAnimationType);
}
- startTransaction.apply();
animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration);
@@ -731,8 +746,6 @@
animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
}
animator.start();
-
- return true;
}
/** Computes destination bounds in old rotation and updates source hint rect if available. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 24993c62..28418be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.WindowManager.TRANSIT_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
@@ -28,10 +29,16 @@
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
+import androidx.annotation.NonNull;
+
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.transition.Transitions;
@@ -206,6 +213,30 @@
return false;
}
+ /** @return whether the transition-request represents a pip-entry. */
+ public boolean requestHasPipEnter(@NonNull TransitionRequestInfo request) {
+ return request.getType() == TRANSIT_PIP;
+ }
+
+ /** Whether a particular change is a window that is entering pip. */
+ public boolean isEnteringPip(@NonNull TransitionInfo.Change change,
+ @WindowManager.TransitionType int transitType) {
+ return false;
+ }
+
+ /** Add PiP-related changes to `outWCT` for the given request. */
+ public void augmentRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT) {
+ throw new IllegalStateException("Request isn't entering PiP");
+ }
+
+ /** Play a transition animation for entering PiP on a specific PiP change. */
+ public void startEnterAnimation(@NonNull final TransitionInfo.Change pipChange,
+ @NonNull final SurfaceControl.Transaction startTransaction,
+ @NonNull final SurfaceControl.Transaction finishTransaction,
+ @NonNull final Transitions.TransitionFinishCallback finishCallback) {
+ }
+
/**
* Callback interface for PiP transitions (both from and to PiP mode)
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index ac7b9033b..a2ff972 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -54,6 +54,7 @@
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -250,6 +251,10 @@
});
}
+ public PipTransitionController getTransitionHandler() {
+ return mPipTaskOrganizer.getTransitionController();
+ }
+
private void reloadResources() {
final Resources res = mContext.getResources();
mBottomOffsetBufferPx = res.getDimensionPixelSize(R.dimen.pip_bottom_offset_buffer);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 10dfdc3..6c0bed0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -108,7 +108,7 @@
static final int EXIT_REASON_ROOT_TASK_VANISHED = 6;
static final int EXIT_REASON_SCREEN_LOCKED = 7;
static final int EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP = 8;
- static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
+ public static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
@IntDef(value = {
EXIT_REASON_UNKNOWN,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW,
@@ -198,6 +198,10 @@
return mStageCoordinator.isSplitScreenVisible();
}
+ public StageCoordinator getTransitionHandler() {
+ return mStageCoordinator;
+ }
+
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index cd121ed..4ff9d48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -21,7 +21,6 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
@@ -58,9 +57,6 @@
class SplitScreenTransitions {
private static final String TAG = "SplitScreenTransitions";
- /** Flag applied to a transition change to identify it as a divider bar for animation. */
- public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
-
private final TransactionPool mTransactionPool;
private final Transitions mTransitions;
private final Runnable mOnFinish;
@@ -187,27 +183,28 @@
}
/** Starts a transition to dismiss split. */
- IBinder startDismissTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
+ IBinder startDismissTransition(WindowContainerTransaction wct,
Transitions.TransitionHandler handler, @SplitScreen.StageType int dismissTop,
@SplitScreenController.ExitReason int reason) {
final int type = reason == EXIT_REASON_DRAG_DIVIDER
? TRANSIT_SPLIT_DISMISS_SNAP : TRANSIT_SPLIT_DISMISS;
- if (transition == null) {
- transition = mTransitions.startTransition(type, wct, handler);
- }
+ IBinder transition = mTransitions.startTransition(type, wct, handler);
+ setDismissTransition(transition, dismissTop, reason);
+ return transition;
+ }
+
+ /** Sets a transition to dismiss split. */
+ void setDismissTransition(@NonNull IBinder transition, @SplitScreen.StageType int dismissTop,
+ @SplitScreenController.ExitReason int reason) {
mPendingDismiss = new DismissTransition(transition, reason, dismissTop);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Dismiss due to %s. toTop=%s",
exitReasonToString(reason), stageTypeToString(dismissTop));
- return transition;
}
- IBinder startRecentTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
- Transitions.TransitionHandler handler, @Nullable RemoteTransition remoteTransition) {
- if (transition == null) {
- transition = mTransitions.startTransition(TRANSIT_OPEN, wct, handler);
- }
+ void setRecentTransition(@NonNull IBinder transition,
+ @Nullable RemoteTransition remoteTransition) {
mPendingRecent = transition;
if (remoteTransition != null) {
@@ -219,7 +216,6 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Enter recent panel");
- return transition;
}
void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 9d6e34d..bb434e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -28,6 +28,7 @@
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
@@ -47,7 +48,6 @@
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
-import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -127,12 +127,15 @@
* This rules are mostly implemented in {@link #onStageVisibilityChanged(StageListenerImpl)} and
* {@link #onStageHasChildrenChanged(StageListenerImpl).}
*/
-class StageCoordinator implements SplitLayout.SplitLayoutHandler,
+public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler,
ShellTaskOrganizer.TaskListener {
private static final String TAG = StageCoordinator.class.getSimpleName();
+ /** Flag applied to a transition change to identify it as a divider bar for animation. */
+ public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
+
private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final MainStage mMainStage;
@@ -636,7 +639,7 @@
if (ENABLE_SHELL_TRANSITIONS) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
- mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
+ mSplitTransitions.startDismissTransition(wct, this,
mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
} else {
exitSplitScreen(
@@ -666,8 +669,8 @@
final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(dismissTop, wct);
- mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
- dismissTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+ mSplitTransitions.startDismissTransition(wct, this, dismissTop,
+ EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
}
}
@@ -729,10 +732,7 @@
.setWindowCrop(mSideStage.mRootLeash, null);
});
- // Hide divider and reset its position.
- mSplitLayout.resetDividerPosition();
- mSplitLayout.release();
- mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ onTransitionAnimationComplete();
Slog.i(TAG, "applyExitSplitScreen, reason = " + exitReasonToString(exitReason));
// Log the exit
if (childrenToTop != null) {
@@ -1128,8 +1128,7 @@
final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(dismissTop, wct);
- mSplitTransitions.startDismissTransition(
- null /* transition */, wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER);
+ mSplitTransitions.startDismissTransition(wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER);
}
@Override
@@ -1318,7 +1317,8 @@
@Nullable TransitionRequestInfo request) {
final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
if (triggerTask == null) {
- if (mMainStage.isActive()) {
+ if (isSplitActive()) {
+ // Check if the display is rotating.
final TransitionRequestInfo.DisplayChange displayChange =
request.getDisplayChange();
if (request.getType() == TRANSIT_CHANGE && displayChange != null
@@ -1345,7 +1345,7 @@
mRecentTasks.ifPresent(recentTasks -> recentTasks.removeSplitPair(triggerTask.taskId));
}
- if (mMainStage.isActive()) {
+ if (isSplitActive()) {
// Try to handle everything while in split-screen, so return a WCT even if it's empty.
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " split is active so using split"
+ "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
@@ -1360,7 +1360,7 @@
int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN ? STAGE_TYPE_SIDE
: STAGE_TYPE_MAIN;
prepareExitSplitScreen(dismissTop, out);
- mSplitTransitions.startDismissTransition(transition, out, this, dismissTop,
+ mSplitTransitions.setDismissTransition(transition, dismissTop,
EXIT_REASON_APP_FINISHED);
}
} else if (isOpening && inFullscreen) {
@@ -1370,12 +1370,12 @@
} else if (activityType == ACTIVITY_TYPE_HOME
|| activityType == ACTIVITY_TYPE_RECENTS) {
// Enter overview panel, so start recent transition.
- mSplitTransitions.startRecentTransition(transition, out, this,
+ mSplitTransitions.setRecentTransition(transition,
request.getRemoteTransition());
} else {
// Occluded by the other fullscreen task, so dismiss both.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
- mSplitTransitions.startDismissTransition(transition, out, this,
+ mSplitTransitions.setDismissTransition(transition,
STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
}
}
@@ -1390,6 +1390,33 @@
return out;
}
+ /**
+ * This is used for mixed scenarios. For such scenarios, just make sure to include exiting
+ * split or entering split when appropriate.
+ */
+ public void addEnterOrExitIfNeeded(@Nullable TransitionRequestInfo request,
+ @NonNull WindowContainerTransaction outWCT) {
+ final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
+ if (triggerTask != null && triggerTask.displayId != mDisplayId) {
+ // Skip handling task on the other display.
+ return;
+ }
+ final @WindowManager.TransitionType int type = request.getType();
+ if (isSplitActive() && !isOpeningType(type)
+ && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " One of the splits became "
+ + "empty during a mixed transition (one not handled by split),"
+ + " so make sure split-screen state is cleaned-up. "
+ + "mainStageCount=%d sideStageCount=%d", mMainStage.getChildCount(),
+ mSideStage.getChildCount());
+ prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, outWCT);
+ }
+ }
+
+ public boolean isSplitActive() {
+ return mMainStage.isActive();
+ }
+
@Override
public void mergeAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
@@ -1482,7 +1509,8 @@
return true;
}
- void onTransitionAnimationComplete() {
+ /** Called to clean-up state and do house-keeping after the animation is done. */
+ public void onTransitionAnimationComplete() {
// If still playing, let it finish.
if (!mMainStage.isActive()) {
// Update divider state after animation so that it is still around and positioned
@@ -1546,8 +1574,8 @@
return true;
}
- private boolean startPendingDismissAnimation(
- @NonNull SplitScreenTransitions.DismissTransition dismissTransition,
+ /** Synchronize split-screen state with transition and make appropriate preparations. */
+ public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
@NonNull SurfaceControl.Transaction finishT) {
// Make some noise if things aren't totally expected. These states shouldn't effect
@@ -1580,7 +1608,7 @@
mRecentTasks.ifPresent(recentTasks -> {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
- if (shouldBreakPairedTaskInRecents(dismissTransition.mReason) && mShouldUpdateRecents) {
+ if (shouldBreakPairedTaskInRecents(dismissReason) && mShouldUpdateRecents) {
for (TransitionInfo.Change change : info.getChanges()) {
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo != null
@@ -1597,30 +1625,38 @@
// Wait until after animation to update divider
// Reset crops so they don't interfere with subsequent launches
- t.setWindowCrop(mMainStage.mRootLeash, null);
- t.setWindowCrop(mSideStage.mRootLeash, null);
+ t.setCrop(mMainStage.mRootLeash, null);
+ t.setCrop(mSideStage.mRootLeash, null);
- if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
- logExit(dismissTransition.mReason);
- // TODO: Have a proper remote for this. Until then, though, reset state and use the
- // normal animation stuff (which falls back to the normal launcher remote).
- mSplitLayout.release(t);
- mSplitTransitions.mPendingDismiss = null;
- return false;
+ if (toStage == STAGE_TYPE_UNDEFINED) {
+ logExit(dismissReason);
} else {
- logExitToStage(dismissTransition.mReason,
- dismissTransition.mDismissTop == STAGE_TYPE_MAIN);
+ logExitToStage(dismissReason, toStage == STAGE_TYPE_MAIN);
}
addDividerBarToTransition(info, t, false /* show */);
- // We're dismissing split by moving the other one to fullscreen.
- // Since we don't have any animations for this yet, just use the internal example
- // animations.
// Hide divider and dim layer on transition finished.
setDividerVisibility(false, finishT);
finishT.hide(mMainStage.mDimLayer);
finishT.hide(mSideStage.mDimLayer);
+ }
+
+ private boolean startPendingDismissAnimation(
+ @NonNull SplitScreenTransitions.DismissTransition dismissTransition,
+ @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.Transaction finishT) {
+ prepareDismissAnimation(dismissTransition.mDismissTop, dismissTransition.mReason, info,
+ t, finishT);
+ if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
+ // TODO: Have a proper remote for this. Until then, though, reset state and use the
+ // normal animation stuff (which falls back to the normal launcher remote).
+ t.hide(mSplitLayout.getDividerLeash());
+ mSplitLayout.release(t);
+ mSplitTransitions.mPendingDismiss = null;
+ return false;
+ }
+
return true;
}
@@ -1793,7 +1829,7 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
- mSplitTransitions.startDismissTransition(null /* transition */, wct,
+ mSplitTransitions.startDismissTransition(wct,
StageCoordinator.this, STAGE_TYPE_UNDEFINED,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 9fd5d20..4b12eb8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -268,13 +268,13 @@
mChildrenTaskInfo.remove(taskId);
mChildrenLeashes.remove(taskId);
mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
- if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
- mCallbacks.onChildTaskEnterPip(taskId);
- }
if (ENABLE_SHELL_TRANSITIONS) {
// Status is managed/synchronized by the transition lifecycle.
return;
}
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ mCallbacks.onChildTaskEnterPip(taskId);
+ }
sendStatusChanged();
} else {
throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
new file mode 100644
index 0000000..1ffe26df
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.transition;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
+import static com.android.wm.shell.splitscreen.StageCoordinator.FLAG_IS_DIVIDER_BAR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.splitscreen.StageCoordinator;
+
+import java.util.ArrayList;
+
+/**
+ * A handler for dealing with transitions involving multiple other handlers. For example: an
+ * activity in split-screen going into PiP.
+ */
+public class DefaultMixedHandler implements Transitions.TransitionHandler {
+
+ private final Transitions mPlayer;
+ private final PipTransitionController mPipHandler;
+ private final StageCoordinator mSplitHandler;
+
+ private static class MixedTransition {
+ static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
+
+ final int mType;
+ final IBinder mTransition;
+
+ Transitions.TransitionFinishCallback mFinishCallback = null;
+
+ /**
+ * Mixed transitions are made up of multiple "parts". This keeps track of how many
+ * parts are currently animating.
+ */
+ int mInFlightSubAnimations = 0;
+
+ MixedTransition(int type, IBinder transition) {
+ mType = type;
+ mTransition = transition;
+ }
+ }
+ private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
+
+ public DefaultMixedHandler(@NonNull Transitions player,
+ @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+ mPlayer = player;
+ mPipHandler = pipHandler;
+ mSplitHandler = splitHandler;
+ }
+
+ @Nullable
+ @Override
+ public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request) {
+ if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitActive()) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request while "
+ + "Split-Screen is active, so treat it as Mixed.");
+ if (request.getRemoteTransition() != null) {
+ throw new IllegalStateException("Unexpected remote transition in"
+ + "pip-enter-from-split request");
+ }
+ mActiveTransitions.add(new MixedTransition(MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT,
+ transition));
+
+ WindowContainerTransaction out = new WindowContainerTransaction();
+ mPipHandler.augmentRequest(transition, request, out);
+ mSplitHandler.addEnterOrExitIfNeeded(request, out);
+ return out;
+ }
+ return null;
+ }
+
+ private TransitionInfo subCopy(@NonNull TransitionInfo info,
+ @WindowManager.TransitionType int newType) {
+ final TransitionInfo out = new TransitionInfo(newType, info.getFlags());
+ for (int i = 0; i < info.getChanges().size(); ++i) {
+ out.getChanges().add(info.getChanges().get(i));
+ }
+ out.setRootLeash(info.getRootLeash(), info.getRootOffset().x, info.getRootOffset().y);
+ out.setAnimationOptions(info.getAnimationOptions());
+ return out;
+ }
+
+ private boolean isHomeOpening(@NonNull TransitionInfo.Change change) {
+ return change.getTaskInfo() != null
+ && change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME;
+ }
+
+ private boolean isWallpaper(@NonNull TransitionInfo.Change change) {
+ return (change.getFlags() & FLAG_IS_WALLPAPER) != 0;
+ }
+
+ @Override
+ public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ MixedTransition mixed = null;
+ for (int i = mActiveTransitions.size() - 1; i >= 0; --i) {
+ if (mActiveTransitions.get(i).mTransition != transition) continue;
+ mixed = mActiveTransitions.remove(i);
+ break;
+ }
+ if (mixed == null) return false;
+
+ if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) {
+ return animateEnterPipFromSplit(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
+ } else {
+ throw new IllegalStateException("Starting mixed animation without a known mixed type? "
+ + mixed.mType);
+ }
+ }
+
+ private boolean animateEnterPipFromSplit(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for "
+ + "entering PIP while Split-Screen is active.");
+ TransitionInfo.Change pipChange = null;
+ TransitionInfo.Change wallpaper = null;
+ final TransitionInfo everythingElse = subCopy(info, TRANSIT_TO_BACK);
+ boolean homeIsOpening = false;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ TransitionInfo.Change change = info.getChanges().get(i);
+ if (mPipHandler.isEnteringPip(change, info.getType())) {
+ if (pipChange != null) {
+ throw new IllegalStateException("More than 1 pip-entering changes in one"
+ + " transition? " + info);
+ }
+ pipChange = change;
+ // going backwards, so remove-by-index is fine.
+ everythingElse.getChanges().remove(i);
+ } else if (isHomeOpening(change)) {
+ homeIsOpening = true;
+ } else if (isWallpaper(change)) {
+ wallpaper = change;
+ }
+ }
+ if (pipChange == null) {
+ // um, something probably went wrong.
+ return false;
+ }
+ final boolean isGoingHome = homeIsOpening;
+ mixed.mFinishCallback = finishCallback;
+ Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ --mixed.mInFlightSubAnimations;
+ if (mixed.mInFlightSubAnimations > 0) return;
+ if (isGoingHome) {
+ mSplitHandler.onTransitionAnimationComplete();
+ }
+ mixed.mFinishCallback.onTransitionFinished(wct, wctCB);
+ };
+ if (isGoingHome) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed "
+ + "since entering-PiP caused us to leave split and return home.");
+ // We need to split the transition into 2 parts: the pip part (animated by pip)
+ // and the dismiss-part (animated by launcher).
+ mixed.mInFlightSubAnimations = 2;
+ // immediately make the wallpaper visible (so that we don't see it pop-in during
+ // the time it takes to start recents animation (which is remote).
+ if (wallpaper != null) {
+ startTransaction.show(wallpaper.getLeash()).setAlpha(wallpaper.getLeash(), 1.f);
+ }
+ // make a new startTransaction because pip's startEnterAnimation "consumes" it so
+ // we need a separate one to send over to launcher.
+ SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction();
+ // Let split update internal state for dismiss.
+ mSplitHandler.prepareDismissAnimation(STAGE_TYPE_UNDEFINED,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT,
+ finishTransaction);
+
+ // We are trying to accommodate launcher's close animation which can't handle the
+ // divider-bar, so if split-handler is closing the divider-bar, just hide it and remove
+ // from transition info.
+ for (int i = everythingElse.getChanges().size() - 1; i >= 0; --i) {
+ if ((everythingElse.getChanges().get(i).getFlags() & FLAG_IS_DIVIDER_BAR) != 0) {
+ everythingElse.getChanges().remove(i);
+ break;
+ }
+ }
+
+ mPipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction,
+ finishCB);
+ // Dispatch the rest of the transition normally. This will most-likely be taken by
+ // recents or default handler.
+ mPlayer.dispatchTransition(mixed.mTransition, everythingElse, otherStartT,
+ finishTransaction, finishCB, this);
+ } else {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Not leaving split, so just "
+ + "forward animation to Pip-Handler.");
+ // This happens if the pip-ing activity is in a multi-activity task (and thus a
+ // new pip task is spawned). In this case, we don't actually exit split so we can
+ // just let pip transition handle the animation verbatim.
+ mixed.mInFlightSubAnimations = 1;
+ mPipHandler.startAnimation(mixed.mTransition, info, startTransaction, finishTransaction,
+ finishCB);
+ }
+ return true;
+ }
+
+ @Override
+ public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ }
+
+ @Override
+ public void onTransitionMerged(@NonNull IBinder transition) {
+ MixedTransition mixed = null;
+ for (int i = mActiveTransitions.size() - 1; i >= 0; --i) {
+ if (mActiveTransitions.get(i).mTransition != transition) continue;
+ mixed = mActiveTransitions.remove(i);
+ break;
+ }
+ if (mixed == null) return;
+ if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) {
+ mPipHandler.onTransitionMerged(transition);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 435d670..e4c9426 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -435,33 +435,42 @@
playing.mToken, (wct, cb) -> onFinish(merging.mToken, wct, cb));
}
- boolean startAnimation(@NonNull ActiveTransition active, TransitionHandler handler) {
- return handler.startAnimation(active.mToken, active.mInfo, active.mStartT, active.mFinishT,
- (wct, cb) -> onFinish(active.mToken, wct, cb));
- }
-
- void playTransition(@NonNull ActiveTransition active) {
+ private void playTransition(@NonNull ActiveTransition active) {
setupAnimHierarchy(active.mInfo, active.mStartT, active.mFinishT);
// If a handler already chose to run this animation, try delegating to it first.
if (active.mHandler != null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try firstHandler %s",
active.mHandler);
- if (startAnimation(active, active.mHandler)) {
+ boolean consumed = active.mHandler.startAnimation(active.mToken, active.mInfo,
+ active.mStartT, active.mFinishT, (wct, cb) -> onFinish(active.mToken, wct, cb));
+ if (consumed) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " animated by firstHandler");
return;
}
}
- // Otherwise give every other handler a chance (in order)
+ // Otherwise give every other handler a chance
+ active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
+ active.mFinishT, (wct, cb) -> onFinish(active.mToken, wct, cb), active.mHandler);
+ }
+
+ /**
+ * Gives every handler (in order) a chance to animate until one consumes the transition.
+ * @return the handler which consumed the transition.
+ */
+ TransitionHandler dispatchTransition(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT,
+ @NonNull TransitionFinishCallback finishCB, @Nullable TransitionHandler skip) {
for (int i = mHandlers.size() - 1; i >= 0; --i) {
- if (mHandlers.get(i) == active.mHandler) continue;
+ if (mHandlers.get(i) == skip) continue;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try handler %s",
mHandlers.get(i));
- if (startAnimation(active, mHandlers.get(i))) {
+ boolean consumed = mHandlers.get(i).startAnimation(transition, info, startT, finishT,
+ finishCB);
+ if (consumed) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " animated by %s",
mHandlers.get(i));
- active.mHandler = mHandlers.get(i);
- return;
+ return mHandlers.get(i);
}
}
throw new IllegalStateException(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index a55f737..0e39527 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -334,7 +334,7 @@
TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
info.addChange(mainChange);
info.addChange(sideChange);
- IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
+ IBinder transition = mSplitScreenTransitions.startDismissTransition(
new WindowContainerTransaction(), mStageCoordinator,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, STAGE_TYPE_SIDE);
boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -356,7 +356,7 @@
TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
info.addChange(mainChange);
info.addChange(sideChange);
- IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
+ IBinder transition = mSplitScreenTransitions.startDismissTransition(
new WindowContainerTransaction(), mStageCoordinator, EXIT_REASON_DRAG_DIVIDER,
STAGE_TYPE_SIDE);
mMainStage.onTaskVanished(mMainChild);
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_off.xml
new file mode 100644
index 0000000..538f328
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_off.xml
@@ -0,0 +1,725 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="7.062"
+ android:valueTo="8.578"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateX"
+ android:startOffset="28"
+ android:valueFrom="8.578"
+ android:valueTo="-1.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateX"
+ android:startOffset="248"
+ android:valueFrom="-1.789"
+ android:valueTo="-7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="3.312"
+ android:valueTo="2.016"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateY"
+ android:startOffset="28"
+ android:valueFrom="2.016"
+ android:valueTo="-8.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateY"
+ android:startOffset="248"
+ android:valueFrom="-8.789"
+ android:valueTo="-3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="180"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="rotation"
+ android:startOffset="28"
+ android:valueFrom="90"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="rotation"
+ android:startOffset="193"
+ android:valueFrom="90"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-135"
+ android:valueTo="-180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="-7"
+ android:valueTo="-8.859"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateX"
+ android:startOffset="28"
+ android:valueFrom="-8.859"
+ android:valueTo="1.69"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateX"
+ android:startOffset="248"
+ android:valueFrom="1.69"
+ android:valueTo="7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="-3.594"
+ android:valueTo="-1.922"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="221"
+ android:propertyName="translateY"
+ android:startOffset="28"
+ android:valueFrom="-1.922"
+ android:valueTo="8.627"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="translateY"
+ android:startOffset="248"
+ android:valueFrom="8.627"
+ android:valueTo="3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="360"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="rotation"
+ android:startOffset="28"
+ android:valueFrom="270"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="rotation"
+ android:startOffset="193"
+ android:valueFrom="270"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="rotation"
+ android:startOffset="248"
+ android:valueFrom="180"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-135"
+ android:valueTo="-180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="66"
+ android:propertyName="pathData"
+ android:startOffset="28"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="72"
+ android:propertyName="pathData"
+ android:startOffset="94"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="166"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="pathData"
+ android:startOffset="193"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="290"
+ android:valueFrom="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueTo="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="pathData"
+ android:startOffset="317"
+ android:valueFrom="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueTo="M5.94 -2.52 C5.94,-2.52 5.94,-2.51 5.94,-2.51 C5.94,-2.51 5.93,-2.52 5.93,-2.52 C5.93,-2.52 4.53,-1.12 4.53,-1.12 C4.53,-1.12 4.55,-1.11 4.55,-1.11 C4.55,-1.11 4.53,-1.13 4.53,-1.13 C4.53,-1.13 4.55,-1.09 4.55,-1.09 C4.55,-1.09 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 5.94,-2.52 5.94,-2.52 C5.94,-2.52 5.94,-2.52 5.94,-2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="66"
+ android:propertyName="pathData"
+ android:startOffset="28"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="72"
+ android:propertyName="pathData"
+ android:startOffset="94"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="166"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="55"
+ android:propertyName="pathData"
+ android:startOffset="193"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="290"
+ android:valueFrom="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueTo="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="pathData"
+ android:startOffset="317"
+ android:valueFrom="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueTo="M-5.94 2.52 C-5.94,2.52 -5.94,2.51 -5.94,2.51 C-5.94,2.51 -5.93,2.52 -5.93,2.52 C-5.93,2.52 -4.53,1.12 -4.53,1.12 C-4.53,1.12 -4.55,1.11 -4.55,1.11 C-4.55,1.11 -4.53,1.13 -4.53,1.13 C-4.53,1.13 -4.55,1.09 -4.55,1.09 C-4.55,1.09 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -5.94,2.52 -5.94,2.52 C-5.94,2.52 -5.94,2.52 -5.94,2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="61"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="61"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="143"
+ android:propertyName="pathData"
+ android:startOffset="88"
+ android:valueFrom="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueTo="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="232"
+ android:valueFrom="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueTo="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueTo="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -8.52,-3.53 -8.52,-3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="61"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="28"
+ android:propertyName="pathData"
+ android:startOffset="61"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="143"
+ android:propertyName="pathData"
+ android:startOffset="88"
+ android:valueFrom="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueTo="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="232"
+ android:valueFrom="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueTo="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="418"
+ android:propertyName="pathData"
+ android:startOffset="248"
+ android:valueFrom="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueTo="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 8.52,3.53 8.52,3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-135"
+ android:valueTo="-180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="683"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G_N_1_T_0"
+ android:rotation="-135"
+ android:translateX="12.008"
+ android:translateY="11.992">
+ <group
+ android:name="_R_G_L_2_G_T_1"
+ android:rotation="180"
+ android:translateX="7.062"
+ android:translateY="3.312">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_1_T_0"
+ android:rotation="-135"
+ android:translateX="12.008"
+ android:translateY="11.992">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:rotation="360"
+ android:translateX="-7"
+ android:translateY="-3.594">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:rotation="-135"
+ android:translateX="12.008"
+ android:translateY="11.992">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c " />
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_on.xml
new file mode 100644
index 0000000..bd67d9f
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_auto_rotate_icon_on.xml
@@ -0,0 +1,781 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="367"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -6.08,2.36 -6.08,2.36 C-6.08,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 7.49,1.78 7.49,1.78 C7.49,1.78 8.87,0.41 8.87,0.41 C8.87,0.41 8.95,0.5 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="45"
+ android:propertyName="pathData"
+ android:startOffset="59"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -2.78,5.89 -2.78,5.89 C-2.78,5.89 -1.29,4.47 -1.29,4.47 C-1.29,4.47 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="103"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 0.36,8.83 0.36,8.83 C0.36,8.83 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="pathData"
+ android:startOffset="121"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 3.22,8.8 3.22,8.8 C3.22,8.8 3.21,8.79 3.21,8.79 C3.21,8.79 3.24,8.8 3.24,8.8 C3.24,8.8 1.8,7.44 1.8,7.44 C1.8,7.44 1.78,7.42 1.78,7.42 C1.78,7.42 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="26"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M8.82 3.18 C8.26,3.74 5.82,6.14 5.82,6.14 C5.82,6.14 5.81,6.14 5.81,6.14 C5.81,6.14 5.83,6.14 5.83,6.14 C5.83,6.14 4.39,4.78 4.39,4.78 C4.39,4.78 4.37,4.76 4.37,4.76 C4.37,4.76 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.7,2.29 8.82,3.18c "
+ android:valueTo="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="181"
+ android:valueFrom="M8.91 3.09 C8.91,3.09 8.91,3.1 8.91,3.1 C8.91,3.1 8.9,3.09 8.9,3.09 C8.9,3.09 7.49,1.74 7.49,1.74 C7.49,1.74 7.5,1.75 7.5,1.75 C7.5,1.75 7.48,1.73 7.48,1.73 C7.48,1.73 7.5,1.77 7.5,1.77 C7.5,1.77 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 8.36,-0.12 9.05,0.58 C9.86,1.4 9.79,2.2 8.91,3.09c "
+ android:valueTo="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="52"
+ android:propertyName="pathData"
+ android:startOffset="198"
+ android:valueFrom="M9.05 0.57 C9.05,0.57 9.05,0.58 9.05,0.58 C9.05,0.58 9.04,0.57 9.04,0.57 C9.04,0.57 7.6,1.83 7.6,1.83 C7.6,1.83 7.61,1.85 7.61,1.85 C7.61,1.85 7.59,1.83 7.59,1.83 C7.59,1.83 7.61,1.86 7.61,1.86 C7.61,1.86 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 9.05,0.58 9.05,0.58 C9.05,0.58 9.05,0.57 9.05,0.57c "
+ android:valueTo="M5.94 -2.52 C5.94,-2.52 5.94,-2.51 5.94,-2.51 C5.94,-2.51 5.93,-2.52 5.93,-2.52 C5.93,-2.52 4.53,-1.12 4.53,-1.12 C4.53,-1.12 4.55,-1.11 4.55,-1.11 C4.55,-1.11 4.53,-1.13 4.53,-1.13 C4.53,-1.13 4.55,-1.09 4.55,-1.09 C4.55,-1.09 4.54,-1.11 4.54,-1.11 C4.54,-1.11 5.95,-2.51 5.95,-2.51 C5.95,-2.51 5.94,-2.52 5.94,-2.52 C5.94,-2.52 5.94,-2.52 5.94,-2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="367"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="41"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 6.08,-2.36 6.08,-2.36 C6.08,-2.36 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -7.49,-1.78 -7.49,-1.78 C-7.49,-1.78 -8.87,-0.41 -8.87,-0.41 C-8.87,-0.41 -8.95,-0.5 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="45"
+ android:propertyName="pathData"
+ android:startOffset="59"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 2.78,-5.89 2.78,-5.89 C2.78,-5.89 1.29,-4.47 1.29,-4.47 C1.29,-4.47 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="103"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 -0.36,-8.83 -0.36,-8.83 C-0.36,-8.83 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="pathData"
+ android:startOffset="121"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -3.22,-8.8 -3.22,-8.8 C-3.22,-8.8 -3.21,-8.79 -3.21,-8.79 C-3.21,-8.79 -3.24,-8.8 -3.24,-8.8 C-3.24,-8.8 -1.8,-7.44 -1.8,-7.44 C-1.8,-7.44 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="26"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M-8.82 -3.18 C-8.26,-3.74 -5.81,-6.14 -5.81,-6.14 C-5.81,-6.14 -5.81,-6.13 -5.81,-6.13 C-5.81,-6.13 -5.83,-6.14 -5.83,-6.14 C-5.83,-6.14 -4.39,-4.78 -4.39,-4.78 C-4.39,-4.78 -4.37,-4.76 -4.37,-4.76 C-4.37,-4.76 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.7,-2.29 -8.82,-3.18c "
+ android:valueTo="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="181"
+ android:valueFrom="M-8.91 -3.09 C-8.91,-3.09 -8.91,-3.09 -8.91,-3.09 C-8.91,-3.09 -8.9,-3.09 -8.9,-3.09 C-8.9,-3.09 -7.49,-1.74 -7.49,-1.74 C-7.49,-1.74 -7.5,-1.75 -7.5,-1.75 C-7.5,-1.75 -7.48,-1.73 -7.48,-1.73 C-7.48,-1.73 -7.5,-1.77 -7.5,-1.77 C-7.5,-1.77 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -8.36,0.12 -9.05,-0.58 C-9.86,-1.4 -9.79,-2.2 -8.91,-3.09c "
+ android:valueTo="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="52"
+ android:propertyName="pathData"
+ android:startOffset="198"
+ android:valueFrom="M-9.05 -0.57 C-9.05,-0.57 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.04,-0.57 -9.04,-0.57 C-9.04,-0.57 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.85 -7.61,-1.85 C-7.61,-1.85 -7.59,-1.83 -7.59,-1.83 C-7.59,-1.83 -7.61,-1.86 -7.61,-1.86 C-7.61,-1.86 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -9.05,-0.58 -9.05,-0.58 C-9.05,-0.58 -9.05,-0.57 -9.05,-0.57c "
+ android:valueTo="M-5.94 2.52 C-5.94,2.52 -5.94,2.51 -5.94,2.51 C-5.94,2.51 -5.93,2.52 -5.93,2.52 C-5.93,2.52 -4.53,1.12 -4.53,1.12 C-4.53,1.12 -4.55,1.11 -4.55,1.11 C-4.55,1.11 -4.53,1.13 -4.53,1.13 C-4.53,1.13 -4.55,1.09 -4.55,1.09 C-4.55,1.09 -4.54,1.11 -4.54,1.11 C-4.54,1.11 -5.95,2.51 -5.95,2.51 C-5.95,2.51 -5.94,2.52 -5.94,2.52 C-5.94,2.52 -5.94,2.52 -5.94,2.52c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="38"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="38"
+ android:valueFrom="M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c "
+ android:valueTo="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="90"
+ android:propertyName="pathData"
+ android:startOffset="55"
+ android:valueFrom="M6.15 -2.35 C6.15,-2.35 6.15,-2.35 6.15,-2.35 C6.16,-2.34 6.15,-2.35 6.16,-2.35 C6.16,-2.35 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 4.72,-0.93 4.72,-0.93 C4.72,-0.93 4.7,-0.94 4.7,-0.94 C4.7,-0.94 6.15,-2.35 6.15,-2.35c "
+ android:valueTo="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="10"
+ android:propertyName="pathData"
+ android:startOffset="145"
+ android:valueFrom="M-0.65 -9.12 C-0.65,-9.12 -0.66,-9.13 -0.66,-9.13 C-0.65,-9.12 -0.66,-9.12 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -0.65,-9.12 -0.65,-9.12c "
+ android:valueTo="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M-3.21 -8.85 C-3.21,-8.85 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -1.8,-7.43 -1.8,-7.43 C-1.8,-7.43 -3.21,-8.85 -3.21,-8.85c "
+ android:valueTo="M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.94 7.53,-0.94 C7.53,-0.94 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -8.52,-3.53 -8.52,-3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="38"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="38"
+ android:valueFrom="M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c "
+ android:valueTo="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="90"
+ android:propertyName="pathData"
+ android:startOffset="55"
+ android:valueFrom="M-6.15 2.35 C-6.15,2.35 -6.15,2.35 -6.15,2.35 C-6.16,2.34 -6.15,2.35 -6.15,2.35 C-6.15,2.35 -6.14,2.36 -6.14,2.36 C-6.14,2.36 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -4.72,0.93 -4.72,0.93 C-4.72,0.93 -4.7,0.94 -4.7,0.94 C-4.7,0.94 -6.15,2.35 -6.15,2.35c "
+ android:valueTo="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="10"
+ android:propertyName="pathData"
+ android:startOffset="145"
+ android:valueFrom="M0.65 9.12 C0.65,9.12 0.66,9.13 0.66,9.13 C0.65,9.12 0.66,9.13 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 0.65,9.12 0.65,9.12c "
+ android:valueTo="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="pathData"
+ android:startOffset="155"
+ android:valueFrom="M3.21 8.85 C3.21,8.85 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 1.8,7.43 1.8,7.43 C1.8,7.43 3.21,8.85 3.21,8.85c "
+ android:valueTo="M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 8.52,3.53 8.52,3.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="-7"
+ android:valueTo="-8.859"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateX"
+ android:startOffset="17"
+ android:valueFrom="-8.859"
+ android:valueTo="1.734"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateX"
+ android:startOffset="155"
+ android:valueFrom="1.734"
+ android:valueTo="7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="-3.594"
+ android:valueTo="-1.922"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateY"
+ android:startOffset="17"
+ android:valueFrom="-1.922"
+ android:valueTo="8.671"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateY"
+ android:startOffset="155"
+ android:valueFrom="8.671"
+ android:valueTo="3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="360"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="103"
+ android:propertyName="rotation"
+ android:startOffset="17"
+ android:valueFrom="270"
+ android:valueTo="270"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="rotation"
+ android:startOffset="121"
+ android:valueFrom="270"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="rotation"
+ android:startOffset="155"
+ android:valueFrom="180"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="7.062"
+ android:valueTo="8.578"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateX"
+ android:startOffset="17"
+ android:valueFrom="8.578"
+ android:valueTo="-1.656"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateX"
+ android:startOffset="155"
+ android:valueFrom="-1.656"
+ android:valueTo="-7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="3.312"
+ android:valueTo="2.016"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="138"
+ android:propertyName="translateY"
+ android:startOffset="17"
+ android:valueFrom="2.016"
+ android:valueTo="-8.656"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="261"
+ android:propertyName="translateY"
+ android:startOffset="155"
+ android:valueFrom="-8.656"
+ android:valueTo="-3.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="180"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="103"
+ android:propertyName="rotation"
+ android:startOffset="17"
+ android:valueFrom="90"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="34"
+ android:propertyName="rotation"
+ android:startOffset="121"
+ android:valueFrom="90"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="367"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="433"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:rotation="0"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M8.52 3.53 C8.52,3.53 2.94,9.08 2.94,9.08 C2.3,9.72 1.27,9.74 0.65,9.12 C0.65,9.12 -7.53,0.95 -7.53,0.95 C-7.53,0.95 -4.7,0.94 -4.7,0.94 C-4.7,0.94 1.78,7.42 1.78,7.42 C1.78,7.42 7.11,2.11 7.11,2.11 C7.11,2.11 7.14,2.14 7.14,2.14 C7.14,2.14 8.48,3.49 8.48,3.49 C8.48,3.49 8.5,3.51 8.5,3.51 C8.5,3.51 8.52,3.53 8.52,3.53c " />
+ <path
+ android:name="_R_G_L_2_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-8.52 -3.53 C-8.52,-3.53 -2.94,-9.08 -2.94,-9.08 C-2.3,-9.72 -1.27,-9.74 -0.65,-9.12 C-0.65,-9.12 7.53,-0.95 7.53,-0.95 C7.53,-0.95 4.7,-0.94 4.7,-0.94 C4.7,-0.94 -1.78,-7.42 -1.78,-7.42 C-1.78,-7.42 -7.11,-2.11 -7.11,-2.11 C-7.11,-2.11 -7.14,-2.14 -7.14,-2.14 C-7.14,-2.14 -8.48,-3.49 -8.48,-3.49 C-8.48,-3.49 -8.5,-3.51 -8.5,-3.51 C-8.5,-3.51 -8.52,-3.53 -8.52,-3.53c " />
+ <path
+ android:name="_R_G_L_2_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M7.54 -0.94 C7.54,-0.94 7.54,-0.95 7.54,-0.95 C7.55,-0.94 7.54,-0.94 7.55,-0.94 C7.55,-0.94 7.53,-0.94 7.53,-0.94 C7.53,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94 C7.54,-0.94 7.52,-0.94 7.52,-0.94 C7.52,-0.94 7.54,-0.94 7.54,-0.94c " />
+ <path
+ android:name="_R_G_L_2_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-7.54 0.94 C-7.54,0.94 -7.54,0.95 -7.54,0.95 C-7.55,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.53,0.94 -7.53,0.94 C-7.53,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94 C-7.54,0.94 -7.52,0.94 -7.52,0.94 C-7.52,0.94 -7.54,0.94 -7.54,0.94c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:rotation="0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:rotation="360"
+ android:translateX="-7"
+ android:translateY="-3.594">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:rotation="0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:rotation="180"
+ android:translateX="7.062"
+ android:translateY="3.312">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="6.984"
+ android:translateY="3.547">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-4.6 -1.06 C-4.6,-1.06 -9.55,-1.06 -9.55,-1.06 C-9.55,-1.06 -9.55,-6.01 -9.55,-6.01 C-9.55,-6.01 -7.55,-6 -7.55,-6 C-7.55,-6 -7.51,-3.04 -7.51,-3.04 C-7.51,-3.04 -4.6,-3.05 -4.6,-3.05 C-4.6,-3.05 -4.6,-1.06 -4.6,-1.06c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_off.xml
new file mode 100644
index 0000000..17a7611
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_off.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-1 6.17 C-1,6.17 0.88,4.29 0.88,4.29 C0.88,4.29 -1,2.41 -1,2.41 C-1,2.41 -1,6.17 -1,6.17c M0.88 -4.29 C0.88,-4.29 -1,-6.17 -1,-6.17 C-1,-6.17 -1,-2.41 -1,-2.41 C-1,-2.41 0.88,-4.29 0.88,-4.29c M-2 -10 C-2,-10 3.71,-4.29 3.71,-4.29 C3.71,-4.29 -0.59,0 -0.59,0 C-0.59,0 3.71,4.29 3.71,4.29 C3.71,4.29 -2,10 -2,10 C-2,10 -3,10 -3,10 C-3,10 -3,2.41 -3,2.41 C-3,2.41 -7.59,7 -7.59,7 C-7.59,7 -9.01,5.59 -9.01,5.59 C-9.01,5.59 -3.41,0 -3.41,0 C-3.41,0 -9.01,-5.59 -9.01,-5.59 C-9.01,-5.59 -7.59,-7 -7.59,-7 C-7.59,-7 -3,-2.41 -3,-2.41 C-3,-2.41 -3,-10 -3,-10 C-3,-10 -2,-10 -2,-10c "/>
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="14.125"
+ android:translateY="12"
+ android:pivotX="-9.109"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-9.09 -1.5 C-8.26,-1.5 -7.59,-0.83 -7.59,0 C-7.59,0.83 -8.26,1.5 -9.09,1.5 C-9.91,1.5 -10.59,0.83 -10.59,0 C-10.59,-0.83 -9.91,-1.5 -9.09,-1.5c "/>
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="14.125"
+ android:translateY="12"
+ android:pivotX="4.875"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M4.92 -1.5 C5.75,-1.5 6.42,-0.83 6.42,0 C6.42,0.83 5.75,1.5 4.92,1.5 C4.09,1.5 3.42,0.83 3.42,0 C3.42,-0.83 4.09,-1.5 4.92,-1.5c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr
+ name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_on.xml
new file mode 100644
index 0000000..2dba48c
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_on.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="267"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-1 6.17 C-1,6.17 0.88,4.29 0.88,4.29 C0.88,4.29 -1,2.41 -1,2.41 C-1,2.41 -1,6.17 -1,6.17c M0.88 -4.29 C0.88,-4.29 -1,-6.17 -1,-6.17 C-1,-6.17 -1,-2.41 -1,-2.41 C-1,-2.41 0.88,-4.29 0.88,-4.29c M-2 -10 C-2,-10 3.71,-4.29 3.71,-4.29 C3.71,-4.29 -0.59,0 -0.59,0 C-0.59,0 3.71,4.29 3.71,4.29 C3.71,4.29 -2,10 -2,10 C-2,10 -3,10 -3,10 C-3,10 -3,2.41 -3,2.41 C-3,2.41 -7.59,7 -7.59,7 C-7.59,7 -9.01,5.59 -9.01,5.59 C-9.01,5.59 -3.41,0 -3.41,0 C-3.41,0 -9.01,-5.59 -9.01,-5.59 C-9.01,-5.59 -7.59,-7 -7.59,-7 C-7.59,-7 -3,-2.41 -3,-2.41 C-3,-2.41 -3,-10 -3,-10 C-3,-10 -2,-10 -2,-10c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="-9.109"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-9.09 -1.5 C-8.26,-1.5 -7.59,-0.83 -7.59,0 C-7.59,0.83 -8.26,1.5 -9.09,1.5 C-9.91,1.5 -10.59,0.83 -10.59,0 C-10.59,-0.83 -9.91,-1.5 -9.09,-1.5c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="4.875"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M4.92 -1.5 C5.75,-1.5 6.42,-0.83 6.42,0 C6.42,0.83 5.75,1.5 4.92,1.5 C4.09,1.5 3.42,0.83 3.42,0 C3.42,-0.83 4.09,-1.5 4.92,-1.5c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_search.xml b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_search.xml
new file mode 100644
index 0000000..3697769
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_bluetooth_icon_search.xml
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="500"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="500"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1017"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="14.125"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-1 6.17 C-1,6.17 0.88,4.29 0.88,4.29 C0.88,4.29 -1,2.41 -1,2.41 C-1,2.41 -1,6.17 -1,6.17c M0.88 -4.29 C0.88,-4.29 -1,-6.17 -1,-6.17 C-1,-6.17 -1,-2.41 -1,-2.41 C-1,-2.41 0.88,-4.29 0.88,-4.29c M-2 -10 C-2,-10 3.71,-4.29 3.71,-4.29 C3.71,-4.29 -0.59,0 -0.59,0 C-0.59,0 3.71,4.29 3.71,4.29 C3.71,4.29 -2,10 -2,10 C-2,10 -3,10 -3,10 C-3,10 -3,2.41 -3,2.41 C-3,2.41 -7.59,7 -7.59,7 C-7.59,7 -9.01,5.59 -9.01,5.59 C-9.01,5.59 -3.41,0 -3.41,0 C-3.41,0 -9.01,-5.59 -9.01,-5.59 C-9.01,-5.59 -7.59,-7 -7.59,-7 C-7.59,-7 -3,-2.41 -3,-2.41 C-3,-2.41 -3,-10 -3,-10 C-3,-10 -2,-10 -2,-10c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M4.56 2.33 C4.56,2.33 2.24,0.01 2.24,0.01 C2.24,0.01 4.57,-2.31 4.57,-2.31 C4.84,-1.59 5,-0.82 5,0 C5,0.82 4.84,1.61 4.56,2.33c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M6.27 -4.03 C6.27,-4.03 7.53,-5.29 7.53,-5.29 C8.46,-3.77 9,-1.99 9.01,-0.1 C9.01,1.85 8.44,3.67 7.47,5.21 C7.47,5.21 6.27,4.01 6.27,4.01 C6.89,2.81 7.25,1.44 7.25,-0.01 C7.25,-1.46 6.9,-2.82 6.27,-4.03c " />
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-8.6 -2.33 C-8.6,-2.33 -6.28,-0.01 -6.28,-0.01 C-6.28,-0.01 -8.61,2.31 -8.61,2.31 C-8.88,1.59 -9.04,0.82 -9.04,0 C-9.04,-0.82 -8.88,-1.61 -8.6,-2.33c " />
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-10.31 4.03 C-10.31,4.03 -11.57,5.29 -11.57,5.29 C-12.5,3.77 -13.04,1.99 -13.05,0.1 C-13.05,-1.85 -12.48,-3.67 -11.51,-5.21 C-11.51,-5.21 -10.31,-4.01 -10.31,-4.01 C-10.93,-2.81 -11.29,-1.44 -11.29,0.01 C-11.29,1.46 -10.94,2.82 -10.31,4.03c " />
+ <path
+ android:name="_R_G_L_0_G_D_5_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M-9.09 0 C-9.09,0 -9.09,0 -9.09,0 C-9.09,0 -9.09,0 -9.09,0 C-9.09,0 -9.09,0 -9.09,0 C-9.09,0 -9.09,0 -9.09,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_6_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M4.92 0 C4.92,0 4.92,0 4.92,0 C4.92,0 4.92,0 4.92,0 C4.92,0 4.92,0 4.92,0 C4.92,0 4.92,0 4.92,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f2ddf9e..fb04bfd 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -441,6 +441,9 @@
they were added. -->
<integer name="config_smart_replies_in_notifications_onclick_init_delay">200</integer>
+ <!-- Smartspace trampoline activity that is used when the user taps smartspace. -->
+ <string name="config_smartspaceTrampolineActivityComponent" translatable="false">com.google.android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity</string>
+
<!-- Screenshot editing default activity. Must handle ACTION_EDIT image/png intents.
Blank sends the user to the Chooser first.
This name is in the ComponentName flattened format (package/class) -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 9cf482f..4ce110b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -17,7 +17,6 @@
package com.android.systemui.shared.system;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
-import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -32,7 +31,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.util.ArrayMap;
-import android.util.IntArray;
import android.util.SparseArray;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -142,21 +140,10 @@
// changes should be ordered top-to-bottom in z
final int mode = change.getMode();
- // Don't move anything that isn't independent within its parents
- if (!TransitionInfo.isIndependent(change, info)) {
- if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
- t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
- }
- return;
- }
+ t.reparent(leash, info.getRootLeash());
+ t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
+ change.getStartAbsBounds().top - info.getRootOffset().y);
- final boolean hasParent = change.getParent() != null;
-
- if (!hasParent) {
- t.reparent(leash, info.getRootLeash());
- t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
- change.getStartAbsBounds().top - info.getRootOffset().y);
- }
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
@@ -196,8 +183,7 @@
.setContainerLayer()
// Initial the surface visible to respect the visibility of the original surface.
.setHidden(false)
- .setParent(change.getParent() == null ? info.getRootLeash()
- : info.getChange(change.getParent()).getLeash())
+ .setParent(info.getRootLeash())
.build();
// Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
@@ -269,58 +255,32 @@
public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
- final SparseArray<RemoteAnimationTargetCompat> childTaskTargets = new SparseArray<>();
- final IntArray excludedParentTaskIds = new IntArray();
+ final SparseArray<TransitionInfo.Change> childTaskTargets = new SparseArray<>();
for (int i = 0; i < info.getChanges().size(); i++) {
final TransitionInfo.Change change = info.getChanges().get(i);
final boolean changeIsWallpaper =
(change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
if (wallpapers != changeIsWallpaper) continue;
+ if (!wallpapers) {
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ // Children always come before parent since changes are in top-to-bottom z-order.
+ if (taskInfo != null) {
+ if (childTaskTargets.contains(taskInfo.taskId)) {
+ // has children, so not a leaf. Skip.
+ continue;
+ }
+ if (taskInfo.hasParentTask()) {
+ childTaskTargets.put(taskInfo.parentTaskId, change);
+ }
+ }
+ }
+
final RemoteAnimationTargetCompat targetCompat =
new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t);
if (leashMap != null) {
leashMap.put(change.getLeash(), targetCompat.leash);
}
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo != null) {
- // Skip wrapping excluded parent task animate target since it will animate its child
- // tasks instead.
- if (excludedParentTaskIds.binarySearch(taskInfo.taskId) != -1) {
- continue;
- }
-
- // Check if there's a matching child task target in cache.
- RemoteAnimationTargetCompat childTaskTarget = childTaskTargets.get(taskInfo.taskId);
- if (childTaskTarget != null) {
- // Launcher monitors leaf task ids to perform animation, override the target
- // with its child task information so Launcher can animate this parent surface
- // directly with leaf task information.
- targetCompat.taskInfo = childTaskTarget.taskInfo;
- targetCompat.taskId = childTaskTarget.taskId;
- childTaskTargets.remove(taskInfo.taskId);
- }
-
- // Check if it has a parent task, cache its information for later use.
- if (taskInfo.parentTaskId != -1
- && excludedParentTaskIds.binarySearch(taskInfo.parentTaskId) == -1) {
- if (!childTaskTargets.contains(taskInfo.parentTaskId)) {
- // Cache the target amd skip wrapping it info the final animation targets.
- // Otherwise, the child task might get transformed multiple-times with the
- // flow like RecentsView#redrawLiveTile.
- childTaskTargets.put(taskInfo.parentTaskId, targetCompat);
- continue;
- }
-
- // There is another child task target cached with the same parent task id.
- // Which means the parent having multiple child tasks in transition. Stop
- // propagate child task info.
- childTaskTarget = childTaskTargets.removeReturnOld(taskInfo.parentTaskId);
- out.add(childTaskTarget);
- excludedParentTaskIds.add(taskInfo.parentTaskId);
- }
- }
-
out.add(targetCompat);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index de35514..d7f8235 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -27,6 +27,7 @@
import static android.window.TransitionFilter.CONTAINER_ORDER_TOP;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -132,16 +133,17 @@
// TODO(b/177438007): Move this set-up logic into launcher's animation impl.
mToken = transition;
// This transition is for opening recents, so recents is on-top. We want to draw
- // the current going-away task on top of recents, though, so move it to front
+ // the current going-away tasks on top of recents, though, so move them to front.
+ // Note that we divide up the "layer space" into 3 regions each the size of
+ // the change count. This way we can easily move changes into above/below/between
+ // while maintaining their relative ordering.
final ArrayList<WindowContainerToken> pausingTasks = new ArrayList<>();
WindowContainerToken pipTask = null;
WindowContainerToken recentsTask = null;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) {
- t.setLayer(leashMap.get(change.getLeash()),
- info.getChanges().size() * 3 - i);
+ for (int i = apps.length - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo taskInfo = apps[i].taskInfo;
+ if (apps[i].mode == MODE_CLOSING) {
+ t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
if (taskInfo == null) {
continue;
}
@@ -154,8 +156,7 @@
} else if (taskInfo != null
&& taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
// This task is for recents, keep it on top.
- t.setLayer(leashMap.get(change.getLeash()),
- info.getChanges().size() * 3 - i);
+ t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
recentsTask = taskInfo.token;
} else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
recentsTask = taskInfo.token;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
index f5c5a43..3d1bc59b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
@@ -18,10 +18,12 @@
import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS;
import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT;
import android.app.smartspace.SmartspaceAction;
import android.app.smartspace.SmartspaceTarget;
import android.content.Context;
+import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
@@ -31,6 +33,7 @@
import com.android.systemui.R;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.util.ViewController;
@@ -132,15 +135,21 @@
*/
static class DreamWeatherViewController extends ViewController<TextView> {
private final LockscreenSmartspaceController mSmartSpaceController;
+ private final ActivityStarter mActivityStarter;
+ private final String mSmartspaceTrampolineActivityComponent;
private SmartspaceTargetListener mSmartspaceTargetListener;
@Inject
DreamWeatherViewController(
@Named(DREAM_WEATHER_COMPLICATION_VIEW) TextView view,
+ @Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT) String smartspaceTrampoline,
+ ActivityStarter activityStarter,
LockscreenSmartspaceController smartspaceController
) {
super(view);
+ mActivityStarter = activityStarter;
mSmartSpaceController = smartspaceController;
+ mSmartspaceTrampolineActivityComponent = smartspaceTrampoline;
}
@Override
@@ -172,6 +181,15 @@
R.dimen.smart_action_button_icon_padding));
}
+ mView.setOnClickListener(v -> {
+ final Intent intent = headerAction.getIntent();
+ if (intent != null && intent.getComponent() != null
+ && intent.getComponent().getClassName()
+ .equals(mSmartspaceTrampolineActivityComponent)) {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ intent, 0 /*delay*/);
+ }
+ });
}
});
mSmartSpaceController.addListener(mSmartspaceTargetListener);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
index 536f3dc..a1660f2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java
@@ -19,6 +19,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;
@@ -76,6 +77,7 @@
String DREAM_WEATHER_COMPLICATION_VIEW = "weather_complication_view";
String DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS =
"weather_complication_layout_params";
+ String SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT = "smartspace_trampoline_activity";
// Order weight of insert into parent container
int INSERT_ORDER_WEIGHT = 1;
@@ -106,5 +108,15 @@
ComplicationLayoutParams.DIRECTION_END,
INSERT_ORDER_WEIGHT);
}
+
+ /**
+ * Provides the smartspace trampoline activity component.
+ */
+ @Provides
+ @DreamWeatherComplicationScope
+ @Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT)
+ static String provideSmartspaceTrampolineActivityComponent(Context context) {
+ return context.getString(R.string.config_smartspaceTrampolineActivityComponent);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index c147fde..517fce1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -144,6 +144,8 @@
private void setPanelExpansion(float expansion) {
mCurrentExpansion = expansion;
+ mCentralSurfaces.setBouncerShowingOverDream(
+ mCurrentExpansion != KeyguardBouncer.EXPANSION_HIDDEN);
mStatusBarKeyguardViewManager.onPanelExpansionChanged(mCurrentExpansion, false, true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 44580aa..d71782d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -156,6 +156,8 @@
// 1000 - dock
public static final BooleanFlag SIMULATE_DOCK_THROUGH_CHARGING =
new BooleanFlag(1000, true);
+ public static final BooleanFlag DOCK_SETUP_ENABLED = new BooleanFlag(1001, false);
+
// 1100 - windowing
@Keep
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index cd695bb..8878c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -317,7 +317,7 @@
};
private final Consumer<Boolean> mNavbarOverlayVisibilityChangeCallback = (visible) -> {
- if (visible) {
+ if (visible && mAutoHideController != null) {
mAutoHideController.touchAutoHide();
}
notifyActiveTouchRegions();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index f736231..da5202b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -19,9 +19,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
@@ -134,9 +132,10 @@
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth);
state.stateDescription = "";
+
if (enabled) {
if (connected) {
- state.icon = new BluetoothConnectedTileIcon();
+ state.icon = ResourceIcon.get(R.drawable.qs_bluetooth_icon_on);
if (!TextUtils.isEmpty(mController.getConnectedDeviceName())) {
state.label = mController.getConnectedDeviceName();
}
@@ -145,21 +144,19 @@
+ ", " + state.secondaryLabel;
} else if (state.isTransient) {
state.icon = ResourceIcon.get(
- com.android.internal.R.drawable.ic_bluetooth_transient_animation);
+ R.drawable.qs_bluetooth_icon_search);
state.stateDescription = state.secondaryLabel;
} else {
state.icon =
- ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
+ ResourceIcon.get(R.drawable.qs_bluetooth_icon_off);
state.stateDescription = mContext.getString(R.string.accessibility_not_connected);
}
state.state = Tile.STATE_ACTIVE;
} else {
- state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
+ state.icon = ResourceIcon.get(R.drawable.qs_bluetooth_icon_off);
state.state = Tile.STATE_INACTIVE;
}
- state.dualLabelContentDescription = mContext.getResources().getString(
- R.string.accessibility_quick_settings_open_settings, getTileLabel());
state.expandedAccessibilityClassName = Switch.class.getName();
}
@@ -244,22 +241,4 @@
refreshState();
}
};
-
- /**
- * Bluetooth icon wrapper (when connected with no battery indicator) for Quick Settings. This is
- * used instead of {@link com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon} in order to
- * use a context that reflects dark/light theme attributes.
- */
- private class BluetoothConnectedTileIcon extends Icon {
-
- BluetoothConnectedTileIcon() {
- // Do nothing. Default constructor to limit visibility.
- }
-
- @Override
- public Drawable getDrawable(Context context) {
- // This method returns Pair<Drawable, String> - the first value is the drawable.
- return context.getDrawable(R.drawable.ic_bluetooth_connected);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 5e81b5d..a1dbf0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -468,6 +468,7 @@
*/
protected int mState; // TODO: remove this. Just use StatusBarStateController
protected boolean mBouncerShowing;
+ private boolean mBouncerShowingOverDream;
private final PhoneStatusBarPolicy mIconPolicy;
@@ -3251,9 +3252,13 @@
}
public boolean onBackPressed() {
- boolean isScrimmedBouncer = mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
- if (mStatusBarKeyguardViewManager.onBackPressed(isScrimmedBouncer /* hideImmediately */)) {
- if (isScrimmedBouncer) {
+ final boolean isScrimmedBouncer =
+ mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
+ final boolean isBouncerOverDream = isBouncerShowingOverDream();
+
+ if (mStatusBarKeyguardViewManager.onBackPressed(
+ isScrimmedBouncer || isBouncerOverDream /* hideImmediately */)) {
+ if (isScrimmedBouncer || isBouncerOverDream) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
} else {
mNotificationPanelViewController.expandWithoutQs();
@@ -3275,7 +3280,8 @@
if (mNotificationPanelViewController.closeUserSwitcherIfOpen()) {
return true;
}
- if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
+ if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
+ && !isBouncerOverDream) {
if (mNotificationPanelViewController.canPanelBeCollapsed()) {
mShadeController.animateCollapsePanels();
}
@@ -3473,6 +3479,16 @@
}
/**
+ * Sets whether the bouncer over dream is showing. Note that the bouncer over dream is handled
+ * independently of the rest of the notification panel. As a result, setting this state via
+ * {@link #setBouncerShowing(boolean)} leads to unintended side effects from states modified
+ * behind the dream.
+ */
+ public void setBouncerShowingOverDream(boolean bouncerShowingOverDream) {
+ mBouncerShowingOverDream = bouncerShowingOverDream;
+ }
+
+ /**
* Propagate the bouncer state to status bar components.
*
* Separate from {@link #setBouncerShowing} because we sometimes re-create the status bar and
@@ -4145,7 +4161,7 @@
}
public boolean isBouncerShowingOverDream() {
- return isBouncerShowing() && mDreamOverlayStateController.isOverlayActive();
+ return mBouncerShowingOverDream;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index d492c57..af1c9e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -424,6 +424,8 @@
// situations, such keeping your finger down while swiping to unlock to an app
// that is locked in landscape (the rotation will cancel the touch event).
expand = false;
+ } else if (mCentralSurfaces.isBouncerShowingOverDream()) {
+ expand = false;
} else {
// If we get a cancel, put the shade back to the state it was in when the
// gesture started
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
index d3c6e9a..313d56f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
@@ -18,6 +18,7 @@
import android.util.Log;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.policy.CallbackController;
import org.jetbrains.annotations.NotNull;
@@ -60,21 +61,13 @@
};
@Inject
- public Monitor(Executor executor, Set<Condition> conditions, Set<Callback> callbacks) {
+ public Monitor(@Main Executor executor, Set<Condition> conditions) {
mConditions = new HashSet<>();
mExecutor = executor;
if (conditions != null) {
mConditions.addAll(conditions);
}
-
- if (callbacks == null) {
- return;
- }
-
- for (Callback callback : callbacks) {
- addCallbackLocked(callback);
- }
}
private void updateConditionMetState() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java b/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java
index fc67973..8e739d6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java
@@ -34,8 +34,7 @@
*/
@Subcomponent.Factory
interface Factory {
- MonitorComponent create(@BindsInstance Set<Condition> conditions,
- @BindsInstance Set<Monitor.Callback> callbacks);
+ MonitorComponent create(@BindsInstance Set<Condition> conditions);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index e175af7..535023f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -420,7 +420,31 @@
verify(mUiEventLogger).log(BouncerSwipeTouchHandler.DreamEvent.DREAM_BOUNCER_FULLY_VISIBLE);
}
+ /**
+ * Ensures {@link CentralSurfaces}
+ */
+ @Test
+ public void testInformBouncerShowingOnExpand() {
+ swipeToPosition(1f, Direction.UP, 0);
+ verify(mCentralSurfaces).setBouncerShowingOverDream(true);
+ }
+
+ /**
+ * Ensures {@link CentralSurfaces}
+ */
+ @Test
+ public void testInformBouncerHidingOnCollapse() {
+ // Must swipe up to set initial state.
+ swipeToPosition(1f, Direction.UP, 0);
+ Mockito.clearInvocations(mCentralSurfaces);
+
+ swipeToPosition(0f, Direction.DOWN, 0);
+ verify(mCentralSurfaces).setBouncerShowingOverDream(false);
+ }
+
+
private void swipeToPosition(float percent, Direction direction, float velocityY) {
+ Mockito.clearInvocations(mTouchSession);
mTouchHandler.onSessionStart(mTouchSession);
ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index cc47248..d65901777 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -10,6 +10,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
@@ -18,6 +19,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSTileHost
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.BluetoothController
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -25,6 +27,7 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -84,6 +87,53 @@
assertThat(tile.restrictionChecked).isEqualTo(UserManager.DISALLOW_BLUETOOTH)
}
+ @Test
+ fun testIcon_whenDisabled_isOffState() {
+ val state = QSTile.BooleanState()
+ disableBluetooth()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_off))
+ }
+
+ @Test
+ fun testIcon_whenDisconnected_isOffState() {
+ val state = QSTile.BooleanState()
+ enableBluetooth()
+ setBluetoothDisconnected()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_off))
+ }
+
+ @Test
+ fun testIcon_whenConnected_isOnState() {
+ val state = QSTile.BooleanState()
+ enableBluetooth()
+ setBluetoothConnected()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_on))
+ }
+
+ @Test
+ fun testIcon_whenConnecting_isSearchState() {
+ val state = QSTile.BooleanState()
+ enableBluetooth()
+ setBluetoothConnecting()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_search))
+ }
+
private class FakeBluetoothTile(
qsTileHost: QSTileHost,
backgroundLooper: Looper,
@@ -114,4 +164,27 @@
restrictionChecked = userRestriction
}
}
+
+ fun enableBluetooth() {
+ `when`(bluetoothController.isBluetoothEnabled).thenReturn(true)
+ }
+
+ fun disableBluetooth() {
+ `when`(bluetoothController.isBluetoothEnabled).thenReturn(false)
+ }
+
+ fun setBluetoothDisconnected() {
+ `when`(bluetoothController.isBluetoothConnecting).thenReturn(false)
+ `when`(bluetoothController.isBluetoothConnected).thenReturn(false)
+ }
+
+ fun setBluetoothConnected() {
+ `when`(bluetoothController.isBluetoothConnecting).thenReturn(false)
+ `when`(bluetoothController.isBluetoothConnected).thenReturn(true)
+ }
+
+ fun setBluetoothConnecting() {
+ `when`(bluetoothController.isBluetoothConnected).thenReturn(false)
+ `when`(bluetoothController.isBluetoothConnecting).thenReturn(true)
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
index 5118637..7589616 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
@@ -65,7 +65,7 @@
mCondition3 = spy(new FakeCondition());
mConditions = new HashSet<>(Arrays.asList(mCondition1, mCondition2, mCondition3));
- mConditionMonitor = new Monitor(mExecutor, mConditions, null /*callbacks*/);
+ mConditionMonitor = new Monitor(mExecutor, mConditions);
}
@Test
@@ -76,8 +76,10 @@
final Monitor monitor = new Monitor(
mExecutor,
- new HashSet<>(Arrays.asList(overridingCondition, regularCondition)),
- new HashSet<>(Arrays.asList(callback)));
+ new HashSet<>(Arrays.asList(overridingCondition, regularCondition)));
+
+ monitor.addCallback(callback);
+ mExecutor.runAllReady();
when(overridingCondition.isOverridingCondition()).thenReturn(true);
when(overridingCondition.isConditionMet()).thenReturn(true);
@@ -123,8 +125,9 @@
final Monitor monitor = new Monitor(
mExecutor,
new HashSet<>(Arrays.asList(overridingCondition, overridingCondition2,
- regularCondition)),
- new HashSet<>(Arrays.asList(callback)));
+ regularCondition)));
+ monitor.addCallback(callback);
+ mExecutor.runAllReady();
when(overridingCondition.isOverridingCondition()).thenReturn(true);
when(overridingCondition.isConditionMet()).thenReturn(true);
@@ -174,8 +177,8 @@
mock(Monitor.Callback.class);
final Condition condition = mock(Condition.class);
when(condition.isConditionMet()).thenReturn(true);
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)),
- new HashSet<>(Arrays.asList(callback1)));
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)));
+ monitor.addCallback(callback1);
final Monitor.Callback callback2 =
mock(Monitor.Callback.class);
@@ -186,7 +189,7 @@
@Test
public void addCallback_noConditions_reportAllConditionsMet() {
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(), null /*callbacks*/);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>());
final Monitor.Callback callback = mock(Monitor.Callback.class);
monitor.addCallback(callback);
@@ -196,7 +199,7 @@
@Test
public void addCallback_withMultipleInstancesOfTheSameCallback_registerOnlyOne() {
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(), null /*callbacks*/);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>());
final Monitor.Callback callback = mock(Monitor.Callback.class);
// Adds the same instance multiple times.
@@ -212,8 +215,7 @@
@Test
public void removeCallback_shouldNoLongerReceiveUpdate() {
final Condition condition = mock(Condition.class);
- final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)),
- null);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)));
final Monitor.Callback callback =
mock(Monitor.Callback.class);
monitor.addCallback(callback);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 35f7e06..aa2f7c1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2281,13 +2281,9 @@
return mAppOpsManager;
}
- /**
- * Provides the basic functionality for activity task related tests when a handler thread is
- * given to initialize the dependency members.
- */
+ /** Provides the basic functionality for unit tests. */
@VisibleForTesting
- public ActivityManagerService(Injector injector, ServiceThread handlerThread) {
- final boolean hasHandlerThread = handlerThread != null;
+ ActivityManagerService(Injector injector, @NonNull ServiceThread handlerThread) {
mInjector = injector;
mContext = mInjector.getContext();
mUiContext = null;
@@ -2295,33 +2291,27 @@
mPackageWatchdog = null;
mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */);
mBatteryStatsService = null;
- mHandler = hasHandlerThread ? new MainHandler(handlerThread.getLooper()) : null;
+ mHandler = new MainHandler(handlerThread.getLooper());
mHandlerThread = handlerThread;
- mConstants = hasHandlerThread
- ? new ActivityManagerConstants(mContext, this, mHandler) : null;
+ mConstants = new ActivityManagerConstants(mContext, this, mHandler);
final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
mPlatformCompat = null;
mProcessList = injector.getProcessList(this);
mProcessList.init(this, activeUids, mPlatformCompat);
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null);
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = hasHandlerThread
- ? new OomAdjuster(this, mProcessList, activeUids, handlerThread) : null;
+ mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread);
- mIntentFirewall = hasHandlerThread
- ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null;
+ mIntentFirewall = null;
mProcessStats = null;
mCpHelper = new ContentProviderHelper(this, false);
- // For the usage of {@link ActiveServices#cleanUpServices} that may be invoked from
- // {@link ActivityTaskSupervisor#cleanUpRemovedTaskLocked}.
- mServices = hasHandlerThread ? new ActiveServices(this) : null;
+ mServices = null;
mSystemThread = null;
mUiHandler = injector.getUiHandler(null /* service */);
mUidObserverController = new UidObserverController(mUiHandler);
- mUserController = hasHandlerThread ? new UserController(this) : null;
- mPendingIntentController = hasHandlerThread
- ? new PendingIntentController(handlerThread.getLooper(), mUserController,
- mConstants) : null;
+ mUserController = new UserController(this);
+ mPendingIntentController =
+ new PendingIntentController(handlerThread.getLooper(), mUserController, mConstants);
mAppRestrictionController = new AppRestrictionController(mContext, this);
mProcStartHandlerThread = null;
mProcStartHandler = null;
@@ -2329,7 +2319,7 @@
mFactoryTest = FACTORY_TEST_OFF;
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mInternal = new LocalService();
- mPendingStartActivityUids = new PendingStartActivityUids(mContext);
+ mPendingStartActivityUids = new PendingStartActivityUids();
mUseFifoUiScheduling = false;
mEnableOffloadQueue = false;
mFgBroadcastQueue = mBgBroadcastQueue = mBgOffloadBroadcastQueue =
@@ -2464,7 +2454,7 @@
}
mInternal = new LocalService();
- mPendingStartActivityUids = new PendingStartActivityUids(mContext);
+ mPendingStartActivityUids = new PendingStartActivityUids();
mTraceErrorLogger = new TraceErrorLogger();
mComponentAliasResolver = new ComponentAliasResolver(this);
}
@@ -17283,7 +17273,7 @@
// next top activity on time. This race will fail the following binder transactions WM
// sends to the activity. After this race issue between WM/ATMS and AMS is solved, this
// workaround can be removed. (b/213288355)
- if (isNewPending && mOomAdjuster != null) { // It can be null in unit test.
+ if (isNewPending) {
mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid);
}
// We need to update the network rules for the app coming to the top state so that
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index bd60057..da09317 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -16,7 +16,6 @@
package com.android.server.am;
-import android.content.Context;
import android.os.SystemClock;
import android.util.Pair;
import android.util.Slog;
@@ -40,11 +39,6 @@
// Key is uid, value is Pair of pid and SystemClock.elapsedRealtime() when the
// uid is added.
private final SparseArray<Pair<Integer, Long>> mPendingUids = new SparseArray();
- private Context mContext;
-
- PendingStartActivityUids(Context context) {
- mContext = context;
- }
/** Returns {@code true} if the uid is put to the pending array. Otherwise it existed. */
synchronized boolean add(int uid, int pid) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index e6bc796..5a40b30 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1447,6 +1447,16 @@
}
}
+ @VisibleForTesting
+ void reregisterService(final ComponentName cn, final int userId) {
+ // If rebinding a package that died, ensure it still has permission
+ // after the rebind delay
+ if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
+ || isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
+ registerService(cn, userId);
+ }
+ }
+
/**
* Inject a system service into the management list.
*/
@@ -1545,12 +1555,9 @@
unbindService(this, name, userid);
if (!mServicesRebinding.contains(servicesBindingTag)) {
mServicesRebinding.add(servicesBindingTag);
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- registerService(name, userid);
- }
- }, ON_BINDING_DIED_REBIND_DELAY_MS);
+ mHandler.postDelayed(() ->
+ reregisterService(name, userid),
+ ON_BINDING_DIED_REBIND_DELAY_MS);
} else {
Slog.v(TAG, getCaption() + " not rebinding in user " + userid
+ " as a previous rebind attempt was made: " + name);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dc4e117..c525129 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6300,7 +6300,7 @@
// starting window is drawn, the transition can start earlier. Exclude finishing and bubble
// because it may be a trampoline.
if (!wasTaskVisible && mStartingData != null && !finishing && !mLaunchedFromBubble
- && mVisibleRequested && !mDisplayContent.mAppTransition.isReady()
+ && !mDisplayContent.mAppTransition.isReady()
&& !mDisplayContent.mAppTransition.isRunning()
&& mDisplayContent.isNextTransitionForward()) {
// The pending transition state will be cleared after the transition is started, so
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 6e205be..feaa10d 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -193,12 +193,18 @@
private void onTimeout() {
if (!mActiveSyncs.contains(mSyncId)) return;
+ boolean allFinished = true;
for (int i = mRootMembers.size() - 1; i >= 0; --i) {
final WindowContainer<?> wc = mRootMembers.valueAt(i);
if (!wc.isSyncFinished()) {
+ allFinished = false;
Slog.i(TAG, "Unfinished container: " + wc);
}
}
+ if (allFinished && !mReady) {
+ Slog.w(TAG, "Sync group " + mSyncId + " timed-out because not ready. If you see "
+ + "this, please file a bug.");
+ }
finishNow();
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6f69e03..1e1cbaf 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1977,23 +1977,23 @@
void moveActivityToPinnedRootTask(@NonNull ActivityRecord r,
@Nullable ActivityRecord launchIntoPipHostActivity, String reason) {
- mService.deferWindowLayout();
final TaskDisplayArea taskDisplayArea = r.getDisplayArea();
+ final Task task = r.getTask();
+ final Task rootTask;
+ Transition newTransition = null;
+ // Create a transition now to collect the current pinned Task dismiss. Only do the
+ // create here as the Task (trigger) to enter PIP is not ready yet.
+ final TransitionController transitionController = task.mTransitionController;
+ if (!transitionController.isCollecting()
+ && transitionController.getTransitionPlayer() != null) {
+ newTransition = transitionController.createTransition(TRANSIT_PIP);
+ }
+
+ transitionController.deferTransitionReady();
+ mService.deferWindowLayout();
try {
- final Task task = r.getTask();
-
- // Create a transition now to collect the current pinned Task dismiss. Only do the
- // create here as the Task (trigger) to enter PIP is not ready yet.
- final TransitionController transitionController = task.mTransitionController;
- Transition newTransition = null;
- if (transitionController.isCollecting()) {
- transitionController.setReady(task, false /* ready */);
- } else if (transitionController.getTransitionPlayer() != null) {
- newTransition = transitionController.createTransition(TRANSIT_PIP);
- }
-
// This will change the root pinned task's windowing mode to its original mode, ensuring
// we only have one root task that is in pinned mode.
final Task rootPinnedTask = taskDisplayArea.getRootPinnedTask();
@@ -2009,7 +2009,6 @@
final TaskFragment organizedTf = r.getOrganizedTaskFragment();
// TODO: Does it make sense to only count non-finishing activities?
final boolean singleActivity = task.getActivityCount() == 1;
- final Task rootTask;
if (singleActivity) {
rootTask = task;
@@ -2075,6 +2074,9 @@
oldTopActivity.mRequestForceTransition = true;
}
}
+
+ transitionController.collect(rootTask);
+
// The intermediate windowing mode to be set on the ActivityRecord later.
// This needs to happen before the re-parenting, otherwise we will always set the
// ActivityRecord to be fullscreen.
@@ -2085,13 +2087,6 @@
rootTask.reparent(taskDisplayArea, true /* onTop */);
}
- // The new PIP Task is ready, start the transition before updating the windowing mode.
- if (newTransition != null) {
- transitionController.requestStartTransition(newTransition, rootTask,
- null /* remoteTransition */, null /* displayChange */);
- }
- transitionController.collect(rootTask);
-
// Defer the windowing mode change until after the transition to prevent the activity
// from doing work and changing the activity visuals while animating
// TODO(task-org): Figure-out more structured way to do this long term.
@@ -2125,9 +2120,23 @@
}
} finally {
mService.continueWindowLayout();
+ try {
+ ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+ } finally {
+ transitionController.continueTransitionReady();
+ }
}
- ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+ if (newTransition != null) {
+ // Request at end since we want task-organizer events from ensureActivitiesVisible
+ // to be recognized.
+ transitionController.requestStartTransition(newTransition, rootTask,
+ null /* remoteTransition */, null /* displayChange */);
+ // A new transition was created just for this operations. Since the operation is
+ // complete, mark it as ready.
+ newTransition.setReady(rootTask, true /* ready */);
+ }
+
resumeFocusedTasksTopActivities();
notifyActivityPipModeChanged(r.getTask(), r);
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index c44f08c..0bdc00b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -713,6 +713,9 @@
for (int i = mParticipants.size() - 1; i >= 0; --i) {
final WindowContainer wc = mParticipants.valueAt(i);
if (wc.asWindowToken() == null || !wc.isVisibleRequested()) continue;
+ // don't include transient launches, though, since those are only temporarily visible.
+ if (mTransientLaunches != null && wc.asActivityRecord() != null
+ && mTransientLaunches.containsKey(wc.asActivityRecord())) continue;
mVisibleAtTransitionEndTokens.add(wc.asWindowToken());
}
@@ -1595,6 +1598,19 @@
}
/**
+ * This transition will be considered not-ready until a corresponding call to
+ * {@link #continueTransitionReady}
+ */
+ void deferTransitionReady() {
+ ++mReadyTracker.mDeferReadyDepth;
+ }
+
+ /** This undoes one call to {@link #deferTransitionReady}. */
+ void continueTransitionReady() {
+ --mReadyTracker.mDeferReadyDepth;
+ }
+
+ /**
* The transition sync mechanism has 2 parts:
* 1. Whether all WM operations for a particular transition are "ready" (eg. did the app
* launch or stop or get a new configuration?).
@@ -1624,6 +1640,14 @@
private boolean mReadyOverride = false;
/**
+ * When non-zero, this transition is forced not-ready (even over setAllReady()). Use this
+ * (via deferTransitionReady/continueTransitionReady) for situations where we want to do
+ * bulk operations which could trigger surface-placement but the existing ready-state
+ * isn't known.
+ */
+ private int mDeferReadyDepth = 0;
+
+ /**
* Adds a ready-group. Any setReady calls in this subtree will be tracked together. For
* now these are only DisplayContents.
*/
@@ -1664,7 +1688,13 @@
boolean allReady() {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " allReady query: used=%b "
+ "override=%b states=[%s]", mUsed, mReadyOverride, groupsToString());
+ // If the readiness has never been touched, mUsed will be false. We never want to
+ // consider a transition ready if nothing has been reported on it.
if (!mUsed) return false;
+ // If we are deferring readiness, we never report ready. This is usually temporary.
+ if (mDeferReadyDepth > 0) return false;
+ // Next check all the ready groups to see if they are ready. We can short-cut this if
+ // ready-override is set (which is treated as "everything is marked ready").
if (mReadyOverride) return true;
for (int i = mReadyGroups.size() - 1; i >= 0; --i) {
final WindowContainer wc = mReadyGroups.keyAt(i);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index c1c390e..417e6ed 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -455,6 +455,24 @@
setReady(wc, true);
}
+ /** @see Transition#deferTransitionReady */
+ void deferTransitionReady() {
+ if (!isShellTransitionsEnabled()) return;
+ if (mCollectingTransition == null) {
+ throw new IllegalStateException("No collecting transition to defer readiness for.");
+ }
+ mCollectingTransition.deferTransitionReady();
+ }
+
+ /** @see Transition#continueTransitionReady */
+ void continueTransitionReady() {
+ if (!isShellTransitionsEnabled()) return;
+ if (mCollectingTransition == null) {
+ throw new IllegalStateException("No collecting transition to defer readiness for.");
+ }
+ mCollectingTransition.continueTransitionReady();
+ }
+
/** @see Transition#finishTransition */
void finishTransition(@NonNull IBinder token) {
// It is usually a no-op but make sure that the metric consumer is removed.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2f4dc51..3bc6dbd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1062,7 +1062,6 @@
Function<SurfaceSession, SurfaceControl.Builder> mSurfaceControlFactory;
Supplier<SurfaceControl.Transaction> mTransactionFactory;
- final Supplier<Surface> mSurfaceFactory;
private final SurfaceControl.Transaction mTransaction;
@@ -1145,7 +1144,7 @@
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
- new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,
+ new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new,
SurfaceControl.Builder::new);
}
@@ -1158,12 +1157,11 @@
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, DisplayWindowSettingsProvider
displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
final WindowManagerService[] wms = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(() ->
wms[0] = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
- atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
+ atm, displayWindowSettingsProvider, transactionFactory,
surfaceControlFactory), 0);
return wms[0];
}
@@ -1188,7 +1186,6 @@
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, DisplayWindowSettingsProvider
displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
installLock(this, INDEX_WINDOW);
mGlobalLock = atm.getGlobalLock();
@@ -1228,7 +1225,6 @@
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
- mSurfaceFactory = surfaceFactory;
mTransaction = mTransactionFactory.get();
mPolicy = policy;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 2f054b00..8ba9af0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -840,6 +840,156 @@
}
@Test
+ public void reregisterService_checksAppIsApproved_pkg() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_PACKAGE);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a", 0, true);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsApproved_pkg_secondary() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_PACKAGE);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a", 0, false);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsApproved_cn() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a/a", 0, true);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsApproved_cn_secondary() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("a/a", 0, false);
+
+ service.reregisterService(cn, 0);
+
+ assertTrue(service.isBound(cn, 0));
+ }
+
+ @Test
+ public void reregisterService_checksAppIsNotApproved_cn_secondary() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+
+ service.addApprovedList("b/b", 0, false);
+
+ service.reregisterService(cn, 0);
+
+ assertFalse(service.isBound(cn, 0));
+ }
+
+ @Test
public void unbindOtherUserServices() throws PackageManager.NameNotFoundException {
Context context = mock(Context.class);
PackageManager pm = mock(PackageManager.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 716612c..75ecfd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -21,6 +21,7 @@
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -34,6 +35,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -284,10 +286,14 @@
.setCreateActivity(true).build().getTopMostActivity();
activity2.getTask().setResumedActivity(activity2, "test");
- mAtm.mAmInternal.deletePendingTopUid(activity1.getUid(), Long.MAX_VALUE);
+ final int[] pendingTopUid = new int[1];
+ doAnswer(invocation -> {
+ pendingTopUid[0] = invocation.getArgument(0);
+ return null;
+ }).when(mAtm.mAmInternal).addPendingTopUid(anyInt(), anyInt(), any());
clearInvocations(mAtm);
activity1.moveFocusableActivityToTop("test");
- assertTrue(mAtm.mAmInternal.isPendingTopUid(activity1.getUid()));
+ assertEquals(activity1.getUid(), pendingTopUid[0]);
verify(mAtm).updateOomAdj();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 8ef9ada..a3b881c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -657,7 +657,7 @@
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
- mAtm.setBooted(true);
+ setBooted(mAtm);
// Trigger resume on all displays
mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -685,7 +685,7 @@
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
- mAtm.setBooted(true);
+ setBooted(mAtm);
// Trigger resume on all displays
mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -771,17 +771,10 @@
@Test
public void testNotStartHomeBeforeBoot() {
final int displayId = 1;
- final boolean isBooting = mAtm.mAmInternal.isBooting();
- final boolean isBooted = mAtm.mAmInternal.isBooted();
- try {
- mAtm.mAmInternal.setBooting(false);
- mAtm.mAmInternal.setBooted(false);
- mRootWindowContainer.onDisplayAdded(displayId);
- verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
- } finally {
- mAtm.mAmInternal.setBooting(isBooting);
- mAtm.mAmInternal.setBooted(isBooted);
- }
+ doReturn(false).when(mAtm).isBooting();
+ doReturn(false).when(mAtm).isBooted();
+ mRootWindowContainer.onDisplayAdded(displayId);
+ verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index dc9a625..18c4eb9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -66,7 +66,6 @@
import android.provider.DeviceConfig;
import android.util.Log;
import android.view.InputChannel;
-import android.view.Surface;
import android.view.SurfaceControl;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
@@ -77,7 +76,6 @@
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
-import com.android.server.appop.AppOpsService;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.input.InputManagerService;
@@ -94,10 +92,8 @@
import org.mockito.Mockito;
import org.mockito.quality.Strictness;
-import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
/**
* JUnit test rule to correctly setting up system services like {@link WindowManagerService}
@@ -125,13 +121,11 @@
private Description mDescription;
private Context mContext;
private StaticMockitoSession mMockitoSession;
- private ActivityManagerService mAmService;
private ActivityTaskManagerService mAtmService;
private WindowManagerService mWmService;
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
- private Supplier<Surface> mSurfaceFactory = () -> mock(Surface.class);
/**
* Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
*/
@@ -289,29 +283,9 @@
}
private void setUpActivityTaskManagerService() {
- // ActivityManagerService
- mAmService = new ActivityManagerService(new AMTestInjector(mContext), null /* thread */);
- spyOn(mAmService);
- doReturn(mock(IPackageManager.class)).when(mAmService).getPackageManager();
- doNothing().when(mAmService).grantImplicitAccess(
- anyInt(), any(), anyInt(), anyInt());
-
// ActivityManagerInternal
- final ActivityManagerInternal amInternal = mAmService.mInternal;
- spyOn(amInternal);
- doNothing().when(amInternal).trimApplications();
- doNothing().when(amInternal).scheduleAppGcs();
- doNothing().when(amInternal).updateCpuStats();
- doNothing().when(amInternal).updateOomAdj();
- doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
- doNothing().when(amInternal).updateActivityUsageStats(
- any(), anyInt(), anyInt(), any(), any());
- doNothing().when(amInternal).startProcess(
- any(), any(), anyBoolean(), anyBoolean(), any(), any());
- doNothing().when(amInternal).updateOomLevelsForDisplay(anyInt());
- doNothing().when(amInternal).broadcastGlobalConfigurationChanged(anyInt(), anyBoolean());
- doNothing().when(amInternal).cleanUpServices(anyInt(), any(), any());
- doNothing().when(amInternal).reportCurKeyguardUsageEvent(anyBoolean());
+ final ActivityManagerInternal amInternal =
+ mock(ActivityManagerInternal.class, withSettings().stubOnly());
doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId();
doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds();
doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt());
@@ -320,7 +294,9 @@
doReturn(false).when(amInternal).isActivityStartsLoggingEnabled();
LocalServices.addService(ActivityManagerInternal.class, amInternal);
- mAtmService = new TestActivityTaskManagerService(mContext, mAmService);
+ final ActivityManagerService amService =
+ mock(ActivityManagerService.class, withSettings().stubOnly());
+ mAtmService = new TestActivityTaskManagerService(mContext, amService);
LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
}
@@ -334,7 +310,7 @@
mWmService = WindowManagerService.main(
mContext, mImService, false, false, wmPolicy, mAtmService,
testDisplayWindowSettingsProvider, StubTransaction::new,
- () -> mSurfaceFactory.get(), (unused) -> new MockSurfaceControlBuilder());
+ (unused) -> new MockSurfaceControlBuilder());
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
@@ -355,7 +331,7 @@
null, null, mTransaction, mWmService.mPowerManagerInternal);
mWmService.onInitReady();
- mAmService.setWindowManager(mWmService);
+ mAtmService.setWindowManager(mWmService);
mWmService.mDisplayEnabled = true;
mWmService.mDisplayReady = true;
// Set configuration for default display
@@ -454,10 +430,6 @@
.spiedInstance(sWakeLock).stubOnly());
}
- void setSurfaceFactory(Supplier<Surface> factory) {
- mSurfaceFactory = factory;
- }
-
void cleanupWindowManagerHandlers() {
final WindowManagerService wm = getWindowManagerService();
if (wm == null) {
@@ -618,32 +590,4 @@
doReturn(true).when(controller).checkKeyguardVisibility(any());
}
}
-
- // TODO: Can we just mock this?
- private static class AMTestInjector extends ActivityManagerService.Injector {
-
- AMTestInjector(Context context) {
- super(context);
- }
-
- @Override
- public Context getContext() {
- return getInstrumentation().getTargetContext();
- }
-
- @Override
- public AppOpsService getAppOpsService(File file, Handler handler) {
- return null;
- }
-
- @Override
- public Handler getUiHandler(ActivityManagerService service) {
- return UiThread.getHandler();
- }
-
- @Override
- public boolean isNetworkRestrictedForUid(int uid) {
- return false;
- }
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 6c1c086..9dedc85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -955,6 +955,29 @@
verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false));
}
+ @Test
+ public void testNotReadyPushPop() {
+ final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController);
+ final ITransitionPlayer player = new ITransitionPlayer.Default();
+ controller.registerTransitionPlayer(player, null /* appThread */);
+ final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
+
+ // Start out with task2 visible and set up a transition that closes task2 and opens task1
+ final Task task1 = createTask(mDisplayContent);
+ openTransition.collectExistenceChange(task1);
+
+ assertFalse(openTransition.allReady());
+
+ openTransition.setAllReady();
+
+ openTransition.deferTransitionReady();
+ assertFalse(openTransition.allReady());
+
+ openTransition.continueTransitionReady();
+ assertTrue(openTransition.allReady());
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {