Merge "Check kotlin format before uploading" into tm-qpr-dev am: bdfc07f1f0

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/20883265

Change-Id: I1f211915948bd6112d605dbd6d2a6569838c1585
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Thales Lima
2023-01-10 17:20:23 +00:00
committed by Automerger Merge Worker
27 changed files with 1038 additions and 903 deletions
+2
View File
@@ -1,2 +1,4 @@
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --config_xml tools/checkstyle.xml --sha ${PREUPLOAD_COMMIT}
ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check ${PREUPLOAD_FILES}
@@ -16,20 +16,17 @@
package com.android.launcher3.taskbar
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
import com.android.launcher3.Utilities.mapToRange
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import com.android.launcher3.R
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.anim.Interpolators
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
import com.android.launcher3.util.DisplayController
/**
* Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners.
*/
/** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
val paint: Paint = Paint()
@@ -39,7 +36,7 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
private val transientBackgroundBounds = context.transientTaskbarBounds
private val isTransientTaskbar = DisplayController.isTransientTaskbar(context);
private val isTransientTaskbar = DisplayController.isTransientTaskbar(context)
private var shadowBlur = 0f
private var keyShadowDistance = 0f
@@ -98,9 +95,7 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
invertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE)
}
/**
* Draws the background with the given paint and height, on the provided canvas.
*/
/** Draws the background with the given paint and height, on the provided canvas. */
fun draw(canvas: Canvas) {
canvas.save()
canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
@@ -124,21 +119,26 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f))
// Draw shadow.
val shadowAlpha = mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f,
Interpolators.LINEAR)
paint.setShadowLayer(shadowBlur, 0f, keyShadowDistance,
val shadowAlpha =
mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f, Interpolators.LINEAR)
paint.setShadowLayer(
shadowBlur,
0f,
keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(shadowAlpha))
)
// Draw background.
val radius = backgroundHeight / 2f;
val radius = backgroundHeight / 2f
canvas.drawRoundRect(
transientBackgroundBounds.left + (delta / 2f),
translationYForSwipe,
transientBackgroundBounds.right - (delta / 2f),
backgroundHeight + translationYForSwipe,
radius, radius, paint
radius,
radius,
paint
)
}
@@ -36,10 +36,8 @@ import com.android.launcher3.anim.AlphaUpdateListener
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import java.io.PrintWriter
/**
* Handles the insets that Taskbar provides to underlying apps and the IME.
*/
class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTaskbarController {
/** Handles the insets that Taskbar provides to underlying apps and the IME. */
class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
/** The bottom insets taskbar provides to the IME when IME is visible. */
val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size)
@@ -77,13 +75,19 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
fun onTaskbarWindowHeightOrInsetsChanged() {
val touchableHeight = controllers.taskbarStashController.touchableHeight
touchableRegion.set(0, windowLayoutParams.height - touchableHeight,
context.deviceProfile.widthPx, windowLayoutParams.height)
touchableRegion.set(
0,
windowLayoutParams.height - touchableHeight,
context.deviceProfile.widthPx,
windowLayoutParams.height
)
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
for (provider in windowLayoutParams.providedInsets) {
if (provider.type == ITYPE_EXTRA_NAVIGATION_BAR
|| provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES) {
if (
provider.type == ITYPE_EXTRA_NAVIGATION_BAR ||
provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES
) {
provider.insetsSize = getInsetsByNavMode(contentHeight)
} else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
provider.insetsSize = getInsetsByNavMode(tappableHeight)
@@ -91,24 +95,20 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
}
val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme)
val insetsSizeOverride = arrayOf(
InsetsFrameProvider.InsetsSizeOverride(
TYPE_INPUT_METHOD,
imeInsetsSize
),
)
val insetsSizeOverride =
arrayOf(
InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
)
// Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
val visInsetsSizeForGestureNavTappableElement = getInsetsByNavMode(0)
val insetsSizeOverrideForGestureNavTappableElement = arrayOf(
InsetsFrameProvider.InsetsSizeOverride(
TYPE_INPUT_METHOD,
imeInsetsSize
),
InsetsFrameProvider.InsetsSizeOverride(
TYPE_VOICE_INTERACTION,
visInsetsSizeForGestureNavTappableElement
),
)
val insetsSizeOverrideForGestureNavTappableElement =
arrayOf(
InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
InsetsFrameProvider.InsetsSizeOverride(
TYPE_VOICE_INTERACTION,
visInsetsSizeForGestureNavTappableElement
),
)
for (provider in windowLayoutParams.providedInsets) {
if (context.isGestureNav && provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement
@@ -120,9 +120,11 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
/**
* @return [Insets] where the [bottomInset] is either used as a bottom inset or
* ```
* right/left inset if using 3 button nav
* ```
*/
private fun getInsetsByNavMode(bottomInset: Int) : Insets {
private fun getInsetsByNavMode(bottomInset: Int): Insets {
val devicePortrait = !context.deviceProfile.isLandscape
if (!TaskbarManager.isPhoneButtonNavMode(context) || devicePortrait) {
// Taskbar or portrait phone mode
@@ -139,9 +141,9 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
* @param providesInsetsTypes The inset types we would like this layout params to provide.
*/
fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray) {
params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size);
params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size)
for (i in providesInsetsTypes.indices) {
params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i]);
params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i])
}
}
@@ -153,14 +155,17 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
insetsInfo.touchableRegion.setEmpty()
// Always have nav buttons be touchable
controllers.navbarButtonsViewController.addVisibleButtonsRegion(
context.dragLayer, insetsInfo.touchableRegion
context.dragLayer,
insetsInfo.touchableRegion
)
var insetsIsTouchableRegion = true
if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
} else if (controllers.navbarButtonsViewController.isImeVisible
&& controllers.taskbarStashController.isStashed()) {
} else if (
controllers.navbarButtonsViewController.isImeVisible &&
controllers.taskbarStashController.isStashed()
) {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
} else if (!controllers.uiController.isTaskbarTouchable) {
// Let touches pass through us.
@@ -174,9 +179,10 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
insetsInfo.touchableRegion.set(touchableRegion)
}
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
} else if (controllers.taskbarViewController.areIconsVisible()
|| AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL)
|| context.isNavBarKidsModeActive
} else if (
controllers.taskbarViewController.areIconsVisible() ||
AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL) ||
context.isNavBarKidsModeActive
) {
// Taskbar has some touchable elements, take over the full taskbar area
insetsInfo.setTouchableInsets(
@@ -198,8 +204,12 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
pw.println(prefix + "TaskbarInsetsController:")
pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
for (provider in windowLayoutParams.providedInsets) {
pw.print("$prefix\tprovidedInsets: (type=" + InsetsState.typeToString(provider.type)
+ " insetsSize=" + provider.insetsSize)
pw.print(
"$prefix\tprovidedInsets: (type=" +
InsetsState.typeToString(provider.type) +
" insetsSize=" +
provider.insetsSize
)
if (provider.insetsSizeOverrides != null) {
pw.print(" insetsSizeOverrides={")
for ((i, overrideSize) in provider.insetsSizeOverrides.withIndex()) {
@@ -10,12 +10,9 @@ import java.io.PrintWriter
private const val TASKBAR_ICONS_FADE_DURATION = 300L
private const val STASHED_HANDLE_FADE_DURATION = 180L
/**
* Controls Taskbar behavior while Voice Interaction Window (assistant) is showing.
*/
class VoiceInteractionWindowController(val context: TaskbarActivityContext)
: TaskbarControllers.LoggableTaskbarController,
TaskbarControllers.BackgroundRendererController {
/** Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. */
class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
TaskbarControllers.LoggableTaskbarController, TaskbarControllers.BackgroundRendererController {
private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context)
@@ -37,8 +34,10 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext)
override fun draw(canvas: Canvas) {
super.draw(canvas)
if (this@VoiceInteractionWindowController.context.isGestureNav
&& controllers.taskbarStashController.isInAppAndNotStashed) {
if (
this@VoiceInteractionWindowController.context.isGestureNav &&
controllers.taskbarStashController.isInAppAndNotStashed
) {
taskbarBackgroundRenderer.draw(canvas)
}
}
@@ -46,8 +45,8 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext)
separateWindowForTaskbarBackground.recreateControllers()
separateWindowForTaskbarBackground.setWillNotDraw(false)
separateWindowLayoutParams = context.createDefaultWindowLayoutParams(
TYPE_APPLICATION_OVERLAY)
separateWindowLayoutParams =
context.createDefaultWindowLayoutParams(TYPE_APPLICATION_OVERLAY)
separateWindowLayoutParams.isSystemApplicationOverlay = true
}
@@ -63,14 +62,16 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext)
// Fade out taskbar icons and stashed handle.
val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f
val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha
.get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
.animateToValue(taskbarIconAlpha)
.setDuration(TASKBAR_ICONS_FADE_DURATION)
val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha
.get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
.animateToValue(taskbarIconAlpha)
.setDuration(STASHED_HANDLE_FADE_DURATION)
val fadeTaskbarIcons =
controllers.taskbarViewController.taskbarIconAlpha
.get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
.animateToValue(taskbarIconAlpha)
.setDuration(TASKBAR_ICONS_FADE_DURATION)
val fadeStashedHandle =
controllers.stashedHandleViewController.stashedHandleAlpha
.get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
.animateToValue(taskbarIconAlpha)
.setDuration(STASHED_HANDLE_FADE_DURATION)
fadeTaskbarIcons.start()
fadeStashedHandle.start()
if (skipAnim) {
@@ -83,23 +84,30 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext)
/**
* Either:
*
* Hides the TaskbarDragLayer background and creates a new window to draw just that background.
*
* OR
*
* Removes the temporary window and show the TaskbarDragLayer background again.
*/
private fun moveTaskbarBackgroundToAppropriateLayer(skipAnim: Boolean) {
val taskbarBackgroundOverride = controllers.taskbarDragLayerController
.overrideBackgroundAlpha
val taskbarBackgroundOverride =
controllers.taskbarDragLayerController.overrideBackgroundAlpha
val moveToLowerLayer = isVoiceInteractionWindowVisible
val onWindowsSynchronized = if (moveToLowerLayer) {
// First add the temporary window, then hide the overlapping taskbar background.
context.addWindowView(separateWindowForTaskbarBackground, separateWindowLayoutParams);
{ taskbarBackgroundOverride.updateValue(0f) }
} else {
// First reapply the original taskbar background, then remove the temporary window.
taskbarBackgroundOverride.updateValue(1f);
{ context.removeWindowView(separateWindowForTaskbarBackground) }
}
val onWindowsSynchronized =
if (moveToLowerLayer) {
// First add the temporary window, then hide the overlapping taskbar background.
context.addWindowView(
separateWindowForTaskbarBackground,
separateWindowLayoutParams
);
{ taskbarBackgroundOverride.updateValue(0f) }
} else {
// First reapply the original taskbar background, then remove the temporary window.
taskbarBackgroundOverride.updateValue(1f);
{ context.removeWindowView(separateWindowForTaskbarBackground) }
}
if (skipAnim) {
onWindowsSynchronized()
@@ -121,4 +129,4 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext)
pw.println(prefix + "VoiceInteractionWindowController:")
pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible")
}
}
}
@@ -30,20 +30,17 @@ import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonL
* [navButtonContainer]
*
* @property navButtonContainer ViewGroup that holds the 3 navigation buttons.
* @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME dismiss).
* @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME
* dismiss).
* @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
*/
abstract class AbstractNavButtonLayoutter(
val resources: Resources,
val navButtonContainer: LinearLayout,
protected val endContextualContainer: ViewGroup,
protected val startContextualContainer: ViewGroup
val resources: Resources,
val navButtonContainer: LinearLayout,
protected val endContextualContainer: ViewGroup,
protected val startContextualContainer: ViewGroup
) : NavButtonLayoutter {
protected val homeButton: ImageView = navButtonContainer
.findViewById(R.id.home)
protected val recentsButton: ImageView = navButtonContainer
.findViewById(R.id.recent_apps)
protected val backButton: ImageView = navButtonContainer
.findViewById(R.id.back)
protected val homeButton: ImageView = navButtonContainer.findViewById(R.id.home)
protected val recentsButton: ImageView = navButtonContainer.findViewById(R.id.recent_apps)
protected val backButton: ImageView = navButtonContainer.findViewById(R.id.back)
}
@@ -35,56 +35,47 @@ import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYS
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYSBAR_HOME_KIDS
class KidsNavLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) : AbstractNavButtonLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) :
AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
startContextualContainer
) {
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
val iconSize: Int = resources.getDimensionPixelSize(
DIMEN_TASKBAR_ICON_SIZE_KIDS)
val buttonWidth: Int = resources.getDimensionPixelSize(
DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
val buttonHeight: Int = resources.getDimensionPixelSize(
DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS)
val buttonRadius: Int = resources.getDimensionPixelSize(
DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS)
val iconSize: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_ICON_SIZE_KIDS)
val buttonWidth: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
val buttonHeight: Int =
resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS)
val buttonRadius: Int =
resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS)
val paddingLeft = (buttonWidth - iconSize) / 2
val paddingTop = (buttonHeight - iconSize) / 2
// Update icons
backButton.setImageDrawable(
backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
backButton.setImageDrawable(backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
backButton.scaleType = ImageView.ScaleType.FIT_CENTER
backButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
homeButton.setImageDrawable(
homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
homeButton.setImageDrawable(homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
homeButton.scaleType = ImageView.ScaleType.FIT_CENTER
homeButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
// Home button layout
val homeLayoutparams = LinearLayout.LayoutParams(
buttonWidth,
buttonHeight
)
val homeButtonLeftMargin: Int = resources.getDimensionPixelSize(
DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS)
val homeLayoutparams = LinearLayout.LayoutParams(buttonWidth, buttonHeight)
val homeButtonLeftMargin: Int =
resources.getDimensionPixelSize(DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS)
homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0)
homeButton.layoutParams = homeLayoutparams
// Back button layout
val backLayoutParams = LinearLayout.LayoutParams(
buttonWidth,
buttonHeight
)
val backButtonLeftMargin: Int = resources.getDimensionPixelSize(
DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS)
val backLayoutParams = LinearLayout.LayoutParams(buttonWidth, buttonHeight)
val backButtonLeftMargin: Int =
resources.getDimensionPixelSize(DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS)
backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0)
backButton.layoutParams = backLayoutParams
@@ -106,4 +97,4 @@ class KidsNavLayoutter(
homeButton.onLongClickListener = null
}
}
}
@@ -30,10 +30,9 @@ import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonL
/**
* Select the correct layout for nav buttons
*
* Since layouts are done dynamically for the nav buttons on Taskbar, this
* class returns a corresponding [NavButtonLayoutter] via
* [Companion.getUiLayoutter]
* that can help position the buttons based on the current [DeviceProfile]
* Since layouts are done dynamically for the nav buttons on Taskbar, this class returns a
* corresponding [NavButtonLayoutter] via [Companion.getUiLayoutter] that can help position the
* buttons based on the current [DeviceProfile]
*/
class NavButtonLayoutFactory {
companion object {
@@ -41,11 +40,10 @@ class NavButtonLayoutFactory {
* Get the correct instance of [NavButtonLayoutter]
*
* No layouts supported for configurations where:
* * taskbar isn't showing AND
* * the device is not in [phoneMode]
* OR
* * phone is showing
* * device is using gesture navigation
* * taskbar isn't showing AND
* * the device is not in [phoneMode] OR
* * phone is showing
* * device is using gesture navigation
*
* @param navButtonsView ViewGroup that contains start, end, nav button ViewGroups
* @param isKidsMode no-op when taskbar is hidden/not showing
@@ -53,44 +51,64 @@ class NavButtonLayoutFactory {
* @param phoneMode refers to the device using the taskbar window on phones
* @param isThreeButtonNav are no-ops when taskbar is present/showing
*/
fun getUiLayoutter(deviceProfile: DeviceProfile,
navButtonsView: FrameLayout,
resources: Resources,
isKidsMode: Boolean,
isInSetup: Boolean,
isThreeButtonNav: Boolean,
phoneMode: Boolean):
NavButtonLayoutter {
val navButtonContainer =
navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
fun getUiLayoutter(
deviceProfile: DeviceProfile,
navButtonsView: FrameLayout,
resources: Resources,
isKidsMode: Boolean,
isInSetup: Boolean,
isThreeButtonNav: Boolean,
phoneMode: Boolean
): NavButtonLayoutter {
val navButtonContainer = navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
val endContextualContainer =
navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS)
navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS)
val startContextualContainer =
navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS)
navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS)
val isPhoneNavMode = phoneMode && isThreeButtonNav
return when {
isPhoneNavMode -> {
if (!deviceProfile.isLandscape) {
PhonePortraitNavLayoutter(resources, navButtonContainer,
endContextualContainer, startContextualContainer)
PhonePortraitNavLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
)
} else {
PhoneLandscapeNavLayoutter(resources, navButtonContainer,
endContextualContainer, startContextualContainer)
PhoneLandscapeNavLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
)
}
}
deviceProfile.isTaskbarPresent -> {
return when {
isInSetup -> {
SetupNavLayoutter(resources, navButtonContainer, endContextualContainer,
startContextualContainer)
SetupNavLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
)
}
isKidsMode -> {
KidsNavLayoutter(resources, navButtonContainer, endContextualContainer,
startContextualContainer)
KidsNavLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
)
}
else ->
TaskbarNavLayoutter(resources, navButtonContainer, endContextualContainer,
startContextualContainer)
TaskbarNavLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
)
}
}
else -> error("No layoutter found")
@@ -98,8 +116,8 @@ class NavButtonLayoutFactory {
}
}
/** Lays out and provides access to the home, recents, and back buttons for various mischief */
/** Lays out and provides access to the home, recents, and back buttons for various mischief */
interface NavButtonLayoutter {
fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean)
}
}
}
@@ -28,24 +28,24 @@ import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.util.DimensionUtils
class PhoneLandscapeNavLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) : AbstractNavButtonLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) :
AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
startContextualContainer
) {
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// TODO(b/230395757): Polish pending, this is just to make it usable
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
val endStartMargins =
resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
TaskbarManager.isPhoneMode(dp))
val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
val taskbarDimensions =
DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
navButtonContainer.removeAllViews()
navButtonContainer.orientation = LinearLayout.VERTICAL
@@ -68,7 +68,7 @@ class PhoneLandscapeNavLayoutter(
// Add the spaces in between the nav buttons
val spaceInBetween: Int =
resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
navButtonContainer.children.forEachIndexed { i, navButton ->
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
buttonLayoutParams.weight = 1f
@@ -86,4 +86,4 @@ class PhoneLandscapeNavLayoutter(
}
}
}
}
}
@@ -26,17 +26,24 @@ import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.util.DimensionUtils
class PhonePortraitNavLayoutter(resources: Resources, navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup) :
AbstractNavButtonLayoutter(resources, navBarContainer, endContextualContainer,
startContextualContainer) {
class PhonePortraitNavLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) :
AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
startContextualContainer
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// TODO(b/230395757): Polish pending, this is just to make it usable
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
TaskbarManager.isPhoneMode(dp))
val taskbarDimensions =
DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
navContainerParams.width = taskbarDimensions.x
navContainerParams.height = ViewGroup.LayoutParams.MATCH_PARENT
@@ -58,7 +65,7 @@ class PhonePortraitNavLayoutter(resources: Resources, navBarContainer: LinearLay
// Add the spaces in between the nav buttons
val spaceInBetween =
resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
for (i in 0 until navButtonContainer.childCount) {
val navButton = navButtonContainer.getChildAt(i)
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
@@ -80,4 +87,4 @@ class PhonePortraitNavLayoutter(resources: Resources, navBarContainer: LinearLay
}
}
}
}
}
@@ -24,16 +24,17 @@ import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
class SetupNavLayoutter(
resources: Resources,
navButtonContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) : AbstractNavButtonLayoutter(
resources: Resources,
navButtonContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) :
AbstractNavButtonLayoutter(
resources,
navButtonContainer,
endContextualContainer,
startContextualContainer
) {
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// Since setup wizard only has back button enabled, it looks strange to be
@@ -46,4 +47,4 @@ class SetupNavLayoutter(
}
navButtonContainer.requestLayout()
}
}
}
@@ -24,20 +24,19 @@ import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
/**
* Layoutter for showing 3 button navigation on large screen
*/
/** Layoutter for showing 3 button navigation on large screen */
class TaskbarNavLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) : AbstractNavButtonLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup
) :
AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
startContextualContainer
) {
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
// Add spacing after the end of the last nav button
@@ -80,4 +79,4 @@ class TaskbarNavLayoutter(
}
}
}
}
}
@@ -20,15 +20,14 @@ import com.android.internal.logging.InstanceIdSequence
import com.android.launcher3.logging.InstanceId
object LogUtils {
/**
* @return a [Pair] of two InstanceIds but with different types, one that can be used by framework
* (if needing to pass through an intent or such) and one used in Launcher
*/
@JvmStatic
fun getShellShareableInstanceId():
Pair<com.android.internal.logging.InstanceId, InstanceId> {
val internalInstanceId = InstanceIdSequence(InstanceId.INSTANCE_ID_MAX).newInstanceId()
val launcherInstanceId = InstanceId(internalInstanceId.id)
return Pair(internalInstanceId, launcherInstanceId)
}
/**
* @return a [Pair] of two InstanceIds but with different types, one that can be used by
* framework (if needing to pass through an intent or such) and one used in Launcher
*/
@JvmStatic
fun getShellShareableInstanceId(): Pair<com.android.internal.logging.InstanceId, InstanceId> {
val internalInstanceId = InstanceIdSequence(InstanceId.INSTANCE_ID_MAX).newInstanceId()
val launcherInstanceId = InstanceId(internalInstanceId.id)
return Pair(internalInstanceId, launcherInstanceId)
}
}
@@ -48,13 +48,15 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
taskContainer: TaskIdAttributeContainer,
alignSecondRow: Boolean = false
): Boolean {
val activity = BaseDraggingActivity
.fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
val taskMenuViewWithArrow = activity.layoutInflater
.inflate(
R.layout.task_menu_with_arrow,
activity.dragLayer,
false
val activity =
BaseDraggingActivity.fromContext<BaseDraggingActivity>(
taskContainer.taskView.context
)
val taskMenuViewWithArrow =
activity.layoutInflater.inflate(
R.layout.task_menu_with_arrow,
activity.dragLayer,
false
) as TaskMenuViewWithArrow<*>
return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignSecondRow)
@@ -63,11 +65,11 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
constructor(
context: Context,
attrs: AttributeSet,
defStyleAttr: Int
) : super(context, attrs, defStyleAttr)
init {
clipToOutline = true
@@ -91,10 +93,10 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
private var optionMeasuredHeight = 0
private val arrowHorizontalPadding: Int
get() = if (taskView.isFocusedTask)
resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
else
0
get() =
if (taskView.isFocusedTask)
resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
else 0
private var iconView: IconView? = null
private var scrim: View? = null
@@ -139,19 +141,20 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
}
private fun addScrim() {
scrim = View(context).apply {
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
alpha = 0f
}
scrim =
View(context).apply {
layoutParams =
FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
alpha = 0f
}
popupContainer.addView(scrim)
}
/** @return true if successfully able to populate task view menu, false otherwise
*/
/** @return true if successfully able to populate task view menu, false otherwise */
private fun populateMenu(): Boolean {
// Icon may not be loaded
if (taskContainer.task.icon == null) return false
@@ -162,9 +165,9 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
private fun addMenuOptions() {
// Add the options
TaskOverlayFactory
.getEnabledShortcuts(taskView, taskContainer)
.forEach { this.addMenuOption(it) }
TaskOverlayFactory.getEnabledShortcuts(taskView, taskContainer).forEach {
this.addMenuOption(it)
}
// Add the spaces between items
val divider = ShapeDrawable(RectShape())
@@ -185,9 +188,9 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
}
private fun addMenuOption(menuOption: SystemShortcut<*>) {
val menuOptionView = mActivityContext.layoutInflater.inflate(
R.layout.task_view_menu_option, this, false
) as LinearLayout
val menuOptionView =
mActivityContext.layoutInflater.inflate(R.layout.task_view_menu_option, this, false)
as LinearLayout
menuOption.setIconAndLabelFor(
menuOptionView.findViewById(R.id.icon),
menuOptionView.findViewById(R.id.text)
@@ -230,24 +233,25 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
}
/**
* Copy the iconView from taskView to dragLayer so it can stay on top of the scrim.
* It needs to be called after [getTargetObjectLocation] because [mTempRect] needs to be
* populated.
* Copy the iconView from taskView to dragLayer so it can stay on top of the scrim. It needs to
* be called after [getTargetObjectLocation] because [mTempRect] needs to be populated.
*/
private fun copyIconToDragLayer(insets: Rect) {
iconView = IconView(context).apply {
layoutParams = FrameLayout.LayoutParams(
taskContainer.iconView.width,
taskContainer.iconView.height
)
x = mTempRect.left.toFloat() - insets.left
y = mTempRect.top.toFloat() - insets.top
drawable = taskContainer.iconView.drawable
setDrawableSize(
taskContainer.iconView.drawableWidth,
taskContainer.iconView.drawableHeight
)
}
iconView =
IconView(context).apply {
layoutParams =
FrameLayout.LayoutParams(
taskContainer.iconView.width,
taskContainer.iconView.height
)
x = mTempRect.left.toFloat() - insets.left
y = mTempRect.top.toFloat() - insets.top
drawable = taskContainer.iconView.drawable
setDrawableSize(
taskContainer.iconView.drawableWidth,
taskContainer.iconView.drawableHeight
)
}
popupContainer.addView(iconView)
}
@@ -281,12 +285,13 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
// which means the arrow is left aligned with the menu
val rightAlignedMenuStartX = mTempRect.left - widthWithArrow
val leftAlignedMenuStartX = mTempRect.right + extraHorizontalSpace
mIsLeftAligned = if (mIsRtl) {
rightAlignedMenuStartX + insets.left < 0
} else {
leftAlignedMenuStartX + (widthWithArrow - extraHorizontalSpace) + insets.left <
mIsLeftAligned =
if (mIsRtl) {
rightAlignedMenuStartX + insets.left < 0
} else {
leftAlignedMenuStartX + (widthWithArrow - extraHorizontalSpace) + insets.left <
dragLayer.width - insets.right
}
}
var menuStartX = if (mIsLeftAligned) leftAlignedMenuStartX else rightAlignedMenuStartX
@@ -311,8 +316,8 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
override fun addArrow() {
popupContainer.addView(mArrow)
mArrow.x = getArrowX()
mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) +
extraSpaceForSecondRowAlignment
mArrow.y =
y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) + extraSpaceForSecondRowAlignment
updateArrowColor()
@@ -322,22 +327,19 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
}
private fun getArrowX(): Float {
return if (mIsLeftAligned)
x - mArrowHeight
else
x + measuredWidth + mArrowOffsetVertical
return if (mIsLeftAligned) x - mArrowHeight else x + measuredWidth + mArrowOffsetVertical
}
override fun updateArrowColor() {
mArrow.background = RoundedArrowDrawable(
mArrowWidth.toFloat(),
mArrowHeight.toFloat(),
mArrowPointRadius.toFloat(),
mIsLeftAligned,
mArrowColor
)
mArrow.background =
RoundedArrowDrawable(
mArrowWidth.toFloat(),
mArrowHeight.toFloat(),
mArrowPointRadius.toFloat(),
mIsLeftAligned,
mArrowColor
)
elevation = mElevation
mArrow.elevation = mElevation
}
}
}
@@ -8,38 +8,29 @@ import android.widget.ImageView
import android.widget.LinearLayout
import androidx.test.runner.AndroidJUnit4
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarManager
import java.lang.IllegalStateException
import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import com.android.launcher3.R
import org.junit.Assume.assumeTrue
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
import java.lang.IllegalStateException
@RunWith(AndroidJUnit4::class)
class NavButtonLayoutFactoryTest {
@Mock
lateinit var mockDeviceProfile: DeviceProfile
@Mock
lateinit var mockParentButtonContainer: FrameLayout
@Mock
lateinit var mockNavLayout: LinearLayout
@Mock
lateinit var mockStartContextualLayout: ViewGroup
@Mock
lateinit var mockEndContextualLayout: ViewGroup
@Mock
lateinit var mockResources: Resources
@Mock
lateinit var mockBackButton: ImageView
@Mock
lateinit var mockRecentsButton: ImageView
@Mock
lateinit var mockHomeButton: ImageView
@Mock lateinit var mockDeviceProfile: DeviceProfile
@Mock lateinit var mockParentButtonContainer: FrameLayout
@Mock lateinit var mockNavLayout: LinearLayout
@Mock lateinit var mockStartContextualLayout: ViewGroup
@Mock lateinit var mockEndContextualLayout: ViewGroup
@Mock lateinit var mockResources: Resources
@Mock lateinit var mockBackButton: ImageView
@Mock lateinit var mockRecentsButton: ImageView
@Mock lateinit var mockHomeButton: ImageView
@Before
fun setup() {
@@ -53,11 +44,11 @@ class NavButtonLayoutFactoryTest {
// Init top level layout
whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
.thenReturn(mockNavLayout)
.thenReturn(mockNavLayout)
whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
.thenReturn(mockEndContextualLayout)
.thenReturn(mockEndContextualLayout)
whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
.thenReturn(mockStartContextualLayout)
.thenReturn(mockStartContextualLayout)
}
@Test
@@ -65,8 +56,12 @@ class NavButtonLayoutFactoryTest {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(isKidsMode = true, isInSetup = false, isThreeButtonNav = false,
phoneMode = false)
getLayoutter(
isKidsMode = true,
isInSetup = false,
isThreeButtonNav = false,
phoneMode = false
)
assert(layoutter is KidsNavLayoutter)
}
@@ -75,8 +70,12 @@ class NavButtonLayoutFactoryTest {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(isKidsMode = false, isInSetup = true, isThreeButtonNav = false,
phoneMode = false)
getLayoutter(
isKidsMode = false,
isInSetup = true,
isThreeButtonNav = false,
phoneMode = false
)
assert(layoutter is SetupNavLayoutter)
}
@@ -85,8 +84,12 @@ class NavButtonLayoutFactoryTest {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
phoneMode = false)
getLayoutter(
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = false,
phoneMode = false
)
assert(layoutter is TaskbarNavLayoutter)
}
@@ -94,8 +97,12 @@ class NavButtonLayoutFactoryTest {
fun noValidLayoutForLargeScreenTaskbarNotPresent() {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = false
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
phoneMode = false)
getLayoutter(
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = false,
phoneMode = false
)
}
@Test
@@ -103,8 +110,12 @@ class NavButtonLayoutFactoryTest {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = false
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
phoneMode = true)
getLayoutter(
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = true,
phoneMode = true
)
assert(layoutter is PhonePortraitNavLayoutter)
}
@@ -114,8 +125,12 @@ class NavButtonLayoutFactoryTest {
mockDeviceProfile.isTaskbarPresent = false
setDeviceProfileLandscape()
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
phoneMode = true)
getLayoutter(
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = true,
phoneMode = true
)
assert(layoutter is PhoneLandscapeNavLayoutter)
}
@@ -123,8 +138,12 @@ class NavButtonLayoutFactoryTest {
fun noValidLayoutForPhoneGestureNav() {
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
mockDeviceProfile.isTaskbarPresent = false
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
phoneMode = true)
getLayoutter(
isKidsMode = false,
isInSetup = false,
isThreeButtonNav = false,
phoneMode = true
)
}
private fun setDeviceProfileLandscape() {
@@ -134,15 +153,20 @@ class NavButtonLayoutFactoryTest {
landscapeField.set(mockDeviceProfile, true)
}
private fun getLayoutter(isKidsMode: Boolean, isInSetup: Boolean,
isThreeButtonNav: Boolean, phoneMode: Boolean):
NavButtonLayoutFactory.NavButtonLayoutter {
private fun getLayoutter(
isKidsMode: Boolean,
isInSetup: Boolean,
isThreeButtonNav: Boolean,
phoneMode: Boolean
): NavButtonLayoutFactory.NavButtonLayoutter {
return NavButtonLayoutFactory.getUiLayoutter(
deviceProfile = mockDeviceProfile,
navButtonsView = mockParentButtonContainer,
resources = mockResources,
isKidsMode = isKidsMode, isInSetup = isInSetup,
isThreeButtonNav = isThreeButtonNav, phoneMode = phoneMode
deviceProfile = mockDeviceProfile,
navButtonsView = mockParentButtonContainer,
resources = mockResources,
isKidsMode = isKidsMode,
isInSetup = isInSetup,
isThreeButtonNav = isThreeButtonNav,
phoneMode = phoneMode
)
}
}
}
@@ -27,15 +27,13 @@ import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
import com.android.wm.shell.util.SplitBounds
import com.google.common.truth.Truth.assertThat
import kotlin.math.roundToInt
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import kotlin.math.roundToInt
/**
* Test for FullscreenDrawParams class.
*/
/** Test for FullscreenDrawParams class. */
@SmallTest
@RunWith(AndroidJUnit4::class)
class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
@@ -61,15 +59,29 @@ class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
val currentRotation = 0
val isRtl = false
mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
isRtl)
params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
mPreviewPositionHelper.updateThumbnailMatrix(
previewRect,
mThumbnailData,
canvasWidth,
canvasHeight,
dp.widthPx,
dp.heightPx,
dp.taskbarSize,
dp.isTablet,
currentRotation,
isRtl
)
params.setProgress(
/* fullscreenProgress= */ 1.0f,
/* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f,
/* previewWidth= */ 0,
dp,
mPreviewPositionHelper
)
val expectedClippedInsets = RectF(0f, 0f, 0f, dp.taskbarSize * TASK_SCALE)
assertThat(params.mCurrentDrawnInsets)
.isEqualTo(expectedClippedInsets)
assertThat(params.mCurrentDrawnInsets).isEqualTo(expectedClippedInsets)
}
@Test
@@ -83,25 +95,42 @@ class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
val isRtl = false
// portrait/vertical split apps
val dividerSize = 10
val splitBounds = SplitBounds(
val splitBounds =
SplitBounds(
Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2),
Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx),
0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
0 /*lefTopTaskId*/,
0 /*rightBottomTaskId*/
)
mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT)
mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
isRtl)
params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
mPreviewPositionHelper.updateThumbnailMatrix(
previewRect,
mThumbnailData,
canvasWidth,
canvasHeight,
dp.widthPx,
dp.heightPx,
dp.taskbarSize,
dp.isTablet,
currentRotation,
isRtl
)
params.setProgress(
/* fullscreenProgress= */ 1.0f,
/* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f,
/* previewWidth= */ 0,
dp,
mPreviewPositionHelper
)
// Probably unhelpful, but also unclear how to test otherwise ¯\_(ツ)_/¯
val fullscreenTaskHeight = dp.heightPx *
(1 - (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent))
val fullscreenTaskHeight =
dp.heightPx * (1 - (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent))
val canvasScreenRatio = canvasHeight / fullscreenTaskHeight
val expectedBottomHint = dp.taskbarSize * canvasScreenRatio
assertThat(params.mCurrentDrawnInsets.bottom)
.isWithin(1f).of(expectedBottomHint)
assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of(expectedBottomHint)
}
@Test
@@ -115,20 +144,37 @@ class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
val isRtl = false
// portrait/vertical split apps
val dividerSize = 10
val splitBounds = SplitBounds(
val splitBounds =
SplitBounds(
Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2),
Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx),
0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
0 /*lefTopTaskId*/,
0 /*rightBottomTaskId*/
)
mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_TOP_OR_LEFT)
mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
isRtl)
params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
mPreviewPositionHelper.updateThumbnailMatrix(
previewRect,
mThumbnailData,
canvasWidth,
canvasHeight,
dp.widthPx,
dp.heightPx,
dp.taskbarSize,
dp.isTablet,
currentRotation,
isRtl
)
params.setProgress(
/* fullscreenProgress= */ 1.0f,
/* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f,
/* previewWidth= */ 0,
dp,
mPreviewPositionHelper
)
assertThat(params.mCurrentDrawnInsets.bottom)
.isWithin(1f).of((0f))
assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of((0f))
}
@Test
@@ -142,20 +188,37 @@ class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
val isRtl = false
// portrait/vertical split apps
val dividerSize = 10
val splitBounds = SplitBounds(
val splitBounds =
SplitBounds(
Rect(0, 0, (dp.widthPx - dividerSize) / 2, dp.heightPx),
Rect((dp.widthPx + dividerSize) / 2, 0, dp.widthPx, dp.heightPx),
0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
0 /*lefTopTaskId*/,
0 /*rightBottomTaskId*/
)
mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT)
mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
isRtl)
params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
mPreviewPositionHelper.updateThumbnailMatrix(
previewRect,
mThumbnailData,
canvasWidth,
canvasHeight,
dp.widthPx,
dp.heightPx,
dp.taskbarSize,
dp.isTablet,
currentRotation,
isRtl
)
params.setProgress(
/* fullscreenProgress= */ 1.0f,
/* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f,
/* previewWidth= */ 0,
dp,
mPreviewPositionHelper
)
assertThat(params.mCurrentDrawnInsets.bottom)
.isWithin(1f).of((dp.taskbarSize * TASK_SCALE))
assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of((dp.taskbarSize * TASK_SCALE))
}
@Test
@@ -168,14 +231,28 @@ class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
val currentRotation = 0
val isRtl = false
mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
isRtl)
params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
mPreviewPositionHelper.updateThumbnailMatrix(
previewRect,
mThumbnailData,
canvasWidth,
canvasHeight,
dp.widthPx,
dp.heightPx,
dp.taskbarSize,
dp.isTablet,
currentRotation,
isRtl
)
params.setProgress(
/* fullscreenProgress= */ 1.0f,
/* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f,
/* previewWidth= */ 0,
dp,
mPreviewPositionHelper
)
val expectedClippedInsets = RectF(0f, 0f, 0f, 0f)
assertThat(params.mCurrentDrawnInsets)
.isEqualTo(expectedClippedInsets)
assertThat(params.mCurrentDrawnInsets).isEqualTo(expectedClippedInsets)
}
}
}
@@ -29,8 +29,8 @@ import org.junit.runner.RunWith
class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
/**
* This is a case when after setting the hotseat, the space needs to be recalculated
* but it doesn't need to change QSB width or remove icons
* This is a case when after setting the hotseat, the space needs to be recalculated but it
* doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_portrait() {
@@ -51,8 +51,8 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
}
/**
* This is a case when after setting the hotseat, and recalculating spaces
* it still needs to remove icons for everything to fit
* This is a case when after setting the hotseat, and recalculating spaces it still needs to
* remove icons for everything to fit
*/
@Test
fun decrease_num_of_icons_when_not_enough_space_portrait() {
@@ -73,8 +73,8 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
}
/**
* This is a case when after setting the hotseat, the space needs to be recalculated
* but it doesn't need to change QSB width or remove icons
* This is a case when after setting the hotseat, the space needs to be recalculated but it
* doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_landscape() {
@@ -94,8 +94,8 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
}
/**
* This is a case when the hotseat spans a certain amount of columns
* and the nav buttons push the hotseat to the side, but not enough to change the border space.
* This is a case when the hotseat spans a certain amount of columns and the nav buttons push
* the hotseat to the side, but not enough to change the border space.
*/
@Test
fun nav_buttons_dont_interfere_with_required_hotseat_width() {
@@ -118,9 +118,7 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
assertThat(dp.hotseatQsbWidth).isEqualTo(1233)
}
/**
* This is a case when after setting the hotseat, the QSB width needs to be changed to fit
*/
/** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@Test
fun decrease_qsb_when_not_enough_space_landscape() {
initializeVarsForTablet(isGestureMode = false, isLandscape = true)
+8 -3
View File
@@ -9,12 +9,17 @@ object LauncherPrefs {
fun getPrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so that we use a single cached instance
return context.applicationContext.getSharedPreferences(
LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
LauncherFiles.SHARED_PREFERENCES_KEY,
Context.MODE_PRIVATE
)
}
@JvmStatic
fun getDevicePrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so that we use a single cached instance
return context.applicationContext.getSharedPreferences(
LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE)
}}
LauncherFiles.DEVICE_PREFERENCES_KEY,
Context.MODE_PRIVATE
)
}
}
@@ -24,12 +24,15 @@ import com.android.launcher3.R
object DimensionUtils {
/**
* Point where x is width, and y is height of taskbar based on provided [deviceProfile]
* x or y could also be -1 to indicate there is no dimension specified
* Point where x is width, and y is height of taskbar based on provided [deviceProfile] x or y
* could also be -1 to indicate there is no dimension specified
*/
@JvmStatic
fun getTaskbarPhoneDimensions(deviceProfile: DeviceProfile, res: Resources,
isPhoneMode: Boolean): Point {
fun getTaskbarPhoneDimensions(
deviceProfile: DeviceProfile,
res: Resources,
isPhoneMode: Boolean
): Point {
val p = Point()
// Taskbar for large screen
if (!isPhoneMode) {
@@ -57,4 +60,4 @@ object DimensionUtils {
p.y = ViewGroup.LayoutParams.MATCH_PARENT
return p
}
}
}
@@ -23,11 +23,11 @@ import androidx.test.core.app.ApplicationProvider
import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER
import com.android.launcher3.util.DisplayController.Info
import com.android.launcher3.util.WindowBounds
import java.io.PrintWriter
import java.io.StringWriter
import org.junit.Before
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.mock
import java.io.PrintWriter
import java.io.StringWriter
import org.mockito.Mockito.`when` as whenever
abstract class DeviceProfileBaseTest {
@@ -49,31 +49,36 @@ abstract class DeviceProfileBaseTest {
isGestureMode = true
}
protected fun newDP(): DeviceProfile = DeviceProfile(
context,
inv,
info,
windowBounds,
SparseArray(),
isMultiWindowMode,
transposeLayoutWithOrientation,
useTwoPanels,
isGestureMode,
DEFAULT_PROVIDER
)
protected fun newDP(): DeviceProfile =
DeviceProfile(
context,
inv,
info,
windowBounds,
SparseArray(),
isMultiWindowMode,
transposeLayoutWithOrientation,
useTwoPanels,
isGestureMode,
DEFAULT_PROVIDER
)
protected fun initializeVarsForPhone(isGestureMode: Boolean = true,
isVerticalBar: Boolean = false) {
val (x, y) = if (isVerticalBar)
Pair(2400, 1080)
else
Pair(1080, 2400)
protected fun initializeVarsForPhone(
isGestureMode: Boolean = true,
isVerticalBar: Boolean = false
) {
val (x, y) = if (isVerticalBar) Pair(2400, 1080) else Pair(1080, 2400)
windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(
if (isVerticalBar) 118 else 0,
if (isVerticalBar) 74 else 118,
if (!isGestureMode && isVerticalBar) 126 else 0,
if (isGestureMode) 63 else if (isVerticalBar) 0 else 126))
windowBounds =
WindowBounds(
Rect(0, 0, x, y),
Rect(
if (isVerticalBar) 118 else 0,
if (isVerticalBar) 74 else 118,
if (!isGestureMode && isVerticalBar) 126 else 0,
if (isGestureMode) 63 else if (isVerticalBar) 0 else 126
)
)
whenever(info.isTablet(any())).thenReturn(false)
whenever(info.getDensityDpi()).thenReturn(420)
@@ -82,79 +87,76 @@ abstract class DeviceProfileBaseTest {
this.isGestureMode = isGestureMode
transposeLayoutWithOrientation = true
inv = InvariantDeviceProfile().apply {
numRows = 5
numColumns = 4
numSearchContainerColumns = 4
inv =
InvariantDeviceProfile().apply {
numRows = 5
numColumns = 4
numSearchContainerColumns = 4
iconSize = floatArrayOf(60f, 54f, 60f, 60f)
iconTextSize = FloatArray(4) { 14f }
deviceType = InvariantDeviceProfile.TYPE_PHONE
iconSize = floatArrayOf(60f, 54f, 60f, 60f)
iconTextSize = FloatArray(4) { 14f }
deviceType = InvariantDeviceProfile.TYPE_PHONE
minCellSize = listOf(
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f)
).toTypedArray()
minCellSize =
listOf(
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f)
)
.toTypedArray()
borderSpaces = listOf(
PointF(16f, 16f),
PointF(16f, 16f),
PointF(16f, 16f),
PointF(16f, 16f)
).toTypedArray()
borderSpaces =
listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
.toTypedArray()
numFolderRows = 3
numFolderColumns = 3
folderStyle = R.style.FolderDefaultStyle
numFolderRows = 3
numFolderColumns = 3
folderStyle = R.style.FolderDefaultStyle
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
horizontalMargin = FloatArray(4) { 22f }
horizontalMargin = FloatArray(4) { 22f }
allAppsCellSize = listOf(
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f)
).toTypedArray()
allAppsIconSize = floatArrayOf(60f, 60f, 60f, 60f)
allAppsIconTextSize = FloatArray(4) { 14f }
allAppsBorderSpaces = listOf(
PointF(16f, 16f),
PointF(16f, 16f),
PointF(16f, 16f),
PointF(16f, 16f)
).toTypedArray()
allAppsCellSize =
listOf(
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f)
)
.toTypedArray()
allAppsIconSize = floatArrayOf(60f, 60f, 60f, 60f)
allAppsIconTextSize = FloatArray(4) { 14f }
allAppsBorderSpaces =
listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
.toTypedArray()
numShownHotseatIcons = 4
numShownHotseatIcons = 4
numDatabaseHotseatIcons = 4
numDatabaseHotseatIcons = 4
hotseatColumnSpan = IntArray(4) { 4 }
hotseatBarBottomSpace = FloatArray(4) { 48f }
hotseatQsbSpace = FloatArray(4) { 36f }
hotseatColumnSpan = IntArray(4) { 4 }
hotseatBarBottomSpace = FloatArray(4) { 48f }
hotseatQsbSpace = FloatArray(4) { 36f }
numAllAppsColumns = 4
numAllAppsColumns = 4
isScalable = true
isScalable = true
inlineQsb = BooleanArray(4) { false }
inlineQsb = BooleanArray(4) { false }
devicePaddingId = R.xml.paddings_handhelds
}
devicePaddingId = R.xml.paddings_handhelds
}
}
protected fun initializeVarsForTablet(isLandscape: Boolean = false,
isGestureMode: Boolean = true) {
val (x, y) = if (isLandscape)
Pair(2560, 1600)
else
Pair(1600, 2560)
protected fun initializeVarsForTablet(
isLandscape: Boolean = false,
isGestureMode: Boolean = true
) {
val (x, y) = if (isLandscape) Pair(2560, 1600) else Pair(1600, 2560)
windowBounds =
WindowBounds(Rect(0, 0, x, y), Rect(0, 104, 0, 0))
windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(0, 104, 0, 0))
whenever(info.isTablet(any())).thenReturn(true)
whenever(info.getDensityDpi()).thenReturn(320)
@@ -163,85 +165,77 @@ abstract class DeviceProfileBaseTest {
this.isGestureMode = isGestureMode
useTwoPanels = false
inv = InvariantDeviceProfile().apply {
numRows = 5
numColumns = 6
numSearchContainerColumns = 3
inv =
InvariantDeviceProfile().apply {
numRows = 5
numColumns = 6
numSearchContainerColumns = 3
iconSize = FloatArray(4) { 60f }
iconTextSize = FloatArray(4) { 14f }
deviceType = InvariantDeviceProfile.TYPE_TABLET
iconSize = FloatArray(4) { 60f }
iconTextSize = FloatArray(4) { 14f }
deviceType = InvariantDeviceProfile.TYPE_TABLET
minCellSize = listOf(
PointF(102f, 120f),
PointF(120f, 104f),
PointF(102f, 120f),
PointF(102f, 120f)
).toTypedArray()
minCellSize =
listOf(
PointF(102f, 120f),
PointF(120f, 104f),
PointF(102f, 120f),
PointF(102f, 120f)
)
.toTypedArray()
borderSpaces = listOf(
PointF(16f, 64f),
PointF(64f, 16f),
PointF(16f, 64f),
PointF(16f, 64f)
).toTypedArray()
borderSpaces =
listOf(PointF(16f, 64f), PointF(64f, 16f), PointF(16f, 64f), PointF(16f, 64f))
.toTypedArray()
numFolderRows = 3
numFolderColumns = 3
folderStyle = R.style.FolderDefaultStyle
numFolderRows = 3
numFolderColumns = 3
folderStyle = R.style.FolderDefaultStyle
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f)
horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f)
allAppsCellSize = listOf(
PointF(96f, 142f),
PointF(126f, 126f),
PointF(96f, 142f),
PointF(96f, 142f)
).toTypedArray()
allAppsIconSize = FloatArray(4) { 60f }
allAppsIconTextSize = FloatArray(4) { 14f }
allAppsBorderSpaces = listOf(
PointF(8f, 16f),
PointF(16f, 16f),
PointF(8f, 16f),
PointF(8f, 16f)
).toTypedArray()
allAppsCellSize =
listOf(
PointF(96f, 142f),
PointF(126f, 126f),
PointF(96f, 142f),
PointF(96f, 142f)
)
.toTypedArray()
allAppsIconSize = FloatArray(4) { 60f }
allAppsIconTextSize = FloatArray(4) { 14f }
allAppsBorderSpaces =
listOf(PointF(8f, 16f), PointF(16f, 16f), PointF(8f, 16f), PointF(8f, 16f))
.toTypedArray()
numShownHotseatIcons = 6
numShownHotseatIcons = 6
numDatabaseHotseatIcons = 6
numDatabaseHotseatIcons = 6
hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
hotseatQsbSpace = FloatArray(4) { 32f }
hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
hotseatQsbSpace = FloatArray(4) { 32f }
numAllAppsColumns = 6
numAllAppsColumns = 6
isScalable = true
devicePaddingId = R.xml.paddings_6x5
isScalable = true
devicePaddingId = R.xml.paddings_6x5
inlineQsb = booleanArrayOf(
false,
true,
false,
false
)
inlineQsb = booleanArrayOf(false, true, false, false)
devicePaddingId = R.xml.paddings_handhelds
}
devicePaddingId = R.xml.paddings_handhelds
}
}
protected fun initializeVarsForTwoPanel(isLandscape: Boolean = false,
isGestureMode: Boolean = true) {
val (x, y) = if (isLandscape)
Pair(2208, 1840)
else
Pair(1840, 2208)
protected fun initializeVarsForTwoPanel(
isLandscape: Boolean = false,
isGestureMode: Boolean = true
) {
val (x, y) = if (isLandscape) Pair(2208, 1840) else Pair(1840, 2208)
windowBounds = WindowBounds(Rect(0, 0, x, y),
Rect(0, 110, 0, 0))
windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(0, 110, 0, 0))
whenever(info.isTablet(any())).thenReturn(true)
whenever(info.getDensityDpi()).thenReturn(420)
@@ -250,74 +244,63 @@ abstract class DeviceProfileBaseTest {
this.isGestureMode = isGestureMode
useTwoPanels = true
inv = InvariantDeviceProfile().apply {
numRows = 4
numColumns = 4
numSearchContainerColumns = 4
inv =
InvariantDeviceProfile().apply {
numRows = 4
numColumns = 4
numSearchContainerColumns = 4
iconSize = floatArrayOf(60f, 52f, 52f, 60f)
iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
deviceType = InvariantDeviceProfile.TYPE_MULTI_DISPLAY
iconSize = floatArrayOf(60f, 52f, 52f, 60f)
iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
deviceType = InvariantDeviceProfile.TYPE_MULTI_DISPLAY
minCellSize = listOf(
PointF(80f, 104f),
PointF(80f, 104f),
PointF(68f, 116f),
PointF(80f, 102f)
).toTypedArray()
minCellSize =
listOf(
PointF(80f, 104f),
PointF(80f, 104f),
PointF(68f, 116f),
PointF(80f, 102f)
)
.toTypedArray()
borderSpaces = listOf(
PointF(16f, 16f),
PointF(16f, 16f),
PointF(16f, 20f),
PointF(20f, 20f)
).toTypedArray()
borderSpaces =
listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 20f), PointF(20f, 20f))
.toTypedArray()
numFolderRows = 3
numFolderColumns = 3
folderStyle = R.style.FolderDefaultStyle
numFolderRows = 3
numFolderColumns = 3
folderStyle = R.style.FolderDefaultStyle
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f)
horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f)
allAppsCellSize = listOf(
PointF(0f, 0f),
PointF(0f, 0f),
PointF(68f, 104f),
PointF(80f, 104f)
).toTypedArray()
allAppsIconSize = floatArrayOf(60f, 60f, 52f, 60f)
allAppsIconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
allAppsBorderSpaces = listOf(
PointF(16f, 16f),
PointF(16f, 16f),
PointF(16f, 28f),
PointF(20f, 16f)
).toTypedArray()
allAppsCellSize =
listOf(PointF(0f, 0f), PointF(0f, 0f), PointF(68f, 104f), PointF(80f, 104f))
.toTypedArray()
allAppsIconSize = floatArrayOf(60f, 60f, 52f, 60f)
allAppsIconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
allAppsBorderSpaces =
listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 28f), PointF(20f, 16f))
.toTypedArray()
numShownHotseatIcons = 6
numShownHotseatIcons = 6
numDatabaseHotseatIcons = 6
numDatabaseHotseatIcons = 6
hotseatColumnSpan = IntArray(4) { 6 }
hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
hotseatColumnSpan = IntArray(4) { 6 }
hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
numAllAppsColumns = 6
numDatabaseAllAppsColumns = 6
numAllAppsColumns = 6
numDatabaseAllAppsColumns = 6
isScalable = true
isScalable = true
inlineQsb = booleanArrayOf(
false,
false,
false,
false
)
inlineQsb = booleanArrayOf(false, false, false, false)
devicePaddingId = R.xml.paddings_handhelds
}
devicePaddingId = R.xml.paddings_handhelds
}
}
fun dump(dp: DeviceProfile): String {
@@ -327,4 +310,4 @@ abstract class DeviceProfileBaseTest {
printWriter.flush()
return stringWriter.toString()
}
}
}
@@ -30,9 +30,7 @@ import com.android.launcher3.util.IntSparseArrayMap
import com.android.launcher3.util.LauncherModelHelper
import java.util.UUID
/**
* Base class for workspace related tests.
*/
/** Base class for workspace related tests. */
abstract class AbstractWorkspaceModelTest {
companion object {
val emptyScreenSpaces = listOf(Rect(0, 0, 5, 5))
@@ -64,10 +62,7 @@ abstract class AbstractWorkspaceModelTest {
mModelHelper.destroy()
}
/**
* Sets up workspaces with the given screen IDs with some items and a 2x2 space.
*/
/** Sets up workspaces with the given screen IDs with some items and a 2x2 space. */
fun setupWorkspaces(screenIdsWithItems: List<Int>) {
var nextItemId = 1
screenIdsWithItems.forEach { screenId ->
@@ -83,8 +78,7 @@ abstract class AbstractWorkspaceModelTest {
screen1: List<Rect>? = null,
screen2: List<Rect>? = null,
screen3: List<Rect>? = null,
) = listOf(screen0, screen1, screen2, screen3)
.let(this::setupWithSpaces)
) = listOf(screen0, screen1, screen2, screen3).let(this::setupWithSpaces)
private fun setupWithSpaces(workspaceSpaces: List<List<Rect>?>) {
var nextItemId = 1
@@ -110,9 +104,7 @@ abstract class AbstractWorkspaceModelTest {
var itemId = itemStartId
val occupancy = GridOccupancy(mIdp.numColumns, mIdp.numRows)
occupancy.markCells(0, 0, mIdp.numColumns, mIdp.numRows, true)
spaces.forEach { spaceRect ->
occupancy.markCells(spaceRect, false)
}
spaces.forEach { spaceRect -> occupancy.markCells(spaceRect, false) }
mExistingScreens.add(screenId)
mScreenOccupancy.append(screenId, occupancy)
for (x in 0 until mIdp.numColumns) {
@@ -139,24 +131,21 @@ abstract class AbstractWorkspaceModelTest {
return itemId
}
fun getExistingItem() = WorkspaceItemInfo()
.apply { intent = Intent().setComponent(ComponentName("a", "b")) }
fun getExistingItem() =
WorkspaceItemInfo().apply { intent = Intent().setComponent(ComponentName("a", "b")) }
fun getNewItem(): WorkspaceItemInfo {
val itemPackage = UUID.randomUUID().toString()
return WorkspaceItemInfo()
.apply { intent = Intent().setComponent(ComponentName(itemPackage, itemPackage)) }
return WorkspaceItemInfo().apply {
intent = Intent().setComponent(ComponentName(itemPackage, itemPackage))
}
}
}
data class NewItemSpace(
val screenId: Int,
val cellX: Int,
val cellY: Int
) {
data class NewItemSpace(val screenId: Int, val cellX: Int, val cellY: Int) {
fun toIntArray() = intArrayOf(screenId, cellX, cellY)
companion object {
fun fromIntArray(array: kotlin.IntArray) = NewItemSpace(array[0], array[1], array[2])
}
}
}
@@ -23,9 +23,9 @@ import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.Executors
import com.android.launcher3.util.IntArray
import com.android.launcher3.util.same
import com.android.launcher3.util.eq
import com.android.launcher3.util.any
import com.android.launcher3.util.eq
import com.android.launcher3.util.same
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -34,31 +34,24 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.times
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
/**
* Tests for [AddWorkspaceItemsTask]
*/
/** Tests for [AddWorkspaceItemsTask] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
@Captor
private lateinit var mAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
@Captor private lateinit var mAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
@Captor
private lateinit var mNotAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
@Captor private lateinit var mNotAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
@Mock
private lateinit var mDataModelCallbacks: BgDataModel.Callbacks
@Mock
private lateinit var mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder
@Mock private lateinit var mDataModelCallbacks: BgDataModel.Callbacks
@Mock private lateinit var mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder
@Before
override fun setup() {
@@ -89,10 +82,7 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
@Test
fun givenNewAndExistingItems_whenExecuteTask_thenOnlyAddNewItem() {
val itemsToAdd = arrayOf(
getNewItem(),
getExistingItem()
)
val itemsToAdd = arrayOf(getNewItem(), getExistingItem())
givenNewItemSpaces(NewItemSpace(1, 0, 0))
val nonEmptyScreenIds = listOf(0)
@@ -132,13 +122,14 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
@Test
fun givenMultipleItems_whenExecuteTask_thenAddThem() {
val itemsToAdd = arrayOf(
getNewItem(),
getExistingItem(),
getNewItem(),
getNewItem(),
getExistingItem(),
)
val itemsToAdd =
arrayOf(
getNewItem(),
getExistingItem(),
getNewItem(),
getNewItem(),
getExistingItem(),
)
givenNewItemSpaces(
NewItemSpace(1, 3, 3),
NewItemSpace(2, 0, 0),
@@ -159,27 +150,16 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
// Items that are added to the second screen should be animated
val itemsAddedToSecondScreen = addedItems.filter { it.itemInfo.screenId == 2 }
assertThat(itemsAddedToSecondScreen.size).isEqualTo(2)
itemsAddedToSecondScreen.forEach {
assertThat(it.isAnimated).isTrue()
}
itemsAddedToSecondScreen.forEach { assertThat(it.isAnimated).isTrue() }
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 3)
}
/**
* Sets up the item space data that will be returned from WorkspaceItemSpaceFinder.
*/
/** Sets up the item space data that will be returned from WorkspaceItemSpaceFinder. */
private fun givenNewItemSpaces(vararg newItemSpaces: NewItemSpace) {
val spaceStack = newItemSpaces.toMutableList()
whenever(
mWorkspaceItemSpaceFinder.findSpaceForItem(
any(),
any(),
any(),
any(),
any(),
any()
mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any(), any(), any())
)
)
.then { spaceStack.removeFirst().toIntArray() }
}
@@ -187,20 +167,21 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
* Verifies if WorkspaceItemSpaceFinder was called with proper arguments and how many times was
* it called.
*/
private fun verifyItemSpaceFinderCall(
nonEmptyScreenIds: List<Int>,
numberOfExpectedCall: Int
) {
private fun verifyItemSpaceFinderCall(nonEmptyScreenIds: List<Int>, numberOfExpectedCall: Int) {
verify(mWorkspaceItemSpaceFinder, times(numberOfExpectedCall))
.findSpaceForItem(
same(mAppState), same(mModelHelper.bgDataModel),
eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())), eq(IntArray()), eq(1), eq(1)
same(mAppState),
same(mModelHelper.bgDataModel),
eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())),
eq(IntArray()),
eq(1),
eq(1)
)
}
/**
* Sets up the workspaces with items, executes the task, collects the added items from the
* model callback then returns it.
* Sets up the workspaces with items, executes the task, collects the added items from the model
* callback then returns it.
*/
private fun testAddItems(
nonEmptyScreenIds: List<Int>,
@@ -209,21 +190,21 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
setupWorkspaces(nonEmptyScreenIds)
val task = newTask(*itemsToAdd)
var updateCount = 0
mModelHelper.executeTaskForTest(task)
.forEach {
updateCount++
it.run()
}
mModelHelper.executeTaskForTest(task).forEach {
updateCount++
it.run()
}
val addedItems = mutableListOf<AddedItem>()
if (updateCount > 0) {
verify(mDataModelCallbacks).bindAppsAdded(
any(),
mNotAnimatedItemArgumentCaptor.capture(), mAnimatedItemArgumentCaptor.capture()
)
verify(mDataModelCallbacks)
.bindAppsAdded(
any(),
mNotAnimatedItemArgumentCaptor.capture(),
mAnimatedItemArgumentCaptor.capture()
)
addedItems.addAll(mAnimatedItemArgumentCaptor.value.map { AddedItem(it, true) })
addedItems.addAll(mNotAnimatedItemArgumentCaptor.value.map { AddedItem(it, false) })
}
return addedItems
@@ -234,12 +215,10 @@ class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
* with a mock.
*/
private fun newTask(vararg items: ItemInfo): AddWorkspaceItemsTask =
items.map { Pair.create(it, Any()) }
items
.map { Pair.create(it, Any()) }
.toMutableList()
.let { AddWorkspaceItemsTask(it, mWorkspaceItemSpaceFinder) }
}
private data class AddedItem(
val itemInfo: ItemInfo,
val isAnimated: Boolean
)
private data class AddedItem(val itemInfo: ItemInfo, val isAnimated: Boolean)
@@ -17,7 +17,7 @@ package com.android.launcher3.model
import android.content.Context
import android.content.Intent
import android.database.Cursor;
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.graphics.Point
import android.os.Process
@@ -38,7 +38,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
/** Unit tests for [GridSizeMigrationUtil] */
/** Unit tests for [GridSizeMigrationUtil] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class GridSizeMigrationUtilTest {
@@ -64,19 +64,20 @@ class GridSizeMigrationUtilTest {
context = modelHelper.sandboxContext
db = modelHelper.provider.db
validPackages = setOf(
TEST_PACKAGE,
testPackage1,
testPackage2,
testPackage3,
testPackage4,
testPackage5,
testPackage6,
testPackage7,
testPackage8,
testPackage9,
testPackage10
)
validPackages =
setOf(
TEST_PACKAGE,
testPackage1,
testPackage2,
testPackage3,
testPackage4,
testPackage5,
testPackage6,
testPackage7,
testPackage8,
testPackage9,
testPackage10
)
idp = InvariantDeviceProfile.INSTANCE[context]
val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
@@ -90,8 +91,8 @@ class GridSizeMigrationUtilTest {
}
/**
* Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is
* not needed anymore
* Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
* needed anymore
*/
@Test
@Throws(Exception::class)
@@ -124,25 +125,27 @@ class GridSizeMigrationUtilTest {
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Check hotseat items
var c = context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
) ?: throw IllegalStateException()
var c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
)
?: throw IllegalStateException()
assertThat(c.count).isEqualTo(idp.numDatabaseHotseatIcons)
@@ -163,14 +166,16 @@ class GridSizeMigrationUtilTest {
c.close()
// Check workspace items
c = context.contentResolver.query(
CONTENT_URI,
arrayOf(CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
) ?: throw IllegalStateException()
c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
)
?: throw IllegalStateException()
intentIndex = c.getColumnIndex(INTENT)
val cellXIndex = c.getColumnIndex(CELLX)
@@ -195,8 +200,8 @@ class GridSizeMigrationUtilTest {
}
/**
* Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is
* not needed anymore
* Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
* needed anymore
*/
@Test
@Throws(Exception::class)
@@ -235,39 +240,46 @@ class GridSizeMigrationUtilTest {
val readerGridB = DbReader(db, TABLE_NAME, context, validPackages)
// migrate from A -> B
GridSizeMigrationUtil.migrate(
context,
db,
readerGridA,
readerGridB,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
readerGridA,
readerGridB,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Check hotseat items in grid B
var c = context.contentResolver.query(
var c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
) ?: throw IllegalStateException()
)
?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
verifyHotseat(c, idp,
mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList())
verifyHotseat(
c,
idp,
mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
)
// Check workspace items in grid B
c = context.contentResolver.query(
c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
) ?: throw IllegalStateException()
)
?: throw IllegalStateException()
var locMap = parseLocMap(context, c)
// Expected items in grid B
// _ _ _ _
@@ -285,38 +297,45 @@ class GridSizeMigrationUtilTest {
// migrate from B -> A
GridSizeMigrationUtil.migrate(
context,
db,
readerGridB,
readerGridA,
5,
Point(5, 5),
DeviceGridState(idp),
DeviceGridState(context)
context,
db,
readerGridB,
readerGridA,
5,
Point(5, 5),
DeviceGridState(idp),
DeviceGridState(context)
)
// Check hotseat items in grid A
c = context.contentResolver.query(
c =
context.contentResolver.query(
TMP_CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
) ?: throw IllegalStateException()
)
?: throw IllegalStateException()
// Expected hotseat items in grid A
// 1 2 _ 3 4
verifyHotseat(c, idp, mutableListOf(
testPackage1, testPackage2, null, testPackage3, testPackage4).toList())
verifyHotseat(
c,
idp,
mutableListOf(testPackage1, testPackage2, null, testPackage3, testPackage4).toList()
)
// Check workspace items in grid A
c = context.contentResolver.query(
c =
context.contentResolver.query(
TMP_CONTENT_URI,
arrayOf(SCREEN, CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
) ?: throw IllegalStateException()
)
?: throw IllegalStateException()
locMap = parseLocMap(context, c)
// Expected workspace items in grid A
// _ _ _ _ _
@@ -338,39 +357,46 @@ class GridSizeMigrationUtilTest {
// migrate from A -> B
GridSizeMigrationUtil.migrate(
context,
db,
readerGridA,
readerGridB,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
readerGridA,
readerGridB,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Check hotseat items in grid B
c = context.contentResolver.query(
c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
) ?: throw IllegalStateException()
)
?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
verifyHotseat(c, idp,
mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList())
verifyHotseat(
c,
idp,
mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
)
// Check workspace items in grid B
c = context.contentResolver.query(
c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, CELLX, CELLY, INTENT),
"container=$CONTAINER_DESKTOP",
null,
null,
null
) ?: throw IllegalStateException()
)
?: throw IllegalStateException()
locMap = parseLocMap(context, c)
// Expected workspace items in grid B
// _ _ _ _
@@ -406,7 +432,7 @@ class GridSizeMigrationUtilTest {
val locMap = mutableMapOf<String, Triple<Int, Int, Int>>()
while (c.moveToNext()) {
locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] =
Triple(c.getInt(screenIndex), c.getInt(cellXIndex), c.getInt(cellYIndex))
Triple(c.getInt(screenIndex), c.getInt(cellXIndex), c.getInt(cellYIndex))
}
c.close()
return locMap.toMap()
@@ -414,12 +440,13 @@ class GridSizeMigrationUtilTest {
@Test
fun migrateToLargerHotseat() {
val srcHotseatItems = intArrayOf(
modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI)
)
val srcHotseatItems =
intArrayOf(
modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI)
)
val numSrcDatabaseHotseatIcons = srcHotseatItems.size
idp.numDatabaseHotseatIcons = 6
idp.numColumns = 4
@@ -427,25 +454,27 @@ class GridSizeMigrationUtilTest {
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Check hotseat items
val c = context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
) ?: throw IllegalStateException()
val c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
)
?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(numSrcDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -483,25 +512,27 @@ class GridSizeMigrationUtilTest {
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Check hotseat items
val c = context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
) ?: throw IllegalStateException()
val c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(SCREEN, INTENT),
"container=$CONTAINER_HOTSEAT",
null,
SCREEN,
null
)
?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(idp.numDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -527,8 +558,8 @@ class GridSizeMigrationUtilTest {
}
/**
* Migrating from a smaller grid to a large one should keep the pages
* if the column difference is less than 2
* Migrating from a smaller grid to a large one should keep the pages if the column difference
* is less than 2
*/
@Test
@Throws(Exception::class)
@@ -549,25 +580,27 @@ class GridSizeMigrationUtilTest {
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Get workspace items
val c = context.contentResolver.query(
CONTENT_URI,
arrayOf(INTENT, SCREEN),
"container=$CONTAINER_DESKTOP",
null,
null,
null
) ?: throw IllegalStateException()
val c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(INTENT, SCREEN),
"container=$CONTAINER_DESKTOP",
null,
null,
null
)
?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -589,8 +622,8 @@ class GridSizeMigrationUtilTest {
}
/**
* Migrating from a smaller grid to a large one should reflow the pages
* if the column difference is more than 2
* Migrating from a smaller grid to a large one should reflow the pages if the column difference
* is more than 2
*/
@Test
@Throws(Exception::class)
@@ -610,25 +643,27 @@ class GridSizeMigrationUtilTest {
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Get workspace items
val c = context.contentResolver.query(
CONTENT_URI,
arrayOf(INTENT, SCREEN),
"container=$CONTAINER_DESKTOP",
null,
null,
null
) ?: throw IllegalStateException()
val c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(INTENT, SCREEN),
"container=$CONTAINER_DESKTOP",
null,
null,
null
)
?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -651,9 +686,7 @@ class GridSizeMigrationUtilTest {
disableNewMigrationLogic()
}
/**
* Migrating from a larger grid to a smaller, we reflow from page 0
*/
/** Migrating from a larger grid to a smaller, we reflow from page 0 */
@Test
@Throws(Exception::class)
fun migrateFromLargerGrid() {
@@ -672,25 +705,27 @@ class GridSizeMigrationUtilTest {
val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
val destReader = DbReader(db, TABLE_NAME, context, validPackages)
GridSizeMigrationUtil.migrate(
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
context,
db,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
DeviceGridState(idp)
)
// Get workspace items
val c = context.contentResolver.query(
CONTENT_URI,
arrayOf(INTENT, SCREEN),
"container=$CONTAINER_DESKTOP",
null,
null,
null
) ?: throw IllegalStateException()
val c =
context.contentResolver.query(
CONTENT_URI,
arrayOf(INTENT, SCREEN),
"container=$CONTAINER_DESKTOP",
null,
null,
null
)
?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -714,11 +749,13 @@ class GridSizeMigrationUtilTest {
}
private fun enableNewMigrationLogic(srcGridSize: String) {
context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
context
.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, true)
.commit()
context.getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
context
.getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
.edit()
.putString(DeviceGridState.KEY_WORKSPACE_SIZE, srcGridSize)
.commit()
@@ -726,9 +763,10 @@ class GridSizeMigrationUtilTest {
}
private fun disableNewMigrationLogic() {
context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
context
.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, false)
.commit()
}
}
}
@@ -24,9 +24,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
/**
* Tests for [WorkspaceItemSpaceFinder]
*/
/** Tests for [WorkspaceItemSpaceFinder] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
@@ -44,17 +42,27 @@ class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
}
private fun findSpace(spanX: Int, spanY: Int): NewItemSpace =
mItemSpaceFinder.findSpaceForItem(
mAppState, mModelHelper.bgDataModel,
mExistingScreens, mNewScreens, spanX, spanY
)
mItemSpaceFinder
.findSpaceForItem(
mAppState,
mModelHelper.bgDataModel,
mExistingScreens,
mNewScreens,
spanX,
spanY
)
.let { NewItemSpace.fromIntArray(it) }
private fun assertRegionVacant(newItemSpace: NewItemSpace, spanX: Int, spanY: Int) {
assertThat(
mScreenOccupancy[newItemSpace.screenId]
.isRegionVacant(newItemSpace.cellX, newItemSpace.cellY, spanX, spanY)
).isTrue()
mScreenOccupancy[newItemSpace.screenId].isRegionVacant(
newItemSpace.cellX,
newItemSpace.cellY,
spanX,
spanY
)
)
.isTrue()
}
@Test
@@ -29,8 +29,8 @@ import org.junit.runner.RunWith
class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
/**
* This is a case when after setting the hotseat, the space needs to be recalculated
* but it doesn't need to change QSB width or remove icons
* This is a case when after setting the hotseat, the space needs to be recalculated but it
* doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_portrait() {
@@ -51,8 +51,8 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
}
/**
* This is a case when after setting the hotseat, and recalculating spaces
* it still needs to remove icons for everything to fit
* This is a case when after setting the hotseat, and recalculating spaces it still needs to
* remove icons for everything to fit
*/
@Test
fun decrease_num_of_icons_when_not_enough_space_portrait() {
@@ -73,8 +73,8 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
}
/**
* This is a case when after setting the hotseat, the space needs to be recalculated
* but it doesn't need to change QSB width or remove icons
* This is a case when after setting the hotseat, the space needs to be recalculated but it
* doesn't need to change QSB width or remove icons
*/
@Test
fun distribute_border_space_when_space_is_enough_landscape() {
@@ -94,8 +94,8 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
}
/**
* This is a case when the hotseat spans a certain amount of columns
* and the nav buttons push the hotseat to the side, but not enough to change the border space.
* This is a case when the hotseat spans a certain amount of columns and the nav buttons push
* the hotseat to the side, but not enough to change the border space.
*/
@Test
fun nav_buttons_dont_interfere_with_required_hotseat_width() {
@@ -118,9 +118,7 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
assertThat(dp.hotseatQsbWidth).isEqualTo(1224)
}
/**
* This is a case when after setting the hotseat, the QSB width needs to be changed to fit
*/
/** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@Test
fun decrease_qsb_when_not_enough_space_landscape() {
initializeVarsForTablet(isGestureMode = false, isLandscape = true)
@@ -22,43 +22,41 @@ package com.android.launcher3.util
* be null"). To fix this, we can use methods that modify the return type to be nullable. This
* causes Kotlin to skip the null checks.
*/
import org.mockito.ArgumentCaptor
import org.mockito.Mockito
/**
* Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
* null is returned.
* Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when null is
* returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
fun <T> eq(obj: T): T = Mockito.eq<T>(obj)
/**
* Returns Mockito.same() as nullable type to avoid java.lang.IllegalStateException when
* null is returned.
* Returns Mockito.same() as nullable type to avoid java.lang.IllegalStateException when null is
* returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
fun <T> same(obj: T): T = Mockito.same<T>(obj)
/**
* Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when
* null is returned.
* Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when null is
* returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
inline fun <reified T> any(): T = any(T::class.java)
/**
* Kotlin type-inferred version of Mockito.nullable()
*/
/** Kotlin type-inferred version of Mockito.nullable() */
inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java)
/**
* Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException
* when null is returned.
* Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException when
* null is returned.
*
* Generic T is nullable because implicitly bounded by Any?.
*/
@@ -82,8 +80,9 @@ inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
/**
* A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
* kotlin tests are mocking kotlin objects and the methods take non-null parameters:
*
* ```
* java.lang.NullPointerException: capture() must not be null
* ```
*/
class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) {
private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz)
@@ -102,15 +101,15 @@ inline fun <reified T : Any> kotlinArgumentCaptor(): KotlinArgumentCaptor<T> =
/**
* Helper function for creating and using a single-use ArgumentCaptor in kotlin.
*
* ```
* val captor = argumentCaptor<Foo>()
* verify(...).someMethod(captor.capture())
* val captured = captor.value
*
* ```
* becomes:
*
* ```
* val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) }
*
* ```
* NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException.
*/
inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
@@ -30,18 +30,18 @@ class MultiPropertyFactoryTest {
private val received = mutableListOf<Float>()
private val receiveProperty: FloatProperty<Any> = object : FloatProperty<Any>("receive") {
override fun setValue(obj: Any?, value: Float) {
received.add(value)
private val receiveProperty: FloatProperty<Any> =
object : FloatProperty<Any>("receive") {
override fun setValue(obj: Any?, value: Float) {
received.add(value)
}
override fun get(o: Any): Float {
return 0f
}
}
override fun get(o: Any): Float {
return 0f
}
}
private val factory = MultiPropertyFactory(null, receiveProperty, 3) {
x: Float, y: Float -> x + y
}
private val factory =
MultiPropertyFactory(null, receiveProperty, 3) { x: Float, y: Float -> x + y }
private val p1 = factory.get(0)
private val p2 = factory.get(1)
@@ -18,9 +18,9 @@ package com.android.launcher3.util
import android.view.InputDevice
import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith