diff options
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) { |