Loading services/core/java/com/android/server/wm/ActivityRecord.java +5 −0 Original line number Diff line number Diff line Loading @@ -1277,11 +1277,16 @@ final class ActivityRecord extends WindowToken { /** Update if handoff is enabled for this activity. */ void setHandoffEnabled(boolean handoffEnabled, boolean allowFullTaskRecreation) { final boolean didChange = mHandoffEnabled != handoffEnabled; mHandoffEnabled = handoffEnabled; mAllowFullTaskRecreation = allowFullTaskRecreation; if (!mHandoffEnabled) { mHandoffActivityData = null; } if (didChange) { mAtmService.notifyHandoffEnablementChanged(this, handoffEnabled); } } /** Loading services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +15 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,10 @@ public abstract class ActivityTaskManagerInternal implements ActiveUids.Observer default void onKeyguardGoingAway() {} } public interface HandoffEnablementListener { default void onHandoffEnabledChanged(int taskId, boolean isEnabled) {} } /** * Returns home activity for the specified user. * Loading Loading @@ -829,4 +833,15 @@ public abstract class ActivityTaskManagerInternal implements ActiveUids.Observer /** Returns the current lock task mode state. */ public abstract int getLockTaskModeState(); /** Returns whether handoff is enabled for the given task. */ public abstract boolean isHandoffEnabledForTask(int taskId); /** Registers a listener for handoff enablement changes. */ public abstract void registerHandoffEnablementListener( @NonNull HandoffEnablementListener listener); /** Unregisters a listener for handoff enablement changes. */ public abstract void unregisterHandoffEnablementListener( @NonNull HandoffEnablementListener listener); } services/core/java/com/android/server/wm/ActivityTaskManagerService.java +55 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,7 @@ import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService; import com.android.server.am.ActivityManagerServiceDumpProcessesProto; import com.android.server.wm.ActivityTaskManagerInternal.HandoffEnablementListener; import com.android.server.am.AppTimeTracker; import com.android.server.am.AssistDataRequester; import com.android.server.am.BaseErrorDialog; Loading Loading @@ -510,6 +511,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final BackNavigationController mBackNavigationController; private TaskChangeNotificationController mTaskChangeNotificationController; private List<ActivityTaskManagerInternal.HandoffEnablementListener> mHandoffEnablementListeners = Collections.synchronizedList(new ArrayList<>()); /** The controller for all operations related to locktask. */ private LockTaskController mLockTaskController; private ActivityStartController mActivityStartController; Loading Loading @@ -4700,6 +4704,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mRecentTasks.notifyTaskPersisterLocked(task, flush); } void notifyHandoffEnablementChanged(ActivityRecord activity, boolean isHandoffEnabled) { if (!android.companion.Flags.enableTaskContinuity()) { return; } final int taskId = activity.getRootTaskId(); mH.post(() -> { for (int i = mHandoffEnablementListeners.size() - 1; i >= 0; i--) { mHandoffEnablementListeners .get(i) .onHandoffEnabledChanged(taskId, isHandoffEnabled); } }); } /** * Clears launch params for the given package. * Loading Loading @@ -6429,6 +6448,42 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final class LocalService extends ActivityTaskManagerInternal { @Override public boolean isHandoffEnabledForTask(int taskId) { if (!android.companion.Flags.enableTaskContinuity()) { return false; } synchronized (mGlobalLock) { final Task task = mRootWindowContainer.anyTaskForId(taskId); if (task == null) { return false; } final ActivityRecord activity = task.getTopNonFinishingActivity(); return activity != null && activity.isHandoffEnabled(); } } @Override public void registerHandoffEnablementListener(@NonNull HandoffEnablementListener listener) { if (!android.companion.Flags.enableTaskContinuity()) { return; } mHandoffEnablementListeners.add(listener); } @Override public void unregisterHandoffEnablementListener( @NonNull HandoffEnablementListener listener) { if (!android.companion.Flags.enableTaskContinuity()) { return; } mHandoffEnablementListeners.remove(listener); } @Override public ComponentName getHomeActivityForUser(int userId) { synchronized (mGlobalLock) { Loading services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +9 −0 Original line number Diff line number Diff line Loading @@ -926,13 +926,22 @@ public class ActivityRecordTests extends WindowTestsBase { } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testSetHandoffEnabled() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); final ActivityRecord activity = createActivityWithTask(); assertFalse(activity.isHandoffEnabled()); assertFalse(activity.isHandoffFullTaskRecreationAllowed()); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener).onHandoffEnabledChanged(activity.getRootTaskId(), true); assertTrue(activity.isHandoffEnabled()); assertTrue(activity.isHandoffFullTaskRecreationAllowed()); activity.setHandoffEnabled(false, false); verify(handoffEnablementListener).onHandoffEnabledChanged(activity.getRootTaskId(), false); assertFalse(activity.isHandoffEnabled()); assertFalse(activity.isHandoffFullTaskRecreationAllowed()); } @Test Loading services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +73 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,79 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { verify(mClientLifecycleManager, never()).scheduleTransactionItem(any(), any()); } @Test public void testAddHandoffEnablementListener_doesNotNotifyIfFlagDisabled() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), true); activity.setHandoffEnabled(false, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), false); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testRegisterHandoffEnablementListener_notifiesListenerOnChange() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener) .onHandoffEnabledChanged(anyInt(), anyBoolean()); activity.setHandoffEnabled(false, true); verify(handoffEnablementListener) .onHandoffEnabledChanged(activity.getRootTaskId(), false); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testUnregisterHandoffEnablementListener_doesNotNotifyListenerOnChange() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); mAtm.getAtmInternal().unregisterHandoffEnablementListener(handoffEnablementListener); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), true); activity.setHandoffEnabled(false, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), false); } @Test public void testIsHandoffEnabledForTask_returnsFalseIfFlagDisabled() { final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); doReturn(true).when(activity).isHandoffEnabled(); assertFalse(mAtm.getAtmInternal().isHandoffEnabledForTask(task.getRootTaskId())); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testIsHandoffEnabledForTask_returnsTrueIfHandoffEnabled() { final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); activity.setHandoffEnabled(true, true); assertTrue(mAtm.getAtmInternal().isHandoffEnabledForTask(task.getRootTaskId())); activity.setHandoffEnabled(false, true); assertFalse(mAtm.getAtmInternal().isHandoffEnabledForTask(task.getRootTaskId())); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testIsHandoffEnabledForTask_returnsFalseIfNoSuchTask() { assertFalse(mAtm.getAtmInternal().isHandoffEnabledForTask(1000)); } @Test public void testRequestHandoffTaskData_failsIfFlagDisabled() { // Create a test task. Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +5 −0 Original line number Diff line number Diff line Loading @@ -1277,11 +1277,16 @@ final class ActivityRecord extends WindowToken { /** Update if handoff is enabled for this activity. */ void setHandoffEnabled(boolean handoffEnabled, boolean allowFullTaskRecreation) { final boolean didChange = mHandoffEnabled != handoffEnabled; mHandoffEnabled = handoffEnabled; mAllowFullTaskRecreation = allowFullTaskRecreation; if (!mHandoffEnabled) { mHandoffActivityData = null; } if (didChange) { mAtmService.notifyHandoffEnablementChanged(this, handoffEnabled); } } /** Loading
services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +15 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,10 @@ public abstract class ActivityTaskManagerInternal implements ActiveUids.Observer default void onKeyguardGoingAway() {} } public interface HandoffEnablementListener { default void onHandoffEnabledChanged(int taskId, boolean isEnabled) {} } /** * Returns home activity for the specified user. * Loading Loading @@ -829,4 +833,15 @@ public abstract class ActivityTaskManagerInternal implements ActiveUids.Observer /** Returns the current lock task mode state. */ public abstract int getLockTaskModeState(); /** Returns whether handoff is enabled for the given task. */ public abstract boolean isHandoffEnabledForTask(int taskId); /** Registers a listener for handoff enablement changes. */ public abstract void registerHandoffEnablementListener( @NonNull HandoffEnablementListener listener); /** Unregisters a listener for handoff enablement changes. */ public abstract void unregisterHandoffEnablementListener( @NonNull HandoffEnablementListener listener); }
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +55 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,7 @@ import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService; import com.android.server.am.ActivityManagerServiceDumpProcessesProto; import com.android.server.wm.ActivityTaskManagerInternal.HandoffEnablementListener; import com.android.server.am.AppTimeTracker; import com.android.server.am.AssistDataRequester; import com.android.server.am.BaseErrorDialog; Loading Loading @@ -510,6 +511,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final BackNavigationController mBackNavigationController; private TaskChangeNotificationController mTaskChangeNotificationController; private List<ActivityTaskManagerInternal.HandoffEnablementListener> mHandoffEnablementListeners = Collections.synchronizedList(new ArrayList<>()); /** The controller for all operations related to locktask. */ private LockTaskController mLockTaskController; private ActivityStartController mActivityStartController; Loading Loading @@ -4700,6 +4704,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mRecentTasks.notifyTaskPersisterLocked(task, flush); } void notifyHandoffEnablementChanged(ActivityRecord activity, boolean isHandoffEnabled) { if (!android.companion.Flags.enableTaskContinuity()) { return; } final int taskId = activity.getRootTaskId(); mH.post(() -> { for (int i = mHandoffEnablementListeners.size() - 1; i >= 0; i--) { mHandoffEnablementListeners .get(i) .onHandoffEnabledChanged(taskId, isHandoffEnabled); } }); } /** * Clears launch params for the given package. * Loading Loading @@ -6429,6 +6448,42 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final class LocalService extends ActivityTaskManagerInternal { @Override public boolean isHandoffEnabledForTask(int taskId) { if (!android.companion.Flags.enableTaskContinuity()) { return false; } synchronized (mGlobalLock) { final Task task = mRootWindowContainer.anyTaskForId(taskId); if (task == null) { return false; } final ActivityRecord activity = task.getTopNonFinishingActivity(); return activity != null && activity.isHandoffEnabled(); } } @Override public void registerHandoffEnablementListener(@NonNull HandoffEnablementListener listener) { if (!android.companion.Flags.enableTaskContinuity()) { return; } mHandoffEnablementListeners.add(listener); } @Override public void unregisterHandoffEnablementListener( @NonNull HandoffEnablementListener listener) { if (!android.companion.Flags.enableTaskContinuity()) { return; } mHandoffEnablementListeners.remove(listener); } @Override public ComponentName getHomeActivityForUser(int userId) { synchronized (mGlobalLock) { Loading
services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +9 −0 Original line number Diff line number Diff line Loading @@ -926,13 +926,22 @@ public class ActivityRecordTests extends WindowTestsBase { } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testSetHandoffEnabled() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); final ActivityRecord activity = createActivityWithTask(); assertFalse(activity.isHandoffEnabled()); assertFalse(activity.isHandoffFullTaskRecreationAllowed()); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener).onHandoffEnabledChanged(activity.getRootTaskId(), true); assertTrue(activity.isHandoffEnabled()); assertTrue(activity.isHandoffFullTaskRecreationAllowed()); activity.setHandoffEnabled(false, false); verify(handoffEnablementListener).onHandoffEnabledChanged(activity.getRootTaskId(), false); assertFalse(activity.isHandoffEnabled()); assertFalse(activity.isHandoffFullTaskRecreationAllowed()); } @Test Loading
services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +73 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,79 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { verify(mClientLifecycleManager, never()).scheduleTransactionItem(any(), any()); } @Test public void testAddHandoffEnablementListener_doesNotNotifyIfFlagDisabled() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), true); activity.setHandoffEnabled(false, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), false); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testRegisterHandoffEnablementListener_notifiesListenerOnChange() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener) .onHandoffEnabledChanged(anyInt(), anyBoolean()); activity.setHandoffEnabled(false, true); verify(handoffEnablementListener) .onHandoffEnabledChanged(activity.getRootTaskId(), false); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testUnregisterHandoffEnablementListener_doesNotNotifyListenerOnChange() { ActivityTaskManagerInternal.HandoffEnablementListener handoffEnablementListener = mock(ActivityTaskManagerInternal.HandoffEnablementListener.class); final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); mAtm.getAtmInternal().registerHandoffEnablementListener(handoffEnablementListener); mAtm.getAtmInternal().unregisterHandoffEnablementListener(handoffEnablementListener); activity.setHandoffEnabled(true, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), true); activity.setHandoffEnabled(false, true); verify(handoffEnablementListener, never()) .onHandoffEnabledChanged(activity.getRootTaskId(), false); } @Test public void testIsHandoffEnabledForTask_returnsFalseIfFlagDisabled() { final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); doReturn(true).when(activity).isHandoffEnabled(); assertFalse(mAtm.getAtmInternal().isHandoffEnabledForTask(task.getRootTaskId())); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testIsHandoffEnabledForTask_returnsTrueIfHandoffEnabled() { final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); activity.setHandoffEnabled(true, true); assertTrue(mAtm.getAtmInternal().isHandoffEnabledForTask(task.getRootTaskId())); activity.setHandoffEnabled(false, true); assertFalse(mAtm.getAtmInternal().isHandoffEnabledForTask(task.getRootTaskId())); } @Test @EnableFlags(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY) public void testIsHandoffEnabledForTask_returnsFalseIfNoSuchTask() { assertFalse(mAtm.getAtmInternal().isHandoffEnabledForTask(1000)); } @Test public void testRequestHandoffTaskData_failsIfFlagDisabled() { // Create a test task. Loading