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