Merge "Making SizeSpecSource platform agnostic" into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
507332f859
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.common.pip
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.PointF
|
||||
import android.util.Size
|
||||
import com.android.wm.shell.R
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState
|
||||
|
||||
class LegacySizeSpecSource(
|
||||
private val context: Context,
|
||||
private val pipDisplayLayoutState: PipDisplayLayoutState
|
||||
) : SizeSpecSource {
|
||||
|
||||
private var mDefaultMinSize = 0
|
||||
/** The absolute minimum an overridden size's edge can be */
|
||||
private var mOverridableMinSize = 0
|
||||
/** The preferred minimum (and default minimum) size specified by apps. */
|
||||
private var mOverrideMinSize: Size? = null
|
||||
|
||||
private var mDefaultSizePercent = 0f
|
||||
private var mMinimumSizePercent = 0f
|
||||
private var mMaxAspectRatioForMinSize = 0f
|
||||
private var mMinAspectRatioForMinSize = 0f
|
||||
|
||||
init {
|
||||
reloadResources()
|
||||
}
|
||||
|
||||
private fun reloadResources() {
|
||||
val res: Resources = context.getResources()
|
||||
|
||||
mDefaultMinSize = res.getDimensionPixelSize(
|
||||
R.dimen.default_minimal_size_pip_resizable_task)
|
||||
mOverridableMinSize = res.getDimensionPixelSize(
|
||||
R.dimen.overridable_minimal_size_pip_resizable_task)
|
||||
|
||||
mDefaultSizePercent = res.getFloat(R.dimen.config_pictureInPictureDefaultSizePercent)
|
||||
mMinimumSizePercent = res.getFraction(R.fraction.config_pipShortestEdgePercent, 1, 1)
|
||||
|
||||
mMaxAspectRatioForMinSize = res.getFloat(
|
||||
R.dimen.config_pictureInPictureAspectRatioLimitForMinSize)
|
||||
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged() {
|
||||
reloadResources()
|
||||
}
|
||||
|
||||
override fun getMaxSize(aspectRatio: Float): Size {
|
||||
val insetBounds = pipDisplayLayoutState.insetBounds
|
||||
|
||||
val shorterLength: Int = Math.min(getDisplayBounds().width(),
|
||||
getDisplayBounds().height())
|
||||
val totalHorizontalPadding: Int = (insetBounds.left +
|
||||
(getDisplayBounds().width() - insetBounds.right))
|
||||
val totalVerticalPadding: Int = (insetBounds.top +
|
||||
(getDisplayBounds().height() - insetBounds.bottom))
|
||||
|
||||
return if (aspectRatio > 1f) {
|
||||
val maxWidth = Math.max(getDefaultSize(aspectRatio).width,
|
||||
shorterLength - totalHorizontalPadding)
|
||||
val maxHeight = (maxWidth / aspectRatio).toInt()
|
||||
Size(maxWidth, maxHeight)
|
||||
} else {
|
||||
val maxHeight = Math.max(getDefaultSize(aspectRatio).height,
|
||||
shorterLength - totalVerticalPadding)
|
||||
val maxWidth = (maxHeight * aspectRatio).toInt()
|
||||
Size(maxWidth, maxHeight)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultSize(aspectRatio: Float): Size {
|
||||
if (mOverrideMinSize != null) {
|
||||
return getMinSize(aspectRatio)
|
||||
}
|
||||
val smallestDisplaySize: Int = Math.min(getDisplayBounds().width(),
|
||||
getDisplayBounds().height())
|
||||
val minSize = Math.max(getMinEdgeSize().toFloat(),
|
||||
smallestDisplaySize * mDefaultSizePercent).toInt()
|
||||
val width: Int
|
||||
val height: Int
|
||||
if (aspectRatio <= mMinAspectRatioForMinSize ||
|
||||
aspectRatio > mMaxAspectRatioForMinSize) {
|
||||
// Beyond these points, we can just use the min size as the shorter edge
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size
|
||||
width = minSize
|
||||
height = Math.round(width / aspectRatio)
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize
|
||||
width = Math.round(height * aspectRatio)
|
||||
}
|
||||
} else {
|
||||
// Within these points, ensure that the bounds fit within the radius of the limits
|
||||
// at the points
|
||||
val widthAtMaxAspectRatioForMinSize: Float = mMaxAspectRatioForMinSize * minSize
|
||||
val radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize.toFloat())
|
||||
height = Math.round(Math.sqrt((radius * radius /
|
||||
(aspectRatio * aspectRatio + 1)).toDouble())).toInt()
|
||||
width = Math.round(height * aspectRatio)
|
||||
}
|
||||
return Size(width, height)
|
||||
}
|
||||
|
||||
override fun getMinSize(aspectRatio: Float): Size {
|
||||
if (mOverrideMinSize != null) {
|
||||
return adjustOverrideMinSizeToAspectRatio(aspectRatio)!!
|
||||
}
|
||||
val shorterLength: Int = Math.min(getDisplayBounds().width(),
|
||||
getDisplayBounds().height())
|
||||
val minWidth: Int
|
||||
val minHeight: Int
|
||||
if (aspectRatio > 1f) {
|
||||
minWidth = Math.min(getDefaultSize(aspectRatio).width.toFloat(),
|
||||
shorterLength * mMinimumSizePercent).toInt()
|
||||
minHeight = (minWidth / aspectRatio).toInt()
|
||||
} else {
|
||||
minHeight = Math.min(getDefaultSize(aspectRatio).height.toFloat(),
|
||||
shorterLength * mMinimumSizePercent).toInt()
|
||||
minWidth = (minHeight * aspectRatio).toInt()
|
||||
}
|
||||
return Size(minWidth, minHeight)
|
||||
}
|
||||
|
||||
override fun getSizeForAspectRatio(size: Size, aspectRatio: Float): Size {
|
||||
val smallestSize = Math.min(size.width, size.height)
|
||||
val minSize = Math.max(getMinEdgeSize(), smallestSize)
|
||||
val width: Int
|
||||
val height: Int
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size.
|
||||
width = minSize
|
||||
height = Math.round(width / aspectRatio)
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize
|
||||
width = Math.round(height * aspectRatio)
|
||||
}
|
||||
return Size(width, height)
|
||||
}
|
||||
|
||||
private fun getDisplayBounds() = pipDisplayLayoutState.displayBounds
|
||||
|
||||
/** Sets the preferred size of PIP as specified by the activity in PIP mode. */
|
||||
override fun setOverrideMinSize(overrideMinSize: Size?) {
|
||||
mOverrideMinSize = overrideMinSize
|
||||
}
|
||||
|
||||
/** Returns the preferred minimal size specified by the activity in PIP. */
|
||||
override fun getOverrideMinSize(): Size? {
|
||||
val overrideMinSize = mOverrideMinSize ?: return null
|
||||
return if (overrideMinSize.width < mOverridableMinSize ||
|
||||
overrideMinSize.height < mOverridableMinSize) {
|
||||
Size(mOverridableMinSize, mOverridableMinSize)
|
||||
} else {
|
||||
overrideMinSize
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMinEdgeSize(): Int {
|
||||
return if (mOverrideMinSize == null) mDefaultMinSize else getOverrideMinEdgeSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adjusted overridden min size if it is set; otherwise, returns null.
|
||||
*
|
||||
*
|
||||
* Overridden min size needs to be adjusted in its own way while making sure that the target
|
||||
* aspect ratio is maintained
|
||||
*
|
||||
* @param aspectRatio target aspect ratio
|
||||
*/
|
||||
private fun adjustOverrideMinSizeToAspectRatio(aspectRatio: Float): Size? {
|
||||
val size = getOverrideMinSize() ?: return null
|
||||
val sizeAspectRatio = size.width / size.height.toFloat()
|
||||
return if (sizeAspectRatio > aspectRatio) {
|
||||
// Size is wider, fix the width and increase the height
|
||||
Size(size.width, (size.width / aspectRatio).toInt())
|
||||
} else {
|
||||
// Size is taller, fix the height and adjust the width.
|
||||
Size((size.height * aspectRatio).toInt(), size.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.common.pip
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.os.SystemProperties
|
||||
import android.util.Size
|
||||
import com.android.wm.shell.R
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState
|
||||
import java.io.PrintWriter
|
||||
|
||||
class PhoneSizeSpecSource(
|
||||
private val context: Context,
|
||||
private val pipDisplayLayoutState: PipDisplayLayoutState
|
||||
) : SizeSpecSource {
|
||||
private var DEFAULT_OPTIMIZED_ASPECT_RATIO = 9f / 16
|
||||
|
||||
private var mDefaultMinSize = 0
|
||||
/** The absolute minimum an overridden size's edge can be */
|
||||
private var mOverridableMinSize = 0
|
||||
/** The preferred minimum (and default minimum) size specified by apps. */
|
||||
private var mOverrideMinSize: Size? = null
|
||||
|
||||
|
||||
/** Default and minimum percentages for the PIP size logic. */
|
||||
private val mDefaultSizePercent: Float
|
||||
private val mMinimumSizePercent: Float
|
||||
|
||||
/** Aspect ratio that the PIP size spec logic optimizes for. */
|
||||
private var mOptimizedAspectRatio = 0f
|
||||
|
||||
init {
|
||||
mDefaultSizePercent = SystemProperties
|
||||
.get("com.android.wm.shell.pip.phone.def_percentage", "0.6").toFloat()
|
||||
mMinimumSizePercent = SystemProperties
|
||||
.get("com.android.wm.shell.pip.phone.min_percentage", "0.5").toFloat()
|
||||
|
||||
reloadResources()
|
||||
}
|
||||
|
||||
private fun reloadResources() {
|
||||
val res: Resources = context.getResources()
|
||||
|
||||
mDefaultMinSize = res.getDimensionPixelSize(
|
||||
R.dimen.default_minimal_size_pip_resizable_task)
|
||||
mOverridableMinSize = res.getDimensionPixelSize(
|
||||
R.dimen.overridable_minimal_size_pip_resizable_task)
|
||||
|
||||
val requestedOptAspRatio = res.getFloat(R.dimen.config_pipLargeScreenOptimizedAspectRatio)
|
||||
// make sure the optimized aspect ratio is valid with a default value to fall back to
|
||||
mOptimizedAspectRatio = if (requestedOptAspRatio > 1) {
|
||||
DEFAULT_OPTIMIZED_ASPECT_RATIO
|
||||
} else {
|
||||
requestedOptAspRatio
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged() {
|
||||
reloadResources()
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the max size of PIP.
|
||||
*
|
||||
* Optimizes for 16:9 aspect ratios, making them take full length of shortest display edge.
|
||||
* As aspect ratio approaches values close to 1:1, the logic does not let PIP occupy the
|
||||
* whole screen. A linear function is used to calculate these sizes.
|
||||
*
|
||||
* @param aspectRatio aspect ratio of the PIP window
|
||||
* @return dimensions of the max size of the PIP
|
||||
*/
|
||||
override fun getMaxSize(aspectRatio: Float): Size {
|
||||
val insetBounds = pipDisplayLayoutState.insetBounds
|
||||
val displayBounds = pipDisplayLayoutState.displayBounds
|
||||
|
||||
val totalHorizontalPadding: Int = (insetBounds.left +
|
||||
(displayBounds.width() - insetBounds.right))
|
||||
val totalVerticalPadding: Int = (insetBounds.top +
|
||||
(displayBounds.height() - insetBounds.bottom))
|
||||
val shorterLength: Int = Math.min(displayBounds.width() - totalHorizontalPadding,
|
||||
displayBounds.height() - totalVerticalPadding)
|
||||
var maxWidth: Int
|
||||
val maxHeight: Int
|
||||
|
||||
// use the optimized max sizing logic only within a certain aspect ratio range
|
||||
if (aspectRatio >= mOptimizedAspectRatio && aspectRatio <= 1 / mOptimizedAspectRatio) {
|
||||
// this formula and its derivation is explained in b/198643358#comment16
|
||||
maxWidth = Math.round(mOptimizedAspectRatio * shorterLength +
|
||||
shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1 + aspectRatio))
|
||||
// make sure the max width doesn't go beyond shorter screen length after rounding
|
||||
maxWidth = Math.min(maxWidth, shorterLength)
|
||||
maxHeight = Math.round(maxWidth / aspectRatio)
|
||||
} else {
|
||||
if (aspectRatio > 1f) {
|
||||
maxWidth = shorterLength
|
||||
maxHeight = Math.round(maxWidth / aspectRatio)
|
||||
} else {
|
||||
maxHeight = shorterLength
|
||||
maxWidth = Math.round(maxHeight * aspectRatio)
|
||||
}
|
||||
}
|
||||
return Size(maxWidth, maxHeight)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the dimensions by a percentage relative to max size to get default size.
|
||||
*
|
||||
* @param aspectRatio aspect ratio of the PIP window
|
||||
* @return dimensions of the default size of the PIP
|
||||
*/
|
||||
override fun getDefaultSize(aspectRatio: Float): Size {
|
||||
val minSize = getMinSize(aspectRatio)
|
||||
if (mOverrideMinSize != null) {
|
||||
return minSize
|
||||
}
|
||||
val maxSize = getMaxSize(aspectRatio)
|
||||
val defaultWidth = Math.max(Math.round(maxSize.width * mDefaultSizePercent),
|
||||
minSize.width)
|
||||
val defaultHeight = Math.round(defaultWidth / aspectRatio)
|
||||
return Size(defaultWidth, defaultHeight)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the dimensions by a certain percentage relative to max size to get min size.
|
||||
*
|
||||
* @param aspectRatio aspect ratio of the PIP window
|
||||
* @return dimensions of the min size of the PIP
|
||||
*/
|
||||
override fun getMinSize(aspectRatio: Float): Size {
|
||||
// if there is an overridden min size provided, return that
|
||||
if (mOverrideMinSize != null) {
|
||||
return adjustOverrideMinSizeToAspectRatio(aspectRatio)!!
|
||||
}
|
||||
val maxSize = getMaxSize(aspectRatio)
|
||||
var minWidth = Math.round(maxSize.width * mMinimumSizePercent)
|
||||
var minHeight = Math.round(maxSize.height * mMinimumSizePercent)
|
||||
|
||||
// make sure the calculated min size is not smaller than the allowed default min size
|
||||
if (aspectRatio > 1f) {
|
||||
minHeight = Math.max(minHeight, mDefaultMinSize)
|
||||
minWidth = Math.round(minHeight * aspectRatio)
|
||||
} else {
|
||||
minWidth = Math.max(minWidth, mDefaultMinSize)
|
||||
minHeight = Math.round(minWidth / aspectRatio)
|
||||
}
|
||||
return Size(minWidth, minHeight)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size for target aspect ratio making sure new size conforms with the rules.
|
||||
*
|
||||
*
|
||||
* Recalculates the dimensions such that the target aspect ratio is achieved, while
|
||||
* maintaining the same maximum size to current size ratio.
|
||||
*
|
||||
* @param size current size
|
||||
* @param aspectRatio target aspect ratio
|
||||
*/
|
||||
override fun getSizeForAspectRatio(size: Size, aspectRatio: Float): Size {
|
||||
if (size == mOverrideMinSize) {
|
||||
return adjustOverrideMinSizeToAspectRatio(aspectRatio)!!
|
||||
}
|
||||
|
||||
val currAspectRatio = size.width.toFloat() / size.height
|
||||
|
||||
// getting the percentage of the max size that current size takes
|
||||
val currentMaxSize = getMaxSize(currAspectRatio)
|
||||
val currentPercent = size.width.toFloat() / currentMaxSize.width
|
||||
|
||||
// getting the max size for the target aspect ratio
|
||||
val updatedMaxSize = getMaxSize(aspectRatio)
|
||||
var width = Math.round(updatedMaxSize.width * currentPercent)
|
||||
var height = Math.round(updatedMaxSize.height * currentPercent)
|
||||
|
||||
// adjust the dimensions if below allowed min edge size
|
||||
val minEdgeSize =
|
||||
if (mOverrideMinSize == null) mDefaultMinSize else getOverrideMinEdgeSize()
|
||||
|
||||
if (width < minEdgeSize && aspectRatio <= 1) {
|
||||
width = minEdgeSize
|
||||
height = Math.round(width / aspectRatio)
|
||||
} else if (height < minEdgeSize && aspectRatio > 1) {
|
||||
height = minEdgeSize
|
||||
width = Math.round(height * aspectRatio)
|
||||
}
|
||||
|
||||
// reduce the dimensions of the updated size to the calculated percentage
|
||||
return Size(width, height)
|
||||
}
|
||||
|
||||
/** Sets the preferred size of PIP as specified by the activity in PIP mode. */
|
||||
override fun setOverrideMinSize(overrideMinSize: Size?) {
|
||||
mOverrideMinSize = overrideMinSize
|
||||
}
|
||||
|
||||
/** Returns the preferred minimal size specified by the activity in PIP. */
|
||||
override fun getOverrideMinSize(): Size? {
|
||||
val overrideMinSize = mOverrideMinSize ?: return null
|
||||
return if (overrideMinSize.width < mOverridableMinSize ||
|
||||
overrideMinSize.height < mOverridableMinSize) {
|
||||
Size(mOverridableMinSize, mOverridableMinSize)
|
||||
} else {
|
||||
overrideMinSize
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adjusted overridden min size if it is set; otherwise, returns null.
|
||||
*
|
||||
*
|
||||
* Overridden min size needs to be adjusted in its own way while making sure that the target
|
||||
* aspect ratio is maintained
|
||||
*
|
||||
* @param aspectRatio target aspect ratio
|
||||
*/
|
||||
private fun adjustOverrideMinSizeToAspectRatio(aspectRatio: Float): Size? {
|
||||
val size = getOverrideMinSize() ?: return null
|
||||
val sizeAspectRatio = size.width / size.height.toFloat()
|
||||
return if (sizeAspectRatio > aspectRatio) {
|
||||
// Size is wider, fix the width and increase the height
|
||||
Size(size.width, (size.width / aspectRatio).toInt())
|
||||
} else {
|
||||
// Size is taller, fix the height and adjust the width.
|
||||
Size((size.height * aspectRatio).toInt(), size.height)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, prefix: String) {
|
||||
val innerPrefix = "$prefix "
|
||||
pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize)
|
||||
pw.println(innerPrefix + "mOverridableMinSize=" + mOverridableMinSize)
|
||||
pw.println(innerPrefix + "mDefaultMinSize=" + mDefaultMinSize)
|
||||
pw.println(innerPrefix + "mDefaultSizePercent=" + mDefaultSizePercent)
|
||||
pw.println(innerPrefix + "mMinimumSizePercent=" + mMinimumSizePercent)
|
||||
pw.println(innerPrefix + "mOptimizedAspectRatio=" + mOptimizedAspectRatio)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.common.pip
|
||||
|
||||
import android.util.Size
|
||||
import java.io.PrintWriter
|
||||
|
||||
interface SizeSpecSource {
|
||||
/** Returns max size allowed for the PIP window */
|
||||
fun getMaxSize(aspectRatio: Float): Size
|
||||
|
||||
/** Returns default size for the PIP window */
|
||||
fun getDefaultSize(aspectRatio: Float): Size
|
||||
|
||||
/** Returns min size allowed for the PIP window */
|
||||
fun getMinSize(aspectRatio: Float): Size
|
||||
|
||||
/** Returns the adjusted size based on current size and target aspect ratio */
|
||||
fun getSizeForAspectRatio(size: Size, aspectRatio: Float): Size
|
||||
|
||||
/** Overrides the minimum pip size requested by the app */
|
||||
fun setOverrideMinSize(overrideMinSize: Size?)
|
||||
|
||||
/** Returns the minimum pip size requested by the app */
|
||||
fun getOverrideMinSize(): Size?
|
||||
|
||||
/** Returns the minimum edge size of the override minimum size, or 0 if not set. */
|
||||
fun getOverrideMinEdgeSize(): Int {
|
||||
val overrideMinSize = getOverrideMinSize() ?: return 0
|
||||
return Math.min(overrideMinSize.width, overrideMinSize.height)
|
||||
}
|
||||
|
||||
fun onConfigurationChanged() {}
|
||||
|
||||
/** Dumps the internal state of the size spec */
|
||||
fun dump(pw: PrintWriter, prefix: String) {}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ import com.android.wm.shell.common.SystemWindows;
|
||||
import com.android.wm.shell.common.TabletopModeController;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.dagger.WMShellBaseModule;
|
||||
import com.android.wm.shell.dagger.WMSingleton;
|
||||
import com.android.wm.shell.onehanded.OneHandedController;
|
||||
@@ -53,7 +55,6 @@ import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
|
||||
import com.android.wm.shell.pip.phone.PhonePipMenuController;
|
||||
import com.android.wm.shell.pip.phone.PipController;
|
||||
import com.android.wm.shell.pip.phone.PipMotionHelper;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||
@@ -87,7 +88,6 @@ public abstract class Pip1Module {
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipSizeSpecHandler pipSizeSpecHandler,
|
||||
PipDisplayLayoutState pipDisplayLayoutState,
|
||||
PipMotionHelper pipMotionHelper,
|
||||
PipMediaController pipMediaController,
|
||||
@@ -110,8 +110,7 @@ public abstract class Pip1Module {
|
||||
context, shellInit, shellCommandHandler, shellController,
|
||||
displayController, pipAnimationController, pipAppOpsListener,
|
||||
pipBoundsAlgorithm,
|
||||
pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler,
|
||||
pipDisplayLayoutState,
|
||||
pipKeepClearAlgorithm, pipBoundsState, pipDisplayLayoutState,
|
||||
pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
|
||||
pipTransitionState, pipTouchHandler, pipTransitionController,
|
||||
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
|
||||
@@ -123,8 +122,8 @@ public abstract class Pip1Module {
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipBoundsState providePipBoundsState(Context context,
|
||||
PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
return new PipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState);
|
||||
SizeSpecSource sizeSpecSource, PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
return new PipBoundsState(context, sizeSpecSource, pipDisplayLayoutState);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@@ -139,21 +138,14 @@ public abstract class Pip1Module {
|
||||
return new PhonePipKeepClearAlgorithm(context);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipSizeSpecHandler providePipSizeSpecHelper(Context context,
|
||||
PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
return new PipSizeSpecHandler(context, pipDisplayLayoutState);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
|
||||
PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
|
||||
PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
|
||||
PipSizeSpecHandler pipSizeSpecHandler) {
|
||||
PipDisplayLayoutState pipDisplayLayoutState, SizeSpecSource sizeSpecSource) {
|
||||
return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
|
||||
pipKeepClearAlgorithm, pipSizeSpecHandler);
|
||||
pipKeepClearAlgorithm, pipDisplayLayoutState, sizeSpecSource);
|
||||
}
|
||||
|
||||
// Handler is used by Icon.loadDrawableAsync
|
||||
@@ -177,14 +169,14 @@ public abstract class Pip1Module {
|
||||
PhonePipMenuController menuPhoneController,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipSizeSpecHandler pipSizeSpecHandler,
|
||||
SizeSpecSource sizeSpecSource,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipMotionHelper pipMotionHelper,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
PipUiEventLogger pipUiEventLogger,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
|
||||
pipBoundsState, pipSizeSpecHandler, pipTaskOrganizer, pipMotionHelper,
|
||||
pipBoundsState, sizeSpecSource, pipTaskOrganizer, pipMotionHelper,
|
||||
floatingContentCoordinator, pipUiEventLogger, mainExecutor);
|
||||
}
|
||||
|
||||
@@ -241,6 +233,13 @@ public abstract class Pip1Module {
|
||||
splitScreenOptional);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static SizeSpecSource provideSizeSpecSource(Context context,
|
||||
PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
return new PhoneSizeSpecSource(context, pipDisplayLayoutState);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipAppOpsListener providePipAppOpsListener(Context context,
|
||||
|
||||
@@ -28,6 +28,8 @@ import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.SystemWindows;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.common.pip.LegacySizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.dagger.WMShellBaseModule;
|
||||
import com.android.wm.shell.dagger.WMSingleton;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
@@ -42,7 +44,6 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.pip.PipTransitionState;
|
||||
import com.android.wm.shell.pip.PipUiEventLogger;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.tv.TvPipBoundsController;
|
||||
import com.android.wm.shell.pip.tv.TvPipBoundsState;
|
||||
@@ -138,23 +139,23 @@ public abstract class TvPipModule {
|
||||
@Provides
|
||||
static TvPipBoundsAlgorithm provideTvPipBoundsAlgorithm(Context context,
|
||||
TvPipBoundsState tvPipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
|
||||
PipSizeSpecHandler pipSizeSpecHandler) {
|
||||
PipDisplayLayoutState pipDisplayLayoutState, SizeSpecSource sizeSpecSource) {
|
||||
return new TvPipBoundsAlgorithm(context, tvPipBoundsState, pipSnapAlgorithm,
|
||||
pipSizeSpecHandler);
|
||||
pipDisplayLayoutState, sizeSpecSource);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static TvPipBoundsState provideTvPipBoundsState(Context context,
|
||||
PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
return new TvPipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState);
|
||||
SizeSpecSource sizeSpecSource, PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
return new TvPipBoundsState(context, sizeSpecSource, pipDisplayLayoutState);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipSizeSpecHandler providePipSizeSpecHelper(Context context,
|
||||
static SizeSpecSource provideSizeSpecSource(Context context,
|
||||
PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
return new PipSizeSpecHandler(context, pipDisplayLayoutState);
|
||||
return new LegacySizeSpecSource(context, pipDisplayLayoutState);
|
||||
}
|
||||
|
||||
// Handler needed for loadDrawableAsync() in PipControlsViewController
|
||||
|
||||
@@ -28,7 +28,7 @@ import android.util.Size;
|
||||
import android.view.Gravity;
|
||||
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@@ -41,7 +41,8 @@ public class PipBoundsAlgorithm {
|
||||
private static final float INVALID_SNAP_FRACTION = -1f;
|
||||
|
||||
@NonNull private final PipBoundsState mPipBoundsState;
|
||||
@NonNull protected final PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
@NonNull protected final PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
@NonNull protected final SizeSpecSource mSizeSpecSource;
|
||||
private final PipSnapAlgorithm mSnapAlgorithm;
|
||||
private final PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
|
||||
|
||||
@@ -53,11 +54,13 @@ public class PipBoundsAlgorithm {
|
||||
public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
|
||||
@NonNull PipSnapAlgorithm pipSnapAlgorithm,
|
||||
@NonNull PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
|
||||
@NonNull PipSizeSpecHandler pipSizeSpecHandler) {
|
||||
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
|
||||
@NonNull SizeSpecSource sizeSpecSource) {
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mSnapAlgorithm = pipSnapAlgorithm;
|
||||
mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
|
||||
mPipSizeSpecHandler = pipSizeSpecHandler;
|
||||
mPipDisplayLayoutState = pipDisplayLayoutState;
|
||||
mSizeSpecSource = sizeSpecSource;
|
||||
reloadResources(context);
|
||||
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
|
||||
// resources as it would clobber mAspectRatio when entering PiP from fullscreen which
|
||||
@@ -74,11 +77,6 @@ public class PipBoundsAlgorithm {
|
||||
R.dimen.config_pictureInPictureDefaultAspectRatio);
|
||||
mDefaultStackGravity = res.getInteger(
|
||||
R.integer.config_defaultPictureInPictureGravity);
|
||||
final String screenEdgeInsetsDpString = res.getString(
|
||||
R.string.config_defaultPictureInPictureScreenEdgeInsets);
|
||||
final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
|
||||
? Size.parseSize(screenEdgeInsetsDpString)
|
||||
: null;
|
||||
mMinAspectRatio = res.getFloat(
|
||||
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
|
||||
mMaxAspectRatio = res.getFloat(
|
||||
@@ -160,8 +158,8 @@ public class PipBoundsAlgorithm {
|
||||
// If either dimension is smaller than the allowed minimum, adjust them
|
||||
// according to mOverridableMinSize
|
||||
return new Size(
|
||||
Math.max(windowLayout.minWidth, mPipSizeSpecHandler.getOverrideMinEdgeSize()),
|
||||
Math.max(windowLayout.minHeight, mPipSizeSpecHandler.getOverrideMinEdgeSize()));
|
||||
Math.max(windowLayout.minWidth, getOverrideMinEdgeSize()),
|
||||
Math.max(windowLayout.minHeight, getOverrideMinEdgeSize()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -255,10 +253,10 @@ public class PipBoundsAlgorithm {
|
||||
final Size size;
|
||||
if (useCurrentMinEdgeSize || useCurrentSize) {
|
||||
// Use the existing size but adjusted to the new aspect ratio.
|
||||
size = mPipSizeSpecHandler.getSizeForAspectRatio(
|
||||
size = mSizeSpecSource.getSizeForAspectRatio(
|
||||
new Size(stackBounds.width(), stackBounds.height()), aspectRatio);
|
||||
} else {
|
||||
size = mPipSizeSpecHandler.getDefaultSize(aspectRatio);
|
||||
size = mSizeSpecSource.getDefaultSize(aspectRatio);
|
||||
}
|
||||
|
||||
final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
|
||||
@@ -287,7 +285,7 @@ public class PipBoundsAlgorithm {
|
||||
getInsetBounds(insetBounds);
|
||||
|
||||
// Calculate the default size
|
||||
defaultSize = mPipSizeSpecHandler.getDefaultSize(mDefaultAspectRatio);
|
||||
defaultSize = mSizeSpecSource.getDefaultSize(mDefaultAspectRatio);
|
||||
|
||||
// Now that we have the default size, apply the snap fraction if valid or position the
|
||||
// bounds using the default gravity.
|
||||
@@ -309,7 +307,11 @@ public class PipBoundsAlgorithm {
|
||||
* Populates the bounds on the screen that the PIP can be visible in.
|
||||
*/
|
||||
public void getInsetBounds(Rect outRect) {
|
||||
outRect.set(mPipSizeSpecHandler.getInsetBounds());
|
||||
outRect.set(mPipDisplayLayoutState.getInsetBounds());
|
||||
}
|
||||
|
||||
private int getOverrideMinEdgeSize() {
|
||||
return mSizeSpecSource.getOverrideMinEdgeSize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.internal.util.function.TriConsumer;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -87,7 +87,7 @@ public class PipBoundsState {
|
||||
private int mStashOffset;
|
||||
private @Nullable PipReentryState mPipReentryState;
|
||||
private final LauncherState mLauncherState = new LauncherState();
|
||||
private final @Nullable PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private final @NonNull SizeSpecSource mSizeSpecSource;
|
||||
private @Nullable ComponentName mLastPipComponentName;
|
||||
private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState();
|
||||
private boolean mIsImeShowing;
|
||||
@@ -127,17 +127,20 @@ public class PipBoundsState {
|
||||
private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
|
||||
private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>();
|
||||
|
||||
public PipBoundsState(@NonNull Context context, PipSizeSpecHandler pipSizeSpecHandler,
|
||||
PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
public PipBoundsState(@NonNull Context context, @NonNull SizeSpecSource sizeSpecSource,
|
||||
@NonNull PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
mContext = context;
|
||||
reloadResources();
|
||||
mPipSizeSpecHandler = pipSizeSpecHandler;
|
||||
mSizeSpecSource = sizeSpecSource;
|
||||
mPipDisplayLayoutState = pipDisplayLayoutState;
|
||||
}
|
||||
|
||||
/** Reloads the resources. */
|
||||
public void onConfigurationChanged() {
|
||||
reloadResources();
|
||||
|
||||
// update the size spec resources upon config change too
|
||||
mSizeSpecSource.onConfigurationChanged();
|
||||
}
|
||||
|
||||
private void reloadResources() {
|
||||
@@ -319,7 +322,7 @@ public class PipBoundsState {
|
||||
/** Sets the preferred size of PIP as specified by the activity in PIP mode. */
|
||||
public void setOverrideMinSize(@Nullable Size overrideMinSize) {
|
||||
final boolean changed = !Objects.equals(overrideMinSize, getOverrideMinSize());
|
||||
mPipSizeSpecHandler.setOverrideMinSize(overrideMinSize);
|
||||
mSizeSpecSource.setOverrideMinSize(overrideMinSize);
|
||||
if (changed && mOnMinimalSizeChangeCallback != null) {
|
||||
mOnMinimalSizeChangeCallback.run();
|
||||
}
|
||||
@@ -328,12 +331,12 @@ public class PipBoundsState {
|
||||
/** Returns the preferred minimal size specified by the activity in PIP. */
|
||||
@Nullable
|
||||
public Size getOverrideMinSize() {
|
||||
return mPipSizeSpecHandler.getOverrideMinSize();
|
||||
return mSizeSpecSource.getOverrideMinSize();
|
||||
}
|
||||
|
||||
/** Returns the minimum edge size of the override minimum size, or 0 if not set. */
|
||||
public int getOverrideMinEdgeSize() {
|
||||
return mPipSizeSpecHandler.getOverrideMinEdgeSize();
|
||||
return mSizeSpecSource.getOverrideMinEdgeSize();
|
||||
}
|
||||
|
||||
/** Get the state of the bounds in motion. */
|
||||
@@ -613,5 +616,6 @@ public class PipBoundsState {
|
||||
}
|
||||
mLauncherState.dump(pw, innerPrefix);
|
||||
mMotionBoundsState.dump(pw, innerPrefix);
|
||||
mSizeSpecSource.dump(pw, innerPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,18 @@
|
||||
|
||||
package com.android.wm.shell.pip;
|
||||
|
||||
import static com.android.wm.shell.pip.PipUtils.dpToPx;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Size;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.dagger.WMSingleton;
|
||||
|
||||
@@ -40,13 +46,51 @@ public class PipDisplayLayoutState {
|
||||
private int mDisplayId;
|
||||
@NonNull private DisplayLayout mDisplayLayout;
|
||||
|
||||
private Point mScreenEdgeInsets = null;
|
||||
|
||||
@Inject
|
||||
public PipDisplayLayoutState(Context context) {
|
||||
mContext = context;
|
||||
mDisplayLayout = new DisplayLayout();
|
||||
reloadResources();
|
||||
}
|
||||
|
||||
/** Update the display layout. */
|
||||
/** Responds to configuration change. */
|
||||
public void onConfigurationChanged() {
|
||||
reloadResources();
|
||||
}
|
||||
|
||||
private void reloadResources() {
|
||||
Resources res = mContext.getResources();
|
||||
|
||||
final String screenEdgeInsetsDpString = res.getString(
|
||||
R.string.config_defaultPictureInPictureScreenEdgeInsets);
|
||||
final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
|
||||
? Size.parseSize(screenEdgeInsetsDpString)
|
||||
: null;
|
||||
mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
|
||||
: new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
|
||||
dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
|
||||
}
|
||||
|
||||
public Point getScreenEdgeInsets() {
|
||||
return mScreenEdgeInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inset bounds the PIP window can be visible in.
|
||||
*/
|
||||
public Rect getInsetBounds() {
|
||||
Rect insetBounds = new Rect();
|
||||
Rect insets = getDisplayLayout().stableInsets();
|
||||
insetBounds.set(insets.left + getScreenEdgeInsets().x,
|
||||
insets.top + getScreenEdgeInsets().y,
|
||||
getDisplayLayout().width() - insets.right - getScreenEdgeInsets().x,
|
||||
getDisplayLayout().height() - insets.bottom - getScreenEdgeInsets().y);
|
||||
return insetBounds;
|
||||
}
|
||||
|
||||
/** Set the display layout. */
|
||||
public void setDisplayLayout(@NonNull DisplayLayout displayLayout) {
|
||||
mDisplayLayout.set(displayLayout);
|
||||
}
|
||||
@@ -87,5 +131,6 @@ public class PipDisplayLayoutState {
|
||||
pw.println(prefix + TAG);
|
||||
pw.println(innerPrefix + "mDisplayId=" + mDisplayId);
|
||||
pw.println(innerPrefix + "getDisplayBounds=" + getDisplayBounds());
|
||||
pw.println(innerPrefix + "mScreenEdgeInsets=" + mScreenEdgeInsets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
private PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
|
||||
private PipBoundsState mPipBoundsState;
|
||||
private PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
private PipMotionHelper mPipMotionHelper;
|
||||
private PipTouchHandler mTouchHandler;
|
||||
@@ -406,7 +405,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipSizeSpecHandler pipSizeSpecHandler,
|
||||
PipDisplayLayoutState pipDisplayLayoutState,
|
||||
PipMotionHelper pipMotionHelper,
|
||||
PipMediaController pipMediaController,
|
||||
@@ -430,7 +428,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
|
||||
return new PipController(context, shellInit, shellCommandHandler, shellController,
|
||||
displayController, pipAnimationController, pipAppOpsListener,
|
||||
pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler,
|
||||
pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState,
|
||||
pipDisplayLayoutState, pipMotionHelper, pipMediaController, phonePipMenuController,
|
||||
pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
|
||||
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
|
||||
@@ -448,7 +446,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
|
||||
@NonNull PipBoundsState pipBoundsState,
|
||||
PipSizeSpecHandler pipSizeSpecHandler,
|
||||
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
|
||||
PipMotionHelper pipMotionHelper,
|
||||
PipMediaController pipMediaController,
|
||||
@@ -474,7 +471,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
mPipBoundsAlgorithm = pipBoundsAlgorithm;
|
||||
mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mPipSizeSpecHandler = pipSizeSpecHandler;
|
||||
mPipDisplayLayoutState = pipDisplayLayoutState;
|
||||
mPipMotionHelper = pipMotionHelper;
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
@@ -711,7 +707,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
// Try to move the PiP window if we have entered PiP mode.
|
||||
if (mPipTransitionState.hasEnteredPip()) {
|
||||
final Rect pipBounds = mPipBoundsState.getBounds();
|
||||
final Point edgeInsets = mPipSizeSpecHandler.getScreenEdgeInsets();
|
||||
final Point edgeInsets = mPipDisplayLayoutState.getScreenEdgeInsets();
|
||||
if ((pipBounds.height() + 2 * edgeInsets.y) > (displayBounds.height() / 2)) {
|
||||
// PiP bounds is too big to fit either half, bail early.
|
||||
return;
|
||||
@@ -770,7 +766,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
|
||||
mTouchHandler.onConfigurationChanged();
|
||||
mPipBoundsState.onConfigurationChanged();
|
||||
mPipSizeSpecHandler.onConfigurationChanged();
|
||||
mPipDisplayLayoutState.onConfigurationChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1224,7 +1220,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
mPipTaskOrganizer.dump(pw, innerPrefix);
|
||||
mPipBoundsState.dump(pw, innerPrefix);
|
||||
mPipInputConsumer.dump(pw, innerPrefix);
|
||||
mPipSizeSpecHandler.dump(pw, innerPrefix);
|
||||
mPipDisplayLayoutState.dump(pw, innerPrefix);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,536 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.pip.phone;
|
||||
|
||||
import static com.android.wm.shell.pip.PipUtils.dpToPx;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Size;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Acts as a source of truth for appropriate size spec for PIP.
|
||||
*/
|
||||
public class PipSizeSpecHandler {
|
||||
private static final String TAG = PipSizeSpecHandler.class.getSimpleName();
|
||||
|
||||
@NonNull private final PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
|
||||
private final SizeSpecSource mSizeSpecSourceImpl;
|
||||
|
||||
/** The preferred minimum (and default minimum) size specified by apps. */
|
||||
@Nullable private Size mOverrideMinSize;
|
||||
private int mOverridableMinSize;
|
||||
|
||||
/** Used to store values obtained from resource files. */
|
||||
private Point mScreenEdgeInsets;
|
||||
private float mMinAspectRatioForMinSize;
|
||||
private float mMaxAspectRatioForMinSize;
|
||||
private int mDefaultMinSize;
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
|
||||
private interface SizeSpecSource {
|
||||
/** Returns max size allowed for the PIP window */
|
||||
Size getMaxSize(float aspectRatio);
|
||||
|
||||
/** Returns default size for the PIP window */
|
||||
Size getDefaultSize(float aspectRatio);
|
||||
|
||||
/** Returns min size allowed for the PIP window */
|
||||
Size getMinSize(float aspectRatio);
|
||||
|
||||
/** Returns the adjusted size based on current size and target aspect ratio */
|
||||
Size getSizeForAspectRatio(Size size, float aspectRatio);
|
||||
|
||||
/** Updates internal resources on configuration changes */
|
||||
default void reloadResources() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines PIP window size optimized for large screens and aspect ratios close to 1:1
|
||||
*/
|
||||
private class SizeSpecLargeScreenOptimizedImpl implements SizeSpecSource {
|
||||
private static final float DEFAULT_OPTIMIZED_ASPECT_RATIO = 9f / 16;
|
||||
|
||||
/** Default and minimum percentages for the PIP size logic. */
|
||||
private final float mDefaultSizePercent;
|
||||
private final float mMinimumSizePercent;
|
||||
|
||||
/** Aspect ratio that the PIP size spec logic optimizes for. */
|
||||
private float mOptimizedAspectRatio;
|
||||
|
||||
private SizeSpecLargeScreenOptimizedImpl() {
|
||||
mDefaultSizePercent = Float.parseFloat(SystemProperties
|
||||
.get("com.android.wm.shell.pip.phone.def_percentage", "0.6"));
|
||||
mMinimumSizePercent = Float.parseFloat(SystemProperties
|
||||
.get("com.android.wm.shell.pip.phone.min_percentage", "0.5"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadResources() {
|
||||
final Resources res = mContext.getResources();
|
||||
|
||||
mOptimizedAspectRatio = res.getFloat(R.dimen.config_pipLargeScreenOptimizedAspectRatio);
|
||||
// make sure the optimized aspect ratio is valid with a default value to fall back to
|
||||
if (mOptimizedAspectRatio > 1) {
|
||||
mOptimizedAspectRatio = DEFAULT_OPTIMIZED_ASPECT_RATIO;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the max size of PIP.
|
||||
*
|
||||
* Optimizes for 16:9 aspect ratios, making them take full length of shortest display edge.
|
||||
* As aspect ratio approaches values close to 1:1, the logic does not let PIP occupy the
|
||||
* whole screen. A linear function is used to calculate these sizes.
|
||||
*
|
||||
* @param aspectRatio aspect ratio of the PIP window
|
||||
* @return dimensions of the max size of the PIP
|
||||
*/
|
||||
@Override
|
||||
public Size getMaxSize(float aspectRatio) {
|
||||
final int totalHorizontalPadding = getInsetBounds().left
|
||||
+ (getDisplayBounds().width() - getInsetBounds().right);
|
||||
final int totalVerticalPadding = getInsetBounds().top
|
||||
+ (getDisplayBounds().height() - getInsetBounds().bottom);
|
||||
|
||||
final int shorterLength = Math.min(getDisplayBounds().width() - totalHorizontalPadding,
|
||||
getDisplayBounds().height() - totalVerticalPadding);
|
||||
|
||||
int maxWidth, maxHeight;
|
||||
|
||||
// use the optimized max sizing logic only within a certain aspect ratio range
|
||||
if (aspectRatio >= mOptimizedAspectRatio && aspectRatio <= 1 / mOptimizedAspectRatio) {
|
||||
// this formula and its derivation is explained in b/198643358#comment16
|
||||
maxWidth = Math.round(mOptimizedAspectRatio * shorterLength
|
||||
+ shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1
|
||||
+ aspectRatio));
|
||||
// make sure the max width doesn't go beyond shorter screen length after rounding
|
||||
maxWidth = Math.min(maxWidth, shorterLength);
|
||||
maxHeight = Math.round(maxWidth / aspectRatio);
|
||||
} else {
|
||||
if (aspectRatio > 1f) {
|
||||
maxWidth = shorterLength;
|
||||
maxHeight = Math.round(maxWidth / aspectRatio);
|
||||
} else {
|
||||
maxHeight = shorterLength;
|
||||
maxWidth = Math.round(maxHeight * aspectRatio);
|
||||
}
|
||||
}
|
||||
|
||||
return new Size(maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the dimensions by a percentage relative to max size to get default size.
|
||||
*
|
||||
* @param aspectRatio aspect ratio of the PIP window
|
||||
* @return dimensions of the default size of the PIP
|
||||
*/
|
||||
@Override
|
||||
public Size getDefaultSize(float aspectRatio) {
|
||||
Size minSize = this.getMinSize(aspectRatio);
|
||||
|
||||
if (mOverrideMinSize != null) {
|
||||
return minSize;
|
||||
}
|
||||
|
||||
Size maxSize = this.getMaxSize(aspectRatio);
|
||||
|
||||
int defaultWidth = Math.max(Math.round(maxSize.getWidth() * mDefaultSizePercent),
|
||||
minSize.getWidth());
|
||||
int defaultHeight = Math.round(defaultWidth / aspectRatio);
|
||||
|
||||
return new Size(defaultWidth, defaultHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the dimensions by a certain percentage relative to max size to get min size.
|
||||
*
|
||||
* @param aspectRatio aspect ratio of the PIP window
|
||||
* @return dimensions of the min size of the PIP
|
||||
*/
|
||||
@Override
|
||||
public Size getMinSize(float aspectRatio) {
|
||||
// if there is an overridden min size provided, return that
|
||||
if (mOverrideMinSize != null) {
|
||||
return adjustOverrideMinSizeToAspectRatio(aspectRatio);
|
||||
}
|
||||
|
||||
Size maxSize = this.getMaxSize(aspectRatio);
|
||||
|
||||
int minWidth = Math.round(maxSize.getWidth() * mMinimumSizePercent);
|
||||
int minHeight = Math.round(maxSize.getHeight() * mMinimumSizePercent);
|
||||
|
||||
// make sure the calculated min size is not smaller than the allowed default min size
|
||||
if (aspectRatio > 1f) {
|
||||
minHeight = Math.max(minHeight, mDefaultMinSize);
|
||||
minWidth = Math.round(minHeight * aspectRatio);
|
||||
} else {
|
||||
minWidth = Math.max(minWidth, mDefaultMinSize);
|
||||
minHeight = Math.round(minWidth / aspectRatio);
|
||||
}
|
||||
return new Size(minWidth, minHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size for target aspect ratio making sure new size conforms with the rules.
|
||||
*
|
||||
* <p>Recalculates the dimensions such that the target aspect ratio is achieved, while
|
||||
* maintaining the same maximum size to current size ratio.
|
||||
*
|
||||
* @param size current size
|
||||
* @param aspectRatio target aspect ratio
|
||||
*/
|
||||
@Override
|
||||
public Size getSizeForAspectRatio(Size size, float aspectRatio) {
|
||||
float currAspectRatio = (float) size.getWidth() / size.getHeight();
|
||||
|
||||
// getting the percentage of the max size that current size takes
|
||||
Size currentMaxSize = getMaxSize(currAspectRatio);
|
||||
float currentPercent = (float) size.getWidth() / currentMaxSize.getWidth();
|
||||
|
||||
// getting the max size for the target aspect ratio
|
||||
Size updatedMaxSize = getMaxSize(aspectRatio);
|
||||
|
||||
int width = Math.round(updatedMaxSize.getWidth() * currentPercent);
|
||||
int height = Math.round(updatedMaxSize.getHeight() * currentPercent);
|
||||
|
||||
// adjust the dimensions if below allowed min edge size
|
||||
if (width < getMinEdgeSize() && aspectRatio <= 1) {
|
||||
width = getMinEdgeSize();
|
||||
height = Math.round(width / aspectRatio);
|
||||
} else if (height < getMinEdgeSize() && aspectRatio > 1) {
|
||||
height = getMinEdgeSize();
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
|
||||
// reduce the dimensions of the updated size to the calculated percentage
|
||||
return new Size(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private class SizeSpecDefaultImpl implements SizeSpecSource {
|
||||
private float mDefaultSizePercent;
|
||||
private float mMinimumSizePercent;
|
||||
|
||||
@Override
|
||||
public void reloadResources() {
|
||||
final Resources res = mContext.getResources();
|
||||
|
||||
mMaxAspectRatioForMinSize = res.getFloat(
|
||||
R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
|
||||
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
|
||||
|
||||
mDefaultSizePercent = res.getFloat(R.dimen.config_pictureInPictureDefaultSizePercent);
|
||||
mMinimumSizePercent = res.getFraction(R.fraction.config_pipShortestEdgePercent, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size getMaxSize(float aspectRatio) {
|
||||
final int shorterLength = Math.min(getDisplayBounds().width(),
|
||||
getDisplayBounds().height());
|
||||
|
||||
final int totalHorizontalPadding = getInsetBounds().left
|
||||
+ (getDisplayBounds().width() - getInsetBounds().right);
|
||||
final int totalVerticalPadding = getInsetBounds().top
|
||||
+ (getDisplayBounds().height() - getInsetBounds().bottom);
|
||||
|
||||
final int maxWidth, maxHeight;
|
||||
|
||||
if (aspectRatio > 1f) {
|
||||
maxWidth = (int) Math.max(getDefaultSize(aspectRatio).getWidth(),
|
||||
shorterLength - totalHorizontalPadding);
|
||||
maxHeight = (int) (maxWidth / aspectRatio);
|
||||
} else {
|
||||
maxHeight = (int) Math.max(getDefaultSize(aspectRatio).getHeight(),
|
||||
shorterLength - totalVerticalPadding);
|
||||
maxWidth = (int) (maxHeight * aspectRatio);
|
||||
}
|
||||
|
||||
return new Size(maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size getDefaultSize(float aspectRatio) {
|
||||
if (mOverrideMinSize != null) {
|
||||
return this.getMinSize(aspectRatio);
|
||||
}
|
||||
|
||||
final int smallestDisplaySize = Math.min(getDisplayBounds().width(),
|
||||
getDisplayBounds().height());
|
||||
final int minSize = (int) Math.max(getMinEdgeSize(),
|
||||
smallestDisplaySize * mDefaultSizePercent);
|
||||
|
||||
final int width;
|
||||
final int height;
|
||||
|
||||
if (aspectRatio <= mMinAspectRatioForMinSize
|
||||
|| aspectRatio > mMaxAspectRatioForMinSize) {
|
||||
// Beyond these points, we can just use the min size as the shorter edge
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size
|
||||
width = minSize;
|
||||
height = Math.round(width / aspectRatio);
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize;
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
} else {
|
||||
// Within these points, ensure that the bounds fit within the radius of the limits
|
||||
// at the points
|
||||
final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
|
||||
final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
|
||||
height = (int) Math.round(Math.sqrt((radius * radius)
|
||||
/ (aspectRatio * aspectRatio + 1)));
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size getMinSize(float aspectRatio) {
|
||||
if (mOverrideMinSize != null) {
|
||||
return adjustOverrideMinSizeToAspectRatio(aspectRatio);
|
||||
}
|
||||
|
||||
final int shorterLength = Math.min(getDisplayBounds().width(),
|
||||
getDisplayBounds().height());
|
||||
final int minWidth, minHeight;
|
||||
|
||||
if (aspectRatio > 1f) {
|
||||
minWidth = (int) Math.min(getDefaultSize(aspectRatio).getWidth(),
|
||||
shorterLength * mMinimumSizePercent);
|
||||
minHeight = (int) (minWidth / aspectRatio);
|
||||
} else {
|
||||
minHeight = (int) Math.min(getDefaultSize(aspectRatio).getHeight(),
|
||||
shorterLength * mMinimumSizePercent);
|
||||
minWidth = (int) (minHeight * aspectRatio);
|
||||
}
|
||||
|
||||
return new Size(minWidth, minHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size getSizeForAspectRatio(Size size, float aspectRatio) {
|
||||
final int smallestSize = Math.min(size.getWidth(), size.getHeight());
|
||||
final int minSize = Math.max(getMinEdgeSize(), smallestSize);
|
||||
|
||||
final int width;
|
||||
final int height;
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size.
|
||||
width = minSize;
|
||||
height = Math.round(width / aspectRatio);
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize;
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
|
||||
return new Size(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public PipSizeSpecHandler(Context context, PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
mContext = context;
|
||||
mPipDisplayLayoutState = pipDisplayLayoutState;
|
||||
|
||||
// choose between two implementations of size spec logic
|
||||
if (supportsPipSizeLargeScreen()) {
|
||||
mSizeSpecSourceImpl = new SizeSpecLargeScreenOptimizedImpl();
|
||||
} else {
|
||||
mSizeSpecSourceImpl = new SizeSpecDefaultImpl();
|
||||
}
|
||||
|
||||
reloadResources();
|
||||
}
|
||||
|
||||
/** Reloads the resources */
|
||||
public void onConfigurationChanged() {
|
||||
reloadResources();
|
||||
}
|
||||
|
||||
private void reloadResources() {
|
||||
final Resources res = mContext.getResources();
|
||||
|
||||
mDefaultMinSize = res.getDimensionPixelSize(
|
||||
R.dimen.default_minimal_size_pip_resizable_task);
|
||||
mOverridableMinSize = res.getDimensionPixelSize(
|
||||
R.dimen.overridable_minimal_size_pip_resizable_task);
|
||||
|
||||
final String screenEdgeInsetsDpString = res.getString(
|
||||
R.string.config_defaultPictureInPictureScreenEdgeInsets);
|
||||
final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
|
||||
? Size.parseSize(screenEdgeInsetsDpString)
|
||||
: null;
|
||||
mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
|
||||
: new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
|
||||
dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
|
||||
|
||||
// update the internal resources of the size spec source's stub
|
||||
mSizeSpecSourceImpl.reloadResources();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Rect getDisplayBounds() {
|
||||
return mPipDisplayLayoutState.getDisplayBounds();
|
||||
}
|
||||
|
||||
public Point getScreenEdgeInsets() {
|
||||
return mScreenEdgeInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inset bounds the PIP window can be visible in.
|
||||
*/
|
||||
public Rect getInsetBounds() {
|
||||
Rect insetBounds = new Rect();
|
||||
DisplayLayout displayLayout = mPipDisplayLayoutState.getDisplayLayout();
|
||||
Rect insets = displayLayout.stableInsets();
|
||||
insetBounds.set(insets.left + mScreenEdgeInsets.x,
|
||||
insets.top + mScreenEdgeInsets.y,
|
||||
displayLayout.width() - insets.right - mScreenEdgeInsets.x,
|
||||
displayLayout.height() - insets.bottom - mScreenEdgeInsets.y);
|
||||
return insetBounds;
|
||||
}
|
||||
|
||||
/** Sets the preferred size of PIP as specified by the activity in PIP mode. */
|
||||
public void setOverrideMinSize(@Nullable Size overrideMinSize) {
|
||||
mOverrideMinSize = overrideMinSize;
|
||||
}
|
||||
|
||||
/** Returns the preferred minimal size specified by the activity in PIP. */
|
||||
@Nullable
|
||||
public Size getOverrideMinSize() {
|
||||
if (mOverrideMinSize != null
|
||||
&& (mOverrideMinSize.getWidth() < mOverridableMinSize
|
||||
|| mOverrideMinSize.getHeight() < mOverridableMinSize)) {
|
||||
return new Size(mOverridableMinSize, mOverridableMinSize);
|
||||
}
|
||||
|
||||
return mOverrideMinSize;
|
||||
}
|
||||
|
||||
/** Returns the minimum edge size of the override minimum size, or 0 if not set. */
|
||||
public int getOverrideMinEdgeSize() {
|
||||
if (mOverrideMinSize == null) return 0;
|
||||
return Math.min(getOverrideMinSize().getWidth(), getOverrideMinSize().getHeight());
|
||||
}
|
||||
|
||||
public int getMinEdgeSize() {
|
||||
return mOverrideMinSize == null ? mDefaultMinSize : getOverrideMinEdgeSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size for the max size spec.
|
||||
*/
|
||||
public Size getMaxSize(float aspectRatio) {
|
||||
return mSizeSpecSourceImpl.getMaxSize(aspectRatio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size for the default size spec.
|
||||
*/
|
||||
public Size getDefaultSize(float aspectRatio) {
|
||||
return mSizeSpecSourceImpl.getDefaultSize(aspectRatio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size for the min size spec.
|
||||
*/
|
||||
public Size getMinSize(float aspectRatio) {
|
||||
return mSizeSpecSourceImpl.getMinSize(aspectRatio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adjusted size so that it conforms to the given aspectRatio.
|
||||
*
|
||||
* @param size current size
|
||||
* @param aspectRatio target aspect ratio
|
||||
*/
|
||||
public Size getSizeForAspectRatio(@NonNull Size size, float aspectRatio) {
|
||||
if (size.equals(mOverrideMinSize)) {
|
||||
return adjustOverrideMinSizeToAspectRatio(aspectRatio);
|
||||
}
|
||||
|
||||
return mSizeSpecSourceImpl.getSizeForAspectRatio(size, aspectRatio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adjusted overridden min size if it is set; otherwise, returns null.
|
||||
*
|
||||
* <p>Overridden min size needs to be adjusted in its own way while making sure that the target
|
||||
* aspect ratio is maintained
|
||||
*
|
||||
* @param aspectRatio target aspect ratio
|
||||
*/
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
Size adjustOverrideMinSizeToAspectRatio(float aspectRatio) {
|
||||
if (mOverrideMinSize == null) {
|
||||
return null;
|
||||
}
|
||||
final Size size = getOverrideMinSize();
|
||||
final float sizeAspectRatio = size.getWidth() / (float) size.getHeight();
|
||||
if (sizeAspectRatio > aspectRatio) {
|
||||
// Size is wider, fix the width and increase the height
|
||||
return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio));
|
||||
} else {
|
||||
// Size is taller, fix the height and adjust the width.
|
||||
return new Size((int) (size.getHeight() * aspectRatio), size.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean supportsPipSizeLargeScreen() {
|
||||
// TODO(b/271468706): switch Tv to having a dedicated SizeSpecSource once the SizeSpecSource
|
||||
// can be injected
|
||||
return SystemProperties
|
||||
.getBoolean("persist.wm.debug.enable_pip_size_large_screen", true) && !isTv();
|
||||
}
|
||||
|
||||
private boolean isTv() {
|
||||
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
|
||||
}
|
||||
|
||||
/** Dumps internal state. */
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
pw.println(prefix + TAG);
|
||||
pw.println(innerPrefix + "mSizeSpecSourceImpl=" + mSizeSpecSourceImpl);
|
||||
pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize);
|
||||
pw.println(innerPrefix + "mScreenEdgeInsets=" + mScreenEdgeInsets);
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.PipAnimationController;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
@@ -85,7 +86,7 @@ public class PipTouchHandler {
|
||||
private final Context mContext;
|
||||
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
@NonNull private final PipBoundsState mPipBoundsState;
|
||||
@NonNull private final PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
@NonNull private final SizeSpecSource mSizeSpecSource;
|
||||
private final PipUiEventLogger mPipUiEventLogger;
|
||||
private final PipDismissTargetHandler mPipDismissTargetHandler;
|
||||
private final PipTaskOrganizer mPipTaskOrganizer;
|
||||
@@ -179,7 +180,7 @@ public class PipTouchHandler {
|
||||
PhonePipMenuController menuController,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
@NonNull PipBoundsState pipBoundsState,
|
||||
@NonNull PipSizeSpecHandler pipSizeSpecHandler,
|
||||
@NonNull SizeSpecSource sizeSpecSource,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipMotionHelper pipMotionHelper,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
@@ -190,7 +191,7 @@ public class PipTouchHandler {
|
||||
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
|
||||
mPipBoundsAlgorithm = pipBoundsAlgorithm;
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mPipSizeSpecHandler = pipSizeSpecHandler;
|
||||
mSizeSpecSource = sizeSpecSource;
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
mMenuController = menuController;
|
||||
mPipUiEventLogger = pipUiEventLogger;
|
||||
@@ -413,7 +414,7 @@ public class PipTouchHandler {
|
||||
|
||||
// Calculate the expanded size
|
||||
float aspectRatio = (float) normalBounds.width() / normalBounds.height();
|
||||
Size expandedSize = mPipSizeSpecHandler.getDefaultSize(aspectRatio);
|
||||
Size expandedSize = mSizeSpecSource.getDefaultSize(aspectRatio);
|
||||
mPipBoundsState.setExpandedBounds(
|
||||
new Rect(0, 0, expandedSize.getWidth(), expandedSize.getHeight()));
|
||||
Rect expandedMovementBounds = new Rect();
|
||||
@@ -517,10 +518,10 @@ public class PipTouchHandler {
|
||||
private void updatePinchResizeSizeConstraints(float aspectRatio) {
|
||||
final int minWidth, minHeight, maxWidth, maxHeight;
|
||||
|
||||
minWidth = mPipSizeSpecHandler.getMinSize(aspectRatio).getWidth();
|
||||
minHeight = mPipSizeSpecHandler.getMinSize(aspectRatio).getHeight();
|
||||
maxWidth = mPipSizeSpecHandler.getMaxSize(aspectRatio).getWidth();
|
||||
maxHeight = mPipSizeSpecHandler.getMaxSize(aspectRatio).getHeight();
|
||||
minWidth = mSizeSpecSource.getMinSize(aspectRatio).getWidth();
|
||||
minHeight = mSizeSpecSource.getMinSize(aspectRatio).getHeight();
|
||||
maxWidth = mSizeSpecSource.getMaxSize(aspectRatio).getWidth();
|
||||
maxHeight = mSizeSpecSource.getMaxSize(aspectRatio).getHeight();
|
||||
|
||||
mPipResizeGestureHandler.updateMinSize(minWidth, minHeight);
|
||||
mPipResizeGestureHandler.updateMaxSize(maxWidth, maxHeight);
|
||||
|
||||
@@ -36,10 +36,11 @@ import androidx.annotation.NonNull;
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState;
|
||||
import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
|
||||
import com.android.wm.shell.pip.PipSnapAlgorithm;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
|
||||
@@ -62,9 +63,10 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
|
||||
public TvPipBoundsAlgorithm(Context context,
|
||||
@NonNull TvPipBoundsState tvPipBoundsState,
|
||||
@NonNull PipSnapAlgorithm pipSnapAlgorithm,
|
||||
@NonNull PipSizeSpecHandler pipSizeSpecHandler) {
|
||||
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
|
||||
@NonNull SizeSpecSource sizeSpecSource) {
|
||||
super(context, tvPipBoundsState, pipSnapAlgorithm,
|
||||
new PipKeepClearAlgorithmInterface() {}, pipSizeSpecHandler);
|
||||
new PipKeepClearAlgorithmInterface() {}, pipDisplayLayoutState, sizeSpecSource);
|
||||
this.mTvPipBoundsState = tvPipBoundsState;
|
||||
this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm();
|
||||
reloadResources(context);
|
||||
@@ -291,7 +293,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
|
||||
expandedSize = mTvPipBoundsState.getTvExpandedSize();
|
||||
} else {
|
||||
int maxHeight = displayLayout.height()
|
||||
- (2 * mPipSizeSpecHandler.getScreenEdgeInsets().y)
|
||||
- (2 * mPipDisplayLayoutState.getScreenEdgeInsets().y)
|
||||
- pipDecorations.top - pipDecorations.bottom;
|
||||
float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
|
||||
|
||||
@@ -311,7 +313,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
|
||||
expandedSize = mTvPipBoundsState.getTvExpandedSize();
|
||||
} else {
|
||||
int maxWidth = displayLayout.width()
|
||||
- (2 * mPipSizeSpecHandler.getScreenEdgeInsets().x)
|
||||
- (2 * mPipDisplayLayoutState.getScreenEdgeInsets().x)
|
||||
- pipDecorations.left - pipDecorations.right;
|
||||
float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
|
||||
if (maxWidth > aspectRatioWidth) {
|
||||
|
||||
@@ -29,10 +29,10 @@ import android.util.Size;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -76,9 +76,9 @@ public class TvPipBoundsState extends PipBoundsState {
|
||||
private Insets mPipMenuTemporaryDecorInsets = Insets.NONE;
|
||||
|
||||
public TvPipBoundsState(@NonNull Context context,
|
||||
@NonNull PipSizeSpecHandler pipSizeSpecHandler,
|
||||
@NonNull SizeSpecSource sizeSpecSource,
|
||||
@NonNull PipDisplayLayoutState pipDisplayLayoutState) {
|
||||
super(context, pipSizeSpecHandler, pipDisplayLayoutState);
|
||||
super(context, sizeSpecSource, pipDisplayLayoutState);
|
||||
mContext = context;
|
||||
updateDefaultGravity();
|
||||
mPreviousCollapsedGravity = mDefaultGravity;
|
||||
|
||||
@@ -32,7 +32,8 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -60,7 +61,8 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
|
||||
private PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private DisplayInfo mDefaultDisplayInfo;
|
||||
private PipBoundsState mPipBoundsState; private PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private PipBoundsState mPipBoundsState;
|
||||
private SizeSpecSource mSizeSpecSource;
|
||||
private PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
|
||||
|
||||
@@ -68,11 +70,12 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
public void setUp() throws Exception {
|
||||
initializeMockResources();
|
||||
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
|
||||
mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
|
||||
|
||||
mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
|
||||
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
|
||||
new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {},
|
||||
mPipSizeSpecHandler);
|
||||
mPipDisplayLayoutState, mSizeSpecSource);
|
||||
|
||||
DisplayLayout layout =
|
||||
new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true);
|
||||
@@ -132,7 +135,7 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_noOverrideMinSize_matchesDefaultSizeAndAspectRatio() {
|
||||
final Size defaultSize = mPipSizeSpecHandler.getDefaultSize(DEFAULT_ASPECT_RATIO);
|
||||
final Size defaultSize = mSizeSpecSource.getDefaultSize(DEFAULT_ASPECT_RATIO);
|
||||
|
||||
mPipBoundsState.setOverrideMinSize(null);
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
@@ -35,7 +35,8 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.internal.util.function.TriConsumer;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -58,6 +59,7 @@ public class PipBoundsStateTest extends ShellTestCase {
|
||||
private static final int OVERRIDABLE_MIN_SIZE = 40;
|
||||
|
||||
private PipBoundsState mPipBoundsState;
|
||||
private SizeSpecSource mSizeSpecSource;
|
||||
private ComponentName mTestComponentName1;
|
||||
private ComponentName mTestComponentName2;
|
||||
|
||||
@@ -69,8 +71,8 @@ public class PipBoundsStateTest extends ShellTestCase {
|
||||
OVERRIDABLE_MIN_SIZE);
|
||||
|
||||
PipDisplayLayoutState pipDisplayLayoutState = new PipDisplayLayoutState(mContext);
|
||||
mPipBoundsState = new PipBoundsState(mContext,
|
||||
new PipSizeSpecHandler(mContext, pipDisplayLayoutState), pipDisplayLayoutState);
|
||||
mSizeSpecSource = new PhoneSizeSpecSource(mContext, pipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, pipDisplayLayoutState);
|
||||
mTestComponentName1 = new ComponentName(mContext, "component1");
|
||||
mTestComponentName2 = new ComponentName(mContext, "component2");
|
||||
}
|
||||
|
||||
@@ -52,8 +52,9 @@ import com.android.wm.shell.TestShellExecutor;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.phone.PhonePipMenuController;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -87,7 +88,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
private PipBoundsState mPipBoundsState;
|
||||
private PipTransitionState mPipTransitionState;
|
||||
private PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private SizeSpecSource mSizeSpecSource;
|
||||
private PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
|
||||
private ComponentName mComponent1;
|
||||
@@ -99,12 +100,12 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
mComponent1 = new ComponentName(mContext, "component1");
|
||||
mComponent2 = new ComponentName(mContext, "component2");
|
||||
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
|
||||
mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
|
||||
mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
|
||||
mPipTransitionState = new PipTransitionState();
|
||||
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
|
||||
new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {},
|
||||
mPipSizeSpecHandler);
|
||||
mPipDisplayLayoutState, mSizeSpecSource);
|
||||
mMainExecutor = new TestShellExecutor();
|
||||
mPipTaskOrganizer = new PipTaskOrganizer(mContext, mMockSyncTransactionQueue,
|
||||
mPipTransitionState, mPipBoundsState, mPipDisplayLayoutState,
|
||||
|
||||
@@ -32,6 +32,8 @@ import android.view.DisplayInfo;
|
||||
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -47,10 +49,10 @@ import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Unit test against {@link PipSizeSpecHandler} with feature flag on.
|
||||
* Unit test against {@link PhoneSizeSpecSource}
|
||||
*/
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class PipSizeSpecHandlerTest extends ShellTestCase {
|
||||
public class PhoneSizeSpecSourceTest extends ShellTestCase {
|
||||
/** A sample overridden min edge size. */
|
||||
private static final int OVERRIDE_MIN_EDGE_SIZE = 40;
|
||||
/** A sample default min edge size */
|
||||
@@ -75,7 +77,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
|
||||
@Mock private Resources mResources;
|
||||
|
||||
private PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
private TestPipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private SizeSpecSource mSizeSpecSource;
|
||||
|
||||
/**
|
||||
* Sets up static Mockito session for SystemProperties and mocks necessary static methods.
|
||||
@@ -158,10 +160,10 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
|
||||
mPipDisplayLayoutState.setDisplayLayout(displayLayout);
|
||||
|
||||
setUpStaticSystemPropertiesSession();
|
||||
mPipSizeSpecHandler = new TestPipSizeSpecHandler(mContext, mPipDisplayLayoutState);
|
||||
mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
|
||||
|
||||
// no overridden min edge size by default
|
||||
mPipSizeSpecHandler.setOverrideMinSize(null);
|
||||
mSizeSpecSource.setOverrideMinSize(null);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -172,19 +174,19 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
|
||||
@Test
|
||||
public void testGetMaxSize() {
|
||||
forEveryTestCaseCheck(sExpectedMaxSizes,
|
||||
(aspectRatio) -> mPipSizeSpecHandler.getMaxSize(aspectRatio));
|
||||
(aspectRatio) -> mSizeSpecSource.getMaxSize(aspectRatio));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultSize() {
|
||||
forEveryTestCaseCheck(sExpectedDefaultSizes,
|
||||
(aspectRatio) -> mPipSizeSpecHandler.getDefaultSize(aspectRatio));
|
||||
(aspectRatio) -> mSizeSpecSource.getDefaultSize(aspectRatio));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMinSize() {
|
||||
forEveryTestCaseCheck(sExpectedMinSizes,
|
||||
(aspectRatio) -> mPipSizeSpecHandler.getMinSize(aspectRatio));
|
||||
(aspectRatio) -> mSizeSpecSource.getMinSize(aspectRatio));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -193,7 +195,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
|
||||
Size initSize = new Size(600, 337);
|
||||
|
||||
Size expectedSize = new Size(338, 601);
|
||||
Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
|
||||
Size actualSize = mSizeSpecSource.getSizeForAspectRatio(initSize, 9f / 16);
|
||||
|
||||
Assert.assertEquals(expectedSize, actualSize);
|
||||
}
|
||||
@@ -201,26 +203,12 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
|
||||
@Test
|
||||
public void testGetSizeForAspectRatio_withOverrideMinSize() {
|
||||
// an initial size with a 1:1 aspect ratio
|
||||
mPipSizeSpecHandler.setOverrideMinSize(new Size(OVERRIDE_MIN_EDGE_SIZE,
|
||||
OVERRIDE_MIN_EDGE_SIZE));
|
||||
// make sure initial size is same as override min size
|
||||
Size initSize = mPipSizeSpecHandler.getOverrideMinSize();
|
||||
Size initSize = new Size(OVERRIDE_MIN_EDGE_SIZE, OVERRIDE_MIN_EDGE_SIZE);
|
||||
mSizeSpecSource.setOverrideMinSize(initSize);
|
||||
|
||||
Size expectedSize = new Size(40, 71);
|
||||
Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
|
||||
Size actualSize = mSizeSpecSource.getSizeForAspectRatio(initSize, 9f / 16);
|
||||
|
||||
Assert.assertEquals(expectedSize, actualSize);
|
||||
}
|
||||
|
||||
static class TestPipSizeSpecHandler extends PipSizeSpecHandler {
|
||||
|
||||
TestPipSizeSpecHandler(Context context, PipDisplayLayoutState displayLayoutState) {
|
||||
super(context, displayLayoutState);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean supportsPipSizeLargeScreen() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,6 @@ public class PipControllerTest extends ShellTestCase {
|
||||
@Mock private PipMotionHelper mMockPipMotionHelper;
|
||||
@Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
|
||||
@Mock private PipBoundsState mMockPipBoundsState;
|
||||
@Mock private PipSizeSpecHandler mMockPipSizeSpecHandler;
|
||||
@Mock private PipDisplayLayoutState mMockPipDisplayLayoutState;
|
||||
@Mock private TaskStackListenerImpl mMockTaskStackListener;
|
||||
@Mock private ShellExecutor mMockExecutor;
|
||||
@@ -134,7 +133,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
|
||||
mShellController, mMockDisplayController, mMockPipAnimationController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
|
||||
mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipDisplayLayoutState,
|
||||
mMockPipBoundsState, mMockPipDisplayLayoutState,
|
||||
mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController,
|
||||
mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler,
|
||||
mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
@@ -226,7 +225,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler,
|
||||
mShellController, mMockDisplayController, mMockPipAnimationController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
|
||||
mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipDisplayLayoutState,
|
||||
mMockPipBoundsState, mMockPipDisplayLayoutState,
|
||||
mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController,
|
||||
mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler,
|
||||
mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
|
||||
@@ -36,6 +36,8 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState;
|
||||
@@ -87,7 +89,7 @@ public class PipResizeGestureHandlerTest extends ShellTestCase {
|
||||
|
||||
private PipBoundsState mPipBoundsState;
|
||||
|
||||
private PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private SizeSpecSource mSizeSpecSource;
|
||||
|
||||
private PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
|
||||
@@ -97,13 +99,14 @@ public class PipResizeGestureHandlerTest extends ShellTestCase {
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
|
||||
mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
|
||||
mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
|
||||
final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm();
|
||||
final PipKeepClearAlgorithmInterface pipKeepClearAlgorithm =
|
||||
new PipKeepClearAlgorithmInterface() {};
|
||||
final PipBoundsAlgorithm pipBoundsAlgorithm = new PipBoundsAlgorithm(mContext,
|
||||
mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm, mPipSizeSpecHandler);
|
||||
mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm, mPipDisplayLayoutState,
|
||||
mSizeSpecSource);
|
||||
final PipMotionHelper motionHelper = new PipMotionHelper(mContext, mPipBoundsState,
|
||||
mPipTaskOrganizer, mPhonePipMenuController, pipSnapAlgorithm,
|
||||
mMockPipTransitionController, mFloatingContentCoordinator);
|
||||
|
||||
@@ -33,6 +33,8 @@ import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState;
|
||||
@@ -92,7 +94,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
private PipSnapAlgorithm mPipSnapAlgorithm;
|
||||
private PipMotionHelper mMotionHelper;
|
||||
private PipResizeGestureHandler mPipResizeGestureHandler;
|
||||
private PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private SizeSpecSource mSizeSpecSource;
|
||||
private PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
|
||||
private DisplayLayout mDisplayLayout;
|
||||
@@ -108,16 +110,16 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
|
||||
mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
|
||||
mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
|
||||
mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
|
||||
mPipSnapAlgorithm = new PipSnapAlgorithm();
|
||||
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm,
|
||||
new PipKeepClearAlgorithmInterface() {}, mPipSizeSpecHandler);
|
||||
new PipKeepClearAlgorithmInterface() {}, mPipDisplayLayoutState, mSizeSpecSource);
|
||||
PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState,
|
||||
mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm,
|
||||
mMockPipTransitionController, mFloatingContentCoordinator);
|
||||
mPipTouchHandler = new PipTouchHandler(mContext, mShellInit, mPhonePipMenuController,
|
||||
mPipBoundsAlgorithm, mPipBoundsState, mPipSizeSpecHandler, mPipTaskOrganizer,
|
||||
mPipBoundsAlgorithm, mPipBoundsState, mSizeSpecSource, mPipTaskOrganizer,
|
||||
pipMotionHelper, mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor);
|
||||
// We aren't actually using ShellInit, so just call init directly
|
||||
mPipTouchHandler.onInit();
|
||||
@@ -162,8 +164,8 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
|
||||
// getting the expected min and max size
|
||||
float aspectRatio = (float) mPipBounds.width() / mPipBounds.height();
|
||||
Size expectedMinSize = mPipSizeSpecHandler.getMinSize(aspectRatio);
|
||||
Size expectedMaxSize = mPipSizeSpecHandler.getMaxSize(aspectRatio);
|
||||
Size expectedMinSize = mSizeSpecSource.getMinSize(aspectRatio);
|
||||
Size expectedMaxSize = mSizeSpecSource.getMaxSize(aspectRatio);
|
||||
|
||||
assertEquals(expectedMovementBounds, mPipBoundsState.getNormalMovementBounds());
|
||||
verify(mPipResizeGestureHandler, times(1))
|
||||
|
||||
@@ -26,9 +26,10 @@ import static org.junit.Assert.assertEquals;
|
||||
import android.view.Gravity;
|
||||
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.common.pip.LegacySizeSpecSource;
|
||||
import com.android.wm.shell.common.pip.SizeSpecSource;
|
||||
import com.android.wm.shell.pip.PipDisplayLayoutState;
|
||||
import com.android.wm.shell.pip.PipSnapAlgorithm;
|
||||
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -47,7 +48,7 @@ public class TvPipGravityTest extends ShellTestCase {
|
||||
|
||||
private TvPipBoundsState mTvPipBoundsState;
|
||||
private TvPipBoundsAlgorithm mTvPipBoundsAlgorithm;
|
||||
private PipSizeSpecHandler mPipSizeSpecHandler;
|
||||
private SizeSpecSource mSizeSpecSource;
|
||||
private PipDisplayLayoutState mPipDisplayLayoutState;
|
||||
|
||||
@Before
|
||||
@@ -57,11 +58,11 @@ public class TvPipGravityTest extends ShellTestCase {
|
||||
}
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
|
||||
mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
|
||||
mTvPipBoundsState = new TvPipBoundsState(mContext, mPipSizeSpecHandler,
|
||||
mSizeSpecSource = new LegacySizeSpecSource(mContext, mPipDisplayLayoutState);
|
||||
mTvPipBoundsState = new TvPipBoundsState(mContext, mSizeSpecSource,
|
||||
mPipDisplayLayoutState);
|
||||
mTvPipBoundsAlgorithm = new TvPipBoundsAlgorithm(mContext, mTvPipBoundsState,
|
||||
mMockPipSnapAlgorithm, mPipSizeSpecHandler);
|
||||
mMockPipSnapAlgorithm, mPipDisplayLayoutState, mSizeSpecSource);
|
||||
|
||||
setRTL(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user