Allow overriding managed profile switching animation
Bug: 203548565 Bug: 188410712 Test: manual Change-Id: I1bf75abcee4309eee5c03f76238bb21fb8549c02
This commit is contained in:
committed by
Kholoud Mohamed
parent
e3fbc9417f
commit
dd7c79d26b
@@ -29,7 +29,6 @@ import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||
|
||||
import android.annotation.DrawableRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
@@ -915,7 +914,7 @@ public class TransitionAnimation {
|
||||
* animation.
|
||||
*/
|
||||
public HardwareBuffer createCrossProfileAppsThumbnail(
|
||||
@DrawableRes int thumbnailDrawableRes, Rect frame) {
|
||||
Drawable thumbnailDrawable, Rect frame) {
|
||||
final int width = frame.width();
|
||||
final int height = frame.height();
|
||||
|
||||
@@ -924,14 +923,13 @@ public class TransitionAnimation {
|
||||
canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
|
||||
final int thumbnailSize = mContext.getResources().getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
|
||||
final Drawable drawable = mContext.getDrawable(thumbnailDrawableRes);
|
||||
drawable.setBounds(
|
||||
thumbnailDrawable.setBounds(
|
||||
(width - thumbnailSize) / 2,
|
||||
(height - thumbnailSize) / 2,
|
||||
(width + thumbnailSize) / 2,
|
||||
(height + thumbnailSize) / 2);
|
||||
drawable.setTint(mContext.getColor(android.R.color.white));
|
||||
drawable.draw(canvas);
|
||||
thumbnailDrawable.setTint(mContext.getColor(android.R.color.white));
|
||||
thumbnailDrawable.draw(canvas);
|
||||
picture.endRecording();
|
||||
|
||||
return Bitmap.createBitmap(picture).getHardwareBuffer();
|
||||
|
||||
@@ -471,9 +471,10 @@ public abstract class WMShellBaseModule {
|
||||
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,
|
||||
DisplayController displayController, Context context,
|
||||
@ShellMainThread ShellExecutor mainExecutor,
|
||||
@ShellMainThread Handler mainHandler,
|
||||
@ShellAnimationThread ShellExecutor animExecutor) {
|
||||
return new Transitions(organizer, pool, displayController, context, mainExecutor,
|
||||
animExecutor);
|
||||
mainHandler, animExecutor);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
|
||||
@@ -25,6 +25,11 @@ import static android.app.ActivityOptions.ANIM_SCALE_UP;
|
||||
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
|
||||
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
|
||||
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
|
||||
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
|
||||
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
|
||||
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
|
||||
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
|
||||
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
|
||||
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
|
||||
@@ -57,11 +62,17 @@ import android.annotation.ColorInt;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
@@ -118,6 +129,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final ShellExecutor mAnimExecutor;
|
||||
private final TransitionAnimation mTransitionAnimation;
|
||||
private final DevicePolicyManager mDevicePolicyManager;
|
||||
|
||||
private final SurfaceSession mSurfaceSession = new SurfaceSession();
|
||||
|
||||
@@ -132,9 +144,24 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
|
||||
private ScreenRotationAnimation mRotationAnimation;
|
||||
|
||||
private Drawable mEnterpriseThumbnailDrawable;
|
||||
|
||||
private BroadcastReceiver mEnterpriseResourceUpdatedReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
boolean isDrawable = intent.getBooleanExtra(
|
||||
EXTRA_RESOURCE_TYPE_DRAWABLE, /* default= */ false);
|
||||
if (!isDrawable) {
|
||||
return;
|
||||
}
|
||||
updateEnterpriseThumbnailDrawable();
|
||||
}
|
||||
};
|
||||
|
||||
DefaultTransitionHandler(@NonNull DisplayController displayController,
|
||||
@NonNull TransactionPool transactionPool, Context context,
|
||||
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
|
||||
@NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler,
|
||||
@NonNull ShellExecutor animExecutor) {
|
||||
mDisplayController = displayController;
|
||||
mTransactionPool = transactionPool;
|
||||
mContext = context;
|
||||
@@ -143,9 +170,23 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
mTransitionAnimation = new TransitionAnimation(context, false /* debug */, Transitions.TAG);
|
||||
mCurrentUserId = UserHandle.myUserId();
|
||||
|
||||
mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
|
||||
updateEnterpriseThumbnailDrawable();
|
||||
mContext.registerReceiver(
|
||||
mEnterpriseResourceUpdatedReceiver,
|
||||
new IntentFilter(ACTION_DEVICE_POLICY_RESOURCE_UPDATED),
|
||||
/* broadcastPermission = */ null,
|
||||
mainHandler);
|
||||
|
||||
AttributeCache.init(context);
|
||||
}
|
||||
|
||||
private void updateEnterpriseThumbnailDrawable() {
|
||||
mEnterpriseThumbnailDrawable = mDevicePolicyManager.getDrawable(
|
||||
WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
|
||||
() -> mContext.getDrawable(R.drawable.ic_corp_badge));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isRotationSeamless(@NonNull TransitionInfo info,
|
||||
DisplayController displayController) {
|
||||
@@ -632,7 +673,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
final boolean isClose = Transitions.isClosingType(change.getMode());
|
||||
if (isOpen) {
|
||||
if (options.getType() == ANIM_OPEN_CROSS_PROFILE_APPS && isTask) {
|
||||
attachCrossProfileThunmbnailAnimation(animations, finishCallback, change,
|
||||
attachCrossProfileThumbnailAnimation(animations, finishCallback, change,
|
||||
cornerRadius);
|
||||
} else if (options.getType() == ANIM_THUMBNAIL_SCALE_UP) {
|
||||
attachThumbnailAnimation(animations, finishCallback, change, options, cornerRadius);
|
||||
@@ -642,13 +683,14 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void attachCrossProfileThunmbnailAnimation(@NonNull ArrayList<Animator> animations,
|
||||
private void attachCrossProfileThumbnailAnimation(@NonNull ArrayList<Animator> animations,
|
||||
@NonNull Runnable finishCallback, TransitionInfo.Change change, float cornerRadius) {
|
||||
final int thumbnailDrawableRes = change.getTaskInfo().userId == mCurrentUserId
|
||||
? R.drawable.ic_account_circle : R.drawable.ic_corp_badge;
|
||||
final Rect bounds = change.getEndAbsBounds();
|
||||
// Show the right drawable depending on the user we're transitioning to.
|
||||
final Drawable thumbnailDrawable = change.getTaskInfo().userId == mCurrentUserId
|
||||
? mContext.getDrawable(R.drawable.ic_account_circle) : mEnterpriseThumbnailDrawable;
|
||||
final HardwareBuffer thumbnail = mTransitionAnimation.createCrossProfileAppsThumbnail(
|
||||
thumbnailDrawableRes, bounds);
|
||||
thumbnailDrawable, bounds);
|
||||
if (thumbnail == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.annotation.Nullable;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
@@ -123,7 +124,8 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
|
||||
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
|
||||
@NonNull DisplayController displayController, @NonNull Context context,
|
||||
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
|
||||
@NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler,
|
||||
@NonNull ShellExecutor animExecutor) {
|
||||
mOrganizer = organizer;
|
||||
mContext = context;
|
||||
mMainExecutor = mainExecutor;
|
||||
@@ -132,7 +134,7 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
mPlayerImpl = new TransitionPlayerImpl();
|
||||
// The very last handler (0 in the list) should be the default one.
|
||||
mHandlers.add(new DefaultTransitionHandler(displayController, pool, context, mainExecutor,
|
||||
animExecutor));
|
||||
mainHandler, animExecutor));
|
||||
// Next lowest priority is remote transitions.
|
||||
mRemoteTransitionHandler = new RemoteTransitionHandler(mainExecutor);
|
||||
mHandlers.add(mRemoteTransitionHandler);
|
||||
|
||||
@@ -54,7 +54,9 @@ import static org.mockito.Mockito.verify;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.view.IDisplayWindowListener;
|
||||
import android.view.IWindowManager;
|
||||
@@ -84,8 +86,6 @@ import com.android.wm.shell.common.TransactionPool;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -106,6 +106,7 @@ public class ShellTransitionTests {
|
||||
private final TestShellExecutor mMainExecutor = new TestShellExecutor();
|
||||
private final ShellExecutor mAnimExecutor = new TestShellExecutor();
|
||||
private final TestTransitionHandler mDefaultHandler = new TestTransitionHandler();
|
||||
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -752,7 +753,7 @@ public class ShellTransitionTests {
|
||||
|
||||
private Transitions createTestTransitions() {
|
||||
return new Transitions(mOrganizer, mTransactionPool, createTestDisplayController(),
|
||||
mContext, mMainExecutor, mAnimExecutor);
|
||||
mContext, mMainExecutor, mMainHandler, mAnimExecutor);
|
||||
}
|
||||
//
|
||||
// private class TestDisplayController extends DisplayController {
|
||||
|
||||
@@ -46,6 +46,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.activityTypeToString;
|
||||
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
|
||||
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
|
||||
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
|
||||
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
|
||||
import static android.content.Intent.ACTION_MAIN;
|
||||
import static android.content.Intent.CATEGORY_HOME;
|
||||
import static android.content.Intent.CATEGORY_LAUNCHER;
|
||||
@@ -241,6 +244,7 @@ import android.app.TaskInfo;
|
||||
import android.app.TaskInfo.CameraCompatControlState;
|
||||
import android.app.WaitResult;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.servertransaction.ActivityConfigurationChangeItem;
|
||||
import android.app.servertransaction.ActivityLifecycleItem;
|
||||
import android.app.servertransaction.ActivityRelaunchItem;
|
||||
@@ -272,6 +276,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
@@ -538,6 +543,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// Tracking splash screen status from previous activity
|
||||
boolean mSplashScreenStyleEmpty = false;
|
||||
|
||||
Drawable mEnterpriseThumbnailDrawable;
|
||||
|
||||
private void updateEnterpriseThumbnailDrawable(Context context) {
|
||||
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
|
||||
mEnterpriseThumbnailDrawable = dpm.getDrawable(
|
||||
WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
|
||||
() -> context.getDrawable(R.drawable.ic_corp_badge));
|
||||
}
|
||||
|
||||
static final int LAUNCH_SOURCE_TYPE_SYSTEM = 1;
|
||||
static final int LAUNCH_SOURCE_TYPE_HOME = 2;
|
||||
static final int LAUNCH_SOURCE_TYPE_SYSTEMUI = 3;
|
||||
@@ -1930,6 +1944,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
mAtmService.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, packageName);
|
||||
|
||||
mActivityRecordInputSink = new ActivityRecordInputSink(this);
|
||||
|
||||
updateEnterpriseThumbnailDrawable(mAtmService.mUiContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6993,12 +7009,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return;
|
||||
}
|
||||
final Rect frame = win.getRelativeFrame();
|
||||
final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId
|
||||
? R.drawable.ic_account_circle
|
||||
: R.drawable.ic_corp_badge;
|
||||
final HardwareBuffer thumbnail =
|
||||
getDisplayContent().mAppTransition
|
||||
.createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame);
|
||||
final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
|
||||
? mAtmService.mUiContext.getDrawable(R.drawable.ic_account_circle)
|
||||
: mEnterpriseThumbnailDrawable;
|
||||
final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
|
||||
.createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
|
||||
if (thumbnail == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@ import static com.android.server.wm.WindowManagerInternal.KeyguardExitAnimationS
|
||||
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
|
||||
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
|
||||
|
||||
import android.annotation.DrawableRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
@@ -101,6 +100,7 @@ import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.os.Binder;
|
||||
import android.os.Debug;
|
||||
@@ -539,8 +539,8 @@ public class AppTransition implements Dump {
|
||||
* animation.
|
||||
*/
|
||||
HardwareBuffer createCrossProfileAppsThumbnail(
|
||||
@DrawableRes int thumbnailDrawableRes, Rect frame) {
|
||||
return mTransitionAnimation.createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame);
|
||||
Drawable thumbnailDrawable, Rect frame) {
|
||||
return mTransitionAnimation.createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
|
||||
}
|
||||
|
||||
Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
|
||||
|
||||
Reference in New Issue
Block a user