diff options
Diffstat (limited to 'core/java/android/window/TaskOrganizerTaskEmbedder.java')
| -rw-r--r-- | core/java/android/window/TaskOrganizerTaskEmbedder.java | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java new file mode 100644 index 000000000000..1b87521f3a96 --- /dev/null +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.window; + +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; + +import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.content.Context; +import android.graphics.Rect; +import android.util.Log; +import android.view.KeyEvent; +import android.view.SurfaceControl; + +/** + * A component which handles embedded display of tasks within another window. The embedded task can + * be presented using the SurfaceControl provided from {@link #getSurfaceControl()}. + * + * @hide + */ +public class TaskOrganizerTaskEmbedder extends TaskEmbedder { + private static final String TAG = "TaskOrgTaskEmbedder"; + private static final boolean DEBUG = false; + + private TaskOrganizer mTaskOrganizer; + private ActivityManager.RunningTaskInfo mTaskInfo; + private WindowContainerToken mTaskToken; + private SurfaceControl mTaskLeash; + private boolean mPendingNotifyBoundsChanged; + + /** + * Constructs a new TaskEmbedder. + * + * @param context the context + * @param host the host for this embedded task + */ + public TaskOrganizerTaskEmbedder(Context context, TaskOrganizerTaskEmbedder.Host host) { + super(context, host); + } + + /** + * Whether this container has been initialized. + * + * @return true if initialized + */ + @Override + public boolean isInitialized() { + return mTaskOrganizer != null; + } + + @Override + public boolean onInitialize() { + if (DEBUG) { + log("onInitialize"); + } + // Register the task organizer + mTaskOrganizer = new TaskOrganizerImpl(); + // TODO(wm-shell): This currently prevents other organizers from controlling MULT_WINDOW + // windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that + // infrastructure is ready. + mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW); + mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true); + + return super.onInitialize(); + } + + @Override + protected boolean onRelease() { + if (DEBUG) { + log("onRelease"); + } + if (!isInitialized()) { + return false; + } + mTaskOrganizer.unregisterOrganizer(); + resetTaskInfo(); + return true; + } + + /** + * Starts presentation of tasks in this container. + */ + @Override + public void start() { + super.start(); + if (DEBUG) { + log("start"); + } + if (!isInitialized()) { + return; + } + if (mTaskToken == null) { + return; + } + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setHidden(mTaskToken, false /* hidden */); + WindowOrganizer.applyTransaction(wct); + // TODO(b/151449487): Only call callback once we enable synchronization + if (mListener != null) { + mListener.onTaskVisibilityChanged(getTaskId(), true); + } + } + + /** + * Stops presentation of tasks in this container. + */ + @Override + public void stop() { + super.stop(); + if (DEBUG) { + log("stop"); + } + if (!isInitialized()) { + return; + } + if (mTaskToken == null) { + return; + } + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setHidden(mTaskToken, true /* hidden */); + WindowOrganizer.applyTransaction(wct); + // TODO(b/151449487): Only call callback once we enable synchronization + if (mListener != null) { + mListener.onTaskVisibilityChanged(getTaskId(), false); + } + } + + /** + * This should be called whenever the position or size of the surface changes + * or if touchable areas above the surface are added or removed. + */ + @Override + public void notifyBoundsChanged() { + super.notifyBoundsChanged(); + if (DEBUG) { + log("notifyBoundsChanged: screenBounds=" + mHost.getScreenBounds()); + } + if (mTaskToken == null) { + mPendingNotifyBoundsChanged = true; + return; + } + mPendingNotifyBoundsChanged = false; + + // Update based on the screen bounds + Rect screenBounds = mHost.getScreenBounds(); + if (screenBounds.left < 0 || screenBounds.top < 0) { + screenBounds.offsetTo(0, 0); + } + + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setBounds(mTaskToken, screenBounds); + // TODO(b/151449487): Enable synchronization + WindowOrganizer.applyTransaction(wct); + } + + /** + * Injects a pair of down/up key events with keycode {@link KeyEvent#KEYCODE_BACK} to the + * virtual display. + */ + @Override + public void performBackPress() { + // Do nothing, the task org task should already have focus if the caller is not focused + return; + } + + /** An opaque unique identifier for this task surface among others being managed by the app. */ + @Override + public int getId() { + return getTaskId(); + } + + /** + * Check if container is ready to launch and create {@link ActivityOptions} to target the + * virtual display. + * @param options The existing options to amend, or null if the caller wants new options to be + * created + */ + @Override + protected ActivityOptions prepareActivityOptions(ActivityOptions options) { + options = super.prepareActivityOptions(options); + options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + return options; + } + + private int getTaskId() { + return mTaskInfo != null + ? mTaskInfo.taskId + : INVALID_TASK_ID; + } + + private void resetTaskInfo() { + if (DEBUG) { + log("resetTaskInfo"); + } + mTaskInfo = null; + mTaskToken = null; + mTaskLeash = null; + } + + private void log(String msg) { + Log.d(TAG, "[" + System.identityHashCode(this) + "] " + msg); + } + + private class TaskOrganizerImpl extends TaskOrganizer { + @Override + public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { + if (DEBUG) { + log("taskAppeared: " + taskInfo.taskId); + } + + mTaskInfo = taskInfo; + mTaskToken = taskInfo.token; + mTaskLeash = leash; + mTransaction.reparent(mTaskLeash, mSurfaceControl) + .show(mTaskLeash) + .show(mSurfaceControl) + .apply(); + if (mPendingNotifyBoundsChanged) { + // TODO: Either defer show or hide and synchronize show with the resize + notifyBoundsChanged(); + } + mHost.post(() -> mHost.onTaskBackgroundColorChanged(TaskOrganizerTaskEmbedder.this, + taskInfo.taskDescription.getBackgroundColor())); + + if (mListener != null) { + mListener.onTaskCreated(taskInfo.taskId, taskInfo.baseActivity); + } + } + + @Override + public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + mTaskInfo.taskDescription = taskInfo.taskDescription; + mHost.post(() -> mHost.onTaskBackgroundColorChanged(TaskOrganizerTaskEmbedder.this, + taskInfo.taskDescription.getBackgroundColor())); + } + + @Override + public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { + if (DEBUG) { + log("taskVanished: " + taskInfo.taskId); + } + + if (mTaskToken != null && (taskInfo == null + || mTaskToken.asBinder().equals(taskInfo.token.asBinder()))) { + if (mListener != null) { + mListener.onTaskRemovalStarted(taskInfo.taskId); + } + resetTaskInfo(); + } + } + + @Override + public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { + if (mListener != null) { + mListener.onBackPressedOnTaskRoot(taskInfo.taskId); + } + } + } +} |
