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

Commit 3da54c3f authored by Jeff Chang's avatar Jeff Chang
Browse files

Provide a queue to defer TaskFragment events

- onTaskFragmentAppeared is called after the whole WCT is finished
- Prevent onTaskFragmentInfoChanged to be called before appeared
  event is sent

Bug: 189385246
Test: atest TaskFragmentOrganizerControllerTest
Change-Id: I8340331e5a6e3e245c7b145c9ad5fd0b074012f9
parent d1cc7309
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -732,6 +732,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {


    WindowOrganizerController mWindowOrganizerController;
    WindowOrganizerController mWindowOrganizerController;
    TaskOrganizerController mTaskOrganizerController;
    TaskOrganizerController mTaskOrganizerController;
    TaskFragmentOrganizerController mTaskFragmentOrganizerController;


    @Nullable
    @Nullable
    private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
    private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
@@ -805,6 +806,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
        GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
        GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
        mWindowOrganizerController = new WindowOrganizerController(this);
        mWindowOrganizerController = new WindowOrganizerController(this);
        mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController;
        mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController;
        mTaskFragmentOrganizerController =
                mWindowOrganizerController.mTaskFragmentOrganizerController;
    }
    }


    public void onSystemReady() {
    public void onSystemReady() {
+1 −0
Original line number Original line Diff line number Diff line
@@ -853,6 +853,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>


        // Send any pending task-info changes that were queued-up during a layout deferment
        // Send any pending task-info changes that were queued-up during a layout deferment
        mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
        mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
        mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents();
        mWmService.mSyncEngine.onSurfacePlacement();
        mWmService.mSyncEngine.onSurfacePlacement();
        mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
        mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();


+17 −5
Original line number Original line Diff line number Diff line
@@ -82,6 +82,7 @@ import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizer;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentInfo;


@@ -160,6 +161,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
    // The TaskFragment that adjacent to this one.
    // The TaskFragment that adjacent to this one.
    private TaskFragment mAdjacentTaskFragment;
    private TaskFragment mAdjacentTaskFragment;


    /**
     * Prevents duplicate calls to onTaskAppeared.
     */
    boolean mTaskFragmentAppearedSent;

    /**
    /**
     * When we are in the process of pausing an activity, before starting the
     * When we are in the process of pausing an activity, before starting the
     * next one, this variable holds the activity that is currently being paused.
     * next one, this variable holds the activity that is currently being paused.
@@ -1970,18 +1976,24 @@ class TaskFragment extends WindowContainer<WindowContainer> {
    @Override
    @Override
    public void onConfigurationChanged(Configuration newParentConfig) {
    public void onConfigurationChanged(Configuration newParentConfig) {
        super.onConfigurationChanged(newParentConfig);
        super.onConfigurationChanged(newParentConfig);
        sendTaskFragmentInfoChanged();
    }


    @Override
    void setSurfaceControl(SurfaceControl sc) {
        super.setSurfaceControl(sc);
        // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
        // emit the callbacks now.
        sendTaskFragmentAppeared();
    }

    void sendTaskFragmentInfoChanged() {
        if (mTaskFragmentOrganizer != null) {
        if (mTaskFragmentOrganizer != null) {
            // Parent config may have changed. The controller will check if there is any important
            // config change for the organizer.
            mTaskFragmentOrganizerController
                    .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, this);
            mTaskFragmentOrganizerController
            mTaskFragmentOrganizerController
                    .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this);
                    .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this);
        }
        }
    }
    }


    // TODO(b/190433129) call when TaskFragment is created from WCT#createTaskFragment
    private void sendTaskFragmentAppeared() {
    private void sendTaskFragmentAppeared() {
        if (mTaskFragmentOrganizer != null) {
        if (mTaskFragmentOrganizer != null) {
            mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this);
            mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this);
+264 −84
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;


import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Binder;
import android.os.IBinder;
import android.os.IBinder;
@@ -33,6 +35,8 @@ import android.window.TaskFragmentInfo;


import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.protolog.common.ProtoLog;


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.WeakHashMap;
@@ -45,16 +49,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr


    private final ActivityTaskManagerService mAtmService;
    private final ActivityTaskManagerService mAtmService;
    private final WindowManagerGlobalLock mGlobalLock;
    private final WindowManagerGlobalLock mGlobalLock;
    private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
            new WeakHashMap<>();
    private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
            new WeakHashMap<>();
    /**
    /**
     * A Map which manages the relationship between
     * A Map which manages the relationship between
     * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState}
     * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState}
     */
     */
    private final ArrayMap<IBinder, TaskFragmentController> mTaskFragmentOrganizerControllers =
    private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState =
            new ArrayMap<>();
            new ArrayMap<>();
    /**
     * A List which manages the TaskFragment pending event {@link PendingTaskFragmentEvent}
     */
    private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents =
            new ArrayList<>();


    TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
    TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
        mAtmService = atm;
        mAtmService = atm;
@@ -65,11 +70,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
     * A class to manage {@link ITaskFragmentOrganizer} and its organized
     * A class to manage {@link ITaskFragmentOrganizer} and its organized
     * {@link TaskFragment TaskFragments}.
     * {@link TaskFragment TaskFragments}.
     */
     */
    private class TaskFragmentController implements IBinder.DeathRecipient {
    private class TaskFragmentOrganizerState implements IBinder.DeathRecipient {
        private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>();
        private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>();
        private final ITaskFragmentOrganizer mOrganizer;
        private final ITaskFragmentOrganizer mOrganizer;
        private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
                new WeakHashMap<>();
        private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
                new WeakHashMap<>();


        TaskFragmentController(ITaskFragmentOrganizer organizer) {
        TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) {
            mOrganizer = organizer;
            mOrganizer = organizer;
            try {
            try {
                mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/);
                mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/);
@@ -85,10 +94,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            }
            }
        }
        }


        void addTaskFragment(TaskFragment taskFragment) {
        /**
            if (!mOrganizedTaskFragments.contains(taskFragment)) {
         * @return {@code true} if taskFragment is organized and not sent the appeared event before.
                mOrganizedTaskFragments.add(taskFragment);
         */
        boolean addTaskFragment(TaskFragment taskFragment) {
            if (taskFragment.mTaskFragmentAppearedSent) {
                return false;
            }
            }
            if (mOrganizedTaskFragments.contains(taskFragment)) {
                return false;
            }
            mOrganizedTaskFragments.add(taskFragment);
            return true;
        }
        }


        void removeTaskFragment(TaskFragment taskFragment) {
        void removeTaskFragment(TaskFragment taskFragment) {
@@ -100,57 +117,39 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            mOrganizedTaskFragments.clear();
            mOrganizedTaskFragments.clear();
            mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
            mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
        }
        }
    }

    @Override
    public void registerOrganizer(ITaskFragmentOrganizer organizer) {
        final int pid = Binder.getCallingPid();
        final long uid = Binder.getCallingUid();
        synchronized (mGlobalLock) {
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
                    "Register task fragment organizer=%s uid=%d pid=%d",
                    organizer.asBinder(), uid, pid);
            if (mTaskFragmentOrganizerControllers.containsKey(organizer.asBinder())) {
                throw new IllegalStateException(
                        "Replacing existing organizer currently unsupported");
            }
            mTaskFragmentOrganizerControllers.put(organizer.asBinder(),
                    new TaskFragmentController(organizer));
        }
    }

    @Override
    public void unregisterOrganizer(ITaskFragmentOrganizer organizer) {
        validateAndGetController(organizer);
        final int pid = Binder.getCallingPid();
        final long uid = Binder.getCallingUid();
        synchronized (mGlobalLock) {
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
                    "Unregister task fragment organizer=%s uid=%d pid=%d",
                    organizer.asBinder(), uid, pid);
            removeOrganizer(organizer);
        }
    }


        void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) {
        void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) {
        final TaskFragmentController controller = validateAndGetController(organizer);

            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
            final TaskFragmentInfo info = tf.getTaskFragmentInfo();
            final TaskFragmentInfo info = tf.getTaskFragmentInfo();
            final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
            final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
                    "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
                    "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
        controller.addTaskFragment(tf);
            try {
            try {
                organizer.onTaskFragmentAppeared(
                organizer.onTaskFragmentAppeared(
                        new TaskFragmentAppearedInfo(info, outSurfaceControl));
                        new TaskFragmentAppearedInfo(info, outSurfaceControl));
                mLastSentTaskFragmentInfos.put(tf, info);
                mLastSentTaskFragmentInfos.put(tf, info);
                tf.mTaskFragmentAppearedSent = true;
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e);
                Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e);
            }
            }
            onTaskFragmentParentInfoChanged(organizer, tf);
        }

        void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) {
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
            try {
                organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
            } catch (RemoteException e) {
                Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e);
            }
            tf.mTaskFragmentAppearedSent = false;
            mLastSentTaskFragmentInfos.remove(tf);
            mLastSentTaskFragmentParentConfigs.remove(tf);
        }
        }


        void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
        void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
        validateAndGetController(organizer);
            // Parent config may have changed. The controller will check if there is any important
            // config change for the organizer.
            onTaskFragmentParentInfoChanged(organizer, tf);


            // Check if the info is different from the last reported info.
            // Check if the info is different from the last reported info.
            final TaskFragmentInfo info = tf.getTaskFragmentInfo();
            final TaskFragmentInfo info = tf.getTaskFragmentInfo();
