1 /* 2 * Copyright (C) 2020 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.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 22 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; 23 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER; 24 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; 25 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; 26 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS; 27 28 import static com.android.internal.util.Preconditions.checkState; 29 import static com.android.server.wm.DisplayAreaProto.NAME; 30 import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER; 31 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; 32 import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA; 33 34 import android.content.res.Configuration; 35 import android.graphics.Rect; 36 import android.util.proto.ProtoOutputStream; 37 import android.window.DisplayAreaInfo; 38 import android.window.IDisplayAreaOrganizer; 39 40 import com.android.server.policy.WindowManagerPolicy; 41 import com.android.server.protolog.common.ProtoLog; 42 43 import java.util.Comparator; 44 import java.util.function.Consumer; 45 import java.util.function.Predicate; 46 47 /** 48 * Container for grouping WindowContainer below DisplayContent. 49 * 50 * DisplayAreas are managed by a {@link DisplayAreaPolicy}, and can override configurations and 51 * can be leashed. 52 * 53 * DisplayAreas can contain nested DisplayAreas. 54 * 55 * DisplayAreas come in three flavors, to ensure that windows have the right Z-Order: 56 * - BELOW_TASKS: Can only contain BELOW_TASK DisplayAreas and WindowTokens that go below tasks. 57 * - ABOVE_TASKS: Can only contain ABOVE_TASK DisplayAreas and WindowTokens that go above tasks. 58 * - ANY: Can contain any kind of DisplayArea, and any kind of WindowToken or the Task container. 59 * 60 * @param <T> type of the children of the DisplayArea. 61 */ 62 public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { 63 64 protected final Type mType; 65 private final String mName; 66 final int mFeatureId; 67 private final DisplayAreaOrganizerController mOrganizerController; 68 IDisplayAreaOrganizer mOrganizer; 69 private final Configuration mTmpConfiguration = new Configuration(); 70 DisplayArea(WindowManagerService wms, Type type, String name)71 DisplayArea(WindowManagerService wms, Type type, String name) { 72 this(wms, type, name, FEATURE_UNDEFINED); 73 } 74 DisplayArea(WindowManagerService wms, Type type, String name, int featureId)75 DisplayArea(WindowManagerService wms, Type type, String name, int featureId) { 76 super(wms); 77 // TODO(display-area): move this up to ConfigurationContainer 78 mOrientation = SCREEN_ORIENTATION_UNSET; 79 mType = type; 80 mName = name; 81 mFeatureId = featureId; 82 mRemoteToken = new RemoteToken(this); 83 mOrganizerController = 84 wms.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController; 85 } 86 87 @Override onChildPositionChanged(WindowContainer child)88 void onChildPositionChanged(WindowContainer child) { 89 super.onChildPositionChanged(child); 90 91 // Verify that we have proper ordering 92 Type.checkChild(mType, Type.typeOf(child)); 93 94 if (child instanceof ActivityStack) { 95 // TODO(display-area): ActivityStacks are type ANY, but are allowed to have siblings. 96 // They might need a separate type. 97 return; 98 } 99 100 for (int i = 1; i < getChildCount(); i++) { 101 final WindowContainer top = getChildAt(i - 1); 102 final WindowContainer bottom = getChildAt(i); 103 if (child == top || child == bottom) { 104 Type.checkSiblings(Type.typeOf(top), Type.typeOf(bottom)); 105 } 106 } 107 } 108 109 @Override needsZBoost()110 boolean needsZBoost() { 111 // Z Boost should only happen at or below the ActivityStack level. 112 return false; 113 } 114 115 @Override fillsParent()116 boolean fillsParent() { 117 return true; 118 } 119 120 @Override getName()121 String getName() { 122 return mName; 123 } 124 125 @Override toString()126 public String toString() { 127 return mName + "@" + System.identityHashCode(this); 128 } 129 130 @Override dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel)131 public final void dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel) { 132 final long token = proto.start(fieldId); 133 super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); 134 proto.write(NAME, mName); 135 proto.end(token); 136 } 137 138 @Override getProtoFieldId()139 long getProtoFieldId() { 140 return DISPLAY_AREA; 141 } 142 forAllDisplayAreas(Consumer<DisplayArea> callback)143 void forAllDisplayAreas(Consumer<DisplayArea> callback) { 144 super.forAllDisplayAreas(callback); 145 callback.accept(this); 146 } 147 setOrganizer(IDisplayAreaOrganizer organizer)148 void setOrganizer(IDisplayAreaOrganizer organizer) { 149 if (mOrganizer == organizer) return; 150 IDisplayAreaOrganizer lastOrganizer = mOrganizer; 151 // Update the new display area organizer before calling sendDisplayAreaVanished since it 152 // could result in a new SurfaceControl getting created that would notify the old organizer 153 // about it. 154 mOrganizer = organizer; 155 sendDisplayAreaVanished(lastOrganizer); 156 sendDisplayAreaAppeared(); 157 } 158 sendDisplayAreaAppeared()159 void sendDisplayAreaAppeared() { 160 if (mOrganizer == null) return; 161 mOrganizerController.onDisplayAreaAppeared(mOrganizer, this); 162 } 163 sendDisplayAreaVanished(IDisplayAreaOrganizer organizer)164 void sendDisplayAreaVanished(IDisplayAreaOrganizer organizer) { 165 if (organizer == null) return; 166 migrateToNewSurfaceControl(); 167 mOrganizerController.onDisplayAreaVanished(organizer, this); 168 } 169 170 @Override onConfigurationChanged(Configuration newParentConfig)171 public void onConfigurationChanged(Configuration newParentConfig) { 172 mTmpConfiguration.setTo(getConfiguration()); 173 super.onConfigurationChanged(newParentConfig); 174 175 if (mOrganizer != null && getConfiguration().diff(mTmpConfiguration) != 0) { 176 mOrganizerController.onDisplayAreaInfoChanged(mOrganizer, this); 177 } 178 } 179 180 @Override isOrganized()181 boolean isOrganized() { 182 return mOrganizer != null; 183 } 184 185 getDisplayAreaInfo()186 DisplayAreaInfo getDisplayAreaInfo() { 187 DisplayAreaInfo info = new DisplayAreaInfo(mRemoteToken.toWindowContainerToken(), 188 getDisplayContent().getDisplayId(), mFeatureId); 189 info.configuration.setTo(getConfiguration()); 190 return info; 191 } 192 193 /** 194 * DisplayArea that contains WindowTokens, and orders them according to their type. 195 */ 196 public static class Tokens extends DisplayArea<WindowToken> { 197 int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 198 199 private final Comparator<WindowToken> mWindowComparator = 200 Comparator.comparingInt(WindowToken::getWindowLayerFromType); 201 202 private final Predicate<WindowState> mGetOrientingWindow = w -> { 203 final WindowManagerPolicy policy = mWmService.mPolicy; 204 if (policy.isKeyguardHostWindow(w.mAttrs)) { 205 if (mWmService.mKeyguardGoingAway) { 206 return false; 207 } 208 // Consider unoccluding only when all unknown visibilities have been 209 // resolved, as otherwise we just may be starting another occluding activity. 210 final boolean isUnoccluding = 211 mDisplayContent.mAppTransition.getAppTransition() 212 == TRANSIT_KEYGUARD_UNOCCLUDE 213 && mDisplayContent.mUnknownAppVisibilityController.allResolved(); 214 // If keyguard is showing, or we're unoccluding, force the keyguard's orientation, 215 // even if SystemUI hasn't updated the attrs yet. 216 if (policy.isKeyguardShowingAndNotOccluded() || isUnoccluding) { 217 return true; 218 } 219 } 220 final int req = w.mAttrs.screenOrientation; 221 if (req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND 222 || req == SCREEN_ORIENTATION_UNSET) { 223 return false; 224 } 225 return true; 226 }; 227 Tokens(WindowManagerService wms, Type type, String name)228 Tokens(WindowManagerService wms, Type type, String name) { 229 super(wms, type, name, FEATURE_WINDOW_TOKENS); 230 } 231 addChild(WindowToken token)232 void addChild(WindowToken token) { 233 addChild(token, mWindowComparator); 234 } 235 236 @Override getOrientation(int candidate)237 int getOrientation(int candidate) { 238 // Find a window requesting orientation. 239 final WindowState win = getWindow(mGetOrientingWindow); 240 241 if (win == null) { 242 return candidate; 243 } 244 int req = win.mAttrs.screenOrientation; 245 ProtoLog.v(WM_DEBUG_ORIENTATION, "%s forcing orientation to %d for display id=%d", 246 win, req, mDisplayContent.getDisplayId()); 247 if (mWmService.mPolicy.isKeyguardHostWindow(win.mAttrs)) { 248 // SystemUI controls the Keyguard orientation asynchronously, and mAttrs may be 249 // stale. We record / use the last known override. 250 if (req != SCREEN_ORIENTATION_UNSET && req != SCREEN_ORIENTATION_UNSPECIFIED) { 251 mLastKeyguardForcedOrientation = req; 252 } else { 253 req = mLastKeyguardForcedOrientation; 254 } 255 } 256 mLastOrientationSource = win; 257 return req; 258 } 259 } 260 261 @Override getDisplayArea()262 DisplayArea getDisplayArea() { 263 return this; 264 } 265 266 /** 267 * Top-most DisplayArea under DisplayContent. 268 */ 269 public static class Root extends DisplayArea<DisplayArea> { 270 private final Dimmer mDimmer = new Dimmer(this); 271 private final Rect mTmpDimBoundsRect = new Rect(); 272 Root(WindowManagerService wms)273 Root(WindowManagerService wms) { 274 super(wms, Type.ANY, "DisplayArea.Root", FEATURE_ROOT); 275 } 276 277 @Override getDimmer()278 Dimmer getDimmer() { 279 return mDimmer; 280 } 281 282 @Override prepareSurfaces()283 void prepareSurfaces() { 284 mDimmer.resetDimStates(); 285 super.prepareSurfaces(); 286 getBounds(mTmpDimBoundsRect); 287 288 // If SystemUI is dragging for recents, we want to reset the dim state so any dim layer 289 // on the display level fades out. 290 if (forAllTasks(task -> !task.canAffectSystemUiFlags())) { 291 mDimmer.resetDimStates(); 292 } 293 294 if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { 295 scheduleAnimation(); 296 } 297 } 298 } 299 300 enum Type { 301 /** Can only contain WindowTokens above the APPLICATION_LAYER. */ 302 ABOVE_TASKS, 303 /** Can only contain WindowTokens below the APPLICATION_LAYER. */ 304 BELOW_TASKS, 305 /** Can contain anything. */ 306 ANY; 307 checkSiblings(Type bottom, Type top)308 static void checkSiblings(Type bottom, Type top) { 309 checkState(!(bottom != BELOW_TASKS && top == BELOW_TASKS), 310 bottom + " must be above BELOW_TASKS"); 311 checkState(!(bottom == ABOVE_TASKS && top != ABOVE_TASKS), 312 top + " must be below ABOVE_TASKS"); 313 } 314 checkChild(Type parent, Type child)315 static void checkChild(Type parent, Type child) { 316 switch (parent) { 317 case ABOVE_TASKS: 318 checkState(child == ABOVE_TASKS, "ABOVE_TASKS can only contain ABOVE_TASKS"); 319 break; 320 case BELOW_TASKS: 321 checkState(child == BELOW_TASKS, "BELOW_TASKS can only contain BELOW_TASKS"); 322 break; 323 } 324 } 325 typeOf(WindowContainer c)326 static Type typeOf(WindowContainer c) { 327 if (c instanceof DisplayArea) { 328 return ((DisplayArea) c).mType; 329 } else if (c instanceof WindowToken && !(c instanceof ActivityRecord)) { 330 return typeOf((WindowToken) c); 331 } else if (c instanceof ActivityStack) { 332 return ANY; 333 } else { 334 throw new IllegalArgumentException("Unknown container: " + c); 335 } 336 } 337 typeOf(WindowToken c)338 private static Type typeOf(WindowToken c) { 339 return c.getWindowLayerFromType() < APPLICATION_LAYER ? BELOW_TASKS : ABOVE_TASKS; 340 } 341 } 342 } 343