diff options
| author | 2017-12-18 20:34:14 +0000 | |
|---|---|---|
| committer | 2017-12-20 17:04:15 +0000 | |
| commit | 089c35e9311386844332dbe2ca09076f845a604c (patch) | |
| tree | 10edc35bd71ac49860015ca6c558f42805345a47 | |
| parent | 5c9d80199e48322ab9939bc78d3ffeb224817a4c (diff) | |
Enforce platform level animation in CrossProfileApps.startMainActivity
With this change, whenever apps start an activity in another profile
using CrossProfileApps.startMainActivity, an animation will be enforced.
For now, we are showing the "open task" animation.
We may put something fancier if we have time in P.
Test: cts-tradefed run cts-dev --module DevicePolicyManager --test - com.android.cts.devicepolicy.CrossProfileAppsHostsideTest
Test: atest services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java
Bug: 70799822
Change-Id: I03525080151c6112633108419d69d64e76a511f3
10 files changed, 68 insertions, 57 deletions
diff --git a/api/current.txt b/api/current.txt index 50b054070919..ea49420cdb65 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11298,7 +11298,7 @@ package android.content.pm.crossprofile { method public android.graphics.drawable.Drawable getProfileSwitchingIcon(android.os.UserHandle); method public java.lang.CharSequence getProfileSwitchingLabel(android.os.UserHandle); method public java.util.List<android.os.UserHandle> getTargetUserProfiles(); - method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); + method public void startMainActivity(android.content.ComponentName, android.os.UserHandle); } } diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 4a21f5c424d5..e61c5b7c78a1 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -36,6 +36,7 @@ import android.os.IRemoteCallback; import android.os.Parcelable; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.UserHandle; import android.transition.Transition; import android.transition.TransitionListenerAdapter; import android.transition.TransitionManager; @@ -265,6 +266,8 @@ public class ActivityOptions { public static final int ANIM_CUSTOM_IN_PLACE = 10; /** @hide */ public static final int ANIM_CLIP_REVEAL = 11; + /** @hide */ + public static final int ANIM_OPEN_CROSS_PROFILE_APPS = 12; private String mPackageName; private Rect mLaunchBounds; @@ -486,6 +489,19 @@ public class ActivityOptions { } /** + * Creates an {@link ActivityOptions} object specifying an animation where the new activity + * is started in another user profile by calling {@link + * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle) + * }. + * @hide + */ + public static ActivityOptions makeOpenCrossProfileAppsAnimation() { + ActivityOptions options = new ActivityOptions(); + options.mAnimationType = ANIM_OPEN_CROSS_PROFILE_APPS; + return options; + } + + /** * Create an ActivityOptions specifying an animation where a thumbnail * is scaled from a given position to the new activity window that is * being started. diff --git a/core/java/android/content/pm/crossprofile/CrossProfileApps.java b/core/java/android/content/pm/crossprofile/CrossProfileApps.java index c9f184a7da53..414c13894f80 100644 --- a/core/java/android/content/pm/crossprofile/CrossProfileApps.java +++ b/core/java/android/content/pm/crossprofile/CrossProfileApps.java @@ -16,7 +16,6 @@ package android.content.pm.crossprofile; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; @@ -61,15 +60,10 @@ public class CrossProfileApps { * @param user The UserHandle of the profile, must be one of the users returned by * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will * be thrown. - * @param sourceBounds The Rect containing the source bounds of the clicked icon, see - * {@link android.content.Intent#setSourceBounds(Rect)}. - * @param startActivityOptions Options to pass to startActivity */ - public void startMainActivity(@NonNull ComponentName component, @NonNull UserHandle user, - @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) { + public void startMainActivity(@NonNull ComponentName component, @NonNull UserHandle user) { try { - mService.startActivityAsUser(mContext.getPackageName(), - component, sourceBounds, startActivityOptions, user); + mService.startActivityAsUser(mContext.getPackageName(), component, user); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } diff --git a/core/java/android/content/pm/crossprofile/ICrossProfileApps.aidl b/core/java/android/content/pm/crossprofile/ICrossProfileApps.aidl index dd8d04f6cf0e..227f91f5d3e1 100644 --- a/core/java/android/content/pm/crossprofile/ICrossProfileApps.aidl +++ b/core/java/android/content/pm/crossprofile/ICrossProfileApps.aidl @@ -26,6 +26,7 @@ import android.os.UserHandle; * @hide */ interface ICrossProfileApps { - void startActivityAsUser(in String callingPackage, in ComponentName component, in Rect sourceBounds, in Bundle startActivityOptions, in UserHandle user); + void startActivityAsUser(in String callingPackage, in ComponentName component, + in UserHandle user); List<UserHandle> getTargetUserProfiles(in String callingPackage); }
\ No newline at end of file diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4b2424ffd213..63882e423fce 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1573,6 +1573,8 @@ <java-symbol type="anim" name="voice_activity_close_enter" /> <java-symbol type="anim" name="voice_activity_open_exit" /> <java-symbol type="anim" name="voice_activity_open_enter" /> + <java-symbol type="anim" name="activity_open_exit" /> + <java-symbol type="anim" name="activity_open_enter" /> <java-symbol type="array" name="config_autoRotationTiltTolerance" /> <java-symbol type="array" name="config_keyboardTapVibePattern" /> diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 69f6d5eef275..8eb519797641 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -23,6 +23,7 @@ import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; import static android.app.ActivityOptions.ANIM_CUSTOM; import static android.app.ActivityOptions.ANIM_SCALE_UP; import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION; +import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN; import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP; import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN; @@ -1476,6 +1477,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } break; + case ANIM_OPEN_CROSS_PROFILE_APPS: + service.mWindowManager.overridePendingAppTransitionStartCrossProfileApps(); + break; default: Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType); break; diff --git a/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java index 854b70439d56..d6281c51b3fa 100644 --- a/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java @@ -19,6 +19,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import android.annotation.UserIdInt; +import android.app.ActivityOptions; import android.app.AppOpsManager; import android.content.ComponentName; import android.content.Context; @@ -74,8 +75,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public void startActivityAsUser( String callingPackage, ComponentName component, - Rect sourceBounds, - Bundle startActivityOptions, UserHandle user) throws RemoteException { Preconditions.checkNotNull(callingPackage); Preconditions.checkNotNull(component); @@ -103,7 +102,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { // CATEGORY_LAUNCHER as calling startActivityAsUser ignore them if component is present. final Intent launchIntent = new Intent(Intent.ACTION_MAIN); launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); - launchIntent.setSourceBounds(sourceBounds); launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); // Only package name is set here, as opposed to component name, because intent action and @@ -114,7 +112,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { final long ident = mInjector.clearCallingIdentity(); try { launchIntent.setComponent(component); - mContext.startActivityAsUser(launchIntent, startActivityOptions, user); + mContext.startActivityAsUser(launchIntent, + ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(), user); } finally { mInjector.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index c2cbced2311c..4a74e295c8fc 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -44,17 +44,17 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIO 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.WindowManagerInternal.AppTransitionListener; +import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; -import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; 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.Nullable; import android.app.ActivityManager; +import android.content.ComponentName; import android.content.Context; import android.content.res.Configuration; -import android.graphics.Bitmap; import android.graphics.GraphicBuffer; import android.graphics.Path; import android.graphics.Rect; @@ -64,6 +64,7 @@ import android.os.IBinder; import android.os.IRemoteCallback; import android.os.RemoteException; import android.os.SystemProperties; +import android.os.UserHandle; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; @@ -199,6 +200,13 @@ public class AppTransition implements Dump { private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6; private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7; private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8; + + /** + * Refers to the transition to activity started by using {@link + * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle) + * }. + */ + private static final int NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS = 9; private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; // These are the possible states for the enter/exit activities during a thumbnail transition @@ -1605,6 +1613,17 @@ public class AppTransition implements Dump { + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); } + } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS + && (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); + Slog.v(TAG, + "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:" + + " anim=" + a + " transit=" + appTransitionToString(transit) + + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); } else { int animAttr = 0; switch (transit) { @@ -1833,6 +1852,17 @@ public class AppTransition implements Dump { } /** + * @see {@link #NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS} + */ + void overridePendingAppTransitionStartCrossProfileApps() { + if (isTransitionSet()) { + clear(); + mNextAppTransitionType = NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS; + postAnimationCallback(); + } + } + + /** * If a future is set for the app transition specs, fetch it in another thread. */ private void fetchAppTransitionSpecsFromFuture() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9fc9f3c15cfc..58a5ca498291 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2706,6 +2706,12 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void overridePendingAppTransitionStartCrossProfileApps() { + synchronized (mWindowMap) { + mAppTransition.overridePendingAppTransitionStartCrossProfileApps(); + } + } + void prolongAnimationsFromSpecs(@NonNull AppTransitionAnimationSpec[] specs, boolean scaleUp) { // This is used by freeform <-> recents windows transition. We need to synchronize // the animation with the appearance of the content of recents, so we will make diff --git a/services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java index 880b77ed81da..ff55a2ba120b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java @@ -205,8 +205,6 @@ public class CrossProfileAppsServiceImplTest { mCrossProfileAppsServiceImpl.startActivityAsUser( PACKAGE_ONE, ACTIVITY_COMPONENT, - null, - null, UserHandle.of(PRIMARY_USER))); verify(mContext, never()) @@ -217,33 +215,6 @@ public class CrossProfileAppsServiceImplTest { } @Test - public void startActivityAsUser_profile_successWithOption() throws Exception { - Bundle options = Bundle.forPair("test_key", "test_value"); - - mCrossProfileAppsServiceImpl.startActivityAsUser( - PACKAGE_ONE, - ACTIVITY_COMPONENT, - null, - options, - UserHandle.of(PROFILE_OF_PRIMARY_USER)); - - ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); - ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); - - verify(mContext) - .startActivityAsUser( - intentCaptor.capture(), - bundleCaptor.capture(), - eq(UserHandle.of(PROFILE_OF_PRIMARY_USER))); - - Intent intent = intentCaptor.getValue(); - assertEquals(ACTIVITY_COMPONENT, intent.getComponent()); - - Bundle bundle = bundleCaptor.getValue(); - assertEquals("test_value", bundle.getString("test_key")); - } - - @Test public void startActivityAsUser_profile_notInstalled() throws Exception { mockAppsInstalled(PACKAGE_ONE, PROFILE_OF_PRIMARY_USER, false); @@ -253,8 +224,6 @@ public class CrossProfileAppsServiceImplTest { mCrossProfileAppsServiceImpl.startActivityAsUser( PACKAGE_ONE, ACTIVITY_COMPONENT, - null, - null, UserHandle.of(PROFILE_OF_PRIMARY_USER))); verify(mContext, never()) @@ -272,8 +241,6 @@ public class CrossProfileAppsServiceImplTest { mCrossProfileAppsServiceImpl.startActivityAsUser( PACKAGE_TWO, ACTIVITY_COMPONENT, - null, - null, UserHandle.of(PROFILE_OF_PRIMARY_USER))); verify(mContext, never()) @@ -293,8 +260,6 @@ public class CrossProfileAppsServiceImplTest { mCrossProfileAppsServiceImpl.startActivityAsUser( PACKAGE_ONE, ACTIVITY_COMPONENT, - null, - null, UserHandle.of(PROFILE_OF_PRIMARY_USER))); verify(mContext, never()) @@ -312,8 +277,6 @@ public class CrossProfileAppsServiceImplTest { mCrossProfileAppsServiceImpl.startActivityAsUser( PACKAGE_ONE, new ComponentName(PACKAGE_TWO, "test"), - null, - null, UserHandle.of(PROFILE_OF_PRIMARY_USER))); verify(mContext, never()) @@ -331,8 +294,6 @@ public class CrossProfileAppsServiceImplTest { mCrossProfileAppsServiceImpl.startActivityAsUser( PACKAGE_ONE, ACTIVITY_COMPONENT, - null, - null, UserHandle.of(SECONDARY_USER))); verify(mContext, never()) @@ -349,8 +310,6 @@ public class CrossProfileAppsServiceImplTest { mCrossProfileAppsServiceImpl.startActivityAsUser( PACKAGE_ONE, ACTIVITY_COMPONENT, - null, - null, UserHandle.of(PRIMARY_USER)); verify(mContext) |