1 /* 2 * Copyright (C) 2023 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.wm.shell.common.pip; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.ActivityTaskManager; 23 import android.app.PictureInPictureParams; 24 import android.app.PictureInPictureUiState; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.pm.ActivityInfo; 28 import android.graphics.Point; 29 import android.graphics.Rect; 30 import android.os.RemoteException; 31 import android.util.ArraySet; 32 import android.util.Size; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.internal.protolog.common.ProtoLog; 36 import com.android.internal.util.function.TriConsumer; 37 import com.android.wm.shell.R; 38 import com.android.wm.shell.common.DisplayLayout; 39 import com.android.wm.shell.protolog.ShellProtoLogGroup; 40 41 import java.io.PrintWriter; 42 import java.lang.annotation.Retention; 43 import java.lang.annotation.RetentionPolicy; 44 import java.util.ArrayList; 45 import java.util.HashMap; 46 import java.util.List; 47 import java.util.Map; 48 import java.util.Objects; 49 import java.util.Set; 50 import java.util.function.Consumer; 51 52 /** 53 * Singleton source of truth for the current state of PIP bounds. 54 */ 55 public class PipBoundsState { 56 public static final int STASH_TYPE_NONE = 0; 57 public static final int STASH_TYPE_LEFT = 1; 58 public static final int STASH_TYPE_RIGHT = 2; 59 public static final int STASH_TYPE_BOTTOM = 3; 60 public static final int STASH_TYPE_TOP = 4; 61 62 @IntDef(prefix = { "STASH_TYPE_" }, value = { 63 STASH_TYPE_NONE, 64 STASH_TYPE_LEFT, 65 STASH_TYPE_RIGHT, 66 STASH_TYPE_BOTTOM, 67 STASH_TYPE_TOP 68 }) 69 @Retention(RetentionPolicy.SOURCE) 70 public @interface StashType {} 71 72 private static final String TAG = PipBoundsState.class.getSimpleName(); 73 74 private final @NonNull Rect mBounds = new Rect(); 75 private final @NonNull Rect mMovementBounds = new Rect(); 76 private final @NonNull Rect mNormalBounds = new Rect(); 77 private final @NonNull Rect mExpandedBounds = new Rect(); 78 private final @NonNull Rect mNormalMovementBounds = new Rect(); 79 private final @NonNull Rect mExpandedMovementBounds = new Rect(); 80 private final @NonNull PipDisplayLayoutState mPipDisplayLayoutState; 81 private final Point mMaxSize = new Point(); 82 private final Point mMinSize = new Point(); 83 private final @NonNull Context mContext; 84 private float mAspectRatio; 85 private int mStashedState = STASH_TYPE_NONE; 86 private int mStashOffset; 87 private @Nullable PipReentryState mPipReentryState; 88 private final LauncherState mLauncherState = new LauncherState(); 89 private final @NonNull SizeSpecSource mSizeSpecSource; 90 private @Nullable ComponentName mLastPipComponentName; 91 private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState(); 92 private boolean mIsImeShowing; 93 private int mImeHeight; 94 private boolean mIsShelfShowing; 95 private int mShelfHeight; 96 /** Whether the user has resized the PIP manually. */ 97 private boolean mHasUserResizedPip; 98 /** Whether the user has moved the PIP manually. */ 99 private boolean mHasUserMovedPip; 100 /** 101 * Areas defined by currently visible apps that they prefer to keep clear from overlays such as 102 * the PiP. Restricted areas may only move the PiP a limited amount from its anchor position. 103 * The system will try to respect these areas, but when not possible will ignore them. 104 * 105 * @see android.view.View#setPreferKeepClearRects 106 */ 107 private final Set<Rect> mRestrictedKeepClearAreas = new ArraySet<>(); 108 /** 109 * Areas defined by currently visible apps holding 110 * {@link android.Manifest.permission#SET_UNRESTRICTED_KEEP_CLEAR_AREAS} that they prefer to 111 * keep clear from overlays such as the PiP. 112 * Unrestricted areas can move the PiP farther than restricted areas, and the system will try 113 * harder to respect these areas. 114 * 115 * @see android.view.View#setPreferKeepClearRects 116 */ 117 private final Set<Rect> mUnrestrictedKeepClearAreas = new ArraySet<>(); 118 /** 119 * Additional to {@link #mUnrestrictedKeepClearAreas}, allow the caller to append named bounds 120 * as unrestricted keep clear area. Values in this map would be appended to 121 * {@link #getUnrestrictedKeepClearAreas()} and this is meant for internal usage only. 122 */ 123 private final Map<String, Rect> mNamedUnrestrictedKeepClearAreas = new HashMap<>(); 124 125 private @Nullable Runnable mOnMinimalSizeChangeCallback; 126 private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback; 127 private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>(); 128 PipBoundsState(@onNull Context context, @NonNull SizeSpecSource sizeSpecSource, @NonNull PipDisplayLayoutState pipDisplayLayoutState)129 public PipBoundsState(@NonNull Context context, @NonNull SizeSpecSource sizeSpecSource, 130 @NonNull PipDisplayLayoutState pipDisplayLayoutState) { 131 mContext = context; 132 reloadResources(); 133 mSizeSpecSource = sizeSpecSource; 134 mPipDisplayLayoutState = pipDisplayLayoutState; 135 } 136 137 /** Reloads the resources. */ onConfigurationChanged()138 public void onConfigurationChanged() { 139 reloadResources(); 140 141 // update the size spec resources upon config change too 142 mSizeSpecSource.onConfigurationChanged(); 143 } 144 reloadResources()145 private void reloadResources() { 146 mStashOffset = mContext.getResources().getDimensionPixelSize(R.dimen.pip_stash_offset); 147 } 148 149 /** Set the current PIP bounds. */ setBounds(@onNull Rect bounds)150 public void setBounds(@NonNull Rect bounds) { 151 mBounds.set(bounds); 152 for (Consumer<Rect> callback : mOnPipExclusionBoundsChangeCallbacks) { 153 callback.accept(bounds); 154 } 155 } 156 157 /** Get the current PIP bounds. */ 158 @NonNull getBounds()159 public Rect getBounds() { 160 return new Rect(mBounds); 161 } 162 163 /** Returns the current movement bounds. */ 164 @NonNull getMovementBounds()165 public Rect getMovementBounds() { 166 return mMovementBounds; 167 } 168 169 /** Set the current normal PIP bounds. */ setNormalBounds(@onNull Rect bounds)170 public void setNormalBounds(@NonNull Rect bounds) { 171 mNormalBounds.set(bounds); 172 } 173 174 /** Get the current normal PIP bounds. */ 175 @NonNull getNormalBounds()176 public Rect getNormalBounds() { 177 return mNormalBounds; 178 } 179 180 /** Set the expanded bounds of PIP. */ setExpandedBounds(@onNull Rect bounds)181 public void setExpandedBounds(@NonNull Rect bounds) { 182 mExpandedBounds.set(bounds); 183 } 184 185 /** Get the PIP expanded bounds. */ 186 @NonNull getExpandedBounds()187 public Rect getExpandedBounds() { 188 return mExpandedBounds; 189 } 190 191 /** Set the normal movement bounds. */ setNormalMovementBounds(@onNull Rect bounds)192 public void setNormalMovementBounds(@NonNull Rect bounds) { 193 mNormalMovementBounds.set(bounds); 194 } 195 196 /** Returns the normal movement bounds. */ 197 @NonNull getNormalMovementBounds()198 public Rect getNormalMovementBounds() { 199 return mNormalMovementBounds; 200 } 201 202 /** Set the expanded movement bounds. */ setExpandedMovementBounds(@onNull Rect bounds)203 public void setExpandedMovementBounds(@NonNull Rect bounds) { 204 mExpandedMovementBounds.set(bounds); 205 } 206 207 /** Sets the max possible size for resize. */ setMaxSize(int width, int height)208 public void setMaxSize(int width, int height) { 209 mMaxSize.set(width, height); 210 } 211 212 /** Sets the min possible size for resize. */ setMinSize(int width, int height)213 public void setMinSize(int width, int height) { 214 mMinSize.set(width, height); 215 } 216 getMaxSize()217 public Point getMaxSize() { 218 return mMaxSize; 219 } 220 getMinSize()221 public Point getMinSize() { 222 return mMinSize; 223 } 224 225 /** Returns the expanded movement bounds. */ 226 @NonNull getExpandedMovementBounds()227 public Rect getExpandedMovementBounds() { 228 return mExpandedMovementBounds; 229 } 230 231 /** Dictate where PiP currently should be stashed, if at all. */ setStashed(@tashType int stashedState)232 public void setStashed(@StashType int stashedState) { 233 if (mStashedState == stashedState) { 234 return; 235 } 236 237 mStashedState = stashedState; 238 try { 239 ActivityTaskManager.getService().onPictureInPictureStateChanged( 240 new PictureInPictureUiState(stashedState != STASH_TYPE_NONE /* isStashed */) 241 ); 242 } catch (RemoteException e) { 243 ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, 244 "%s: Unable to set alert PiP state change.", TAG); 245 } 246 } 247 248 /** 249 * Return where the PiP is stashed, if at all. 250 * @return {@code STASH_NONE}, {@code STASH_LEFT} or {@code STASH_RIGHT}. 251 */ getStashedState()252 public @StashType int getStashedState() { 253 return mStashedState; 254 } 255 256 /** Whether PiP is stashed or not. */ isStashed()257 public boolean isStashed() { 258 return mStashedState != STASH_TYPE_NONE; 259 } 260 261 /** Returns the offset from the edge of the screen for PiP stash. */ getStashOffset()262 public int getStashOffset() { 263 return mStashOffset; 264 } 265 266 /** Set the PIP aspect ratio. */ setAspectRatio(float aspectRatio)267 public void setAspectRatio(float aspectRatio) { 268 mAspectRatio = aspectRatio; 269 } 270 271 /** Get the PIP aspect ratio. */ getAspectRatio()272 public float getAspectRatio() { 273 return mAspectRatio; 274 } 275 276 /** Save the reentry state to restore to when re-entering PIP mode. */ saveReentryState(Size size, float fraction)277 public void saveReentryState(Size size, float fraction) { 278 mPipReentryState = new PipReentryState(size, fraction); 279 } 280 281 /** Returns the saved reentry state. */ 282 @Nullable getReentryState()283 public PipReentryState getReentryState() { 284 return mPipReentryState; 285 } 286 287 /** Set the last {@link ComponentName} to enter PIP mode. */ setLastPipComponentName(@ullable ComponentName lastPipComponentName)288 public void setLastPipComponentName(@Nullable ComponentName lastPipComponentName) { 289 final boolean changed = !Objects.equals(mLastPipComponentName, lastPipComponentName); 290 mLastPipComponentName = lastPipComponentName; 291 if (changed) { 292 clearReentryState(); 293 setHasUserResizedPip(false); 294 setHasUserMovedPip(false); 295 } 296 } 297 298 /** Get the last PIP component name, if any. */ 299 @Nullable getLastPipComponentName()300 public ComponentName getLastPipComponentName() { 301 return mLastPipComponentName; 302 } 303 304 /** Returns the display's bounds. */ 305 @NonNull getDisplayBounds()306 public Rect getDisplayBounds() { 307 return mPipDisplayLayoutState.getDisplayBounds(); 308 } 309 310 /** Get a copy of the display layout. */ 311 @NonNull getDisplayLayout()312 public DisplayLayout getDisplayLayout() { 313 return mPipDisplayLayoutState.getDisplayLayout(); 314 } 315 316 /** 317 * Clears the PiP re-entry state. 318 */ 319 @VisibleForTesting clearReentryState()320 public void clearReentryState() { 321 mPipReentryState = null; 322 } 323 324 /** Sets the preferred size of PIP as specified by the activity in PIP mode. */ setOverrideMinSize(@ullable Size overrideMinSize)325 public void setOverrideMinSize(@Nullable Size overrideMinSize) { 326 final boolean changed = !Objects.equals(overrideMinSize, getOverrideMinSize()); 327 mSizeSpecSource.setOverrideMinSize(overrideMinSize); 328 if (changed && mOnMinimalSizeChangeCallback != null) { 329 mOnMinimalSizeChangeCallback.run(); 330 } 331 } 332 333 /** Returns the preferred minimal size specified by the activity in PIP. */ 334 @Nullable getOverrideMinSize()335 public Size getOverrideMinSize() { 336 return mSizeSpecSource.getOverrideMinSize(); 337 } 338 339 /** Returns the minimum edge size of the override minimum size, or 0 if not set. */ getOverrideMinEdgeSize()340 public int getOverrideMinEdgeSize() { 341 return mSizeSpecSource.getOverrideMinEdgeSize(); 342 } 343 344 /** Get the state of the bounds in motion. */ 345 @NonNull getMotionBoundsState()346 public MotionBoundsState getMotionBoundsState() { 347 return mMotionBoundsState; 348 } 349 350 /** Set whether the IME is currently showing and its height. */ setImeVisibility(boolean imeShowing, int imeHeight)351 public void setImeVisibility(boolean imeShowing, int imeHeight) { 352 mIsImeShowing = imeShowing; 353 mImeHeight = imeHeight; 354 } 355 356 /** Returns whether the IME is currently showing. */ isImeShowing()357 public boolean isImeShowing() { 358 return mIsImeShowing; 359 } 360 361 /** Returns the IME height. */ getImeHeight()362 public int getImeHeight() { 363 return mImeHeight; 364 } 365 366 /** Set whether the shelf is showing and its height. */ setShelfVisibility(boolean showing, int height)367 public void setShelfVisibility(boolean showing, int height) { 368 setShelfVisibility(showing, height, true); 369 } 370 371 /** Set whether the shelf is showing and its height. */ setShelfVisibility(boolean showing, int height, boolean updateMovementBounds)372 public void setShelfVisibility(boolean showing, int height, boolean updateMovementBounds) { 373 final boolean shelfShowing = showing && height > 0; 374 if (shelfShowing == mIsShelfShowing && height == mShelfHeight) { 375 return; 376 } 377 378 mIsShelfShowing = showing; 379 mShelfHeight = height; 380 if (mOnShelfVisibilityChangeCallback != null) { 381 mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight, 382 updateMovementBounds); 383 } 384 } 385 386 /** Set the keep clear areas onscreen. The PiP should ideally not cover them. */ setKeepClearAreas(@onNull Set<Rect> restrictedAreas, @NonNull Set<Rect> unrestrictedAreas)387 public void setKeepClearAreas(@NonNull Set<Rect> restrictedAreas, 388 @NonNull Set<Rect> unrestrictedAreas) { 389 mRestrictedKeepClearAreas.clear(); 390 mRestrictedKeepClearAreas.addAll(restrictedAreas); 391 mUnrestrictedKeepClearAreas.clear(); 392 mUnrestrictedKeepClearAreas.addAll(unrestrictedAreas); 393 } 394 395 /** Add a named unrestricted keep clear area. */ addNamedUnrestrictedKeepClearArea(@onNull String name, Rect unrestrictedArea)396 public void addNamedUnrestrictedKeepClearArea(@NonNull String name, Rect unrestrictedArea) { 397 mNamedUnrestrictedKeepClearAreas.put(name, unrestrictedArea); 398 } 399 400 /** Remove a named unrestricted keep clear area. */ removeNamedUnrestrictedKeepClearArea(@onNull String name)401 public void removeNamedUnrestrictedKeepClearArea(@NonNull String name) { 402 mNamedUnrestrictedKeepClearAreas.remove(name); 403 } 404 405 406 /** 407 * @return restricted keep clear areas. 408 */ 409 @NonNull getRestrictedKeepClearAreas()410 public Set<Rect> getRestrictedKeepClearAreas() { 411 return mRestrictedKeepClearAreas; 412 } 413 414 /** 415 * @return unrestricted keep clear areas. 416 */ 417 @NonNull getUnrestrictedKeepClearAreas()418 public Set<Rect> getUnrestrictedKeepClearAreas() { 419 if (mNamedUnrestrictedKeepClearAreas.isEmpty()) return mUnrestrictedKeepClearAreas; 420 final Set<Rect> unrestrictedAreas = new ArraySet<>(mUnrestrictedKeepClearAreas); 421 unrestrictedAreas.addAll(mNamedUnrestrictedKeepClearAreas.values()); 422 return unrestrictedAreas; 423 } 424 425 /** 426 * Initialize states when first entering PiP. 427 */ setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo, PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm)428 public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo, 429 PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) { 430 setLastPipComponentName(componentName); 431 setAspectRatio(pipBoundsAlgorithm.getAspectRatioOrDefault(params)); 432 setOverrideMinSize(pipBoundsAlgorithm.getMinimalSize(activityInfo)); 433 } 434 435 /** Returns whether the shelf is currently showing. */ isShelfShowing()436 public boolean isShelfShowing() { 437 return mIsShelfShowing; 438 } 439 440 /** Returns the shelf height. */ getShelfHeight()441 public int getShelfHeight() { 442 return mShelfHeight; 443 } 444 445 /** Returns whether the user has resized the PIP. */ hasUserResizedPip()446 public boolean hasUserResizedPip() { 447 return mHasUserResizedPip; 448 } 449 450 /** Set whether the user has resized the PIP. */ setHasUserResizedPip(boolean hasUserResizedPip)451 public void setHasUserResizedPip(boolean hasUserResizedPip) { 452 mHasUserResizedPip = hasUserResizedPip; 453 } 454 455 /** Returns whether the user has moved the PIP. */ hasUserMovedPip()456 public boolean hasUserMovedPip() { 457 return mHasUserMovedPip; 458 } 459 460 /** Set whether the user has moved the PIP. */ setHasUserMovedPip(boolean hasUserMovedPip)461 public void setHasUserMovedPip(boolean hasUserMovedPip) { 462 mHasUserMovedPip = hasUserMovedPip; 463 } 464 465 /** 466 * Registers a callback when the minimal size of PIP that is set by the app changes. 467 */ setOnMinimalSizeChangeCallback(@ullable Runnable onMinimalSizeChangeCallback)468 public void setOnMinimalSizeChangeCallback(@Nullable Runnable onMinimalSizeChangeCallback) { 469 mOnMinimalSizeChangeCallback = onMinimalSizeChangeCallback; 470 } 471 472 /** Set a callback to be notified when the shelf visibility changes. */ setOnShelfVisibilityChangeCallback( @ullable TriConsumer<Boolean, Integer, Boolean> onShelfVisibilityChangeCallback)473 public void setOnShelfVisibilityChangeCallback( 474 @Nullable TriConsumer<Boolean, Integer, Boolean> onShelfVisibilityChangeCallback) { 475 mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback; 476 } 477 478 /** 479 * Add a callback to watch out for PiP bounds. This is mostly used by SystemUI's 480 * Back-gesture handler, to avoid conflicting with PiP when it's stashed. 481 */ addPipExclusionBoundsChangeCallback( @ullable Consumer<Rect> onPipExclusionBoundsChangeCallback)482 public void addPipExclusionBoundsChangeCallback( 483 @Nullable Consumer<Rect> onPipExclusionBoundsChangeCallback) { 484 mOnPipExclusionBoundsChangeCallbacks.add(onPipExclusionBoundsChangeCallback); 485 for (Consumer<Rect> callback : mOnPipExclusionBoundsChangeCallbacks) { 486 callback.accept(getBounds()); 487 } 488 } 489 490 /** 491 * Remove a callback that was previously added. 492 */ removePipExclusionBoundsChangeCallback( @ullable Consumer<Rect> onPipExclusionBoundsChangeCallback)493 public void removePipExclusionBoundsChangeCallback( 494 @Nullable Consumer<Rect> onPipExclusionBoundsChangeCallback) { 495 mOnPipExclusionBoundsChangeCallbacks.remove(onPipExclusionBoundsChangeCallback); 496 } 497 getLauncherState()498 public LauncherState getLauncherState() { 499 return mLauncherState; 500 } 501 502 /** Source of truth for the current bounds of PIP that may be in motion. */ 503 public static class MotionBoundsState { 504 /** The bounds used when PIP is in motion (e.g. during a drag or animation) */ 505 private final @NonNull Rect mBoundsInMotion = new Rect(); 506 /** The destination bounds to which PIP is animating. */ 507 private final @NonNull Rect mAnimatingToBounds = new Rect(); 508 509 /** Whether PIP is being dragged or animated (e.g. resizing, in fling, etc). */ isInMotion()510 public boolean isInMotion() { 511 return !mBoundsInMotion.isEmpty(); 512 } 513 514 /** Set the temporary bounds used to represent the drag or animation bounds of PIP. */ setBoundsInMotion(@onNull Rect bounds)515 public void setBoundsInMotion(@NonNull Rect bounds) { 516 mBoundsInMotion.set(bounds); 517 } 518 519 /** Set the bounds to which PIP is animating. */ setAnimatingToBounds(@onNull Rect bounds)520 public void setAnimatingToBounds(@NonNull Rect bounds) { 521 mAnimatingToBounds.set(bounds); 522 } 523 524 /** Called when all ongoing motion operations have ended. */ onAllAnimationsEnded()525 public void onAllAnimationsEnded() { 526 mBoundsInMotion.setEmpty(); 527 } 528 529 /** Called when an ongoing physics animation has ended. */ onPhysicsAnimationEnded()530 public void onPhysicsAnimationEnded() { 531 mAnimatingToBounds.setEmpty(); 532 } 533 534 /** Returns the motion bounds. */ 535 @NonNull getBoundsInMotion()536 public Rect getBoundsInMotion() { 537 return mBoundsInMotion; 538 } 539 540 /** Returns the destination bounds to which PIP is currently animating. */ 541 @NonNull getAnimatingToBounds()542 public Rect getAnimatingToBounds() { 543 return mAnimatingToBounds; 544 } 545 dump(PrintWriter pw, String prefix)546 void dump(PrintWriter pw, String prefix) { 547 final String innerPrefix = prefix + " "; 548 pw.println(prefix + MotionBoundsState.class.getSimpleName()); 549 pw.println(innerPrefix + "mBoundsInMotion=" + mBoundsInMotion); 550 pw.println(innerPrefix + "mAnimatingToBounds=" + mAnimatingToBounds); 551 } 552 } 553 554 /** Data class for Launcher state. */ 555 public static final class LauncherState { 556 private int mAppIconSizePx; 557 setAppIconSizePx(int appIconSizePx)558 public void setAppIconSizePx(int appIconSizePx) { 559 mAppIconSizePx = appIconSizePx; 560 } 561 getAppIconSizePx()562 public int getAppIconSizePx() { 563 return mAppIconSizePx; 564 } 565 dump(PrintWriter pw, String prefix)566 void dump(PrintWriter pw, String prefix) { 567 final String innerPrefix = prefix + " "; 568 pw.println(prefix + LauncherState.class.getSimpleName()); 569 pw.println(innerPrefix + "getAppIconSizePx=" + getAppIconSizePx()); 570 } 571 } 572 573 /** 574 * Represents the state of pip to potentially restore upon reentry. 575 */ 576 @VisibleForTesting 577 public static final class PipReentryState { 578 private static final String TAG = PipReentryState.class.getSimpleName(); 579 580 private final @Nullable Size mSize; 581 private final float mSnapFraction; 582 PipReentryState(@ullable Size size, float snapFraction)583 PipReentryState(@Nullable Size size, float snapFraction) { 584 mSize = size; 585 mSnapFraction = snapFraction; 586 } 587 588 @Nullable getSize()589 public Size getSize() { 590 return mSize; 591 } 592 getSnapFraction()593 public float getSnapFraction() { 594 return mSnapFraction; 595 } 596 dump(PrintWriter pw, String prefix)597 void dump(PrintWriter pw, String prefix) { 598 final String innerPrefix = prefix + " "; 599 pw.println(prefix + TAG); 600 pw.println(innerPrefix + "mSize=" + mSize); 601 pw.println(innerPrefix + "mSnapFraction=" + mSnapFraction); 602 } 603 } 604 605 /** Dumps internal state. */ dump(PrintWriter pw, String prefix)606 public void dump(PrintWriter pw, String prefix) { 607 final String innerPrefix = prefix + " "; 608 pw.println(prefix + TAG); 609 pw.println(innerPrefix + "mBounds=" + mBounds); 610 pw.println(innerPrefix + "mNormalBounds=" + mNormalBounds); 611 pw.println(innerPrefix + "mExpandedBounds=" + mExpandedBounds); 612 pw.println(innerPrefix + "mMovementBounds=" + mMovementBounds); 613 pw.println(innerPrefix + "mNormalMovementBounds=" + mNormalMovementBounds); 614 pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds); 615 pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName); 616 pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio); 617 pw.println(innerPrefix + "mStashedState=" + mStashedState); 618 pw.println(innerPrefix + "mStashOffset=" + mStashOffset); 619 pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing); 620 pw.println(innerPrefix + "mImeHeight=" + mImeHeight); 621 pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing); 622 pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight); 623 pw.println(innerPrefix + "mHasUserMovedPip=" + mHasUserMovedPip); 624 pw.println(innerPrefix + "mHasUserResizedPip=" + mHasUserResizedPip); 625 if (mPipReentryState == null) { 626 pw.println(innerPrefix + "mPipReentryState=null"); 627 } else { 628 mPipReentryState.dump(pw, innerPrefix); 629 } 630 mLauncherState.dump(pw, innerPrefix); 631 mMotionBoundsState.dump(pw, innerPrefix); 632 mSizeSpecSource.dump(pw, innerPrefix); 633 } 634 } 635