Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4dd8759e authored by Joe Antonetti's avatar Joe Antonetti
Browse files

[Handoff][1/N] Create Listener for Handoff enablement change

Add a listener on `ActivityTaskManagerInternal` allowing handoff enablement change events to flow down to `TaskContinuityManagerService`

Flag: android.companion.enable_task_continuity
Bug: 400970610
Test: Added Unit Tests
Change-Id: I33ffaf0614cafad6dc2a34b08f4f37e205fa10ae
parent e45b09dc
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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);
        }
    }

    /**
+15 −0
Original line number Diff line number Diff line
@@ -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.
     *
@@ -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);
}
+55 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -4692,6 +4696,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.
     *
@@ -6421,6 +6440,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) {
+9 −0
Original line number Diff line number Diff line
@@ -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
+73 −0
Original line number Diff line number Diff line
@@ -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.