@@ -159,8 +158,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                    info.getConfiguration(), lastInfo.getConfiguration())) {
                    info.getConfiguration(), lastInfo.getConfiguration())) {
                return;
                return;
            }
            }

            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName());
                    tf.getName());
            try {
            try {
                organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
                organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
                mLastSentTaskFragmentInfos.put(tf, info);
                mLastSentTaskFragmentInfos.put(tf, info);
@@ -169,23 +168,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            }
            }
        }
        }


    void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) {
        final TaskFragmentController controller = validateAndGetController(organizer);

        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
        try {
            organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
        } catch (RemoteException e) {
            Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e);
        }
        mLastSentTaskFragmentInfos.remove(tf);
        mLastSentTaskFragmentParentConfigs.remove(tf);
        controller.removeTaskFragment(tf);
    }

        void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
        void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
        validateAndGetController(organizer);

            // Check if the parent info is different from the last reported parent info.
            // Check if the parent info is different from the last reported parent info.
            if (tf.getParent() == null || tf.getParent().asTask() == null) {
            if (tf.getParent() == null || tf.getParent().asTask() == null) {
                mLastSentTaskFragmentParentConfigs.remove(tf);
                mLastSentTaskFragmentParentConfigs.remove(tf);
@@ -197,7 +180,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) {
            if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) {
                return;
                return;
            }
            }

            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
                    "TaskFragment parent info changed name=%s parentTaskId=%d",
                    "TaskFragment parent info changed name=%s parentTaskId=%d",
                    tf.getName(), parent.mTaskId);
                    tf.getName(), parent.mTaskId);
