diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java index b310dd638e6c5..9a6df23ca9714 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java @@ -18,9 +18,12 @@ package com.android.wm.shell.back; import android.view.MotionEvent; +import com.android.wm.shell.common.annotations.ExternalThread; + /** - * Interface for SysUI to get access to the Back animation related methods. + * Interface for external process to get access to the Back animation related methods. */ +@ExternalThread public interface BackAnimation { /** @@ -32,4 +35,11 @@ public interface BackAnimation { * Sets whether the back gesture is past the trigger threshold or not. */ void setTriggerBack(boolean triggerBack); + + /** + * Returns a binder that can be passed to an external process to update back animations. + */ + default IBackAnimation createExternalInterface() { + return null; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 229e8ee049821..a5140c3aafff2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -16,6 +16,7 @@ package com.android.wm.shell.back; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import android.animation.Animator; @@ -26,6 +27,7 @@ import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; import android.app.WindowConfiguration; +import android.content.Context; import android.graphics.Point; import android.graphics.PointF; import android.hardware.HardwareBuffer; @@ -35,16 +37,18 @@ import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceControl; import android.window.BackNavigationInfo; +import android.window.IOnBackInvokedCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.annotations.ShellMainThread; /** * Controls the window animation run when a user initiates a back gesture. */ -public class BackAnimationController { +public class BackAnimationController implements RemoteCallable { private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability"; public static final boolean IS_ENABLED = SystemProperties @@ -72,18 +76,26 @@ public class BackAnimationController { private BackNavigationInfo mBackNavigationInfo; private final SurfaceControl.Transaction mTransaction; private final IActivityTaskManager mActivityTaskManager; + private final Context mContext; + @Nullable + private IOnBackInvokedCallback mBackToLauncherCallback; - public BackAnimationController(@ShellMainThread ShellExecutor shellExecutor) { - this(shellExecutor, new SurfaceControl.Transaction(), ActivityTaskManager.getService()); + public BackAnimationController( + @ShellMainThread ShellExecutor shellExecutor, + Context context) { + this(shellExecutor, new SurfaceControl.Transaction(), ActivityTaskManager.getService(), + context); } @VisibleForTesting BackAnimationController(@NonNull ShellExecutor shellExecutor, @NonNull SurfaceControl.Transaction transaction, - @NonNull IActivityTaskManager activityTaskManager) { + @NonNull IActivityTaskManager activityTaskManager, + Context context) { mShellExecutor = shellExecutor; mTransaction = transaction; mActivityTaskManager = activityTaskManager; + mContext = context; } public BackAnimation getBackAnimationImpl() { @@ -92,7 +104,27 @@ public class BackAnimationController { private final BackAnimation mBackAnimation = new BackAnimationImpl(); + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mShellExecutor; + } + private class BackAnimationImpl implements BackAnimation { + private IBackAnimationImpl mBackAnimation; + + @Override + public IBackAnimation createExternalInterface() { + if (mBackAnimation != null) { + mBackAnimation.invalidate(); + } + mBackAnimation = new IBackAnimationImpl(BackAnimationController.this); + return mBackAnimation; + } @Override public void onBackMotion(MotionEvent event) { @@ -105,6 +137,48 @@ public class BackAnimationController { } } + private static class IBackAnimationImpl extends IBackAnimation.Stub { + private BackAnimationController mController; + + IBackAnimationImpl(BackAnimationController controller) { + mController = controller; + } + + @Override + public void setBackToLauncherCallback(IOnBackInvokedCallback callback) { + executeRemoteCallWithTaskPermission(mController, "setBackToLauncherCallback", + (controller) -> mController.setBackToLauncherCallback(callback)); + } + + @Override + public void clearBackToLauncherCallback() { + executeRemoteCallWithTaskPermission(mController, "clearBackToLauncherCallback", + (controller) -> mController.clearBackToLauncherCallback()); + } + + @Override + public void onBackToLauncherAnimationFinished() { + executeRemoteCallWithTaskPermission(mController, "onBackToLauncherAnimationFinished", + (controller) -> mController.onBackToLauncherAnimationFinished()); + } + + void invalidate() { + mController = null; + } + } + + private void setBackToLauncherCallback(IOnBackInvokedCallback callback) { + mBackToLauncherCallback = callback; + } + + private void clearBackToLauncherCallback() { + mBackToLauncherCallback = null; + } + + private void onBackToLauncherAnimationFinished() { + finishAnimation(); + } + /** * Called when a new motion event needs to be transferred to this * {@link BackAnimationController} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl new file mode 100644 index 0000000000000..6311f879fd459 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl @@ -0,0 +1,45 @@ +/* + * 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.back; + +import android.window.IOnBackInvokedCallback; + +/** + * Interface for Launcher process to register back invocation callbacks. + */ +interface IBackAnimation { + + /** + * Sets a {@link IOnBackInvokedCallback} to be invoked when + * back navigation has type {@link BackNavigationInfo#TYPE_RETURN_TO_HOME}. + */ + void setBackToLauncherCallback(in IOnBackInvokedCallback callback); + + /** + * Clears the previously registered {@link IOnBackInvokedCallback}. + */ + void clearBackToLauncherCallback(); + + /** + * Notifies Shell that the back to launcher animation has fully finished + * (including the transition animation that runs after the finger is lifted). + * + * At this point the top window leash (if one was created) should be ready to be released. + * //TODO: Remove once we play the transition animation through shell transitions. + */ + void onBackToLauncherAnimationFinished(); +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 9f4ff7c8dc060..2e54c792ed57f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -696,11 +696,12 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static Optional provideBackAnimationController( + Context context, @ShellMainThread ShellExecutor shellExecutor ) { if (BackAnimationController.IS_ENABLED) { return Optional.of( - new BackAnimationController(shellExecutor)); + new BackAnimationController(shellExecutor, context)); } return Optional.empty(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index b738c47ef6ff9..21ced0dc59814 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.verify; import android.app.IActivityTaskManager; import android.app.WindowConfiguration; +import android.content.Context; import android.hardware.HardwareBuffer; import android.os.RemoteCallback; import android.os.RemoteException; @@ -51,6 +52,9 @@ public class BackAnimationControllerTest { private final ShellExecutor mShellExecutor = new TestShellExecutor(); + @Mock + private Context mContext; + @Mock private SurfaceControl.Transaction mTransaction; @@ -63,7 +67,7 @@ public class BackAnimationControllerTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mController = new BackAnimationController( - mShellExecutor, mTransaction, mActivityTaskManager); + mShellExecutor, mTransaction, mActivityTaskManager, mContext); } private void createNavigationInfo(SurfaceControl topWindowLeash, diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index eebc7918c72c5..08b4d3f68a874 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -59,6 +59,7 @@ public class QuickStepContract { public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation"; // See IRecentTasks.aidl public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks"; + public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation"; public static final String NAV_BAR_MODE_3BUTTON_OVERLAY = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 00a314943f7a9..1218fd3079314 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -26,6 +26,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_BACK_ANIMATION; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; @@ -104,6 +105,7 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; import com.android.systemui.statusbar.policy.CallbackController; +import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; @@ -163,6 +165,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private final Optional mStartingSurface; private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController; private final Optional mRecentTasks; + private final Optional mBackAnimation; private final UiEventLogger mUiEventLogger; private Region mActiveNavBarRegion; @@ -508,6 +511,9 @@ public class OverviewProxyService extends CurrentUserTracker implements mRecentTasks.ifPresent(recentTasks -> params.putBinder( KEY_EXTRA_RECENT_TASKS, recentTasks.createExternalInterface().asBinder())); + mBackAnimation.ifPresent((backAnimation) -> params.putBinder( + KEY_EXTRA_SHELL_BACK_ANIMATION, + backAnimation.createExternalInterface().asBinder())); try { mOverviewProxy.onInitialize(params); @@ -566,6 +572,7 @@ public class OverviewProxyService extends CurrentUserTracker implements Optional splitScreenOptional, Optional oneHandedOptional, Optional recentTasks, + Optional backAnimation, Optional startingSurface, BroadcastDispatcher broadcastDispatcher, ShellTransitions shellTransitions, @@ -593,6 +600,7 @@ public class OverviewProxyService extends CurrentUserTracker implements mOneHandedOptional = oneHandedOptional; mShellTransitions = shellTransitions; mRecentTasks = recentTasks; + mBackAnimation = backAnimation; mUiEventLogger = uiEventLogger; // Assumes device always starts with back button until launcher tells it that it does not