diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml new file mode 100644 index 0000000000000..3254ebba2f660 --- /dev/null +++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml index e511cc9d99314..b73e14fc637f3 100644 --- a/core/res/res/anim/task_open_enter.xml +++ b/core/res/res/anim/task_open_enter.xml @@ -16,7 +16,7 @@ ** limitations under the License. */ --> - + diff --git a/core/res/res/anim/task_open_enter_cross_profile_apps.xml b/core/res/res/anim/task_open_enter_cross_profile_apps.xml new file mode 100644 index 0000000000000..ad89fde920659 --- /dev/null +++ b/core/res/res/anim/task_open_enter_cross_profile_apps.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index a659b370560f3..6c1661c4abc2e 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -631,4 +631,8 @@ 2dp + + + 72dp + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4343ba01702b0..9f582ad8768d9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1578,8 +1578,10 @@ - - + + + + @@ -1726,6 +1728,7 @@ + diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 2ac758344f52e..d4b437a5a25e1 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -49,14 +49,17 @@ import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; import static com.android.server.wm.proto.AppTransitionProto.APP_TRANSITION_STATE; import static com.android.server.wm.proto.AppTransitionProto.LAST_USED_APP_TRANSITION; +import android.annotation.DrawableRes; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Color; import android.graphics.GraphicBuffer; import android.graphics.Path; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Binder; import android.os.Debug; import android.os.IBinder; @@ -70,7 +73,10 @@ import android.util.Slog; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import android.view.AppTransitionAnimationSpec; +import android.view.DisplayListCanvas; import android.view.IAppTransitionAnimationSpecsFuture; +import android.view.RenderNode; +import android.view.ThreadedRenderer; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -391,6 +397,11 @@ public class AppTransition implements Dump { mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; } + + boolean isNextAppTransitionOpenCrossProfileApps() { + return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS; + } + /** * @return true if and only if we are currently fetching app transition specs from the future * passed into {@link #overridePendingAppTransitionMultiThumbFuture} @@ -977,6 +988,43 @@ public class AppTransition implements Dump { } } + /** + * Creates an overlay with a background color and a thumbnail for the cross profile apps + * animation. + */ + GraphicBuffer createCrossProfileAppsThumbnail( + @DrawableRes int thumbnailDrawableRes, Rect frame) { + final int width = frame.width(); + final int height = frame.height(); + + final RenderNode node = RenderNode.create("CrossProfileAppsThumbnail", null); + node.setLeftTopRightBottom(0, 0, width, height); + node.setClipToBounds(false); + + final DisplayListCanvas canvas = node.start(width, height); + canvas.drawColor(Color.argb(0.6f, 0, 0, 0)); + final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.cross_profile_apps_thumbnail_size); + final Drawable drawable = mService.mContext.getDrawable(thumbnailDrawableRes); + drawable.setBounds( + (width - thumbnailSize) / 2, + (height - thumbnailSize) / 2, + (width + thumbnailSize) / 2, + (height + thumbnailSize) / 2); + drawable.draw(canvas); + node.end(canvas); + + return ThreadedRenderer.createHardwareBitmap(node, width, height) + .createGraphicBufferHandle(); + } + + Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) { + final Animation animation = loadAnimationRes( + "android", com.android.internal.R.anim.cross_profile_apps_thumbnail_enter); + return prepareThumbnailAnimationWithDuration(animation, appRect.width(), + appRect.height(), 0, null); + } + /** * This animation runs for the thumbnail that gets cross faded with the enter/exit activity * when a thumbnail is specified with the pending animation override. @@ -1624,9 +1672,10 @@ public class AppTransition implements Dump { && (transit == TRANSIT_ACTIVITY_OPEN || transit == TRANSIT_TASK_OPEN || transit == TRANSIT_TASK_TO_FRONT)) { + a = loadAnimationRes("android", enter - ? com.android.internal.R.anim.activity_open_enter - : com.android.internal.R.anim.activity_open_exit); + ? com.android.internal.R.anim.task_open_enter_cross_profile_apps + : com.android.internal.R.anim.task_open_exit); Slog.v(TAG, "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:" + " anim=" + a + " transit=" + appTransitionToString(transit) @@ -2007,6 +2056,8 @@ public class AppTransition implements Dump { return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP"; case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN"; + case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: + return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS"; default: return "unknown type=" + mNextAppTransitionType; } diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java index 0d65790ce9e56..487b52ca02b95 100644 --- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java +++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java @@ -85,10 +85,14 @@ class AppWindowThumbnail implements Animatable { } void startAnimation(Transaction t, Animation anim) { + startAnimation(t, anim, null /* position */); + } + + void startAnimation(Transaction t, Animation anim, Point position) { anim.restrictDuration(MAX_ANIMATION_DURATION); anim.scaleCurrentDuration(mAppToken.mService.getTransitionAnimationScaleLocked()); mSurfaceAnimator.startAnimation(t, new LocalAnimationAdapter( - new WindowAnimationSpec(anim, null /* position */, + new WindowAnimationSpec(anim, position, mAppToken.mService.mAppTransition.canSkipFirstFrame()), mAppToken.mService.mSurfaceAnimationRunner), false /* hidden */); } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 01e925e509c82..fc0564d35a3f7 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; @@ -31,6 +30,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; + import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.AppTransition.TRANSIT_UNSET; @@ -56,7 +56,6 @@ import static com.android.server.wm.proto.AppWindowTokenProto.WINDOW_TOKEN; import android.annotation.CallSuper; import android.app.Activity; -import android.app.WindowConfiguration.WindowingMode; import android.content.res.Configuration; import android.graphics.GraphicBuffer; import android.graphics.Point; @@ -69,13 +68,14 @@ import android.os.Trace; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; -import android.view.SurfaceControl.Transaction; -import android.view.animation.Animation; import android.view.IApplicationToken; import android.view.SurfaceControl; +import android.view.SurfaceControl.Transaction; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; +import android.view.animation.Animation; +import com.android.internal.R; import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.policy.WindowManagerPolicy.StartingSurface; @@ -1775,6 +1775,37 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader)); } + /** + * Attaches a surface with a thumbnail for the + * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation. + */ + void attachCrossProfileAppsThumbnailAnimation() { + if (!isReallyAnimating()) { + return; + } + clearThumbnail(); + + final WindowState win = findMainWindow(); + if (win == null) { + return; + } + final Rect frame = win.mFrame; + final int thumbnailDrawableRes = getTask().mUserId == mService.mCurrentUserId + ? R.drawable.ic_account_circle + : R.drawable.ic_corp_badge_no_background; + final GraphicBuffer thumbnail = + mService.mAppTransition + .createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame); + if (thumbnail == null) { + return; + } + mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnail); + final Animation animation = + mService.mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(win.mFrame); + mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left, + frame.top)); + } + private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) { final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 08f49f6893231..a512fdf828b33 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT; import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN; import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN; + import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE; @@ -43,28 +44,19 @@ import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING; import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE; import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD; -import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; -import android.content.res.Configuration; -import android.graphics.GraphicBuffer; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.os.Binder; import android.os.Debug; import android.os.Trace; import android.util.ArraySet; import android.util.Slog; import android.util.SparseIntArray; import android.view.Display; -import android.view.DisplayInfo; -import android.view.Surface; import android.view.SurfaceControl; import android.view.WindowManager.LayoutParams; import android.view.animation.Animation; @@ -414,7 +406,6 @@ class WindowSurfacePlacer { } wtoken.updateReportedVisibilityLocked(); wtoken.waitingToShow = false; - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()"); mService.openSurfaceTransaction(); @@ -435,6 +426,8 @@ class WindowSurfacePlacer { } if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) { wtoken.attachThumbnailAnimation(); + } else if (mService.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) { + wtoken.attachCrossProfileAppsThumbnailAnimation(); } } return topOpeningApp;