Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +19 −6 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.START_ANY_ACTIVITY; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; Loading Loading @@ -1133,19 +1134,31 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } void reportTaskToFrontNoLaunch(ActivityRecord r) { void reportWaitingActivityLaunchedIfNeeded(ActivityRecord r, int result) { if (mWaitingActivityLaunched.isEmpty()) { return; } if (result != START_DELIVERED_TO_TOP && result != START_TASK_TO_FRONT) { return; } boolean changed = false; for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { WaitResult w = mWaitingActivityLaunched.remove(i); if (w.who == null) { changed = true; // Set result to START_TASK_TO_FRONT so that startActivityMayWait() knows that // the starting activity ends up moving another activity to front, and it should // wait for this new activity to become visible instead. // Do not modify other fields. w.result = START_TASK_TO_FRONT; w.result = result; // Unlike START_TASK_TO_FRONT, When an intent is delivered to top, there // will be no followup launch signals. Assign the result and launched component. if (result == START_DELIVERED_TO_TOP) { w.who = r.realActivity; } } } if (changed) { mService.notifyAll(); } Loading services/core/java/com/android/server/am/ActivityStarter.java +44 −32 Original line number Diff line number Diff line Loading @@ -879,11 +879,11 @@ class ActivityStarter { } // We're waiting for an activity launch to finish, but that activity simply // brought another activity to front. Let startActivityMayWait() know about // this, so it waits for the new activity to become visible instead. if (result == START_TASK_TO_FRONT && !mSupervisor.mWaitingActivityLaunched.isEmpty()) { mSupervisor.reportTaskToFrontNoLaunch(mStartActivity); } // brought another activity to front. We must also handle the case where the task is already // in the front as a result of the trampoline activity being in the same task (it will be // considered focused as the trampoline will be finished). Let startActivityMayWait() know // about this, so it waits for the new activity to become visible instead. mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result); ActivityStack startedActivityStack = null; final ActivityStack currentStack = r.getStack(); Loading Loading @@ -1076,7 +1076,11 @@ class ActivityStarter { if (outResult != null) { outResult.result = res; if (res == ActivityManager.START_SUCCESS) { final ActivityRecord r = outRecord[0]; switch(res) { case START_SUCCESS: { mSupervisor.mWaitingActivityLaunched.add(outResult); do { try { Loading @@ -1088,12 +1092,18 @@ class ActivityStarter { if (outResult.result == START_TASK_TO_FRONT) { res = START_TASK_TO_FRONT; } break; } if (res == START_TASK_TO_FRONT) { final ActivityRecord r = outRecord[0]; // ActivityRecord may represent a different activity, but it should not be in // the resumed state. case START_DELIVERED_TO_TOP: { outResult.timeout = false; outResult.who = r.realActivity; outResult.totalTime = 0; outResult.thisTime = 0; break; } case START_TASK_TO_FRONT: { // ActivityRecord may represent a different activity, but it should not be // in the resumed state. if (r.nowVisible && r.state == RESUMED) { outResult.timeout = false; outResult.who = r.realActivity; Loading @@ -1110,6 +1120,8 @@ class ActivityStarter { } } while (!outResult.timeout && outResult.who == null); } break; } } } Loading services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +35 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.am; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; Loading @@ -25,6 +27,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import android.app.ActivityManager; import android.app.WaitResult; import android.content.ComponentName; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; Loading @@ -45,7 +49,7 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS * Tests for the {@link ActivityStackSupervisor} class. * * Build/Install/Run: * bit FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests * atest FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests */ @MediumTest @Presubmit Loading Loading @@ -146,4 +150,34 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { assertFalse(mSupervisor.mStoppingActivities.contains(firstActivity)); } /** * Ensures that waiting results are notified of launches. */ @Test public void testReportWaitingActivityLaunchedIfNeeded() throws Exception { final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(mFullscreenStack).build(); // #notifyAll will be called on the ActivityManagerService. we must hold the object lock // when this happens. synchronized (mSupervisor.mService) { final WaitResult taskToFrontWait = new WaitResult(); mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait); mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT); assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty()); assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT); assertEquals(taskToFrontWait.who, null); final WaitResult deliverToTopWait = new WaitResult(); mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait); mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_DELIVERED_TO_TOP); assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty()); assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP); assertEquals(deliverToTopWait.who, firstActivity.realActivity); } } } Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +19 −6 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.START_ANY_ACTIVITY; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; Loading Loading @@ -1133,19 +1134,31 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } void reportTaskToFrontNoLaunch(ActivityRecord r) { void reportWaitingActivityLaunchedIfNeeded(ActivityRecord r, int result) { if (mWaitingActivityLaunched.isEmpty()) { return; } if (result != START_DELIVERED_TO_TOP && result != START_TASK_TO_FRONT) { return; } boolean changed = false; for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { WaitResult w = mWaitingActivityLaunched.remove(i); if (w.who == null) { changed = true; // Set result to START_TASK_TO_FRONT so that startActivityMayWait() knows that // the starting activity ends up moving another activity to front, and it should // wait for this new activity to become visible instead. // Do not modify other fields. w.result = START_TASK_TO_FRONT; w.result = result; // Unlike START_TASK_TO_FRONT, When an intent is delivered to top, there // will be no followup launch signals. Assign the result and launched component. if (result == START_DELIVERED_TO_TOP) { w.who = r.realActivity; } } } if (changed) { mService.notifyAll(); } Loading
services/core/java/com/android/server/am/ActivityStarter.java +44 −32 Original line number Diff line number Diff line Loading @@ -879,11 +879,11 @@ class ActivityStarter { } // We're waiting for an activity launch to finish, but that activity simply // brought another activity to front. Let startActivityMayWait() know about // this, so it waits for the new activity to become visible instead. if (result == START_TASK_TO_FRONT && !mSupervisor.mWaitingActivityLaunched.isEmpty()) { mSupervisor.reportTaskToFrontNoLaunch(mStartActivity); } // brought another activity to front. We must also handle the case where the task is already // in the front as a result of the trampoline activity being in the same task (it will be // considered focused as the trampoline will be finished). Let startActivityMayWait() know // about this, so it waits for the new activity to become visible instead. mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result); ActivityStack startedActivityStack = null; final ActivityStack currentStack = r.getStack(); Loading Loading @@ -1076,7 +1076,11 @@ class ActivityStarter { if (outResult != null) { outResult.result = res; if (res == ActivityManager.START_SUCCESS) { final ActivityRecord r = outRecord[0]; switch(res) { case START_SUCCESS: { mSupervisor.mWaitingActivityLaunched.add(outResult); do { try { Loading @@ -1088,12 +1092,18 @@ class ActivityStarter { if (outResult.result == START_TASK_TO_FRONT) { res = START_TASK_TO_FRONT; } break; } if (res == START_TASK_TO_FRONT) { final ActivityRecord r = outRecord[0]; // ActivityRecord may represent a different activity, but it should not be in // the resumed state. case START_DELIVERED_TO_TOP: { outResult.timeout = false; outResult.who = r.realActivity; outResult.totalTime = 0; outResult.thisTime = 0; break; } case START_TASK_TO_FRONT: { // ActivityRecord may represent a different activity, but it should not be // in the resumed state. if (r.nowVisible && r.state == RESUMED) { outResult.timeout = false; outResult.who = r.realActivity; Loading @@ -1110,6 +1120,8 @@ class ActivityStarter { } } while (!outResult.timeout && outResult.who == null); } break; } } } Loading
services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +35 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.am; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; Loading @@ -25,6 +27,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import android.app.ActivityManager; import android.app.WaitResult; import android.content.ComponentName; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; Loading @@ -45,7 +49,7 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS * Tests for the {@link ActivityStackSupervisor} class. * * Build/Install/Run: * bit FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests * atest FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests */ @MediumTest @Presubmit Loading Loading @@ -146,4 +150,34 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { assertFalse(mSupervisor.mStoppingActivities.contains(firstActivity)); } /** * Ensures that waiting results are notified of launches. */ @Test public void testReportWaitingActivityLaunchedIfNeeded() throws Exception { final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(mFullscreenStack).build(); // #notifyAll will be called on the ActivityManagerService. we must hold the object lock // when this happens. synchronized (mSupervisor.mService) { final WaitResult taskToFrontWait = new WaitResult(); mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait); mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT); assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty()); assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT); assertEquals(taskToFrontWait.who, null); final WaitResult deliverToTopWait = new WaitResult(); mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait); mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_DELIVERED_TO_TOP); assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty()); assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP); assertEquals(deliverToTopWait.who, firstActivity.realActivity); } } }