diff options
15 files changed, 187 insertions, 99 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 8508c2c95666..1725db046a95 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -120,17 +120,6 @@ public abstract class ActivityManagerInternal { public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi); /** - * Sets if the given pid is currently running a remote animation, which is taken a signal for - * determining oom adjustment and scheduling behavior. - * - * @param pid The pid we are setting overlay UI for. - * @param runningRemoteAnimation True if the process is running a remote animation, false - * otherwise. - * @see RemoteAnimationAdapter - */ - public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation); - - /** * Called after the network policy rules are updated by * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and * {@param procStateSeq}. diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index bc2fe545a8ac..c686440171a2 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -55,6 +55,7 @@ public class RemoteAnimationAdapter implements Parcelable { /** @see #getCallingPid */ private int mCallingPid; + private int mCallingUid; /** * @param runner The interface that gets notified when we actually need to start the animation. @@ -103,10 +104,11 @@ public class RemoteAnimationAdapter implements Parcelable { } /** - * To be called by system_server to keep track which pid is running this animation. + * To be called by system_server to keep track which pid and uid is running this animation. */ - public void setCallingPid(int pid) { + public void setCallingPidUid(int pid, int uid) { mCallingPid = pid; + mCallingUid = uid; } /** @@ -116,6 +118,13 @@ public class RemoteAnimationAdapter implements Parcelable { return mCallingPid; } + /** + * @return The uid of the process running the animation. + */ + public int getCallingUid() { + return mCallingUid; + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index 884cae440bed..da599efb6eee 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -118,9 +118,9 @@ public class RemoteAnimationDefinition implements Parcelable { * To be called by system_server to keep track which pid is running the remote animations inside * this definition. */ - public void setCallingPid(int pid) { + public void setCallingPidUid(int pid, int uid) { for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) { - mTransitionAnimationMap.valueAt(i).adapter.setCallingPid(pid); + mTransitionAnimationMap.valueAt(i).adapter.setCallingPidUid(pid, uid); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e58fe6762b68..ed2ee25f4f9a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8471,32 +8471,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - if (pid == Process.myPid()) { - Slog.wtf(TAG, "system can't run remote animation"); - return; - } - synchronized (ActivityManagerService.this) { - final ProcessRecord pr; - synchronized (mPidsSelfLocked) { - pr = mPidsSelfLocked.get(pid); - if (pr == null) { - Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid); - return; - } - } - if (pr.runningRemoteAnimation == runningRemoteAnimation) { - return; - } - pr.runningRemoteAnimation = runningRemoteAnimation; - if (DEBUG_OOM_ADJ) { - Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation - + " for pid=" + pid); - } - updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); - } - } - public final void enterSafeMode() { synchronized(this) { // It only makes sense to do this before the system is ready @@ -17975,11 +17949,6 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation); - } - - @Override public List<ProcessMemoryState> getMemoryStateForProcesses() { List<ProcessMemoryState> processMemoryStates = new ArrayList<>(); synchronized (mPidsSelfLocked) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 563b2f3bfb32..ea3084274ae0 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.MY_PID; @@ -1348,6 +1349,25 @@ class ProcessRecord implements WindowProcessListener { } } + @Override + public void setRunningRemoteAnimation(boolean runningRemoteAnimation) { + if (pid == Process.myPid()) { + Slog.wtf(TAG, "system can't run remote animation"); + return; + } + synchronized (mService) { + if (this.runningRemoteAnimation == runningRemoteAnimation) { + return; + } + this.runningRemoteAnimation = runningRemoteAnimation; + if (DEBUG_OOM_ADJ) { + Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation + + " for pid=" + pid); + } + mService.updateOomAdjLocked(this, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + } + } + public long getInputDispatchingTimeout() { return mWindowProcessController.getInputDispatchingTimeout(); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 8a9dfc7569dc..747837bc933f 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1462,16 +1462,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Nullable IRecentsAnimationRunner recentsAnimationRunner) { enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()"); final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { final ComponentName recentsComponent = mRecentTasks.getRecentsComponent(); final int recentsUid = mRecentTasks.getRecentsComponentUid(); + final WindowProcessController caller = getProcessController(callingPid, callingUid); // Start a new recents animation final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor, getActivityStartController(), mWindowManager, intent, recentsComponent, - recentsUid, callingPid); + recentsUid, caller); if (recentsAnimationRunner == null) { anim.preloadRecentsActivity(); } else { @@ -4650,7 +4652,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) { mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimations"); - definition.setCallingPid(Binder.getCallingPid()); + definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); synchronized (mGlobalLock) { final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r == null) { @@ -4670,7 +4672,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { RemoteAnimationAdapter adapter) { mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimationForNextActivityStart"); - adapter.setCallingPid(Binder.getCallingPid()); + adapter.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); synchronized (mGlobalLock) { final long origId = Binder.clearCallingIdentity(); try { @@ -4687,7 +4689,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { RemoteAnimationDefinition definition) { mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimations"); - definition.setCallingPid(Binder.getCallingPid()); + definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); synchronized (mGlobalLock) { final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId); if (display == null) { diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 0a3e7a4860d5..036bef755a87 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -33,6 +33,7 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_O import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; +import android.annotation.Nullable; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Intent; @@ -60,7 +61,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, private final Intent mTargetIntent; private final ComponentName mRecentsComponent; private final int mRecentsUid; - private final int mCallingPid; + private final @Nullable WindowProcessController mCaller; private final int mUserId; private final int mTargetActivityType; @@ -76,7 +77,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor, ActivityStartController activityStartController, WindowManagerService wm, - Intent targetIntent, ComponentName recentsComponent, int recentsUid, int callingPid) { + Intent targetIntent, ComponentName recentsComponent, int recentsUid, + @Nullable WindowProcessController caller) { mService = atm; mStackSupervisor = stackSupervisor; mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay(); @@ -85,7 +87,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mTargetIntent = targetIntent; mRecentsComponent = recentsComponent; mRecentsUid = recentsUid; - mCallingPid = callingPid; + mCaller = caller; mUserId = atm.getCurrentUserId(); mTargetActivityType = targetIntent.getComponent() != null && recentsComponent.equals(targetIntent.getComponent()) @@ -190,7 +192,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent); - mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true)); + if (mCaller != null) { + mCaller.setRunningRecentsAnimation(true); + } mWindowManager.deferSurfaceLayout(); try { @@ -286,8 +290,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mService.stopAppSwitches(); } - mService.mH.post( - () -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false)); + if (mCaller != null) { + mCaller.setRunningRecentsAnimation(false); + } mWindowManager.inSurfaceTransaction(() -> { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, @@ -453,7 +458,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, /** * Called only when the animation should be canceled prior to starting. */ - private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) { + static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) { try { recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index b4bfedda94c7..a1bc406c4550 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -129,7 +129,7 @@ class RemoteAnimationController implements DeathRecipient { writeStartDebugStatement(); } }); - sendRunningRemoteAnimation(true); + setRunningRemoteAnimation(true); } void cancelAnimation(String reason) { @@ -216,7 +216,7 @@ class RemoteAnimationController implements DeathRecipient { mService.closeSurfaceTransaction("RemoteAnimationController#finished"); } } - sendRunningRemoteAnimation(false); + setRunningRemoteAnimation(false); if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation"); } @@ -235,12 +235,18 @@ class RemoteAnimationController implements DeathRecipient { } } - private void sendRunningRemoteAnimation(boolean running) { + private void setRunningRemoteAnimation(boolean running) { final int pid = mRemoteAnimationAdapter.getCallingPid(); + final int uid = mRemoteAnimationAdapter.getCallingUid(); if (pid == 0) { throw new RuntimeException("Calling pid of remote animation was null"); } - mService.sendSetRunningRemoteAnimation(pid, running); + final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid); + if (wpc == null) { + Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid); + return; + } + wpc.setRunningRemoteAnimation(running); } private void linkToDeathOfRunner() throws RemoteException { @@ -417,7 +423,7 @@ class RemoteAnimationController implements DeathRecipient { mHandler.removeCallbacks(mTimeoutRunnable); releaseFinishedCallback(); invokeAnimationCancelled(); - sendRunningRemoteAnimation(false); + setRunningRemoteAnimation(false); } } diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index ac9028329023..a7b53688dbdc 100644 --- a/services/core/java/com/android/server/wm/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -122,17 +122,20 @@ public class SafeActivityOptions { if (mOriginalOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, mOriginalCallingPid, mOriginalCallingUid); - setCallingPidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid); + setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid, + mOriginalCallingUid); } if (mCallerOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, mRealCallingPid, mRealCallingUid); - setCallingPidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid); + setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid, + mRealCallingUid); } return mergeActivityOptions(mOriginalOptions, mCallerOptions); } - private void setCallingPidForRemoteAnimationAdapter(ActivityOptions options, int callingPid) { + private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options, + int callingPid, int callingUid) { final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); if (adapter == null) { return; @@ -141,7 +144,7 @@ public class SafeActivityOptions { Slog.wtf(TAG, "Safe activity options constructed after clearing calling id"); return; } - adapter.setCallingPid(callingPid); + adapter.setCallingPidUid(callingPid, callingUid); } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 57f402c8fe9c..3ad6ddc99a46 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4556,7 +4556,6 @@ public class WindowManagerService extends IWindowManager.Stub public static final int SEAMLESS_ROTATION_TIMEOUT = 54; public static final int RESTORE_POINTER_ICON = 55; public static final int SET_HAS_OVERLAY_UI = 58; - public static final int SET_RUNNING_REMOTE_ANIMATION = 59; public static final int ANIMATION_FAILSAFE = 60; public static final int RECOMPUTE_FOCUS = 61; public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62; @@ -4935,10 +4934,6 @@ public class WindowManagerService extends IWindowManager.Stub mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1); break; } - case SET_RUNNING_REMOTE_ANIMATION: { - mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1); - break; - } case ANIMATION_FAILSAFE: { synchronized (mGlobalLock) { if (mRecentsAnimationController != null) { @@ -7625,11 +7620,6 @@ public class WindowManagerService extends IWindowManager.Stub return mSurfaceBuilderFactory.make(s); } - void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0) - .sendToTarget(); - } - void startSeamlessRotation() { // We are careful to reset this in case a window was removed before it finished // seamless rotation. diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index b6960f0d1fe6..4cb546f107c7 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -56,6 +56,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import android.view.IRemoteAnimationRunner; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.HeavyWeightSwitcherActivity; @@ -176,6 +177,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // Registered display id as a listener to override config change private int mDisplayId; + /** Whether our process is currently running a {@link RecentsAnimation} */ + private boolean mRunningRecentsAnimation; + + /** Whether our process is currently running a {@link IRemoteAnimationRunner} */ + private boolean mRunningRemoteAnimation; + public WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name, int uid, int userId, Object owner, WindowProcessListener listener) { mInfo = info; @@ -1079,6 +1086,30 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } + void setRunningRecentsAnimation(boolean running) { + if (mRunningRecentsAnimation == running) { + return; + } + mRunningRecentsAnimation = running; + updateRunningRemoteOrRecentsAnimation(); + } + + void setRunningRemoteAnimation(boolean running) { + if (mRunningRemoteAnimation == running) { + return; + } + mRunningRemoteAnimation = running; + updateRunningRemoteOrRecentsAnimation(); + } + + private void updateRunningRemoteOrRecentsAnimation() { + + // Posting on handler so WM lock isn't held when we call into AM. + mAtm.mH.sendMessage(PooledLambda.obtainMessage( + WindowProcessListener::setRunningRemoteAnimation, mListener, + mRunningRecentsAnimation || mRunningRemoteAnimation)); + } + @Override public String toString() { return mOwner != null ? mOwner.toString() : null; diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java index 527d54a40d03..23d7a6a9d293 100644 --- a/services/core/java/com/android/server/wm/WindowProcessListener.java +++ b/services/core/java/com/android/server/wm/WindowProcessListener.java @@ -17,6 +17,8 @@ package com.android.server.wm; import android.util.proto.ProtoOutputStream; +import android.view.IRemoteAnimationRunner; +import android.view.RemoteAnimationAdapter; /** * Interface used by the owner/creator of a process that owns windows to listen to changes from the @@ -60,4 +62,14 @@ public interface WindowProcessListener { /** App died :(...oh well */ void appDied(); void writeToProto(ProtoOutputStream proto, long fieldId); + + /** + * Sets if the process is currently running a remote animation, which is taken a signal for + * determining oom adjustment and scheduling behavior. + * + * @param runningRemoteAnimation True if the process is running a remote animation, false + * otherwise. + * @see RemoteAnimationAdapter + */ + void setRunningRemoteAnimation(boolean runningRemoteAnimation); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index f60241846044..d1dc38273a28 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -207,7 +207,7 @@ public class AppTransitionTests extends WindowTestsBase { final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( runner, 100, 50, true /* changeNeedsSnapshot */); // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid. - adapter.setCallingPid(123); + adapter.setCallingPidUid(123, 456); // Simulate activity finish flows to prepare app transition & set visibility, // make sure transition is set as expected. diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index cb74c3e32252..74791e2ea97f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -79,7 +79,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { when(mMockRunner.asBinder()).thenReturn(new Binder()); mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */); - mAdapter.setCallingPid(123); + mAdapter.setCallingPidUid(123, 456); mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0); mController = new RemoteAnimationController(mWm, mAdapter, mHandler); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index a7c84a1c28b4..8c56ffaa6314 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -23,12 +23,18 @@ import static com.android.server.wm.ActivityDisplay.POSITION_TOP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.content.pm.ApplicationInfo; import android.platform.test.annotations.Presubmit; +import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; /** * Tests for the {@link WindowProcessController} class. @@ -39,43 +45,89 @@ import org.junit.Test; @Presubmit public class WindowProcessControllerTests extends ActivityTestsBase { + WindowProcessController mWpc; + WindowProcessListener mMockListener; + + @Before + public void setUp() { + mMockListener = mock(WindowProcessListener.class); + mWpc = new WindowProcessController( + mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener); + } + @Test public void testDisplayConfigurationListener() { - final WindowProcessController wpc = new WindowProcessController( - mService, mock(ApplicationInfo.class), null, 0, -1, null, null); + //By default, the process should not listen to any display. - assertEquals(INVALID_DISPLAY, wpc.getDisplayId()); + assertEquals(INVALID_DISPLAY, mWpc.getDisplayId()); // Register to display 1 as a listener. TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer(); - wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); - assertTrue(testActivityDisplay1.containsListener(wpc)); - assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); + assertTrue(testActivityDisplay1.containsListener(mWpc)); + assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId()); // Move to display 2. TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer(); - wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2); - assertFalse(testActivityDisplay1.containsListener(wpc)); - assertTrue(testActivityDisplay2.containsListener(wpc)); - assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2); + assertFalse(testActivityDisplay1.containsListener(mWpc)); + assertTrue(testActivityDisplay2.containsListener(mWpc)); + assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId()); // Null ActivityDisplay will not change anything. - wpc.registerDisplayConfigurationListenerLocked(null); - assertTrue(testActivityDisplay2.containsListener(wpc)); - assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(null); + assertTrue(testActivityDisplay2.containsListener(mWpc)); + assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId()); // Unregister listener will remove the wpc from registered displays. - wpc.unregisterDisplayConfigurationListenerLocked(); - assertFalse(testActivityDisplay1.containsListener(wpc)); - assertFalse(testActivityDisplay2.containsListener(wpc)); - assertEquals(INVALID_DISPLAY, wpc.getDisplayId()); + mWpc.unregisterDisplayConfigurationListenerLocked(); + assertFalse(testActivityDisplay1.containsListener(mWpc)); + assertFalse(testActivityDisplay2.containsListener(mWpc)); + assertEquals(INVALID_DISPLAY, mWpc.getDisplayId()); // Unregistration still work even if the display was removed. - wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); - assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); + assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId()); mRootActivityContainer.removeChild(testActivityDisplay1); - wpc.unregisterDisplayConfigurationListenerLocked(); - assertEquals(INVALID_DISPLAY, wpc.getDisplayId()); + mWpc.unregisterDisplayConfigurationListenerLocked(); + assertEquals(INVALID_DISPLAY, mWpc.getDisplayId()); + } + + @Test + public void testSetRunningRecentsAnimation() { + mWpc.setRunningRecentsAnimation(true); + mWpc.setRunningRecentsAnimation(false); + mService.mH.runWithScissors(() -> {}, 0); + + InOrder orderVerifier = Mockito.inOrder(mMockListener); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true)); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false)); + } + + @Test + public void testSetRunningRemoteAnimation() { + mWpc.setRunningRemoteAnimation(true); + mWpc.setRunningRemoteAnimation(false); + mService.mH.runWithScissors(() -> {}, 0); + + InOrder orderVerifier = Mockito.inOrder(mMockListener); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true)); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false)); + } + + @Test + public void testSetRunningBothAnimations() { + mWpc.setRunningRemoteAnimation(true); + mWpc.setRunningRecentsAnimation(true); + + mWpc.setRunningRecentsAnimation(false); + mWpc.setRunningRemoteAnimation(false); + mService.mH.runWithScissors(() -> {}, 0); + + InOrder orderVerifier = Mockito.inOrder(mMockListener); + orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true)); + orderVerifier.verify(mMockListener, times(1)).setRunningRemoteAnimation(eq(false)); + orderVerifier.verifyNoMoreInteractions(); } private TestActivityDisplay createTestActivityDisplayInContainer() { |