summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/OverlayHost.java129
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java32
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java23
4 files changed, 197 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/wm/OverlayHost.java b/services/core/java/com/android/server/wm/OverlayHost.java
new file mode 100644
index 000000000000..14f8983571c8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/OverlayHost.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 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 com.android.server.wm;
+
+import android.content.res.Configuration;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class to assist WindowContainer in the hosting of
+ * SurfacePackage based overlays. Manages overlays inside
+ * one parent control, and manages the lifetime of that parent control
+ * in order to obscure details from WindowContainer.
+ *
+ * Also handles multiplexing of event dispatch and tracking of overlays
+ * to make things easier for WindowContainer.
+ */
+class OverlayHost {
+ // Lazily initialized when required
+ SurfaceControl mSurfaceControl;
+ final ArrayList<SurfaceControlViewHost.SurfacePackage> mOverlays = new ArrayList<>();
+ final WindowManagerService mWmService;
+
+ OverlayHost(WindowManagerService wms) {
+ mWmService = wms;
+ }
+
+ void requireOverlaySurfaceControl() {
+ if (mSurfaceControl == null) {
+ final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null)
+ .setContainerLayer()
+ .setHidden(true)
+ .setName("Overlay Host Leash");
+
+ mSurfaceControl = b.build();
+ }
+ }
+
+ void setParent(SurfaceControl.Transaction t, SurfaceControl newParent) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ t.reparent(mSurfaceControl, newParent);
+ if (newParent != null) {
+ t.show(mSurfaceControl);
+ } else {
+ t.hide(mSurfaceControl);
+ }
+ }
+
+ void setLayer(SurfaceControl.Transaction t, int layer) {
+ if (mSurfaceControl != null) {
+ t.setLayer(mSurfaceControl, layer);
+ }
+ }
+
+ void addOverlay(SurfaceControlViewHost.SurfacePackage p, SurfaceControl currentParent) {
+ requireOverlaySurfaceControl();
+ mOverlays.add(p);
+
+ SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
+ t.reparent(p.getSurfaceControl(), mSurfaceControl)
+ .show(p.getSurfaceControl());
+ setParent(t,currentParent);
+ t.apply();
+ }
+
+ boolean removeOverlay(SurfaceControlViewHost.SurfacePackage p) {
+ final SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
+
+ for (int i = mOverlays.size() - 1; i >= 0; i--) {
+ SurfaceControlViewHost.SurfacePackage l = mOverlays.get(i);
+ if (l.getSurfaceControl().isSameSurface(p.getSurfaceControl())) {
+ mOverlays.remove(i);
+ t.reparent(l.getSurfaceControl(), null);
+ l.release();
+ }
+ }
+ t.apply();
+ return mOverlays.size() > 0;
+ }
+
+ void dispatchConfigurationChanged(Configuration c) {
+ for (int i = mOverlays.size() - 1; i >= 0; i--) {
+ SurfaceControlViewHost.SurfacePackage l = mOverlays.get(i);
+ try {
+ l.getRemoteInterface().onConfigurationChanged(c);
+ } catch (Exception e) {
+ removeOverlay(l);
+ }
+ }
+ }
+
+ private void dispatchDetachedFromWindow() {
+ for (int i = mOverlays.size() - 1; i >= 0; i--) {
+ SurfaceControlViewHost.SurfacePackage l = mOverlays.get(i);
+ try {
+ l.getRemoteInterface().onDispatchDetachedFromWindow();
+ } catch (Exception e) {
+ // Oh well we are tearing down anyway.
+ }
+ l.release();
+ }
+ }
+
+ void release() {
+ dispatchDetachedFromWindow();
+ mOverlays.clear();
+ final SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
+ t.remove(mSurfaceControl).apply();
+ mSurfaceControl = null;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 61acb97c9db1..137d7f869e4e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -85,6 +85,7 @@ import android.view.MagnificationSpec;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
import android.view.TaskTransitionSpec;
@@ -312,6 +313,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
private final List<WindowContainerListener> mListeners = new ArrayList<>();
+ private OverlayHost mOverlayHost;
+
WindowContainer(WindowManagerService wms) {
mWmService = wms;
mTransitionController = mWmService.mAtmService.getTransitionController();
@@ -341,6 +344,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
super.onConfigurationChanged(newParentConfig);
updateSurfacePositionNonOrganized();
scheduleAnimation();
+ if (mOverlayHost != null) {
+ mOverlayHost.dispatchConfigurationChanged(getConfiguration());
+ }
}
void reparent(WindowContainer newParent, int position) {
@@ -487,6 +493,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
t.reparent(sc, mSurfaceControl);
}
}
+
+ if (mOverlayHost != null) {
+ mOverlayHost.setParent(t, mSurfaceControl);
+ }
+
scheduleAnimation();
}
@@ -632,6 +643,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
mLastSurfacePosition.set(0, 0);
scheduleAnimation();
}
+ if (mOverlayHost != null) {
+ mOverlayHost.release();
+ mOverlayHost = null;
+ }
// This must happen after updating the surface so that sync transactions can be handled
// properly.
@@ -2308,6 +2323,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
wc.assignLayer(t, layer++);
}
}
+ if (mOverlayHost != null) {
+ mOverlayHost.setLayer(t, layer++);
+ }
}
void assignChildLayers() {
@@ -3570,4 +3588,18 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type, @Nullable AnimationAdapter snapshotAnim);
}
+
+ void addOverlay(SurfaceControlViewHost.SurfacePackage overlay) {
+ if (mOverlayHost == null) {
+ mOverlayHost = new OverlayHost(mWmService);
+ }
+ mOverlayHost.addOverlay(overlay, mSurfaceControl);
+ }
+
+ void removeOverlay(SurfaceControlViewHost.SurfacePackage overlay) {
+ if (mOverlayHost != null && !mOverlayHost.removeOverlay(overlay)) {
+ mOverlayHost.release();
+ mOverlayHost = null;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 62c674b15f89..1ab191bb6650 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -32,6 +32,7 @@ import android.view.IWindow;
import android.view.InputChannel;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControlViewHost;
import android.view.WindowInfo;
import android.view.WindowManager.DisplayImePolicy;
@@ -767,4 +768,16 @@ public abstract class WindowManagerInternal {
* {@code false} otherwise.
*/
public abstract boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken);
+
+ /**
+ * Internal methods for other parts of SystemServer to manage
+ * SurfacePackage based overlays on tasks.
+ *
+ * Callers prepare a view hierarchy with SurfaceControlViewHost
+ * and send the package to WM here. The remote view hierarchy will receive
+ * configuration change, lifecycle events, etc, forwarded over the
+ * ISurfaceControlViewHost interface inside the SurfacePackage.
+ */
+ public abstract void addTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay);
+ public abstract void removeTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c239e684ea9a..964deffcd9f8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -267,6 +267,7 @@ import android.view.RemoteAnimationAdapter;
import android.view.ScrollCaptureResponse;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceSession;
import android.view.TaskTransitionSpec;
import android.view.View;
@@ -7891,6 +7892,28 @@ public class WindowManagerService extends IWindowManager.Stub
public boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
return WindowManagerService.this.shouldRestoreImeVisibility(imeTargetWindowToken);
}
+
+ @Override
+ public void addTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay) {
+ synchronized (mGlobalLock) {
+ final Task task = mRoot.getRootTask(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("no task with taskId" + taskId);
+ }
+ task.addOverlay(overlay);
+ }
+ }
+
+ @Override
+ public void removeTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay) {
+ synchronized (mGlobalLock) {
+ final Task task = mRoot.getRootTask(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("no task with taskId" + taskId);
+ }
+ task.removeOverlay(overlay);
+ }
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {