1 /* 2 * Copyright (C) 2017 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.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 28 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 29 import static android.app.WindowConfiguration.activityTypeToString; 30 import static android.app.WindowConfiguration.windowingModeToString; 31 32 import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION; 33 import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION; 34 import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGURATION; 35 36 import android.annotation.CallSuper; 37 import android.app.WindowConfiguration; 38 import android.content.res.Configuration; 39 import android.graphics.Point; 40 import android.graphics.Rect; 41 import android.util.proto.ProtoOutputStream; 42 43 import com.android.internal.annotations.VisibleForTesting; 44 45 import java.io.PrintWriter; 46 import java.util.ArrayList; 47 48 /** 49 * Contains common logic for classes that have override configurations and are organized in a 50 * hierarchy. 51 */ 52 public abstract class ConfigurationContainer<E extends ConfigurationContainer> { 53 /** 54 * {@link #Rect} returned from {@link #getRequestedOverrideBounds()} to prevent original value 55 * from being set directly. 56 */ 57 private Rect mReturnBounds = new Rect(); 58 59 /** 60 * Contains requested override configuration settings applied to this configuration container. 61 */ 62 private Configuration mRequestedOverrideConfiguration = new Configuration(); 63 64 /** 65 * Contains the requested override configuration with parent and policy constraints applied. 66 * This is the set of overrides that gets applied to the full and merged configurations. 67 */ 68 private Configuration mResolvedOverrideConfiguration = new Configuration(); 69 70 /** True if mRequestedOverrideConfiguration is not empty */ 71 private boolean mHasOverrideConfiguration; 72 73 /** 74 * Contains full configuration applied to this configuration container. Corresponds to full 75 * parent's config with applied {@link #mResolvedOverrideConfiguration}. 76 */ 77 private Configuration mFullConfiguration = new Configuration(); 78 79 /** 80 * Contains merged override configuration settings from the top of the hierarchy down to this 81 * particular instance. It is different from {@link #mFullConfiguration} because it starts from 82 * topmost container's override config instead of global config. 83 */ 84 private Configuration mMergedOverrideConfiguration = new Configuration(); 85 86 private ArrayList<ConfigurationContainerListener> mChangeListeners = new ArrayList<>(); 87 88 // TODO: Can't have ag/2592611 soon enough! 89 private final Configuration mRequestsTmpConfig = new Configuration(); 90 private final Configuration mResolvedTmpConfig = new Configuration(); 91 92 // Used for setting bounds 93 private final Rect mTmpRect = new Rect(); 94 95 static final int BOUNDS_CHANGE_NONE = 0; 96 97 /** 98 * Return value from {@link #setBounds(Rect)} indicating the position of the override bounds 99 * changed. 100 */ 101 static final int BOUNDS_CHANGE_POSITION = 1; 102 103 /** 104 * Return value from {@link #setBounds(Rect)} indicating the size of the override bounds 105 * changed. 106 */ 107 static final int BOUNDS_CHANGE_SIZE = 1 << 1; 108 109 /** 110 * Returns full configuration applied to this configuration container. 111 * This method should be used for getting settings applied in each particular level of the 112 * hierarchy. 113 */ getConfiguration()114 public Configuration getConfiguration() { 115 return mFullConfiguration; 116 } 117 118 /** 119 * Notify that parent config changed and we need to update full configuration. 120 * @see #mFullConfiguration 121 */ onConfigurationChanged(Configuration newParentConfig)122 public void onConfigurationChanged(Configuration newParentConfig) { 123 mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration); 124 resolveOverrideConfiguration(newParentConfig); 125 mFullConfiguration.setTo(newParentConfig); 126 mFullConfiguration.updateFrom(mResolvedOverrideConfiguration); 127 onMergedOverrideConfigurationChanged(); 128 if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) { 129 // This depends on the assumption that change-listeners don't do 130 // their own override resolution. This way, dependent hierarchies 131 // can stay properly synced-up with a primary hierarchy's constraints. 132 // Since the hierarchies will be merged, this whole thing will go away 133 // before the assumption will be broken. 134 // Inform listeners of the change. 135 for (int i = mChangeListeners.size() - 1; i >= 0; --i) { 136 mChangeListeners.get(i).onRequestedOverrideConfigurationChanged( 137 mResolvedOverrideConfiguration); 138 } 139 } 140 for (int i = mChangeListeners.size() - 1; i >= 0; --i) { 141 mChangeListeners.get(i).onMergedOverrideConfigurationChanged( 142 mMergedOverrideConfiguration); 143 } 144 for (int i = getChildCount() - 1; i >= 0; --i) { 145 dispatchConfigurationToChild(getChildAt(i), mFullConfiguration); 146 } 147 } 148 149 /** 150 * Dispatches the configuration to child when {@link #onConfigurationChanged(Configuration)} is 151 * called. This allows the derived classes to override how to dispatch the configuration. 152 */ dispatchConfigurationToChild(E child, Configuration config)153 void dispatchConfigurationToChild(E child, Configuration config) { 154 child.onConfigurationChanged(config); 155 } 156 157 /** 158 * Resolves the current requested override configuration into 159 * {@link #mResolvedOverrideConfiguration} 160 * 161 * @param newParentConfig The new parent configuration to resolve overrides against. 162 */ resolveOverrideConfiguration(Configuration newParentConfig)163 void resolveOverrideConfiguration(Configuration newParentConfig) { 164 mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration); 165 } 166 167 /** Returns {@code true} if requested override override configuration is not empty. */ hasRequestedOverrideConfiguration()168 boolean hasRequestedOverrideConfiguration() { 169 return mHasOverrideConfiguration; 170 } 171 172 /** Returns requested override configuration applied to this configuration container. */ getRequestedOverrideConfiguration()173 public Configuration getRequestedOverrideConfiguration() { 174 return mRequestedOverrideConfiguration; 175 } 176 177 /** Returns the resolved override configuration. */ getResolvedOverrideConfiguration()178 Configuration getResolvedOverrideConfiguration() { 179 return mResolvedOverrideConfiguration; 180 } 181 182 /** 183 * Update override configuration and recalculate full config. 184 * @see #mRequestedOverrideConfiguration 185 * @see #mFullConfiguration 186 */ onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration)187 public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) { 188 // Pre-compute this here, so we don't need to go through the entire Configuration when 189 // writing to proto (which has significant cost if we write a lot of empty configurations). 190 mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration); 191 mRequestedOverrideConfiguration.setTo(overrideConfiguration); 192 final Rect newBounds = mRequestedOverrideConfiguration.windowConfiguration.getBounds(); 193 if (mHasOverrideConfiguration && providesMaxBounds() 194 && diffRequestedOverrideMaxBounds(newBounds) != BOUNDS_CHANGE_NONE) { 195 mRequestedOverrideConfiguration.windowConfiguration.setMaxBounds(newBounds); 196 } 197 // Update full configuration of this container and all its children. 198 final ConfigurationContainer parent = getParent(); 199 onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY); 200 } 201 202 /** 203 * Get merged override configuration from the top of the hierarchy down to this particular 204 * instance. This should be reported to client as override config. 205 */ getMergedOverrideConfiguration()206 public Configuration getMergedOverrideConfiguration() { 207 return mMergedOverrideConfiguration; 208 } 209 210 /** 211 * Update merged override configuration based on corresponding parent's config and notify all 212 * its children. If there is no parent, merged override configuration will set equal to current 213 * override config. 214 * @see #mMergedOverrideConfiguration 215 */ onMergedOverrideConfigurationChanged()216 void onMergedOverrideConfigurationChanged() { 217 final ConfigurationContainer parent = getParent(); 218 if (parent != null) { 219 mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration()); 220 mMergedOverrideConfiguration.updateFrom(mResolvedOverrideConfiguration); 221 } else { 222 mMergedOverrideConfiguration.setTo(mResolvedOverrideConfiguration); 223 } 224 for (int i = getChildCount() - 1; i >= 0; --i) { 225 final ConfigurationContainer child = getChildAt(i); 226 child.onMergedOverrideConfigurationChanged(); 227 } 228 } 229 230 /** 231 * Indicates whether this container chooses not to override any bounds from its parent, either 232 * because it doesn't request to override them or the request is dropped during configuration 233 * resolution. In this case, it will inherit the bounds of the first ancestor which specifies a 234 * bounds subject to policy constraints. 235 * 236 * @return {@code true} if this container level uses bounds from parent level. {@code false} 237 * otherwise. 238 */ matchParentBounds()239 public boolean matchParentBounds() { 240 return getResolvedOverrideBounds().isEmpty(); 241 } 242 243 /** 244 * Returns whether the bounds specified are considered the same as the existing requested 245 * override bounds. This is either when the two bounds are equal or the requested override 246 * bounds are empty and the specified bounds is null. 247 * 248 * @return {@code true} if the bounds are equivalent, {@code false} otherwise 249 */ equivalentRequestedOverrideBounds(Rect bounds)250 public boolean equivalentRequestedOverrideBounds(Rect bounds) { 251 return equivalentBounds(getRequestedOverrideBounds(), bounds); 252 } 253 254 /** Similar to {@link #equivalentRequestedOverrideBounds(Rect)}, but compares max bounds. */ equivalentRequestedOverrideMaxBounds(Rect bounds)255 public boolean equivalentRequestedOverrideMaxBounds(Rect bounds) { 256 return equivalentBounds(getRequestedOverrideMaxBounds(), bounds); 257 } 258 259 /** 260 * Returns whether the two bounds are equal to each other or are a combination of null or empty. 261 */ equivalentBounds(Rect bounds, Rect other)262 public static boolean equivalentBounds(Rect bounds, Rect other) { 263 return bounds == other 264 || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null))) 265 || (other != null && other.isEmpty() && bounds == null); 266 } 267 268 /** 269 * Returns the effective bounds of this container, inheriting the first non-empty bounds set in 270 * its ancestral hierarchy, including itself. 271 */ getBounds()272 public Rect getBounds() { 273 mReturnBounds.set(getConfiguration().windowConfiguration.getBounds()); 274 return mReturnBounds; 275 } 276 getBounds(Rect outBounds)277 public void getBounds(Rect outBounds) { 278 outBounds.set(getBounds()); 279 } 280 281 /** Similar to {@link #getBounds()}, but reports the max bounds. */ getMaxBounds()282 public Rect getMaxBounds() { 283 mReturnBounds.set(getConfiguration().windowConfiguration.getMaxBounds()); 284 return mReturnBounds; 285 } 286 287 /** 288 * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}. 289 */ getPosition(Point out)290 public void getPosition(Point out) { 291 Rect bounds = getBounds(); 292 out.set(bounds.left, bounds.top); 293 } 294 getResolvedOverrideBounds()295 Rect getResolvedOverrideBounds() { 296 mReturnBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); 297 return mReturnBounds; 298 } 299 300 /** 301 * Returns the bounds requested on this container. These may not be the actual bounds the 302 * container ends up with due to policy constraints. The {@link Rect} handed back is 303 * shared for all calls to this method and should not be modified. 304 */ getRequestedOverrideBounds()305 public Rect getRequestedOverrideBounds() { 306 mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getBounds()); 307 308 return mReturnBounds; 309 } 310 311 /** Similar to {@link #getRequestedOverrideBounds()}, but returns the max bounds. */ getRequestedOverrideMaxBounds()312 public Rect getRequestedOverrideMaxBounds() { 313 mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getMaxBounds()); 314 315 return mReturnBounds; 316 } 317 318 /** 319 * Returns {@code true} if the {@link WindowConfiguration} in the requested override 320 * {@link Configuration} specifies bounds. 321 */ hasOverrideBounds()322 public boolean hasOverrideBounds() { 323 return !getRequestedOverrideBounds().isEmpty(); 324 } 325 326 /** 327 * Sets the passed in {@link Rect} to the current bounds. 328 * @see #getRequestedOverrideBounds() 329 */ getRequestedOverrideBounds(Rect outBounds)330 public void getRequestedOverrideBounds(Rect outBounds) { 331 outBounds.set(getRequestedOverrideBounds()); 332 } 333 334 /** 335 * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor. 336 * This value will be reported when {@link #getBounds()} and 337 * {@link #getRequestedOverrideBounds()}. If 338 * an empty {@link Rect} or null is specified, this container will be considered to match its 339 * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent. 340 * 341 * @param bounds The bounds defining the container size. 342 * 343 * @return a bitmask representing the types of changes made to the bounds. 344 */ setBounds(Rect bounds)345 public int setBounds(Rect bounds) { 346 int boundsChange = diffRequestedOverrideBounds(bounds); 347 final boolean overrideMaxBounds = providesMaxBounds() 348 && diffRequestedOverrideMaxBounds(bounds) != BOUNDS_CHANGE_NONE; 349 350 if (boundsChange == BOUNDS_CHANGE_NONE && !overrideMaxBounds) { 351 return boundsChange; 352 } 353 354 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration()); 355 mRequestsTmpConfig.windowConfiguration.setBounds(bounds); 356 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig); 357 358 return boundsChange; 359 } 360 setBounds(int left, int top, int right, int bottom)361 public int setBounds(int left, int top, int right, int bottom) { 362 mTmpRect.set(left, top, right, bottom); 363 return setBounds(mTmpRect); 364 } 365 366 /** 367 * Returns {@code true} if this {@link ConfigurationContainer} provides the maximum bounds to 368 * its child {@link ConfigurationContainer}s. Returns {@code false}, otherwise. 369 * <p> 370 * The maximum bounds is how large a window can be expanded. 371 * </p> 372 */ providesMaxBounds()373 protected boolean providesMaxBounds() { 374 return false; 375 } 376 diffRequestedOverrideMaxBounds(Rect bounds)377 int diffRequestedOverrideMaxBounds(Rect bounds) { 378 if (equivalentRequestedOverrideMaxBounds(bounds)) { 379 return BOUNDS_CHANGE_NONE; 380 } 381 382 int boundsChange = BOUNDS_CHANGE_NONE; 383 384 final Rect existingBounds = getRequestedOverrideMaxBounds(); 385 386 if (bounds == null || existingBounds.left != bounds.left 387 || existingBounds.top != bounds.top) { 388 boundsChange |= BOUNDS_CHANGE_POSITION; 389 } 390 391 if (bounds == null || existingBounds.width() != bounds.width() 392 || existingBounds.height() != bounds.height()) { 393 boundsChange |= BOUNDS_CHANGE_SIZE; 394 } 395 396 return boundsChange; 397 } 398 diffRequestedOverrideBounds(Rect bounds)399 int diffRequestedOverrideBounds(Rect bounds) { 400 if (equivalentRequestedOverrideBounds(bounds)) { 401 return BOUNDS_CHANGE_NONE; 402 } 403 404 int boundsChange = BOUNDS_CHANGE_NONE; 405 406 final Rect existingBounds = getRequestedOverrideBounds(); 407 408 if (bounds == null || existingBounds.left != bounds.left 409 || existingBounds.top != bounds.top) { 410 boundsChange |= BOUNDS_CHANGE_POSITION; 411 } 412 413 if (bounds == null || existingBounds.width() != bounds.width() 414 || existingBounds.height() != bounds.height()) { 415 boundsChange |= BOUNDS_CHANGE_SIZE; 416 } 417 418 return boundsChange; 419 } 420 getWindowConfiguration()421 public WindowConfiguration getWindowConfiguration() { 422 return mFullConfiguration.windowConfiguration; 423 } 424 425 /** Returns the windowing mode the configuration container is currently in. */ getWindowingMode()426 public int getWindowingMode() { 427 return mFullConfiguration.windowConfiguration.getWindowingMode(); 428 } 429 430 /** Returns the windowing mode override that is requested by this container. */ getRequestedOverrideWindowingMode()431 public int getRequestedOverrideWindowingMode() { 432 return mRequestedOverrideConfiguration.windowConfiguration.getWindowingMode(); 433 } 434 435 /** Sets the requested windowing mode override for the configuration container. */ setWindowingMode( int windowingMode)436 public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) { 437 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration()); 438 mRequestsTmpConfig.windowConfiguration.setWindowingMode(windowingMode); 439 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig); 440 } 441 442 /** Sets the always on top flag for this configuration container. 443 * When you call this function, make sure that the following functions are called as well to 444 * keep proper z-order. 445 * - {@link TaskDisplayArea#positionChildAt(int POSITION_TOP, Task, boolean)}; 446 * */ setAlwaysOnTop(boolean alwaysOnTop)447 public void setAlwaysOnTop(boolean alwaysOnTop) { 448 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration()); 449 mRequestsTmpConfig.windowConfiguration.setAlwaysOnTop(alwaysOnTop); 450 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig); 451 } 452 453 /** Sets the windowing mode for the configuration container. */ setDisplayWindowingMode(int windowingMode)454 void setDisplayWindowingMode(int windowingMode) { 455 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration()); 456 mRequestsTmpConfig.windowConfiguration.setDisplayWindowingMode(windowingMode); 457 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig); 458 } 459 460 /** 461 * Returns true if this container is currently in multi-window mode. I.e. sharing the screen 462 * with another activity. 463 */ inMultiWindowMode()464 public boolean inMultiWindowMode() { 465 /*@WindowConfiguration.WindowingMode*/ int windowingMode = 466 mFullConfiguration.windowConfiguration.getWindowingMode(); 467 return WindowConfiguration.inMultiWindowMode(windowingMode); 468 } 469 470 /** Returns true if this container is currently in split-screen windowing mode. */ inSplitScreenWindowingMode()471 public boolean inSplitScreenWindowingMode() { 472 /*@WindowConfiguration.WindowingMode*/ int windowingMode = 473 mFullConfiguration.windowConfiguration.getWindowingMode(); 474 475 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 476 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 477 } 478 479 /** Returns true if this container is currently in split-screen secondary windowing mode. */ inSplitScreenSecondaryWindowingMode()480 public boolean inSplitScreenSecondaryWindowingMode() { 481 /*@WindowConfiguration.WindowingMode*/ int windowingMode = 482 mFullConfiguration.windowConfiguration.getWindowingMode(); 483 484 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 485 } 486 inSplitScreenPrimaryWindowingMode()487 public boolean inSplitScreenPrimaryWindowingMode() { 488 return mFullConfiguration.windowConfiguration.getWindowingMode() 489 == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 490 } 491 492 /** 493 * Returns true if this container can be put in either 494 * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or 495 * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on 496 * its current state. 497 */ supportsSplitScreenWindowingMode()498 public boolean supportsSplitScreenWindowingMode() { 499 return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode(); 500 } 501 inPinnedWindowingMode()502 public boolean inPinnedWindowingMode() { 503 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED; 504 } 505 inFreeformWindowingMode()506 public boolean inFreeformWindowingMode() { 507 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM; 508 } 509 510 /** Returns the activity type associated with the the configuration container. */ 511 /*@WindowConfiguration.ActivityType*/ getActivityType()512 public int getActivityType() { 513 return mFullConfiguration.windowConfiguration.getActivityType(); 514 } 515 516 /** Sets the activity type to associate with the configuration container. */ setActivityType( int activityType)517 public void setActivityType(/*@WindowConfiguration.ActivityType*/ int activityType) { 518 int currentActivityType = getActivityType(); 519 if (currentActivityType == activityType) { 520 return; 521 } 522 if (currentActivityType != ACTIVITY_TYPE_UNDEFINED) { 523 throw new IllegalStateException("Can't change activity type once set: " + this 524 + " activityType=" + activityTypeToString(activityType)); 525 } 526 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration()); 527 mRequestsTmpConfig.windowConfiguration.setActivityType(activityType); 528 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig); 529 } 530 isActivityTypeHome()531 public boolean isActivityTypeHome() { 532 return getActivityType() == ACTIVITY_TYPE_HOME; 533 } 534 isActivityTypeRecents()535 public boolean isActivityTypeRecents() { 536 return getActivityType() == ACTIVITY_TYPE_RECENTS; 537 } 538 isActivityTypeAssistant()539 public boolean isActivityTypeAssistant() { 540 return getActivityType() == ACTIVITY_TYPE_ASSISTANT; 541 } 542 543 /** 544 * Overrides the night mode applied to this ConfigurationContainer. 545 * @return true if the nightMode has been changed. 546 */ setOverrideNightMode(int nightMode)547 public boolean setOverrideNightMode(int nightMode) { 548 final int currentUiMode = mRequestedOverrideConfiguration.uiMode; 549 final int currentNightMode = currentUiMode & Configuration.UI_MODE_NIGHT_MASK; 550 final int validNightMode = nightMode & Configuration.UI_MODE_NIGHT_MASK; 551 if (currentNightMode == validNightMode) { 552 return false; 553 } 554 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration()); 555 mRequestsTmpConfig.uiMode = validNightMode 556 | (currentUiMode & ~Configuration.UI_MODE_NIGHT_MASK); 557 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig); 558 return true; 559 } 560 isActivityTypeDream()561 public boolean isActivityTypeDream() { 562 return getActivityType() == ACTIVITY_TYPE_DREAM; 563 } 564 isActivityTypeStandard()565 public boolean isActivityTypeStandard() { 566 return getActivityType() == ACTIVITY_TYPE_STANDARD; 567 } 568 isActivityTypeStandardOrUndefined()569 public boolean isActivityTypeStandardOrUndefined() { 570 /*@WindowConfiguration.ActivityType*/ final int activityType = getActivityType(); 571 return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED; 572 } 573 isCompatibleActivityType(int currentType, int otherType)574 public static boolean isCompatibleActivityType(int currentType, int otherType) { 575 if (currentType == otherType) { 576 return true; 577 } 578 if (currentType == ACTIVITY_TYPE_ASSISTANT) { 579 // Assistant activities are only compatible with themselves... 580 return false; 581 } 582 // Otherwise we are compatible if us or other is not currently defined. 583 return currentType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED; 584 } 585 586 /** 587 * Returns true if this container is compatible with the input windowing mode and activity type. 588 * The container is compatible: 589 * - If {@param activityType} and {@param windowingMode} match this container activity type and 590 * windowing mode. 591 * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or 592 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also 593 * standard or undefined and its windowing mode matches {@param windowingMode}. 594 * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or 595 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't 596 * also standard or undefined and its activity type matches {@param activityType} regardless of 597 * if {@param windowingMode} matches the containers windowing mode. 598 */ isCompatible(int windowingMode, int activityType)599 public boolean isCompatible(int windowingMode, int activityType) { 600 final int thisActivityType = getActivityType(); 601 final int thisWindowingMode = getWindowingMode(); 602 final boolean sameActivityType = thisActivityType == activityType; 603 final boolean sameWindowingMode = thisWindowingMode == windowingMode; 604 605 if (sameActivityType && sameWindowingMode) { 606 return true; 607 } 608 609 if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD) 610 || !isActivityTypeStandardOrUndefined()) { 611 // Only activity type need to match for non-standard activity types that are defined. 612 return sameActivityType; 613 } 614 615 // Otherwise we are compatible if the windowing mode is the same. 616 return sameWindowingMode; 617 } 618 registerConfigurationChangeListener(ConfigurationContainerListener listener)619 void registerConfigurationChangeListener(ConfigurationContainerListener listener) { 620 if (mChangeListeners.contains(listener)) { 621 return; 622 } 623 mChangeListeners.add(listener); 624 listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration); 625 listener.onMergedOverrideConfigurationChanged(mMergedOverrideConfiguration); 626 } 627 unregisterConfigurationChangeListener(ConfigurationContainerListener listener)628 void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) { 629 mChangeListeners.remove(listener); 630 } 631 632 @VisibleForTesting containsListener(ConfigurationContainerListener listener)633 boolean containsListener(ConfigurationContainerListener listener) { 634 return mChangeListeners.contains(listener); 635 } 636 637 /** 638 * Must be called when new parent for the container was set. 639 */ onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)640 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { 641 // Removing parent usually means that we've detached this entity to destroy it or to attach 642 // to another parent. In both cases we don't need to update the configuration now. 643 if (newParent != null) { 644 // Update full configuration of this container and all its children. 645 onConfigurationChanged(newParent.mFullConfiguration); 646 // Update merged override configuration of this container and all its children. 647 onMergedOverrideConfigurationChanged(); 648 } 649 } 650 651 /** 652 * Write to a protocol buffer output stream. Protocol buffer message definition is at 653 * {@link com.android.server.wm.ConfigurationContainerProto}. 654 * 655 * @param proto Stream to write the ConfigurationContainer object to. 656 * @param fieldId Field Id of the ConfigurationContainer as defined in the parent 657 * message. 658 * @param logLevel Determines the amount of data to be written to the Protobuf. 659 * @hide 660 */ 661 @CallSuper dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)662 protected void dumpDebug(ProtoOutputStream proto, long fieldId, 663 @WindowTraceLogLevel int logLevel) { 664 // Critical log level logs only visible elements to mitigate performance overheard 665 if (logLevel != WindowTraceLogLevel.ALL && !mHasOverrideConfiguration) { 666 return; 667 } 668 669 final long token = proto.start(fieldId); 670 mRequestedOverrideConfiguration.dumpDebug(proto, OVERRIDE_CONFIGURATION, 671 logLevel == WindowTraceLogLevel.CRITICAL); 672 if (logLevel == WindowTraceLogLevel.ALL) { 673 mFullConfiguration.dumpDebug(proto, FULL_CONFIGURATION, false /* critical */); 674 mMergedOverrideConfiguration.dumpDebug(proto, MERGED_OVERRIDE_CONFIGURATION, 675 false /* critical */); 676 } 677 proto.end(token); 678 } 679 680 /** 681 * Dumps the names of this container children in the input print writer indenting each 682 * level with the input prefix. 683 */ dumpChildrenNames(PrintWriter pw, String prefix)684 public void dumpChildrenNames(PrintWriter pw, String prefix) { 685 final String childPrefix = prefix + " "; 686 pw.println(getName() 687 + " type=" + activityTypeToString(getActivityType()) 688 + " mode=" + windowingModeToString(getWindowingMode()) 689 + " override-mode=" + windowingModeToString(getRequestedOverrideWindowingMode()) 690 + " requested-bounds=" + getRequestedOverrideBounds().toShortString() 691 + " bounds=" + getBounds().toShortString()); 692 for (int i = getChildCount() - 1; i >= 0; --i) { 693 final E cc = getChildAt(i); 694 pw.print(childPrefix + "#" + i + " "); 695 cc.dumpChildrenNames(pw, childPrefix); 696 } 697 } 698 getName()699 String getName() { 700 return toString(); 701 } 702 isAlwaysOnTop()703 public boolean isAlwaysOnTop() { 704 return mFullConfiguration.windowConfiguration.isAlwaysOnTop(); 705 } 706 hasChild()707 boolean hasChild() { 708 return getChildCount() > 0; 709 } 710 getChildCount()711 abstract protected int getChildCount(); 712 getChildAt(int index)713 abstract protected E getChildAt(int index); 714 getParent()715 abstract protected ConfigurationContainer getParent(); 716 717 } 718