blob: 3eeadc367b0d9b18cd0f0203e6a01f075512f417 [file] [log] [blame]
Hongwei Wang37568ad2019-09-04 10:33:51 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.pip;
18
Hongwei Wangebf18082019-09-26 14:25:11 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
20import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Hongwei Wang37568ad2019-09-04 10:33:51 -070021import static android.util.TypedValue.COMPLEX_UNIT_DIP;
Hongwei Wangebf18082019-09-26 14:25:11 -070022import static android.view.Surface.ROTATION_0;
23import static android.view.Surface.ROTATION_180;
Hongwei Wang37568ad2019-09-04 10:33:51 -070024
Hongwei Wangebf18082019-09-26 14:25:11 -070025import android.app.ActivityManager;
26import android.app.ActivityTaskManager;
Hongwei Wang43a752b2019-09-17 20:20:30 +000027import android.content.ComponentName;
Hongwei Wang37568ad2019-09-04 10:33:51 -070028import android.content.Context;
29import android.content.res.Resources;
30import android.graphics.Point;
31import android.graphics.Rect;
32import android.os.RemoteException;
33import android.util.DisplayMetrics;
34import android.util.Log;
35import android.util.Size;
36import android.util.TypedValue;
37import android.view.DisplayInfo;
38import android.view.Gravity;
Hongwei Wang37568ad2019-09-04 10:33:51 -070039import android.view.IWindowManager;
40import android.view.WindowManagerGlobal;
Wale Ogunwale57946582020-03-21 14:29:07 -070041import android.window.WindowContainerTransaction;
Hongwei Wang37568ad2019-09-04 10:33:51 -070042
Hongwei Wang37568ad2019-09-04 10:33:51 -070043import java.io.PrintWriter;
44
jorgegil@google.com5bdec5f2020-02-28 13:14:39 -080045import javax.inject.Inject;
Ben Lin6189fa42020-04-29 14:59:16 -070046import javax.inject.Singleton;
jorgegil@google.com5bdec5f2020-02-28 13:14:39 -080047
Hongwei Wang37568ad2019-09-04 10:33:51 -070048/**
49 * Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant
50 * state changes originated from Window Manager and is the source of truth for PiP window bounds.
51 */
Ben Lin6189fa42020-04-29 14:59:16 -070052@Singleton
Hongwei Wang37568ad2019-09-04 10:33:51 -070053public class PipBoundsHandler {
54
55 private static final String TAG = PipBoundsHandler.class.getSimpleName();
56 private static final float INVALID_SNAP_FRACTION = -1f;
57
Hongwei Wang37568ad2019-09-04 10:33:51 -070058 private final Context mContext;
59 private final IWindowManager mWindowManager;
60 private final PipSnapAlgorithm mSnapAlgorithm;
61 private final DisplayInfo mDisplayInfo = new DisplayInfo();
Hongwei Wang37568ad2019-09-04 10:33:51 -070062 private final Rect mTmpInsets = new Rect();
Hongwei Wang37568ad2019-09-04 10:33:51 -070063
Hongwei Wang9b751802019-09-11 12:13:21 -070064 /**
65 * Tracks the destination bounds, used for any following
66 * {@link #onMovementBoundsChanged(Rect, Rect, Rect, DisplayInfo)} calculations.
67 */
68 private final Rect mLastDestinationBounds = new Rect();
69
Hongwei Wang43a752b2019-09-17 20:20:30 +000070 private ComponentName mLastPipComponentName;
Hongwei Wang37568ad2019-09-04 10:33:51 -070071 private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
Hongwei Wang2e725be2020-03-10 11:01:28 -070072 private Size mReentrySize;
Hongwei Wang37568ad2019-09-04 10:33:51 -070073
74 private float mDefaultAspectRatio;
75 private float mMinAspectRatio;
76 private float mMaxAspectRatio;
77 private float mAspectRatio;
78 private int mDefaultStackGravity;
79 private int mDefaultMinSize;
80 private Point mScreenEdgeInsets;
81 private int mCurrentMinSize;
Hongwei Wang2e725be2020-03-10 11:01:28 -070082 private Size mOverrideMinimalSize;
Hongwei Wang37568ad2019-09-04 10:33:51 -070083
Hongwei Wang37568ad2019-09-04 10:33:51 -070084 private boolean mIsImeShowing;
85 private int mImeHeight;
86 private boolean mIsShelfShowing;
87 private int mShelfHeight;
88
jorgegil@google.com5bdec5f2020-02-28 13:14:39 -080089 @Inject
90 public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm) {
Hongwei Wang37568ad2019-09-04 10:33:51 -070091 mContext = context;
jorgegil@google.com5bdec5f2020-02-28 13:14:39 -080092 mSnapAlgorithm = pipSnapAlgorithm;
Hongwei Wang37568ad2019-09-04 10:33:51 -070093 mWindowManager = WindowManagerGlobal.getWindowManagerService();
Hongwei Wang77598952019-09-17 16:42:37 +000094 reloadResources();
Hongwei Wang43a752b2019-09-17 20:20:30 +000095 // Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
96 // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
97 // triggers a configuration change and the resources to be reloaded.
98 mAspectRatio = mDefaultAspectRatio;
Hongwei Wang37568ad2019-09-04 10:33:51 -070099 }
100
101 /**
102 * TODO: move the resources to SysUI package.
103 */
104 private void reloadResources() {
105 final Resources res = mContext.getResources();
106 mDefaultAspectRatio = res.getFloat(
107 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
108 mDefaultStackGravity = res.getInteger(
109 com.android.internal.R.integer.config_defaultPictureInPictureGravity);
110 mDefaultMinSize = res.getDimensionPixelSize(
111 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
112 mCurrentMinSize = mDefaultMinSize;
113 final String screenEdgeInsetsDpString = res.getString(
114 com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
115 final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
116 ? Size.parseSize(screenEdgeInsetsDpString)
117 : null;
118 mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
119 : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
120 dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
121 mMinAspectRatio = res.getFloat(
122 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
123 mMaxAspectRatio = res.getFloat(
124 com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
125 }
126
Hongwei Wang37568ad2019-09-04 10:33:51 -0700127 public void setMinEdgeSize(int minEdgeSize) {
128 mCurrentMinSize = minEdgeSize;
129 }
130
Ben Lin3afa6b02020-04-28 14:22:56 -0700131 protected float getAspectRatio() {
132 return mAspectRatio;
133 }
134
Hongwei Wang37568ad2019-09-04 10:33:51 -0700135 /**
Hongwei Wang9b751802019-09-11 12:13:21 -0700136 * Sets both shelf visibility and its height if applicable.
137 * @return {@code true} if the internal shelf state is changed, {@code false} otherwise.
138 */
139 public boolean setShelfHeight(boolean shelfVisible, int shelfHeight) {
140 final boolean shelfShowing = shelfVisible && shelfHeight > 0;
141 if (shelfShowing == mIsShelfShowing && shelfHeight == mShelfHeight) {
142 return false;
143 }
144
145 mIsShelfShowing = shelfVisible;
146 mShelfHeight = shelfHeight;
147 return true;
148 }
149
150 /**
Hongwei Wang37568ad2019-09-04 10:33:51 -0700151 * Responds to IPinnedStackListener on IME visibility change.
152 */
153 public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
154 mIsImeShowing = imeVisible;
155 mImeHeight = imeHeight;
156 }
157
158 /**
Hongwei Wang37568ad2019-09-04 10:33:51 -0700159 * Responds to IPinnedStackListener on movement bounds change.
160 * Note that both inset and normal bounds will be calculated here rather than in the caller.
161 */
162 public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
163 Rect animatingBounds, DisplayInfo displayInfo) {
164 getInsetBounds(insetBounds);
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700165 final Rect defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700166 normalBounds.set(defaultBounds);
167 if (animatingBounds.isEmpty()) {
168 animatingBounds.set(defaultBounds);
169 }
170 if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
171 transformBoundsToAspectRatio(normalBounds, mAspectRatio,
172 false /* useCurrentMinEdgeSize */);
173 }
174 displayInfo.copyFrom(mDisplayInfo);
175 }
176
177 /**
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700178 * Responds to IPinnedStackListener on saving reentry snap fraction and size
Hongwei Wang43a752b2019-09-17 20:20:30 +0000179 * for a given {@link ComponentName}.
Hongwei Wang37568ad2019-09-04 10:33:51 -0700180 */
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700181 public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000182 mReentrySnapFraction = getSnapFraction(bounds);
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700183 mReentrySize = new Size(bounds.width(), bounds.height());
Hongwei Wang43a752b2019-09-17 20:20:30 +0000184 mLastPipComponentName = componentName;
Hongwei Wang37568ad2019-09-04 10:33:51 -0700185 }
186
187 /**
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700188 * Responds to IPinnedStackListener on resetting reentry snap fraction and size
Hongwei Wang43a752b2019-09-17 20:20:30 +0000189 * for a given {@link ComponentName}.
Hongwei Wang37568ad2019-09-04 10:33:51 -0700190 */
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700191 public void onResetReentryBounds(ComponentName componentName) {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000192 if (componentName.equals(mLastPipComponentName)) {
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700193 onResetReentryBoundsUnchecked();
Hongwei Wang37568ad2019-09-04 10:33:51 -0700194 }
195 }
196
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700197 private void onResetReentryBoundsUnchecked() {
Hongwei Wang37568ad2019-09-04 10:33:51 -0700198 mReentrySnapFraction = INVALID_SNAP_FRACTION;
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700199 mReentrySize = null;
Hongwei Wang43a752b2019-09-17 20:20:30 +0000200 mLastPipComponentName = null;
Hongwei Wangebf18082019-09-26 14:25:11 -0700201 mLastDestinationBounds.setEmpty();
Hongwei Wang37568ad2019-09-04 10:33:51 -0700202 }
203
Hongwei Wang9b751802019-09-11 12:13:21 -0700204 public Rect getLastDestinationBounds() {
205 return mLastDestinationBounds;
206 }
207
Hongwei Wang951dc022020-03-30 16:16:16 -0700208 public Rect getDisplayBounds() {
209 return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
210 }
211
Hongwei Wang37568ad2019-09-04 10:33:51 -0700212 /**
213 * Responds to IPinnedStackListener on {@link DisplayInfo} change.
214 * It will normally follow up with a
215 * {@link #onMovementBoundsChanged(Rect, Rect, Rect, DisplayInfo)} callback.
216 */
217 public void onDisplayInfoChanged(DisplayInfo displayInfo) {
218 mDisplayInfo.copyFrom(displayInfo);
219 }
220
221 /**
222 * Responds to IPinnedStackListener on configuration change.
223 */
224 public void onConfigurationChanged() {
225 reloadResources();
226 }
227
228 /**
229 * Responds to IPinnedStackListener on resetting aspect ratio for the pinned window.
230 * It will normally follow up with a
231 * {@link #onMovementBoundsChanged(Rect, Rect, Rect, DisplayInfo)} callback.
232 */
233 public void onAspectRatioChanged(float aspectRatio) {
234 mAspectRatio = aspectRatio;
235 }
236
237 /**
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800238 * @return {@link Rect} of the destination PiP window bounds.
Hongwei Wang37568ad2019-09-04 10:33:51 -0700239 */
Hongwei Wang309cffa2020-04-06 11:11:01 -0700240 Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds,
241 Size minimalSize) {
242 if (!componentName.equals(mLastPipComponentName)) {
243 onResetReentryBoundsUnchecked();
244 mLastPipComponentName = componentName;
245 }
Hongwei Wang43a752b2019-09-17 20:20:30 +0000246 final Rect destinationBounds;
247 if (bounds == null) {
Ben Lin094c7752020-03-11 12:10:51 -0700248 final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
Hongwei Wangebf18082019-09-26 14:25:11 -0700249 destinationBounds = new Rect(defaultBounds);
Hongwei Wang2e725be2020-03-10 11:01:28 -0700250 if (mReentrySnapFraction == INVALID_SNAP_FRACTION && mReentrySize == null) {
251 mOverrideMinimalSize = minimalSize;
252 }
Hongwei Wang37568ad2019-09-04 10:33:51 -0700253 } else {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000254 destinationBounds = new Rect(bounds);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700255 }
256 if (isValidPictureInPictureAspectRatio(aspectRatio)) {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000257 transformBoundsToAspectRatio(destinationBounds, aspectRatio,
258 false /* useCurrentMinEdgeSize */);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700259 }
Hongwei Wang37568ad2019-09-04 10:33:51 -0700260 mAspectRatio = aspectRatio;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800261 mLastDestinationBounds.set(destinationBounds);
262 return destinationBounds;
263 }
264
265 float getDefaultAspectRatio() {
266 return mDefaultAspectRatio;
Hongwei Wang37568ad2019-09-04 10:33:51 -0700267 }
268
269 /**
Hongwei Wangebf18082019-09-26 14:25:11 -0700270 * Updates the display info, calculating and returning the new stack and movement bounds in the
271 * new orientation of the device if necessary.
272 *
273 * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
274 */
275 public boolean onDisplayRotationChanged(Rect outBounds, int displayId, int fromRotation,
276 int toRotation, WindowContainerTransaction t) {
277 // Bail early if the event is not sent to current {@link #mDisplayInfo}
278 if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
279 return false;
280 }
281
282 // Bail early if the pinned stack is staled.
283 final ActivityManager.StackInfo pinnedStackInfo;
284 try {
285 pinnedStackInfo = ActivityTaskManager.getService()
286 .getStackInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
287 if (pinnedStackInfo == null) return false;
288 } catch (RemoteException e) {
289 Log.e(TAG, "Failed to get StackInfo for pinned stack", e);
290 return false;
291 }
292
293 // Calculate the snap fraction of the current stack along the old movement bounds
294 final Rect postChangeStackBounds = new Rect(mLastDestinationBounds);
295 final float snapFraction = getSnapFraction(postChangeStackBounds);
296
297 // Populate the new {@link #mDisplayInfo}.
298 // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
299 // therefore, the width/height may require a swap first.
300 // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
301 mDisplayInfo.rotation = toRotation;
302 updateDisplayInfoIfNeeded();
303
304 // Calculate the stack bounds in the new orientation based on same fraction along the
305 // rotated movement bounds.
306 final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
307 false /* adjustForIme */);
308 mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
309 snapFraction);
Hongwei Wangebf18082019-09-26 14:25:11 -0700310
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800311 outBounds.set(postChangeStackBounds);
312 mLastDestinationBounds.set(outBounds);
313 t.setBounds(pinnedStackInfo.stackToken, outBounds);
Hongwei Wangebf18082019-09-26 14:25:11 -0700314 return true;
315 }
316
317 private void updateDisplayInfoIfNeeded() {
318 final boolean updateNeeded;
319 if ((mDisplayInfo.rotation == ROTATION_0) || (mDisplayInfo.rotation == ROTATION_180)) {
320 updateNeeded = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight);
321 } else {
322 updateNeeded = (mDisplayInfo.logicalWidth < mDisplayInfo.logicalHeight);
323 }
324 if (updateNeeded) {
325 final int newLogicalHeight = mDisplayInfo.logicalWidth;
326 mDisplayInfo.logicalWidth = mDisplayInfo.logicalHeight;
327 mDisplayInfo.logicalHeight = newLogicalHeight;
328 }
329 }
330
331 /**
Hongwei Wang37568ad2019-09-04 10:33:51 -0700332 * @return whether the given {@param aspectRatio} is valid.
333 */
334 private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
335 return Float.compare(mMinAspectRatio, aspectRatio) <= 0
336 && Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
337 }
338
339 /**
Ben Lin04c83f62019-12-20 10:56:45 -0800340 * Sets the current bound with the currently store aspect ratio.
341 * @param stackBounds
342 */
343 public void transformBoundsToAspectRatio(Rect stackBounds) {
344 transformBoundsToAspectRatio(stackBounds, mAspectRatio, true);
345 }
346
347 /**
Hongwei Wang37568ad2019-09-04 10:33:51 -0700348 * Set the current bounds (or the default bounds if there are no current bounds) with the
349 * specified aspect ratio.
350 */
351 private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
352 boolean useCurrentMinEdgeSize) {
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700353 // Save the snap fraction and adjust the size based on the new aspect ratio.
Hongwei Wang37568ad2019-09-04 10:33:51 -0700354 final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
355 getMovementBounds(stackBounds));
Hongwei Wang610d2282020-01-31 15:09:37 -0800356 final int minEdgeSize;
357 final Size size;
358 if (useCurrentMinEdgeSize) {
359 minEdgeSize = mCurrentMinSize;
360 size = mSnapAlgorithm.getSizeForAspectRatio(
361 new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
362 } else {
363 minEdgeSize = mDefaultMinSize;
364 size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
365 mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
366 }
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700367
Hongwei Wang37568ad2019-09-04 10:33:51 -0700368 final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
369 final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
370 stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
Hongwei Wang2e725be2020-03-10 11:01:28 -0700371 // apply the override minimal size if applicable, this minimal size is specified by app
372 if (mOverrideMinimalSize != null) {
373 transformBoundsToMinimalSize(stackBounds, aspectRatio, mOverrideMinimalSize);
374 }
Hongwei Wang37568ad2019-09-04 10:33:51 -0700375 mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700376 }
377
378 /**
Hongwei Wang2e725be2020-03-10 11:01:28 -0700379 * Transforms a given bounds to meet the minimal size constraints.
380 * This function assumes the given {@param stackBounds} qualifies {@param aspectRatio}.
381 */
382 private void transformBoundsToMinimalSize(Rect stackBounds, float aspectRatio,
383 Size minimalSize) {
384 if (minimalSize == null) return;
385 final Size adjustedMinimalSize;
386 final float minimalSizeAspectRatio =
387 minimalSize.getWidth() / (float) minimalSize.getHeight();
388 if (minimalSizeAspectRatio > aspectRatio) {
389 // minimal size is wider, fixed the width and increase the height
390 adjustedMinimalSize = new Size(
391 minimalSize.getWidth(), (int) (minimalSize.getWidth() / aspectRatio));
392 } else {
393 adjustedMinimalSize = new Size(
394 (int) (minimalSize.getHeight() * aspectRatio), minimalSize.getHeight());
395 }
396 final Rect containerBounds = new Rect(stackBounds);
397 Gravity.apply(mDefaultStackGravity,
398 adjustedMinimalSize.getWidth(), adjustedMinimalSize.getHeight(),
399 containerBounds, stackBounds);
400 }
401
402 /**
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700403 * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
404 * provided, then it will apply the default bounds to the provided snap fraction and size.
Hongwei Wang37568ad2019-09-04 10:33:51 -0700405 */
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700406 private Rect getDefaultBounds(float snapFraction, Size size) {
Hongwei Wang37568ad2019-09-04 10:33:51 -0700407 final Rect defaultBounds = new Rect();
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700408 if (snapFraction != INVALID_SNAP_FRACTION && size != null) {
Hongwei Wang37568ad2019-09-04 10:33:51 -0700409 defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
410 final Rect movementBounds = getMovementBounds(defaultBounds);
411 mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
412 } else {
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700413 final Rect insetBounds = new Rect();
414 getInsetBounds(insetBounds);
415 size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
416 mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700417 Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
418 0, Math.max(mIsImeShowing ? mImeHeight : 0,
419 mIsShelfShowing ? mShelfHeight : 0),
420 defaultBounds);
421 }
422 return defaultBounds;
423 }
424
425 /**
426 * Populates the bounds on the screen that the PIP can be visible in.
427 */
Ben Lin3afa6b02020-04-28 14:22:56 -0700428 protected void getInsetBounds(Rect outRect) {
Hongwei Wang37568ad2019-09-04 10:33:51 -0700429 try {
430 mWindowManager.getStableInsets(mContext.getDisplayId(), mTmpInsets);
431 outRect.set(mTmpInsets.left + mScreenEdgeInsets.x,
432 mTmpInsets.top + mScreenEdgeInsets.y,
433 mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
434 mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
435 } catch (RemoteException e) {
436 Log.e(TAG, "Failed to get stable insets from WM", e);
437 }
438 }
439
440 /**
441 * @return the movement bounds for the given {@param stackBounds} and the current state of the
442 * controller.
443 */
444 private Rect getMovementBounds(Rect stackBounds) {
445 return getMovementBounds(stackBounds, true /* adjustForIme */);
446 }
447
448 /**
449 * @return the movement bounds for the given {@param stackBounds} and the current state of the
450 * controller.
451 */
452 private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
453 final Rect movementBounds = new Rect();
454 getInsetBounds(movementBounds);
455
456 // Apply the movement bounds adjustments based on the current state.
457 mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
458 (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
459 return movementBounds;
460 }
461
462 /**
Hongwei Wang37568ad2019-09-04 10:33:51 -0700463 * @return the default snap fraction to apply instead of the default gravity when calculating
464 * the default stack bounds when first entering PiP.
465 */
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700466 public float getSnapFraction(Rect stackBounds) {
Hongwei Wang37568ad2019-09-04 10:33:51 -0700467 return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
468 }
469
470 /**
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700471 * Applies the given snap fraction to the given stack bounds.
472 */
473 public void applySnapFraction(Rect stackBounds, float snapFraction) {
474 final Rect movementBounds = getMovementBounds(stackBounds);
475 mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
476 }
477
478 /**
Hongwei Wang37568ad2019-09-04 10:33:51 -0700479 * @return the pixels for a given dp value.
480 */
481 private int dpToPx(float dpValue, DisplayMetrics dm) {
482 return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
483 }
484
485 /**
486 * Dumps internal states.
487 */
488 public void dump(PrintWriter pw, String prefix) {
489 final String innerPrefix = prefix + " ";
490 pw.println(prefix + TAG);
Hongwei Wang43a752b2019-09-17 20:20:30 +0000491 pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700492 pw.println(innerPrefix + "mReentrySnapFraction=" + mReentrySnapFraction);
Hongwei Wang309cffa2020-04-06 11:11:01 -0700493 pw.println(innerPrefix + "mReentrySize=" + mReentrySize);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700494 pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo);
495 pw.println(innerPrefix + "mDefaultAspectRatio=" + mDefaultAspectRatio);
496 pw.println(innerPrefix + "mMinAspectRatio=" + mMinAspectRatio);
497 pw.println(innerPrefix + "mMaxAspectRatio=" + mMaxAspectRatio);
498 pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio);
499 pw.println(innerPrefix + "mDefaultStackGravity=" + mDefaultStackGravity);
Hongwei Wang37568ad2019-09-04 10:33:51 -0700500 pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
501 pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
502 pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
503 pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
504 mSnapAlgorithm.dump(pw, innerPrefix);
505 }
506}