summaryrefslogtreecommitdiff
path: root/core/java/android/window/TaskOrganizerTaskEmbedder.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/window/TaskOrganizerTaskEmbedder.java')
-rw-r--r--core/java/android/window/TaskOrganizerTaskEmbedder.java274
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);
+ }
+ }
+ }
+}