diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index e4427f49e0308..57a4dab5729c8 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -24,9 +24,11 @@ import android.graphics.Insets; import android.graphics.Rect; import android.os.Bundle; import android.view.MotionEvent; +import android.window.TransitionFilter; import com.android.systemui.shared.recents.IPinnedStackAnimationListener; import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.system.RemoteTransitionCompat; /** * Temporary callbacks into SystemUI. @@ -192,4 +194,13 @@ interface ISystemUiProxy { * @param destinationBounds the destination bounds the PiP window lands into */ void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 31; + + /** + * Registers a RemoteTransitionCompat that will handle transitions. This parameter bundles an + * IRemoteTransition and a filter that must pass for it. + */ + void registerRemoteTransition(in RemoteTransitionCompat remoteTransition) = 32; + + /** Unegisters a RemoteTransitionCompat that will handle transitions. */ + void unregisterRemoteTransition(in RemoteTransitionCompat remoteTransition) = 33; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java index d672c2c1dc588..325e268a63eaa 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java @@ -60,7 +60,8 @@ public abstract class ActivityOptionsCompat { public static ActivityOptions makeRemoteAnimation( RemoteAnimationAdapterCompat remoteAnimationAdapter) { - return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped()); + return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped(), + remoteAnimationAdapter.getRemoteTransition().getTransition()); } public static ActivityOptions makeCustomAnimation(Context context, int enterResId, diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java index 02e509eef25fa..f105fcec8e9fd 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java @@ -16,12 +16,21 @@ package com.android.systemui.shared.system; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_OPEN; +import static android.view.WindowManager.TRANSIT_TO_BACK; +import static android.view.WindowManager.TRANSIT_TO_FRONT; + import android.os.RemoteException; import android.util.Log; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; +import android.window.IRemoteTransition; +import android.window.TransitionInfo; /** * @see RemoteAnimationAdapter @@ -29,17 +38,28 @@ import android.view.RemoteAnimationTarget; public class RemoteAnimationAdapterCompat { private final RemoteAnimationAdapter mWrapped; + private final RemoteTransitionCompat mRemoteTransition; public RemoteAnimationAdapterCompat(RemoteAnimationRunnerCompat runner, long duration, long statusBarTransitionDelay) { mWrapped = new RemoteAnimationAdapter(wrapRemoteAnimationRunner(runner), duration, statusBarTransitionDelay); + mRemoteTransition = buildRemoteTransition(runner); } RemoteAnimationAdapter getWrapped() { return mWrapped; } + /** Helper to just build a remote transition. Use this if the legacy adapter isn't needed. */ + public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner) { + return new RemoteTransitionCompat(wrapRemoteTransition(runner)); + } + + public RemoteTransitionCompat getRemoteTransition() { + return mRemoteTransition; + } + private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner( final RemoteAnimationRunnerCompat remoteAnimationAdapter) { return new IRemoteAnimationRunner.Stub() { @@ -72,4 +92,63 @@ public class RemoteAnimationAdapterCompat { } }; } + + private static IRemoteTransition.Stub wrapRemoteTransition( + final RemoteAnimationRunnerCompat remoteAnimationAdapter) { + return new IRemoteTransition.Stub() { + @Override + public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t, + IRemoteAnimationFinishedCallback finishCallback) { + final RemoteAnimationTargetCompat[] appsCompat = + RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */); + final RemoteAnimationTargetCompat[] wallpapersCompat = + RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */); + final Runnable animationFinishedCallback = new Runnable() { + @Override + public void run() { + try { + finishCallback.onAnimationFinished(); + } catch (RemoteException e) { + Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" + + " finished callback", e); + } + } + }; + + // TODO(b/177438007): Move this set-up logic into launcher's animation impl. + boolean isReturnToHome = false; + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + if (change.getTaskInfo() != null + && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) { + isReturnToHome = change.getMode() == TRANSIT_OPEN + || change.getMode() == TRANSIT_TO_FRONT; + break; + } + } + + if (isReturnToHome) { + // Need to "boost" the closing things since that's what launcher expects. + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + final SurfaceControl leash = change.getLeash(); + final int mode = info.getChanges().get(i).getMode(); + // Only deal with roots + if (change.getParent() != null) continue; + if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { + t.setLayer(leash, info.getChanges().size() * 3 - i); + } + } + // Make wallpaper visible immediately since launcher apparently won't do this. + for (int i = wallpapersCompat.length - 1; i >= 0; --i) { + t.show(wallpapersCompat[i].leash.getSurfaceControl()); + t.setAlpha(wallpapersCompat[i].leash.getSurfaceControl(), 1.f); + } + } + t.apply(); + remoteAnimationAdapter.onAnimationStart(appsCompat, wallpapersCompat, + animationFinishedCallback); + } + }; + } } 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 a1c1f93638a8e..f88e38a5923c4 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 @@ -22,6 +22,10 @@ import android.graphics.Point; import android.graphics.Rect; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; +import android.view.WindowManager; +import android.window.TransitionInfo; + +import java.util.ArrayList; /** * @see RemoteAnimationTarget @@ -73,6 +77,45 @@ public class RemoteAnimationTargetCompat { mStartLeash = app.startLeash; } + private static int newModeToLegacyMode(int newMode) { + switch (newMode) { + case WindowManager.TRANSIT_OPEN: + case WindowManager.TRANSIT_TO_FRONT: + return MODE_OPENING; + case WindowManager.TRANSIT_CLOSE: + case WindowManager.TRANSIT_TO_BACK: + return MODE_CLOSING; + default: + return 2; // MODE_CHANGING + } + } + + public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order) { + taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; + mode = newModeToLegacyMode(change.getMode()); + leash = new SurfaceControlCompat(change.getLeash()); + isTranslucent = (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0 + || (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0; + clipRect = null; + position = null; + localBounds = new Rect(change.getEndAbsBounds()); + localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y); + sourceContainerBounds = null; + screenSpaceBounds = change.getEndAbsBounds(); + prefixOrderIndex = order; + // TODO(shell-transitions): I guess we need to send content insets? evaluate how its used. + contentInsets = new Rect(0, 0, 0, 0); + if (change.getTaskInfo() != null) { + isNotInRecents = !change.getTaskInfo().isRunning; + activityType = change.getTaskInfo().getActivityType(); + } else { + isNotInRecents = true; + activityType = ACTIVITY_TYPE_UNDEFINED; + } + pictureInPictureParams = null; + mStartLeash = null; + } + public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) { final RemoteAnimationTargetCompat[] appsCompat = new RemoteAnimationTargetCompat[apps != null ? apps.length : 0]; @@ -82,6 +125,24 @@ public class RemoteAnimationTargetCompat { return appsCompat; } + /** + * Represents a TransitionInfo object as an array of old-style targets + * + * @param wallpapers If true, this will return wallpaper targets; otherwise it returns + * non-wallpaper targets. + */ + public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers) { + final ArrayList out = new ArrayList<>(); + for (int i = 0; i < info.getChanges().size(); i++) { + boolean changeIsWallpaper = + (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0; + if (wallpapers != changeIsWallpaper) continue; + out.add(new RemoteAnimationTargetCompat(info.getChanges().get(i), + info.getChanges().size() - i)); + } + return out.toArray(new RemoteAnimationTargetCompat[out.size()]); + } + /** * @see SurfaceControl#release() */ @@ -91,4 +152,4 @@ public class RemoteAnimationTargetCompat { mStartLeash.release(); } } -} \ No newline at end of file +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl new file mode 100644 index 0000000000000..1550ab3bed63b --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl @@ -0,0 +1,19 @@ +/* + * 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. + */ + +package com.android.systemui.shared.system; + +parcelable RemoteTransitionCompat; 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 new file mode 100644 index 0000000000000..5c27b89c03de9 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -0,0 +1,213 @@ +/* + * 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. + */ + +package com.android.systemui.shared.system; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.view.WindowManager.TRANSIT_OPEN; +import static android.view.WindowManager.TRANSIT_TO_FRONT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcelable; +import android.window.IRemoteTransition; +import android.window.TransitionFilter; + +import com.android.internal.util.DataClass; + +/** + * Wrapper to expose RemoteTransition (shell transitions) to Launcher. + * + * @see IRemoteTransition + * @see TransitionFilter + */ +@DataClass +public class RemoteTransitionCompat implements Parcelable { + @NonNull final IRemoteTransition mTransition; + @Nullable TransitionFilter mFilter = null; + + RemoteTransitionCompat(IRemoteTransition transition) { + mTransition = transition; + } + + /** Adds a filter check that restricts this remote transition to home open transitions. */ + public void addHomeOpenCheck() { + if (mFilter == null) { + mFilter = new TransitionFilter(); + } + mFilter.mRequirements = + new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()}; + mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME; + mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; + } + + + + // Code below generated by codegen v1.0.21. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + /* package-private */ RemoteTransitionCompat( + @NonNull IRemoteTransition transition, + @Nullable TransitionFilter filter) { + this.mTransition = transition; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTransition); + this.mFilter = filter; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull IRemoteTransition getTransition() { + return mTransition; + } + + @DataClass.Generated.Member + public @Nullable TransitionFilter getFilter() { + return mFilter; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mFilter != null) flg |= 0x2; + dest.writeByte(flg); + dest.writeStrongInterface(mTransition); + if (mFilter != null) dest.writeTypedObject(mFilter, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected RemoteTransitionCompat(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + IRemoteTransition transition = IRemoteTransition.Stub.asInterface(in.readStrongBinder()); + TransitionFilter filter = (flg & 0x2) == 0 ? null : (TransitionFilter) in.readTypedObject(TransitionFilter.CREATOR); + + this.mTransition = transition; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTransition); + this.mFilter = filter; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public RemoteTransitionCompat[] newArray(int size) { + return new RemoteTransitionCompat[size]; + } + + @Override + public RemoteTransitionCompat createFromParcel(@NonNull android.os.Parcel in) { + return new RemoteTransitionCompat(in); + } + }; + + /** + * A builder for {@link RemoteTransitionCompat} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static class Builder { + + private @NonNull IRemoteTransition mTransition; + private @Nullable TransitionFilter mFilter; + + private long mBuilderFieldsSet = 0L; + + public Builder( + @NonNull IRemoteTransition transition) { + mTransition = transition; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTransition); + } + + @DataClass.Generated.Member + public @NonNull Builder setTransition(@NonNull IRemoteTransition value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mTransition = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setFilter(@NonNull TransitionFilter value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mFilter = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull RemoteTransitionCompat build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; // Mark builder used + + if ((mBuilderFieldsSet & 0x2) == 0) { + mFilter = null; + } + RemoteTransitionCompat o = new RemoteTransitionCompat( + mTransition, + mFilter); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x4) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1606862689344L, + codegenVersion = "1.0.21", + sourceFile = "frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java", + inputSignatures = "final @android.annotation.NonNull com.android.systemui.shared.system.IRemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic void addHomeOpenCheck()\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index deca14a3cad3e..19520df087578 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -30,6 +30,7 @@ import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.WMComponent; import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider; import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider; +import com.android.wm.shell.transition.Transitions; import java.util.Optional; import java.util.concurrent.ExecutionException; @@ -113,7 +114,8 @@ public class SystemUIFactory { .setHideDisplayCutout(mWMComponent.getHideDisplayCutout()) .setShellCommandHandler(mWMComponent.getShellCommandHandler()) .setAppPairs(mWMComponent.getAppPairs()) - .setTaskViewFactory(mWMComponent.getTaskViewFactory()); + .setTaskViewFactory(mWMComponent.getTaskViewFactory()) + .setTransitions(mWMComponent.getTransitions()); } else { // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option // is separating this logic into newly creating SystemUITestsFactory. @@ -126,7 +128,8 @@ public class SystemUIFactory { .setHideDisplayCutout(Optional.ofNullable(null)) .setShellCommandHandler(Optional.ofNullable(null)) .setAppPairs(Optional.ofNullable(null)) - .setTaskViewFactory(Optional.ofNullable(null)); + .setTaskViewFactory(Optional.ofNullable(null)) + .setTransitions(Transitions.createEmptyForTesting()); } mSysUIComponent = builder.build(); if (initializeComponents) { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 82d313e7e706f..062410abb689b 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -33,6 +33,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -84,6 +85,9 @@ public interface SysUIComponent { @BindsInstance Builder setShellCommandHandler(Optional shellDump); + @BindsInstance + Builder setTransitions(Transitions t); + SysUIComponent build(); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index ced606c6915ef..60b665f0a51a7 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -27,6 +27,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -87,4 +88,8 @@ public interface WMComponent { @WMSingleton Optional getTaskViewFactory(); + + /** Gets transitions */ + @WMSingleton + Transitions getTransitions(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 54e30af675ab5..f318388f7c545 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -56,12 +56,14 @@ import android.os.Looper; import android.os.PatternMatcher; import android.os.RemoteException; import android.os.UserHandle; +import android.util.ArraySet; import android.util.Log; import android.view.InputMonitor; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; import android.view.accessibility.AccessibilityManager; +import android.window.IRemoteTransition; import androidx.annotation.NonNull; @@ -86,6 +88,7 @@ import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.RemoteTransitionCompat; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; @@ -96,6 +99,7 @@ import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHandedEvents; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; +import com.android.wm.shell.transition.Transitions; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -142,6 +146,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private final ScreenshotHelper mScreenshotHelper; private final Optional mOneHandedOptional; private final CommandQueue mCommandQueue; + private final Transitions mShellTransitions; private Region mActiveNavBarRegion; @@ -158,6 +163,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private float mWindowCornerRadius; private boolean mSupportsRoundedCornersOnWindows; private int mNavBarMode = NAV_BAR_MODE_3BUTTON; + private final ArraySet mRemoteTransitions = new ArraySet<>(); @VisibleForTesting public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() { @@ -530,6 +536,31 @@ public class OverviewProxyService extends CurrentUserTracker implements } } + @Override + public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) { + if (!verifyCaller("registerRemoteTransition")) return; + final long binderToken = Binder.clearCallingIdentity(); + try { + mRemoteTransitions.add(remoteTransition.getTransition()); + mShellTransitions.registerRemote( + remoteTransition.getFilter(), remoteTransition.getTransition()); + } finally { + Binder.restoreCallingIdentity(binderToken); + } + } + + @Override + public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) { + if (!verifyCaller("registerRemoteTransition")) return; + final long binderToken = Binder.clearCallingIdentity(); + try { + mRemoteTransitions.remove(remoteTransition.getTransition()); + mShellTransitions.unregisterRemote(remoteTransition.getTransition()); + } finally { + Binder.restoreCallingIdentity(binderToken); + } + } + private boolean verifyCaller(String reason) { final int callerId = Binder.getCallingUserHandle().getIdentifier(); if (callerId != mCurrentBoundedUserId) { @@ -639,7 +670,8 @@ public class OverviewProxyService extends CurrentUserTracker implements Optional splitScreenOptional, Optional> statusBarOptionalLazy, Optional oneHandedOptional, - BroadcastDispatcher broadcastDispatcher) { + BroadcastDispatcher broadcastDispatcher, + Transitions shellTransitions) { super(broadcastDispatcher); mContext = context; mPipOptional = pipOptional; @@ -658,6 +690,7 @@ public class OverviewProxyService extends CurrentUserTracker implements mSysUiState = sysUiState; mSysUiState.addCallback(this::notifySystemUiStateFlags); mOneHandedOptional = oneHandedOptional; + mShellTransitions = shellTransitions; // Assumes device always starts with back button until launcher tells it that it does not mNavBarButtonAlpha = 1.0f; @@ -806,6 +839,12 @@ public class OverviewProxyService extends CurrentUserTracker implements // Clean up the minimized state if launcher dies mSplitScreenOptional.ifPresent( splitScreen -> splitScreen.setMinimized(false)); + + // Clean up any registered remote transitions + for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) { + mShellTransitions.unregisterRemote(mRemoteTransitions.valueAt(i)); + } + mRemoteTransitions.clear(); } public void startConnectionToCurrentUser() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java index 4d32a3b4077f5..b63274ba246ac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java @@ -42,6 +42,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.pip.Pip; +import com.android.wm.shell.transition.Transitions; import org.junit.Before; import org.junit.Test; @@ -75,6 +76,7 @@ public class OverviewProxyServiceTest extends SysuiTestCase { @Mock private Optional mMockOneHandedOptional; @Mock private PackageManager mPackageManager; @Mock private SysUiState mMockSysUiState; + @Mock private Transitions mMockTransitions; @Before public void setUp() throws RemoteException { @@ -89,7 +91,7 @@ public class OverviewProxyServiceTest extends SysuiTestCase { mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController, mMockSysUiState, mMockPipOptional, mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional, - mMockBroadcastDispatcher)); + mMockBroadcastDispatcher, mMockTransitions)); } @Test