@@ -208,12 +190,110 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
                Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
            }
            }
        }
        }
    }

    @Override
    public void registerOrganizer(ITaskFragmentOrganizer organizer) {
        final int pid = Binder.getCallingPid();
        final long uid = Binder.getCallingUid();
        synchronized (mGlobalLock) {
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
                    "Register task fragment organizer=%s uid=%d pid=%d",
                    organizer.asBinder(), uid, pid);
            if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) {
                throw new IllegalStateException(
                        "Replacing existing organizer currently unsupported");
            }
            mTaskFragmentOrganizerState.put(organizer.asBinder(),
                    new TaskFragmentOrganizerState(organizer));
        }
    }

    @Override
    public void unregisterOrganizer(ITaskFragmentOrganizer organizer) {
        validateAndGetState(organizer);
        final int pid = Binder.getCallingPid();
        final long uid = Binder.getCallingUid();
        synchronized (mGlobalLock) {
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
                    "Unregister task fragment organizer=%s uid=%d pid=%d",
                    organizer.asBinder(), uid, pid);
            removeOrganizer(organizer);
        }
    }

    void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
        if (!state.addTaskFragment(taskFragment)) {
            return;
        }
        PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment,
                PendingTaskFragmentEvent.EVENT_APPEARED);
        if (pendingEvent == null) {
            pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer,
                    PendingTaskFragmentEvent.EVENT_APPEARED);
            mPendingTaskFragmentEvents.add(pendingEvent);
        }
    }

    void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
        handleTaskFragmentInfoChanged(organizer, taskFragment,
                PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
    }

    void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer,
            TaskFragment taskFragment) {
        handleTaskFragmentInfoChanged(organizer, taskFragment,
                PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED);
    }

    private void handleTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer,
            TaskFragment taskFragment, int eventType) {
        validateAndGetState(organizer);
        if (!taskFragment.mTaskFragmentAppearedSent) {
            // Skip if TaskFragment still not appeared.
            return;
        }
        PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment);
        if (pendingEvent == null) {
            pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, eventType);
        } else {
            if (pendingEvent.mEventType == PendingTaskFragmentEvent.EVENT_VANISHED) {
                // Skipped the info changed event if vanished event is pending.
                return;
            }
            // Remove and add for re-ordering.
            mPendingTaskFragmentEvents.remove(pendingEvent);
        }
        mPendingTaskFragmentEvents.add(pendingEvent);
    }

    void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
        for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
            PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
            if (taskFragment == entry.mTaskFragment) {
                mPendingTaskFragmentEvents.remove(i);
                if (entry.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED) {
                    // If taskFragment appeared callback is pending, ignore the vanished request.
                    return;
                }
            }
        }
        if (!taskFragment.mTaskFragmentAppearedSent) {
            return;
        }
        PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(taskFragment,
                organizer, PendingTaskFragmentEvent.EVENT_VANISHED);
        mPendingTaskFragmentEvents.add(pendingEvent);
        state.removeTaskFragment(taskFragment);
    }


    private void removeOrganizer(ITaskFragmentOrganizer organizer) {
    private void removeOrganizer(ITaskFragmentOrganizer organizer) {
        final TaskFragmentController controller = validateAndGetController(organizer);
        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
        // remove all of the children of the organized TaskFragment
        // remove all of the children of the organized TaskFragment
        controller.dispose();
        state.dispose();
        mTaskFragmentOrganizerControllers.remove(organizer.asBinder());
        mTaskFragmentOrganizerState.remove(organizer.asBinder());
    }
    }


    /**
    /**
@@ -222,13 +302,113 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
     * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the
     * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the
     * {@link TaskFragment} after the organizer process died.
     * {@link TaskFragment} after the organizer process died.
     */
     */
    private TaskFragmentController validateAndGetController(ITaskFragmentOrganizer organizer) {
    private TaskFragmentOrganizerState validateAndGetState(ITaskFragmentOrganizer organizer) {
        final TaskFragmentController controller =
        final TaskFragmentOrganizerState state =
                mTaskFragmentOrganizerControllers.get(organizer.asBinder());
                mTaskFragmentOrganizerState.get(organizer.asBinder());
        if (controller == null) {
        if (state == null) {
            throw new IllegalArgumentException(
            throw new IllegalArgumentException(
                    "TaskFragmentOrganizer has not been registered. Organizer=" + organizer);
                    "TaskFragmentOrganizer has not been registered. Organizer=" + organizer);
        }
        }
        return controller;
        return state;
    }

    /**
     * A class to store {@link ITaskFragmentOrganizer} and its organized
     * {@link TaskFragment TaskFragments} with different pending event request.
     */
    private static class PendingTaskFragmentEvent {
        static final int EVENT_APPEARED = 0;
        static final int EVENT_VANISHED = 1;
        static final int EVENT_INFO_CHANGED = 2;
        static final int EVENT_PARENT_INFO_CHANGED = 3;

        @IntDef(prefix = "EVENT_", value = {
                EVENT_APPEARED,
                EVENT_VANISHED,
                EVENT_INFO_CHANGED,
                EVENT_PARENT_INFO_CHANGED
        })
        @Retention(RetentionPolicy.SOURCE)
        public @interface EventType {}

        @EventType
        final int mEventType;
        final TaskFragment mTaskFragment;
        final ITaskFragmentOrganizer mTaskFragmentOrg;

        PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg,
                @EventType int eventType) {
            mTaskFragment = taskFragment;
            mTaskFragmentOrg = taskFragmentOrg;
            mEventType = eventType;
        }

        /**
         * @return {@code true} if the pending event is related with taskFragment created, vanished
         * and information changed.
         */
        boolean isLifecycleEvent() {
            switch (mEventType) {
                case EVENT_APPEARED:
                case EVENT_VANISHED:
                case EVENT_INFO_CHANGED:
                case EVENT_PARENT_INFO_CHANGED:
                    return true;
                default:
                    return false;
            }
        }
    }

    @Nullable
    private PendingTaskFragmentEvent getLastPendingLifecycleEvent(TaskFragment tf) {
        for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
            PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
            if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) {
                return entry;
            }
        }
        return null;
    }

    @Nullable
    private PendingTaskFragmentEvent getPendingTaskFragmentEvent(TaskFragment taskFragment,
            int type) {
        for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
            PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
            if (taskFragment == entry.mTaskFragment && type == entry.mEventType) {
                return entry;
            }
        }
        return null;
    }

    void dispatchPendingEvents() {
        if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
                || mPendingTaskFragmentEvents.isEmpty()) {
            return;
        }
        for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) {
            PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
            final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg;
            final TaskFragment taskFragment = event.mTaskFragment;
            final TaskFragmentOrganizerState state =
                    mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder());
            if (state == null) continue;
            switch (event.mEventType) {
                case PendingTaskFragmentEvent.EVENT_APPEARED:
                    state.onTaskFragmentAppeared(taskFragmentOrg, taskFragment);
                    break;
                case PendingTaskFragmentEvent.EVENT_VANISHED:
                    state.onTaskFragmentVanished(taskFragmentOrg, taskFragment);
                    break;
                case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
                    state.onTaskFragmentInfoChanged(taskFragmentOrg, taskFragment);
                    break;
                case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
                    state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
            }
        }
        mPendingTaskFragmentEvents.clear();
    }
    }
}
}
+10 −0
Original line number Original line Diff line number Diff line
@@ -102,6 +102,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
        mController.registerOrganizer(mIOrganizer);
        mController.registerOrganizer(mIOrganizer);


        mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.dispatchPendingEvents();


        verify(mOrganizer).onTaskFragmentAppeared(any());
        verify(mOrganizer).onTaskFragmentAppeared(any());
    }
    }
