1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 20 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 21 import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER; 22 import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP; 23 24 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; 25 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; 26 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.graphics.Point; 30 import android.os.IBinder; 31 import android.os.RemoteException; 32 import android.util.Slog; 33 import android.view.DisplayInfo; 34 import android.view.IWindow; 35 import android.view.SurfaceControl; 36 import android.view.WindowManager; 37 import android.view.animation.Animation; 38 39 /** 40 * Represents a piece of the hierarchy under which a client Shell can manage sub-windows. 41 */ 42 public class ShellRoot { 43 private static final String TAG = "ShellRoot"; 44 private final DisplayContent mDisplayContent; 45 private final int mShellRootLayer; 46 private IWindow mClient; 47 private WindowToken mToken; 48 private final IBinder.DeathRecipient mDeathRecipient; 49 private SurfaceControl mSurfaceControl = null; 50 private IWindow mAccessibilityWindow; 51 private IBinder.DeathRecipient mAccessibilityWindowDeath; 52 private int mWindowType; 53 ShellRoot(@onNull IWindow client, @NonNull DisplayContent dc, @WindowManager.ShellRootLayer final int shellRootLayer)54 ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc, 55 @WindowManager.ShellRootLayer final int shellRootLayer) { 56 mDisplayContent = dc; 57 mShellRootLayer = shellRootLayer; 58 mDeathRecipient = () -> mDisplayContent.removeShellRoot(shellRootLayer); 59 try { 60 client.asBinder().linkToDeath(mDeathRecipient, 0); 61 } catch (RemoteException e) { 62 Slog.e(TAG, "Unable to add shell root layer " + shellRootLayer + " on display " 63 + dc.getDisplayId(), e); 64 return; 65 } 66 mClient = client; 67 switch (shellRootLayer) { 68 case SHELL_ROOT_LAYER_DIVIDER: 69 mWindowType = TYPE_DOCK_DIVIDER; 70 break; 71 case SHELL_ROOT_LAYER_PIP: 72 mWindowType = TYPE_APPLICATION_OVERLAY; 73 break; 74 default: 75 throw new IllegalArgumentException(shellRootLayer 76 + " is not an acceptable shell root layer."); 77 } 78 mToken = new WindowToken.Builder(dc.mWmService, client.asBinder(), mWindowType) 79 .setDisplayContent(dc) 80 .setPersistOnEmpty(true) 81 .setOwnerCanManageAppTokens(true) 82 .build(); 83 mSurfaceControl = mToken.makeChildSurface(null) 84 .setContainerLayer() 85 .setName("Shell Root Leash " + dc.getDisplayId()) 86 .setCallsite("ShellRoot") 87 .build(); 88 mToken.getPendingTransaction().show(mSurfaceControl); 89 } 90 getWindowType()91 int getWindowType() { 92 return mWindowType; 93 } 94 clear()95 void clear() { 96 if (mClient != null) { 97 mClient.asBinder().unlinkToDeath(mDeathRecipient, 0); 98 mClient = null; 99 } 100 if (mToken != null) { 101 mToken.removeImmediately(); 102 mToken = null; 103 } 104 } 105 getSurfaceControl()106 SurfaceControl getSurfaceControl() { 107 return mSurfaceControl; 108 } 109 getClient()110 IWindow getClient() { 111 return mClient; 112 } 113 startAnimation(Animation anim)114 void startAnimation(Animation anim) { 115 // Only do this for the divider 116 if (mToken.windowType != TYPE_DOCK_DIVIDER) { 117 return; 118 } 119 120 DisplayInfo displayInfo = mToken.getFixedRotationTransformDisplayInfo(); 121 if (displayInfo == null) { 122 displayInfo = mDisplayContent.getDisplayInfo(); 123 } 124 125 // Mostly copied from WindowState to enable keyguard transition animation 126 anim.initialize(displayInfo.logicalWidth, displayInfo.logicalHeight, 127 displayInfo.appWidth, displayInfo.appHeight); 128 anim.restrictDuration(MAX_ANIMATION_DURATION); 129 anim.scaleCurrentDuration(mDisplayContent.mWmService.getWindowAnimationScaleLocked()); 130 final AnimationAdapter adapter = new LocalAnimationAdapter( 131 new WindowAnimationSpec(anim, new Point(0, 0), false /* canSkipFirstFrame */, 132 0 /* windowCornerRadius */), 133 mDisplayContent.mWmService.mSurfaceAnimationRunner); 134 mToken.startAnimation(mToken.getPendingTransaction(), adapter, false /* hidden */, 135 ANIMATION_TYPE_WINDOW_ANIMATION); 136 } 137 138 @Nullable getAccessibilityWindowToken()139 IBinder getAccessibilityWindowToken() { 140 if (mAccessibilityWindow != null) { 141 return mAccessibilityWindow.asBinder(); 142 } 143 return null; 144 } 145 setAccessibilityWindow(IWindow window)146 void setAccessibilityWindow(IWindow window) { 147 if (mAccessibilityWindow != null) { 148 mAccessibilityWindow.asBinder().unlinkToDeath(mAccessibilityWindowDeath, 0); 149 } 150 mAccessibilityWindow = window; 151 if (mAccessibilityWindow != null) { 152 try { 153 mAccessibilityWindowDeath = () -> { 154 synchronized (mDisplayContent.mWmService.mGlobalLock) { 155 mAccessibilityWindow = null; 156 setAccessibilityWindow(null); 157 } 158 }; 159 mAccessibilityWindow.asBinder().linkToDeath(mAccessibilityWindowDeath, 0); 160 } catch (RemoteException e) { 161 mAccessibilityWindow = null; 162 } 163 } 164 } 165 } 166