blob: f8edc2b871be89d8cdddb9b37e4a1b73b1717aab [file] [log] [blame]
/*
* 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.graphics.Rect;
import android.view.InsetsState;
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.
*
* These overlays are to be used for various types of System UI and UI
* under the systems control. Provided SurfacePackages will be able
* to overlay application content, without engaging the usual cross process
* obscured touch filtering mechanisms. It's imperative that all UI provided
* be under complete control of the system.
*/
class TrustedOverlayHost {
// Lazily initialized when required
SurfaceControl mSurfaceControl;
final ArrayList<SurfaceControlViewHost.SurfacePackage> mOverlays = new ArrayList<>();
final WindowManagerService mWmService;
TrustedOverlayHost(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();
SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
t.setTrustedOverlay(mSurfaceControl, true).apply();
}
}
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 setVisibility(SurfaceControl.Transaction t, boolean visible) {
if (mSurfaceControl != null) {
t.setVisibility(mSurfaceControl, visible);
}
}
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 dispatchInsetsChanged(InsetsState s, Rect insetFrame) {
for (int i = mOverlays.size() - 1; i >= 0; i--) {
SurfaceControlViewHost.SurfacePackage l = mOverlays.get(i);
try {
l.getRemoteInterface().onInsetsChanged(s, insetFrame);
} catch (Exception e) {
}
}
}
void release() {
dispatchDetachedFromWindow();
mOverlays.clear();
final SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
t.remove(mSurfaceControl).apply();
mSurfaceControl = null;
}
}