@@ -110,6 +111,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
    public void testOnTaskFragmentInfoChanged() {
    public void testOnTaskFragmentInfoChanged() {
        mController.registerOrganizer(mIOrganizer);
        mController.registerOrganizer(mIOrganizer);
        mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.dispatchPendingEvents();


        // No callback if the info is not changed.
        // No callback if the info is not changed.
        doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
        doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
@@ -117,6 +119,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {


        mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
        mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
                mTaskFragment);
                mTaskFragment);
        mController.dispatchPendingEvents();


        verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
        verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());


@@ -125,6 +128,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {


        mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
        mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
                mTaskFragment);
                mTaskFragment);
        mController.dispatchPendingEvents();


        verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo);
        verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo);
    }
    }
@@ -133,7 +137,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
    public void testOnTaskFragmentVanished() {
    public void testOnTaskFragmentVanished() {
        mController.registerOrganizer(mIOrganizer);
        mController.registerOrganizer(mIOrganizer);


        mTaskFragment.mTaskFragmentAppearedSent = true;
        mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.dispatchPendingEvents();


        verify(mOrganizer).onTaskFragmentVanished(any());
        verify(mOrganizer).onTaskFragmentVanished(any());
    }
    }
@@ -148,8 +154,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
        doReturn(parentConfig).when(parent).getConfiguration();
        doReturn(parentConfig).when(parent).getConfiguration();
        doReturn(parent).when(parent).asTask();
        doReturn(parent).when(parent).asTask();


        mTaskFragment.mTaskFragmentAppearedSent = true;
        mController.onTaskFragmentParentInfoChanged(
        mController.onTaskFragmentParentInfoChanged(
                mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
                mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.dispatchPendingEvents();


        verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
        verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());


@@ -158,6 +166,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {


        mController.onTaskFragmentParentInfoChanged(
        mController.onTaskFragmentParentInfoChanged(
                mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
                mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.dispatchPendingEvents();


        verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any());
        verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any());


@@ -166,6 +175,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {


        mController.onTaskFragmentParentInfoChanged(
        mController.onTaskFragmentParentInfoChanged(
                mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
                mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
        mController.dispatchPendingEvents();


        verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
        verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
    }
    }