diff options
13 files changed, 82 insertions, 9 deletions
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index ccc37d72e846..d9a46903ee38 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -193,6 +193,7 @@ public class ActivityOptions { = "android:activity.exitCoordinatorIndex"; private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport"; + private static final String KEY_ROTATION_ANIMATION_HINT = "android:activity.rotationAnimationHint"; /** @hide */ public static final int ANIM_NONE = 0; @@ -244,6 +245,7 @@ public class ActivityOptions { private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; private boolean mTaskOverlay; private AppTransitionAnimationSpec mAnimSpecs[]; + private int mRotationAnimationHint = -1; /** * Create an ActivityOptions specifying a custom animation to run when @@ -863,6 +865,7 @@ public class ActivityOptions { mAnimationFinishedListener = IRemoteCallback.Stub.asInterface( opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER)); } + mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT); } /** @@ -1216,6 +1219,7 @@ public class ActivityOptions { if (mAnimationFinishedListener != null) { b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder()); } + b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint); return b; } @@ -1262,6 +1266,27 @@ public class ActivityOptions { return null; } + /** + * Returns the rotation animation set by {@link setRotationAnimationHint} or -1 + * if unspecified. + * @hide + */ + public int getRotationAnimationHint() { + return mRotationAnimationHint; + } + + + /** + * Set a rotation animation to be used if launching the activity + * triggers an orientation change, or -1 to clear. See + * {@link android.view.WindowManager.LayoutParams} for rotation + * animation values. + * @hide + */ + public void setRotationAnimationHint(int hint) { + mRotationAnimationHint = hint; + } + /** @hide */ @Override public String toString() { diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 72126d0329a3..e3ff54d40316 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -112,7 +112,7 @@ interface IWindowManager int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId, int configChanges, boolean voiceInteraction, boolean launchTaskBehind, in Rect taskBounds, in Configuration configuration, int taskResizeMode, - boolean alwaysFocusable, boolean homeTask, int targetSdkVersion); + boolean alwaysFocusable, boolean homeTask, int targetSdkVersion, int rotationAnimationHint); /** * * @param token The token we are adding to the input task Id. diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index a8afaf20a1c5..9a8c8a86499a 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -416,6 +416,8 @@ public interface WindowManagerPolicy { * screen with other application windows. */ public boolean isInMultiWindowMode(); + + public int getRotationAnimationHint(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 772c76642b9e..a98601a33300 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.ActivityOptions; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -44,6 +45,7 @@ import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.TextView; @@ -448,12 +450,24 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void run() { int result = ActivityManager.START_CANCELED; + + // Normally an activity will set it's requested rotation + // animation on its window. However when launching an activity + // causes the orientation to change this is too late. In these cases + // the default animation is used. This doesn't look good for + // the camera (as it rotates the camera contents out of sync + // with physical reality). So, we ask the WindowManager to + // force the crossfade animation if an orientation change + // happens to occur during the launch. + ActivityOptions o = ActivityOptions.makeBasic(); + o.setRotationAnimationHint( + WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE); try { result = ActivityManagerNative.getDefault().startActivityAsUser( null, getContext().getBasePackageName(), intent, intent.resolveTypeIfNeeded(getContext().getContentResolver()), - null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, + null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, o.toBundle(), UserHandle.CURRENT.getIdentifier()); } catch (RemoteException e) { Log.w(TAG, "Unable to start camera activity", e); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 4de769db61c6..fcb1da0033bb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.ActivityOptions; import android.app.IActivityManager; import android.app.Notification; import android.app.PendingIntent; @@ -3322,13 +3323,26 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); int result = ActivityManager.START_CANCELED; + ActivityOptions options = new ActivityOptions(getActivityOptions()); + if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) { + // Normally an activity will set it's requested rotation + // animation on its window. However when launching an activity + // causes the orientation to change this is too late. In these cases + // the default animation is used. This doesn't look good for + // the camera (as it rotates the camera contents out of sync + // with physical reality). So, we ask the WindowManager to + // force the crossfade animation if an orientation change + // happens to occur during the launch. + options.setRotationAnimationHint( + WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE); + } try { result = ActivityManagerNative.getDefault().startActivityAsUser( null, mContext.getBasePackageName(), intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, - getActivityOptions(), UserHandle.CURRENT.getIdentifier()); + options.toBundle(), UserHandle.CURRENT.getIdentifier()); } catch (RemoteException e) { Log.w(TAG, "Unable to start activity", e); } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 50b6c0c7502f..6e40cfff5411 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -221,6 +221,8 @@ final class ActivityRecord { boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session IVoiceInteractionSession voiceSession; // Voice interaction session for this activity + int mRotationAnimationHint; + private static String startingWindowStateToString(int state) { switch (state) { case STARTING_WINDOW_NOT_SHOWN: @@ -635,6 +637,7 @@ final class ActivityRecord { if (options != null) { pendingOptions = options; mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind(); + mRotationAnimationHint = pendingOptions.getRotationAnimationHint(); PendingIntent usageReport = pendingOptions.getUsageTimeReport(); if (usageReport != null) { appTimeTracker = new AppTimeTracker(usageReport); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 6d229466ebf9..fc649a1ea140 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -5199,7 +5199,7 @@ final class ActivityStack { (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig, task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(), - r.appInfo.targetSdkVersion); + r.appInfo.targetSdkVersion, r.mRotationAnimationHint); r.taskConfigOverride = task.mOverrideConfig; } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 22521b916ba8..0e732271403b 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2874,8 +2874,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { + mTopFullscreenOpaqueWindowState + " rotationAnimation=" + (mTopFullscreenOpaqueWindowState == null ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)); - if (mTopFullscreenOpaqueWindowState != null && mTopIsFullscreen) { - switch (mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation) { + if (mTopFullscreenOpaqueWindowState != null) { + int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint(); + if (animationHint < 0 && mTopIsFullscreen) { + animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation; + } + switch (animationHint) { case ROTATION_ANIMATION_CROSSFADE: anim[0] = R.anim.rotation_animation_xfade_exit; anim[1] = R.anim.rotation_animation_enter; diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index edcc32e5b587..776a1753aa72 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -132,6 +132,7 @@ class AppWindowToken extends WindowToken { boolean mAlwaysFocusable; boolean mAppStopped; + int mRotationAnimationHint; int mPendingRelaunchCount; ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b8accf547686..59ddab08c4c8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3429,7 +3429,7 @@ public class WindowManagerService extends IWindowManager.Stub int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId, int configChanges, boolean voiceInteraction, boolean launchTaskBehind, Rect taskBounds, Configuration config, int taskResizeMode, boolean alwaysFocusable, - boolean homeTask, int targetSdkVersion) { + boolean homeTask, int targetSdkVersion, int rotationAnimationHint) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "addAppToken()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); @@ -3467,6 +3467,7 @@ public class WindowManagerService extends IWindowManager.Stub atoken.mAlwaysFocusable = alwaysFocusable; if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken + " to stack=" + stackId + " task=" + taskId + " at " + addPos); + atoken.mRotationAnimationHint = rotationAnimationHint; Task task = mTaskIdToTask.get(taskId); if (task == null) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 99fec7bdb791..1ac3d44c7a45 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2908,4 +2908,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean shouldBeReplacedWithChildren() { return isChildWindow() || mAttrs.type == TYPE_APPLICATION; } + + public int getRotationAnimationHint() { + if (mAppToken != null) { + return mAppToken.mRotationAnimationHint; + } else { + return -1; + } + } } diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index a726a15f7cc2..063dd8631565 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -93,7 +93,7 @@ public class WindowManagerPermissionTests extends TestCase { try { mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null, - Configuration.EMPTY, 0, false, false, 0); + Configuration.EMPTY, 0, false, false, 0, -1); fail("IWindowManager.addAppToken did not throw SecurityException as" + " expected"); } catch (SecurityException e) { diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 04a59bcfb5ae..4e4da8bb3f08 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -78,7 +78,8 @@ public class IWindowManagerImpl implements IWindowManager { @Override public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4, boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10, - Rect arg11, Configuration arg12, int arg13, boolean arg14, boolean arg15, int arg16) + Rect arg11, Configuration arg12, int arg13, boolean arg14, boolean arg15, int arg16, + int arg17) throws RemoteException { // TODO Auto-generated method stub } |