summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/IWindowManager.aidl12
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java330
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java35
-rw-r--r--services/core/java/com/android/server/wm/ShellRoot.java74
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java20
6 files changed, 474 insertions, 0 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b829c9f36f84..9496827b1a84 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -44,6 +44,7 @@ import android.view.RemoteAnimationAdapter;
import android.view.IRotationWatcher;
import android.view.ISystemGestureExclusionListener;
import android.view.IWallpaperVisibilityListener;
+import android.view.IWindow;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.KeyEvent;
@@ -120,6 +121,17 @@ interface IWindowManager
void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
/**
+ * Adds a root container that a client shell can populate with its own windows (usually via
+ * WindowlessWindowManager).
+ *
+ * @param client an IWindow used for window-level communication (ime, finish draw, etc.).
+ * @param windowType used by WM to determine the z-order. This is the same as the window type
+ * used in {@link WindowManager.LayoutParams}.
+ * @return a SurfaceControl to add things to.
+ */
+ SurfaceControl addShellRoot(int displayId, IWindow client, int windowType);
+
+ /**
* Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
* used for recents, where generating the thumbnails of the specs takes a non-trivial amount of
* time, so we want to move that off the critical path for starting the new activity.
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 6821265df28b..dd38a332df68 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -124,6 +124,7 @@ import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.wm.DisplayWindowController;
+import com.android.systemui.wm.SystemWindows;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -323,6 +324,7 @@ public class Dependency {
@Inject Lazy<Recents> mRecents;
@Inject Lazy<StatusBar> mStatusBar;
@Inject Lazy<DisplayWindowController> mDisplayWindowController;
+ @Inject Lazy<SystemWindows> mSystemWindows;
@Inject
public Dependency() {
@@ -513,6 +515,7 @@ public class Dependency {
mProviders.put(Recents.class, mRecents::get);
mProviders.put(StatusBar.class, mStatusBar::get);
mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);
+ mProviders.put(SystemWindows.class, mSystemWindows::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
new file mode 100644
index 000000000000..5ec61c3313f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2019 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.systemui.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DragEvent;
+import android.view.IWindow;
+import android.view.IWindowManager;
+import android.view.IWindowSession;
+import android.view.IWindowSessionCallback;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowlessViewRoot;
+import android.view.WindowlessWindowManager;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.HashMap;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Represents the "windowing" layer of the System-UI. This layer allows system-ui components to
+ * place and manipulate windows without talking to WindowManager.
+ */
+@Singleton
+public class SystemWindows {
+ private static final String TAG = "SystemWindows";
+
+ private final SparseArray<PerDisplay> mPerDisplay = new SparseArray<>();
+ final HashMap<View, WindowlessViewRoot> mViewRoots = new HashMap<>();
+ Context mContext;
+ IWindowSession mSession;
+ DisplayWindowController mDisplayController;
+ IWindowManager mWmService;
+
+ private final DisplayWindowController.DisplayWindowListener mDisplayListener =
+ new DisplayWindowController.DisplayWindowListener() {
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ pd.updateConfiguration(newConfig);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) { }
+ };
+
+ @Inject
+ public SystemWindows(Context context, DisplayWindowController displayController,
+ IWindowManager wmService) {
+ mContext = context;
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mDisplayController.addDisplayWindowListener(mDisplayListener);
+ try {
+ mSession = wmService.openSession(
+ new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float scale) {}
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to create layer", e);
+ }
+ }
+
+ /**
+ * Adds a view to system-ui window management.
+ */
+ public void addView(View view, WindowManager.LayoutParams attrs, int displayId,
+ int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ pd = new PerDisplay(displayId);
+ mPerDisplay.put(displayId, pd);
+ }
+ pd.addView(view, attrs, windowType);
+ }
+
+ /**
+ * Removes a view from system-ui window management.
+ * @param view
+ */
+ public void removeView(View view) {
+ WindowlessViewRoot root = mViewRoots.remove(view);
+ root.die();
+ }
+
+ /**
+ * Updates the layout params of a view.
+ */
+ public void updateViewLayout(@NonNull View view, ViewGroup.LayoutParams params) {
+ WindowlessViewRoot root = mViewRoots.get(view);
+ if (root == null || !(params instanceof WindowManager.LayoutParams)) {
+ return;
+ }
+ view.setLayoutParams(params);
+ root.relayout((WindowManager.LayoutParams) params);
+ }
+
+ /**
+ * Adds a root for system-ui window management with no views. Only useful for IME.
+ */
+ public void addRoot(int displayId, int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ pd = new PerDisplay(displayId);
+ mPerDisplay.put(displayId, pd);
+ }
+ pd.addRoot(windowType);
+ }
+
+ /**
+ * Get the IWindow token for a specific root.
+ *
+ * @param windowType A window type from {@link android.view.WindowManager}.
+ */
+ IWindow getWindow(int displayId, int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ return null;
+ }
+ return pd.getWindow(windowType);
+ }
+
+ private class PerDisplay {
+ final int mDisplayId;
+ private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
+
+ PerDisplay(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ public void addView(View view, WindowManager.LayoutParams attrs, int windowType) {
+ SysUiWindowManager wwm = addRoot(windowType);
+ if (wwm == null) {
+ Slog.e(TAG, "Unable to create systemui root");
+ return;
+ }
+ final Display display = mDisplayController.getDisplay(mDisplayId);
+ WindowlessViewRoot viewRoot = new WindowlessViewRoot(mContext, display, wwm);
+ attrs.flags |= FLAG_HARDWARE_ACCELERATED;
+ viewRoot.addView(view, attrs);
+ mViewRoots.put(view, viewRoot);
+ }
+
+ SysUiWindowManager addRoot(int windowType) {
+ SysUiWindowManager wwm = mWwms.get(windowType);
+ if (wwm != null) {
+ return wwm;
+ }
+ SurfaceControl rootSurface = null;
+ ContainerWindow win = new ContainerWindow();
+ try {
+ rootSurface = mWmService.addShellRoot(mDisplayId, win, windowType);
+ } catch (RemoteException e) {
+ }
+ if (rootSurface == null) {
+ Slog.e(TAG, "Unable to get root surfacecontrol for systemui");
+ return null;
+ }
+ Context displayContext = mDisplayController.getDisplayContext(mDisplayId);
+ wwm = new SysUiWindowManager(mDisplayId, displayContext, rootSurface, win);
+ mWwms.put(windowType, wwm);
+ return wwm;
+ }
+
+ IWindow getWindow(int windowType) {
+ SysUiWindowManager wwm = mWwms.get(windowType);
+ if (wwm == null) {
+ return null;
+ }
+ return wwm.mContainerWindow;
+ }
+
+ void updateConfiguration(Configuration configuration) {
+ for (int i = 0; i < mWwms.size(); ++i) {
+ mWwms.valueAt(i).updateConfiguration(configuration);
+ }
+ }
+ }
+
+ /**
+ * A subclass of WindowlessWindowManager that provides insets to its viewroots.
+ */
+ public class SysUiWindowManager extends WindowlessWindowManager {
+ final int mDisplayId;
+ ContainerWindow mContainerWindow;
+ public SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface,
+ ContainerWindow container) {
+ super(ctx.getResources().getConfiguration(), rootSurface, null /* hostInputToken */);
+ mContainerWindow = container;
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ int requestedWidth, int requestedHeight, int viewVisibility, int flags,
+ long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
+ Rect outVisibleInsets, Rect outStableInsets,
+ DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
+ SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
+ int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
+ viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
+ outContentInsets, outVisibleInsets, outStableInsets,
+ cutout, mergedConfiguration, outSurfaceControl, outInsetsState);
+ if (res != 0) {
+ return res;
+ }
+ DisplayLayout dl = mDisplayController.getDisplayLayout(mDisplayId);
+ outStableInsets.set(dl.stableInsets());
+ return 0;
+ }
+
+ void updateConfiguration(Configuration configuration) {
+ setConfiguration(configuration);
+ }
+ }
+
+ class ContainerWindow extends IWindow.Stub {
+ ContainerWindow() {}
+
+ @Override
+ public void resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets,
+ boolean reportDraw, MergedConfiguration newMergedConfiguration, Rect backDropFrame,
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {}
+
+ @Override
+ public void locationInParentDisplayChanged(Point offset) {}
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {}
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {}
+
+ @Override
+ public void showInsets(int types, boolean fromIme) {}
+
+ @Override
+ public void hideInsets(int types, boolean fromIme) {}
+
+ @Override
+ public void moved(int newX, int newY) {}
+
+ @Override
+ public void dispatchAppVisibility(boolean visible) {}
+
+ @Override
+ public void dispatchGetNewSurface() {}
+
+ @Override
+ public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {}
+
+ @Override
+ public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {}
+
+ @Override
+ public void closeSystemDialogs(String reason) {}
+
+ @Override
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
+ boolean sync) {}
+
+ @Override
+ public void dispatchWallpaperCommand(String action, int x, int y,
+ int z, Bundle extras, boolean sync) {}
+
+ /* Drag/drop */
+ @Override
+ public void dispatchDragEvent(DragEvent event) {}
+
+ @Override
+ public void updatePointerIcon(float x, float y) {}
+
+ @Override
+ public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
+ int localValue, int localChanges) {}
+
+ @Override
+ public void dispatchWindowShown() {}
+
+ @Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
+
+ @Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {}
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index aa0e97318eed..9e5734b57f87 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -167,6 +167,7 @@ import android.os.UserHandle;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -174,6 +175,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.ISystemGestureExclusionListener;
+import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputWindowHandle;
@@ -563,6 +565,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
/** Corner radius that windows should have in order to match the display. */
private final float mWindowCornerRadius;
+ private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
@@ -1017,6 +1021,37 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return token;
}
+ SurfaceControl addShellRoot(@NonNull IWindow client, int windowType) {
+ ShellRoot root = mShellRoots.get(windowType);
+ if (root != null) {
+ if (root.getClient() == client) {
+ return root.getSurfaceControl();
+ }
+ root.clear();
+ mShellRoots.remove(windowType);
+ }
+ root = new ShellRoot(client, this, windowType);
+ SurfaceControl rootLeash = root.getSurfaceControl();
+ if (rootLeash == null) {
+ // Root didn't finish initializing, so don't add it.
+ root.clear();
+ return null;
+ }
+ mShellRoots.put(windowType, root);
+ SurfaceControl out = new SurfaceControl();
+ out.copyFrom(rootLeash);
+ return out;
+ }
+
+ void removeShellRoot(int windowType) {
+ ShellRoot root = mShellRoots.get(windowType);
+ if (root == null) {
+ return;
+ }
+ root.clear();
+ mShellRoots.remove(windowType);
+ }
+
/** Changes the display the input window token is housed on to this one. */
void reParentWindowToken(WindowToken token) {
final DisplayContent prevDc = token.getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
new file mode 100644
index 000000000000..9732637fdd4d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 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.annotation.NonNull;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.IWindow;
+import android.view.SurfaceControl;
+
+/**
+ * Represents a piece of the hierarchy under which a client Shell can manage sub-windows.
+ */
+public class ShellRoot {
+ private static final String TAG = "ShellRoot";
+ private final DisplayContent mDisplayContent;
+ private IWindow mClient;
+ private WindowToken mToken;
+ private final IBinder.DeathRecipient mDeathRecipient;
+ private SurfaceControl mSurfaceControl = null;
+
+ ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc, final int windowType) {
+ mDisplayContent = dc;
+ mDeathRecipient = () -> mDisplayContent.removeShellRoot(windowType);
+ try {
+ client.asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to add shell root for layer " + windowType + " on display "
+ + dc.getDisplayId(), e);
+ return;
+ }
+ mClient = client;
+ mToken = new WindowToken(
+ dc.mWmService, client.asBinder(), windowType, true, dc, true, false);
+ mSurfaceControl = mToken.makeChildSurface(null)
+ .setContainerLayer().setName("Shell Root Leash " + dc.getDisplayId()).build();
+ mToken.getPendingTransaction().show(mSurfaceControl);
+ }
+
+ void clear() {
+ if (mClient != null) {
+ mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
+ mClient = null;
+ }
+ if (mToken != null) {
+ mToken.removeImmediately();
+ mToken = null;
+ }
+ }
+
+ SurfaceControl getSurfaceControl() {
+ return mSurfaceControl;
+ }
+
+ IWindow getClient() {
+ return mClient;
+ }
+}
+
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d1bd7452cfb8..be62b680b880 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3712,6 +3712,26 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public SurfaceControl addShellRoot(int displayId, IWindow client, int windowType) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ return null;
+ }
+ return dc.addShellRoot(client, windowType);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
synchronized (mGlobalLock) {