Merge "Remove ScreenRecord for a closed bug" into main
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 3dcf2b4..7d39bf8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -342,10 +342,10 @@
mBubbleBarViewController.showOverflow(update.showOverflow);
}
- BubbleBarBubble bubbleToSelect = null;
if (update.addedBubble != null) {
mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
}
+ BubbleBarBubble bubbleToSelect = null;
if (update.selectedBubbleKey != null) {
if (mSelectedBubble == null
|| !update.selectedBubbleKey.equals(mSelectedBubble.getKey())) {
@@ -363,7 +363,7 @@
&& update.removedBubbles.isEmpty()
&& !mBubbles.isEmpty()) {
// A bubble was added from the overflow (& now it's empty / not showing)
- mBubbleBarViewController.removeOverflowAndAddBubble(update.addedBubble);
+ mBubbleBarViewController.removeOverflowAndAddBubble(update.addedBubble, bubbleToSelect);
} else if (update.addedBubble != null && update.removedBubbles.size() == 1) {
// we're adding and removing a bubble at the same time. handle this as a single update.
RemovedBubble removedBubble = update.removedBubbles.get(0);
@@ -371,7 +371,8 @@
boolean showOverflow = update.showOverflowChanged && update.showOverflow;
if (bubbleToRemove != null) {
mBubbleBarViewController.addBubbleAndRemoveBubble(update.addedBubble,
- bubbleToRemove, isExpanding, suppressAnimation, showOverflow);
+ bubbleToRemove, bubbleToSelect, isExpanding, suppressAnimation,
+ showOverflow);
} else {
mBubbleBarViewController.addBubble(update.addedBubble, isExpanding,
suppressAnimation, bubbleToSelect);
@@ -387,7 +388,7 @@
if (bubble != null && overflowNeedsToBeAdded) {
// First removal, show the overflow
overflowNeedsToBeAdded = false;
- mBubbleBarViewController.addOverflowAndRemoveBubble(bubble);
+ mBubbleBarViewController.addOverflowAndRemoveBubble(bubble, bubbleToSelect);
} else if (bubble != null) {
mBubbleBarViewController.removeBubble(bubble);
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index aa6ad25..2d4d279 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -741,35 +741,32 @@
/** Add a new bubble and remove an old bubble from the bubble bar. */
public void addBubbleAndRemoveBubble(BubbleView addedBubble, BubbleView removedBubble,
- Runnable onEndRunnable) {
+ @Nullable BubbleView bubbleToSelect, Runnable onEndRunnable) {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) mIconSize, (int) mIconSize,
Gravity.LEFT);
- boolean isOverflowSelected =
- mSelectedBubbleView != null && mSelectedBubbleView.isOverflow();
- boolean removingOverflow = removedBubble.isOverflow();
- boolean addingOverflow = addedBubble.isOverflow();
-
+ int addedIndex = addedBubble.isOverflow() ? getChildCount() : 0;
if (!isExpanded()) {
removeView(removedBubble);
- int index = addingOverflow ? getChildCount() : 0;
- addView(addedBubble, index, lp);
+ addView(addedBubble, addedIndex, lp);
if (onEndRunnable != null) {
onEndRunnable.run();
}
return;
}
- int index = addingOverflow ? getChildCount() : 0;
addedBubble.setScaleX(0f);
addedBubble.setScaleY(0f);
- addView(addedBubble, index, lp);
-
- if (isOverflowSelected && removingOverflow) {
- // The added bubble will be selected
- mSelectedBubbleView = addedBubble;
- }
- int indexOfSelectedBubble = indexOfChild(mSelectedBubbleView);
+ addView(addedBubble, addedIndex, lp);
+ int indexOfCurrentSelectedBubble = indexOfChild(mSelectedBubbleView);
int indexOfBubbleToRemove = indexOfChild(removedBubble);
-
+ int indexOfNewlySelectedBubble = bubbleToSelect == null
+ ? indexOfCurrentSelectedBubble : indexOfChild(bubbleToSelect);
+ // Since removed bubble is kept till the end of the animation we should check if there are
+ // more than one bubble. In such a case the bar will remain open without the selected bubble
+ if (mSelectedBubbleView == removedBubble
+ && bubbleToSelect == null
+ && getBubbleChildCount() > 1) {
+ Log.w(TAG, "Remove the currently selected bubble without selecting a new one.");
+ }
mBubbleAnimator = new BubbleAnimator(mIconSize, mExpandedBarIconsSpacing,
getChildCount(), mBubbleBarLocation.isOnLeft(isLayoutRtl()));
BubbleAnimator.Listener listener = new BubbleAnimator.Listener() {
@@ -802,8 +799,8 @@
invalidate();
}
};
- mBubbleAnimator.animateNewAndRemoveOld(indexOfSelectedBubble, indexOfBubbleToRemove,
- listener);
+ mBubbleAnimator.animateNewAndRemoveOld(indexOfCurrentSelectedBubble,
+ indexOfNewlySelectedBubble, indexOfBubbleToRemove, addedIndex, listener);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 84243f5..0b627d2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -843,11 +843,12 @@
}
/** Adds a new bubble and removes an old bubble at the same time. */
- public void addBubbleAndRemoveBubble(BubbleBarBubble addedBubble,
- BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation,
- boolean addOverflowToo) {
+ public void addBubbleAndRemoveBubble(BubbleBarBubble addedBubble, BubbleBarBubble removedBubble,
+ @Nullable BubbleBarBubble bubbleToSelect, boolean isExpanding,
+ boolean suppressAnimation, boolean addOverflowToo) {
+ BubbleView bubbleToSelectView = bubbleToSelect == null ? null : bubbleToSelect.getView();
mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView(),
- addOverflowToo ? () -> showOverflow(true) : null);
+ bubbleToSelectView, addOverflowToo ? () -> showOverflow(true) : null);
addedBubble.getView().setOnClickListener(mBubbleClickListener);
addedBubble.getView().setController(mBubbleViewController);
removedBubble.getView().setController(null);
@@ -878,22 +879,26 @@
}
/** Adds the overflow view to the bubble bar while animating a view away. */
- public void addOverflowAndRemoveBubble(BubbleBarBubble removedBubble) {
+ public void addOverflowAndRemoveBubble(BubbleBarBubble removedBubble,
+ @Nullable BubbleBarBubble bubbleToSelect) {
if (mOverflowAdded) return;
mOverflowAdded = true;
+ BubbleView bubbleToSelectView = bubbleToSelect == null ? null : bubbleToSelect.getView();
mBarView.addBubbleAndRemoveBubble(mOverflowBubble.getView(), removedBubble.getView(),
- null /* onEndRunnable */);
+ bubbleToSelectView, null /* onEndRunnable */);
mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
mOverflowBubble.getView().setController(mBubbleViewController);
removedBubble.getView().setController(null);
}
/** Removes the overflow view to the bubble bar while animating a view in. */
- public void removeOverflowAndAddBubble(BubbleBarBubble addedBubble) {
+ public void removeOverflowAndAddBubble(BubbleBarBubble addedBubble,
+ @Nullable BubbleBarBubble bubbleToSelect) {
if (!mOverflowAdded) return;
mOverflowAdded = false;
+ BubbleView bubbleToSelectView = bubbleToSelect == null ? null : bubbleToSelect.getView();
mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), mOverflowBubble.getView(),
- null /* onEndRunnable */);
+ bubbleToSelectView, null /* onEndRunnable */);
addedBubble.getView().setOnClickListener(mBubbleClickListener);
addedBubble.getView().setController(mBubbleViewController);
mOverflowBubble.getView().setController(null);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt
index 944e806..26d6ccc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt
@@ -18,6 +18,8 @@
import androidx.core.animation.Animator
import androidx.core.animation.ValueAnimator
+import kotlin.math.max
+import kotlin.math.min
/**
* Animates individual bubbles within the bubble bar while the bubble bar is expanded.
@@ -70,14 +72,18 @@
fun animateNewAndRemoveOld(
selectedBubbleIndex: Int,
+ newlySelectedBubbleIndex: Int,
removedBubbleIndex: Int,
+ addedBubbleIndex: Int,
listener: Listener,
) {
animator = createAnimator(listener)
state =
State.AddingAndRemoving(
selectedBubbleIndex = selectedBubbleIndex,
+ newlySelectedBubbleIndex = newlySelectedBubbleIndex,
removedBubbleIndex = removedBubbleIndex,
+ addedBubbleIndex = addedBubbleIndex,
)
animator.start()
}
@@ -137,6 +143,7 @@
getBubbleTranslationXWhileAddingBubbleAtLimit(
bubbleIndex = bubbleIndex,
removedBubbleIndex = state.removedBubbleIndex,
+ addedBubbleIndex = state.addedBubbleIndex,
addedBubbleScale = animator.animatedFraction,
removedBubbleScale = 1 - animator.animatedFraction,
)
@@ -187,34 +194,25 @@
State.Idle -> 0f
is State.AddingBubble -> getArrowPositionWhenAddingBubble(state)
is State.RemovingBubble -> getArrowPositionWhenRemovingBubble(state)
- is State.AddingAndRemoving -> {
- // we never remove the selected bubble, so the arrow stays pointing to its center
- val tx =
- getBubbleTranslationXWhileAddingBubbleAtLimit(
- bubbleIndex = state.selectedBubbleIndex,
- removedBubbleIndex = state.removedBubbleIndex,
- addedBubbleScale = animator.animatedFraction,
- removedBubbleScale = 1 - animator.animatedFraction,
- )
- tx + iconSize / 2f
- }
+ is State.AddingAndRemoving -> getArrowPositionWhenAddingAndRemovingBubble(state)
}
}
private fun getArrowPositionWhenAddingBubble(state: State.AddingBubble): Float {
val scale = animator.animatedFraction
- var tx = getBubbleTranslationXWhileScalingBubble(
- bubbleIndex = state.selectedBubbleIndex,
- scalingBubbleIndex = 0,
- bubbleScale = scale
- ) + iconSize / 2f
+ var tx =
+ getBubbleTranslationXWhileScalingBubble(
+ bubbleIndex = state.selectedBubbleIndex,
+ scalingBubbleIndex = 0,
+ bubbleScale = scale,
+ ) + iconSize / 2f
if (state.newlySelectedBubbleIndex != null) {
val selectedBubbleScale = if (state.newlySelectedBubbleIndex == 0) scale else 1f
val finalTx =
getBubbleTranslationXWhileScalingBubble(
bubbleIndex = state.newlySelectedBubbleIndex,
scalingBubbleIndex = 0,
- bubbleScale = 1f,
+ bubbleScale = scale,
) + iconSize * selectedBubbleScale / 2f
tx += (finalTx - tx) * animator.animatedFraction
}
@@ -266,6 +264,46 @@
}
}
+ private fun getArrowPositionWhenAddingAndRemovingBubble(state: State.AddingAndRemoving): Float {
+ // The bubble bar keeps constant width while adding and removing bubble. So we just need to
+ // find selected bubble arrow position on the animation start and newly selected bubble
+ // arrow position on the animation end interpolating the arrow between these positions
+ // during the animation.
+ // The indexes in the state are provided for the bubble bar containing all bubbles. So for
+ // certain circumstances indexes should be adjusted.
+ // When animation is started added bubble has zero scale as well as removed bubble when the
+ // animation is ended, so for both cases we should compute translation as it is one less
+ // bubble.
+ val bubbleCountOnEnd = bubbleCount - 1
+ var selectedIndex = state.selectedBubbleIndex
+ // We only need to adjust the selected index if added bubble was added before the selected.
+ if (selectedIndex > state.addedBubbleIndex) {
+ // If the selectedIndex is higher index than the added bubble index, we need to reduce
+ // selectedIndex by one because the added bubble has zero scale when animation is
+ // started.
+ selectedIndex--
+ }
+ var newlySelectedIndex = state.newlySelectedBubbleIndex
+ // We only need to adjust newlySelectedIndex if removed bubble was removed before the newly
+ // selected bubble.
+ if (newlySelectedIndex > state.removedBubbleIndex) {
+ // If the newlySelectedIndex is higher index than the removed bubble index, we need to
+ // reduce newlySelectedIndex by one because the removed bubble has zero scale when
+ // animation is ended.
+ newlySelectedIndex--
+ }
+ val iconAndSpacing: Float = iconSize + expandedBarIconSpacing
+ val startTx = getBubblesToTheLeft(selectedIndex, bubbleCountOnEnd) * iconAndSpacing
+ val endTx = getBubblesToTheLeft(newlySelectedIndex, bubbleCountOnEnd) * iconAndSpacing
+ val tx = startTx + (endTx - startTx) * animator.animatedFraction
+ return tx + iconSize / 2f
+ }
+
+ private fun getBubblesToTheLeft(bubbleIndex: Int, bubbleCount: Int = this.bubbleCount): Int =
+ // when bar is on left the index - 0 corresponds to the right - most bubble and when the
+ // bubble bar is on the right - 0 corresponds to the left - most bubble.
+ if (onLeft) bubbleCount - bubbleIndex - 1 else bubbleIndex
+
/**
* Returns the translation X for the bubble at index {@code bubbleIndex} when the bubble bar is
* expanded and a bubble is animating in or out.
@@ -290,6 +328,7 @@
// the bar is on the left and the current bubble is to the right of the scaling
// bubble so account for its scale
(bubbleCount - bubbleIndex - 2 + bubbleScale) * iconAndSpacing
+
bubbleIndex == scalingBubbleIndex -> {
// the bar is on the left and this is the scaling bubble
val totalIconSize = (bubbleCount - bubbleIndex - 1) * iconSize
@@ -299,6 +338,7 @@
val scaledSpace = bubbleScale * expandedBarIconSpacing
totalIconSize + totalSpacing + scaledSpace + pivotAdjustment
}
+
else ->
// the bar is on the left and the scaling bubble is on the right. the current
// bubble is unaffected by the scaling bubble
@@ -310,10 +350,12 @@
// the bar is on the right and the scaling bubble is on the right. the current
// bubble is unaffected by the scaling bubble
iconAndSpacing * bubbleIndex
+
bubbleIndex == scalingBubbleIndex ->
// the bar is on the right, and this is the animating bubble. it only needs to
// be adjusted for the scaling pivot.
iconAndSpacing * bubbleIndex + pivotAdjustment
+
else ->
// the bar is on the right and the scaling bubble is on the left so account for
// its scale
@@ -325,61 +367,67 @@
private fun getBubbleTranslationXWhileAddingBubbleAtLimit(
bubbleIndex: Int,
removedBubbleIndex: Int,
+ addedBubbleIndex: Int,
addedBubbleScale: Float,
removedBubbleScale: Float,
): Float {
val iconAndSpacing = iconSize + expandedBarIconSpacing
// the bubbles are scaling from the center, so we need to adjust their translation so
// that the distance to the adjacent bubble scales at the same rate.
- val addedBubblePivotAdjustment = -(1 - addedBubbleScale) * iconSize / 2f
- val removedBubblePivotAdjustment = -(1 - removedBubbleScale) * iconSize / 2f
+ val addedBubblePivotAdjustment = (addedBubbleScale - 1) * iconSize / 2f
+ val removedBubblePivotAdjustment = (removedBubbleScale - 1) * iconSize / 2f
- return if (onLeft) {
- // this is how many bubbles there are to the left of the current bubble.
- // when the bubble bar is on the right the added bubble is the right-most bubble so it
- // doesn't affect the translation of any other bubble.
- // when the removed bubble is to the left of the current bubble, we need to subtract it
- // from bubblesToLeft and use removedBubbleScale instead when calculating the
- // translation.
- val bubblesToLeft = bubbleCount - bubbleIndex - 1
- when {
- bubbleIndex == 0 ->
- // this is the added bubble and it's the right-most bubble. account for all the
- // other bubbles -- including the removed bubble -- and adjust for the added
- // bubble pivot.
- (bubblesToLeft - 1 + removedBubbleScale) * iconAndSpacing +
- addedBubblePivotAdjustment
- bubbleIndex < removedBubbleIndex ->
+ val minAddedRemovedIndex = min(addedBubbleIndex, removedBubbleIndex)
+ val maxAddedRemovedIndex = max(addedBubbleIndex, removedBubbleIndex)
+ val isBetweenAddedAndRemoved =
+ bubbleIndex in (minAddedRemovedIndex + 1)..<maxAddedRemovedIndex
+ val isRemovedBubbleToLeftOfAddedBubble = onLeft == addedBubbleIndex < removedBubbleIndex
+ val bubblesToLeft = getBubblesToTheLeft(bubbleIndex)
+ return when {
+ isBetweenAddedAndRemoved -> {
+ if (isRemovedBubbleToLeftOfAddedBubble) {
// the removed bubble is to the left so account for it
(bubblesToLeft - 1 + removedBubbleScale) * iconAndSpacing
- bubbleIndex == removedBubbleIndex -> {
- // this is the removed bubble. all the bubbles to the left are at full scale
- // but we need to scale the spacing between the removed bubble and the bubble to
- // its left because the removed bubble disappears towards the left side
+ } else {
+ // the added bubble is to the left so account for it
+ (bubblesToLeft - 1 + addedBubbleScale) * iconAndSpacing
+ }
+ }
+
+ bubbleIndex == addedBubbleIndex -> {
+ if (isRemovedBubbleToLeftOfAddedBubble) {
+ // the removed bubble is to the left so account for it
+ (bubblesToLeft - 1 + removedBubbleScale) * iconAndSpacing
+ } else {
+ // it's the left-most scaling bubble, all bubbles on the left are at full scale
+ bubblesToLeft * iconAndSpacing
+ } + addedBubblePivotAdjustment
+ }
+
+ bubbleIndex == removedBubbleIndex -> {
+ if (isRemovedBubbleToLeftOfAddedBubble) {
+ // All the bubbles to the left are at full scale, but we need to scale the
+ // spacing between the removed bubble and the bubble next to it
val totalIconSize = bubblesToLeft * iconSize
val totalSpacing =
(bubblesToLeft - 1 + removedBubbleScale) * expandedBarIconSpacing
- totalIconSize + totalSpacing + removedBubblePivotAdjustment
- }
- else ->
- // both added and removed bubbles are to the right so they don't affect the tx
- bubblesToLeft * iconAndSpacing
+ totalIconSize + totalSpacing
+ } else {
+ // The added bubble is to the left, so account for it
+ (bubblesToLeft - 1 + addedBubbleScale) * iconAndSpacing
+ } + removedBubblePivotAdjustment
}
- } else {
- when {
- bubbleIndex == 0 -> addedBubblePivotAdjustment // we always add bubbles at index 0
- bubbleIndex < removedBubbleIndex ->
- // the bar is on the right and the removed bubble is on the right. the current
- // bubble is unaffected by the removed bubble. only need to factor in the added
- // bubble's scale.
- iconAndSpacing * (bubbleIndex - 1 + addedBubbleScale)
- bubbleIndex == removedBubbleIndex ->
- // the bar is on the right, and this is the animating bubble.
- iconAndSpacing * (bubbleIndex - 1 + addedBubbleScale) +
- removedBubblePivotAdjustment
- else ->
- // both the added and the removed bubbles are to the left of the current bubble
- iconAndSpacing * (bubbleIndex - 2 + addedBubbleScale + removedBubbleScale)
+
+ else -> {
+ // if bubble index is on the right side of the animated bubbles, we need to deduct
+ // one, since both the added and the removed bubbles takes a single place
+ val onTheRightOfAnimatedBubbles =
+ if (onLeft) {
+ bubbleIndex < minAddedRemovedIndex
+ } else {
+ bubbleIndex > maxAddedRemovedIndex
+ }
+ (bubblesToLeft - if (onTheRightOfAnimatedBubbles) 1 else 0) * iconAndSpacing
}
}
}
@@ -413,10 +461,17 @@
val removingLastRemainingBubble: Boolean,
) : State
- // TODO add index where bubble is being added, and index for newly selected bubble
/** A new bubble is being added and an old bubble is being removed from the bubble bar. */
- data class AddingAndRemoving(val selectedBubbleIndex: Int, val removedBubbleIndex: Int) :
- State
+ data class AddingAndRemoving(
+ /** The index of the selected bubble. */
+ val selectedBubbleIndex: Int,
+ /** The index of the newly selected bubble. */
+ val newlySelectedBubbleIndex: Int,
+ /** The index of the bubble being removed. */
+ val removedBubbleIndex: Int,
+ /** The index of the added bubble. */
+ val addedBubbleIndex: Int,
+ ) : State
}
/** Callbacks for the animation. */
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
index 417bb74..7c09e9a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
@@ -17,8 +17,6 @@
package com.android.launcher3.uioverrides.flags
import android.app.PendingIntent
-import android.app.blob.BlobHandle.createWithSha256
-import android.app.blob.BlobStoreManager
import android.content.Context
import android.content.IIntentReceiver
import android.content.IIntentSender.Stub
@@ -29,10 +27,8 @@
import android.net.Uri
import android.os.Bundle
import android.os.IBinder
-import android.os.ParcelFileDescriptor.AutoCloseOutputStream
import android.provider.DeviceConfig
import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
-import android.provider.Settings.Secure
import android.text.Html
import android.util.AttributeSet
import android.view.inputmethod.EditorInfo
@@ -44,33 +40,16 @@
import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceViewHolder
import androidx.preference.SwitchPreference
-import com.android.launcher3.AutoInstallsLayout
import com.android.launcher3.ExtendedEditText
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherPrefs
-import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
-import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
-import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
-import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
-import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
-import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
-import com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL
-import com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG
-import com.android.launcher3.LauncherSettings.Settings.LAYOUT_PROVIDER_KEY
-import com.android.launcher3.LauncherSettings.Settings.createBlobProviderKey
import com.android.launcher3.R
-import com.android.launcher3.model.data.FolderInfo
-import com.android.launcher3.model.data.ItemInfo
-import com.android.launcher3.model.data.LauncherAppWidgetInfo
-import com.android.launcher3.pm.UserCache
import com.android.launcher3.proxy.ProxyActivityStarter
import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher
-import com.android.launcher3.shortcuts.ShortcutKey
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
-import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR
-import com.android.launcher3.util.LauncherLayoutBuilder
+import com.android.launcher3.util.LayoutImportExportHelper
import com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT
import com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_COUNT
import com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN
@@ -80,14 +59,12 @@
import com.android.launcher3.util.OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN
import com.android.launcher3.util.PluginManagerWrapper
import com.android.launcher3.util.StartActivityParams
-import com.android.launcher3.util.UserIconInfo
import com.android.quickstep.util.DeviceConfigHelper
import com.android.quickstep.util.DeviceConfigHelper.Companion.NAMESPACE_LAUNCHER
import com.android.quickstep.util.DeviceConfigHelper.DebugInfo
import com.android.systemui.shared.plugins.PluginEnabler
import com.android.systemui.shared.plugins.PluginPrefs
-import java.io.OutputStreamWriter
-import java.security.MessageDigest
+import java.nio.charset.StandardCharsets
import java.util.Locale
import java.util.concurrent.Executor
@@ -421,26 +398,12 @@
title = "Export"
intent =
createUriPickerIntent(ACTION_CREATE_DOCUMENT, MAIN_EXECUTOR) { uri ->
- model.enqueueModelUpdateTask { _, dataModel, _ ->
- val builder = LauncherLayoutBuilder()
- dataModel.workspaceItems.forEach { info ->
- val loc =
- when (info.container) {
- CONTAINER_DESKTOP ->
- builder.atWorkspace(info.cellX, info.cellY, info.screenId)
- CONTAINER_HOTSEAT -> builder.atHotseat(info.screenId)
- else -> return@forEach
- }
- loc.addItem(info)
- }
- dataModel.appWidgets.forEach { info ->
- builder.atWorkspace(info.cellX, info.cellY, info.screenId).addItem(info)
- }
-
+ LayoutImportExportHelper.exportModelDbAsXml(context) { layoutXml ->
context.contentResolver.openOutputStream(uri).use { os ->
- builder.build(OutputStreamWriter(os))
+ val bytes: ByteArray =
+ layoutXml.toByteArray(StandardCharsets.UTF_8) // Encode to UTF-8
+ os?.write(bytes)
}
-
MAIN_EXECUTOR.execute {
Toast.makeText(context, "File saved", Toast.LENGTH_LONG).show()
}
@@ -458,66 +421,12 @@
resolver.openInputStream(uri).use { stream ->
stream?.readAllBytes() ?: return@createUriPickerIntent
}
-
- val digest = MessageDigest.getInstance("SHA-256").digest(data)
- val handle = createWithSha256(digest, LAYOUT_DIGEST_LABEL, 0, LAYOUT_DIGEST_TAG)
- val blobManager = context.getSystemService(BlobStoreManager::class.java)!!
-
- blobManager.openSession(blobManager.createSession(handle)).use { session ->
- AutoCloseOutputStream(session.openWrite(0, -1)).use { it.write(data) }
- session.allowPublicAccess()
-
- session.commit(ORDERED_BG_EXECUTOR) {
- Secure.putString(
- resolver,
- LAYOUT_PROVIDER_KEY,
- createBlobProviderKey(digest),
- )
-
- MODEL_EXECUTOR.submit { model.modelDbController.createEmptyDB() }.get()
- MAIN_EXECUTOR.submit { model.forceReload() }.get()
- MODEL_EXECUTOR.submit {}.get()
- Secure.putString(resolver, LAYOUT_PROVIDER_KEY, null)
- }
- }
+ LayoutImportExportHelper.importModelFromXml(context, data)
}
category.addPreference(this)
}
}
- private fun LauncherLayoutBuilder.ItemTarget.addItem(info: ItemInfo) {
- val userType: String? =
- when (UserCache.INSTANCE.get(context).getUserInfo(info.user).type) {
- UserIconInfo.TYPE_WORK -> AutoInstallsLayout.USER_TYPE_WORK
- UserIconInfo.TYPE_CLONED -> AutoInstallsLayout.USER_TYPE_CLONED
- else -> null
- }
- when (info.itemType) {
- ITEM_TYPE_APPLICATION ->
- info.targetComponent?.let { c -> putApp(c.packageName, c.className, userType) }
- ITEM_TYPE_DEEP_SHORTCUT ->
- ShortcutKey.fromItemInfo(info).let { key ->
- putShortcut(key.packageName, key.id, userType)
- }
- ITEM_TYPE_FOLDER ->
- (info as FolderInfo).let { folderInfo ->
- putFolder(folderInfo.title?.toString() ?: "").also { folderBuilder ->
- folderInfo.getContents().forEach { folderContent ->
- folderBuilder.addItem(folderContent)
- }
- }
- }
- ITEM_TYPE_APPWIDGET ->
- putWidget(
- (info as LauncherAppWidgetInfo).providerName.packageName,
- info.providerName.className,
- info.spanX,
- info.spanY,
- userType,
- )
- }
- }
-
private fun createUriPickerIntent(
action: String,
executor: Executor,
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e27b607..124be41 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -100,7 +100,6 @@
import android.widget.Toast;
import android.window.DesktopModeFlags;
import android.window.PictureInPictureSurfaceTransaction;
-import android.window.TransitionInfo;
import android.window.WindowAnimationState;
import androidx.annotation.NonNull;
@@ -957,10 +956,10 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
- super.onRecentsAnimationStart(controller, targets, transitionInfo);
+ RecentsAnimationTargets targets) {
+ super.onRecentsAnimationStart(controller, targets);
if (targets.hasDesktopTasks(mContext)) {
- mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets, transitionInfo);
+ mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
} else {
int untrimmedAppCount = mRemoteTargetHandles.length;
mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(targets);
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index e0fa77a..cfbcf0a 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -33,7 +33,6 @@
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -492,7 +491,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo info) {
+ RecentsAnimationTargets targets) {
mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED);
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index 66f307c..089706f 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -23,7 +23,6 @@
import android.os.Trace
import android.util.Log
import android.view.View
-import android.window.TransitionInfo
import androidx.annotation.BinderThread
import androidx.annotation.UiThread
import androidx.annotation.VisibleForTesting
@@ -370,7 +369,6 @@
override fun onRecentsAnimationStart(
controller: RecentsAnimationController,
targets: RecentsAnimationTargets,
- transitionInfo: TransitionInfo,
) {
Log.d(TAG, "recents animation started: $command")
updateRecentsViewFocus(command)
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 64c1129..1f95c41 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -268,7 +268,7 @@
*
* @return the overview intent
*/
- Intent getOverviewIntentIgnoreSysUiState() {
+ public Intent getOverviewIntentIgnoreSysUiState() {
return mIsDefaultHome ? mMyHomeIntent : mOverviewIntent;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 87bf81c..8fc1a78 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -26,7 +26,6 @@
import android.os.Bundle;
import android.util.ArraySet;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -94,7 +93,7 @@
RemoteAnimationTarget[] appTargets, Rect homeContentInsets,
Rect minimizedHomeBounds, Bundle extras) {
onAnimationStart(controller, appTargets, new RemoteAnimationTarget[0],
- homeContentInsets, minimizedHomeBounds, extras, /* transitionInfo= */ null);
+ homeContentInsets, minimizedHomeBounds, extras);
}
// Called only in R+ platform
@@ -102,8 +101,7 @@
public final void onAnimationStart(RecentsAnimationControllerCompat animationController,
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
- Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras,
- TransitionInfo transitionInfo) {
+ Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras) {
long appCount = Arrays.stream(appTargets)
.filter(app -> app.mode == MODE_CLOSING)
.count();
@@ -143,7 +141,7 @@
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
ActiveGestureProtoLogProxy.logOnRecentsAnimationStart(targets.apps.length);
for (RecentsAnimationListener listener : getListeners()) {
- listener.onRecentsAnimationStart(mController, targets, transitionInfo);
+ listener.onRecentsAnimationStart(mController, targets);
}
});
}
@@ -207,7 +205,7 @@
*/
public interface RecentsAnimationListener {
default void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {}
+ RecentsAnimationTargets targets) {}
/**
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 8edbacb..89337e5 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -24,7 +24,6 @@
import android.graphics.Rect;
import android.util.Log;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -214,8 +213,7 @@
* Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this creates distinct
* transform params per app in {@code targets.apps} list.
*/
- public RemoteTargetHandle[] assignTargetsForDesktop(
- RemoteAnimationTargets targets, TransitionInfo transitionInfo) {
+ public RemoteTargetHandle[] assignTargetsForDesktop(RemoteAnimationTargets targets) {
resizeRemoteTargetHandles(targets);
for (int i = 0; i < mRemoteTargetHandles.length; i++) {
@@ -224,7 +222,6 @@
.filter(target -> target.taskId != primaryTaskTarget.taskId).toList();
mRemoteTargetHandles[i].mTransformParams.setTargetSet(
createRemoteAnimationTargetsForTarget(targets, excludeTargets));
- mRemoteTargetHandles[i].mTransformParams.setTransitionInfo(transitionInfo);
mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
}
return mRemoteTargetHandles;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.kt b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
index a7405a0..75694af 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.kt
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
@@ -45,7 +45,6 @@
import android.window.RemoteTransition
import android.window.TaskSnapshot
import android.window.TransitionFilter
-import android.window.TransitionInfo
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
@@ -1175,7 +1174,6 @@
homeContentInsets: Rect?,
minimizedHomeBounds: Rect?,
extras: Bundle?,
- transitionInfo: TransitionInfo?,
) =
listener.onAnimationStart(
RecentsAnimationControllerCompat(controller),
@@ -1188,7 +1186,6 @@
// https://developer.android.com/guide/components/aidl#Bundles
classLoader = SplitBounds::class.java.classLoader
},
- transitionInfo,
)
override fun onAnimationCanceled(taskIds: IntArray?, taskSnapshots: Array<TaskSnapshot>?) =
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index cea7931..731c256 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
@@ -36,7 +35,6 @@
import android.os.SystemProperties;
import android.util.Log;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -54,7 +52,6 @@
import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -70,7 +67,6 @@
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
- private TransitionInfo mTransitionInfo;
private RecentsAnimationDeviceState mDeviceState;
// Temporary until we can hook into gesture state events
@@ -112,16 +108,6 @@
return SystemUiProxy.INSTANCE.get(mCtx);
}
- /**
- * Preloads the recents animation.
- */
- public void preloadRecentsAnimation(Intent intent) {
- // Pass null animation handler to indicate this start is for preloading
- UI_HELPER_EXECUTOR.execute(() -> {
- ActivityManagerWrapper.getInstance().preloadRecentsActivity(intent);
- });
- }
-
boolean shouldIgnoreMotionEvents() {
return mShouldIgnoreMotionEvents;
}
@@ -168,7 +154,7 @@
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
ActiveGestureProtoLogProxy.logStartRecentsAnimationCallback(
"onRecentsAnimationStart");
@@ -182,7 +168,6 @@
}
mController = controller;
mTargets = targets;
- mTransitionInfo = transitionInfo;
// TODO(b/236226779): We can probably get away w/ setting mLastAppearedTaskTargets
// to all appeared targets directly vs just looking at running ones
int[] runningTaskIds = mLastGestureState.getRunningTaskIds(targets.apps.length > 1);
@@ -451,7 +436,7 @@
public void notifyRecentsAnimationState(
RecentsAnimationCallbacks.RecentsAnimationListener listener) {
if (isRecentsAnimationRunning()) {
- listener.onRecentsAnimationStart(mController, mTargets, mTransitionInfo);
+ listener.onRecentsAnimationStart(mController, mTargets);
}
// TODO: Do we actually need to report canceled/finished?
}
@@ -491,7 +476,6 @@
mController = null;
mCallbacks = null;
mTargets = null;
- mTransitionInfo = null;
mLastGestureState = null;
mLastAppearedTaskTargets = null;
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 3e90374..dec36cf 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -189,8 +189,7 @@
RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
recentsView.getSizeStrategy(), targets, forDesktop);
if (forDesktop) {
- remoteTargetHandles =
- gluer.assignTargetsForDesktop(targets, /* transitionInfo=*/ null);
+ remoteTargetHandles = gluer.assignTargetsForDesktop(targets);
} else if (v.containsMultipleTasks()) {
remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets,
((GroupedTaskView) v).getSplitBoundsConfig());
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index a06029b..efd9a56 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -49,7 +49,6 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
-import android.os.Trace;
import android.util.Log;
import android.view.Choreographer;
import android.view.InputDevice;
@@ -68,7 +67,6 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.desktop.DesktopAppLaunchTransitionManager;
-import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarActivityContext;
@@ -96,6 +94,7 @@
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
import com.android.quickstep.util.ActiveTrackpadList;
+import com.android.quickstep.util.ActivityPreloadUtil;
import com.android.quickstep.util.ContextualSearchInvoker;
import com.android.quickstep.util.ContextualSearchStateManager;
import com.android.quickstep.views.RecentsViewContainer;
@@ -183,7 +182,7 @@
recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
unfoldTransition, dragAndDrop);
tis.initInputMonitor("TISBinder#onInitialize()");
- tis.preloadOverview(true /* fromInit */);
+ ActivityPreloadUtil.preloadOverviewForTIS(tis, true /* fromInit */);
}));
}
@@ -350,16 +349,6 @@
));
}
- /**
- * Preloads the Overview activity.
- * <p>
- * This method should only be used when the All Set page of the SUW is reached to safely
- * preload the Launcher for the SUW first reveal.
- */
- public void preloadOverviewForSUWAllSet() {
- executeForTouchInteractionService(tis -> tis.preloadOverview(false, true));
- }
-
@Override
public void onRotationProposal(int rotation, boolean isValid) {
executeForTaskbarManager(taskbarManager ->
@@ -1035,47 +1024,6 @@
}
}
- private void preloadOverview(boolean fromInit) {
- Trace.beginSection("preloadOverview(fromInit=" + fromInit + ")");
- preloadOverview(fromInit, false);
- Trace.endSection();
- }
-
- private void preloadOverview(boolean fromInit, boolean forSUWAllSet) {
- if (!LockedUserState.get(this).isUserUnlocked()) {
- return;
- }
-
- if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
- // Prevent the overview from being started before the real home on first boot.
- return;
- }
-
- if ((RestoreDbTask.isPending(this) && !forSUWAllSet)
- || !mDeviceState.isUserSetupComplete()) {
- // Preloading while a restore is pending may cause launcher to start the restore
- // too early.
- return;
- }
-
- final BaseContainerInterface containerInterface =
- mOverviewComponentObserver.getContainerInterface();
- final Intent overviewIntent = new Intent(
- mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
- if (containerInterface.getCreatedContainer() != null && fromInit) {
- // The activity has been created before the initialization of overview service. It is
- // usually happens when booting or launcher is the top activity, so we should already
- // have the latest state.
- return;
- }
-
- // TODO(b/258022658): Remove temporary logging.
- Log.i(TAG, "preloadOverview: forSUWAllSet=" + forSUWAllSet
- + ", isHomeAndOverviewSame=" + mOverviewComponentObserver.isHomeAndOverviewSame());
- ActiveGestureProtoLogProxy.logPreloadRecentsAnimation();
- mTaskAnimationManager.preloadRecentsAnimation(overviewIntent);
- }
-
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (!LockedUserState.get(this).isUserUnlocked()) {
@@ -1103,7 +1051,7 @@
return;
}
- preloadOverview(false /* fromInit */);
+ ActivityPreloadUtil.preloadOverviewForTIS(this, false /* fromInit */);
}
private static boolean isTablet(Configuration config) {
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
index 973fb2f..12bae53 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
@@ -49,7 +49,6 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.animation.Interpolator;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -125,8 +124,8 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
- super.onRecentsAnimationStart(controller, targets, transitionInfo);
+ RecentsAnimationTargets targets) {
+ super.onRecentsAnimationStart(controller, targets);
initTransformParams();
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 503b900..01f5522 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -37,7 +37,6 @@
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.view.VelocityTracker;
-import android.window.TransitionInfo;
import com.android.app.animation.Interpolators;
import com.android.launcher3.R;
@@ -250,7 +249,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
mRecentsAnimationController = controller;
mTransformParams.setTargetSet(targets);
applyTransform();
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index c91bebe..6dcb7bc 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -28,7 +28,6 @@
import android.content.Intent;
import android.graphics.Point;
import android.view.MotionEvent;
-import android.window.TransitionInfo;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
@@ -173,7 +172,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
mRecentsAnimationController = controller;
mStateCallback.setState(STATE_TARGET_RECEIVED);
}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 4995e77..c986b88 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -73,6 +73,7 @@
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener;
import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.util.ActivityPreloadUtil;
import com.android.quickstep.util.LottieAnimationColorUtils;
import com.android.quickstep.util.TISBindHelper;
@@ -202,6 +203,7 @@
OverviewComponentObserver.INSTANCE.get(this)
.addOverviewChangeListener(mOverviewChangeListener);
+ ActivityPreloadUtil.preloadOverviewForSUWAllSet(this);
}
private InvariantDeviceProfile getIDP() {
@@ -291,7 +293,6 @@
private void onTISConnected(TISBinder binder) {
setSetupUIVisible(isResumed());
binder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
- binder.preloadOverviewForSUWAllSet();
TaskbarManager taskbarManager = binder.getTaskbarManager();
if (taskbarManager != null) {
mLauncherStartAnim = taskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
@@ -299,10 +300,7 @@
}
private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
- TISBinder binder = mTISBindHelper.getBinder();
- if (binder != null) {
- binder.preloadOverviewForSUWAllSet();
- }
+ ActivityPreloadUtil.preloadOverviewForSUWAllSet(this);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/ActivityPreloadUtil.kt b/quickstep/src/com/android/quickstep/util/ActivityPreloadUtil.kt
new file mode 100644
index 0000000..47b39db
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/ActivityPreloadUtil.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.content.Context
+import android.content.Intent
+import android.os.Trace
+import com.android.launcher3.provider.RestoreDbTask
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.LockedUserState
+import com.android.quickstep.OverviewComponentObserver
+import com.android.quickstep.RecentsAnimationDeviceState
+import com.android.systemui.shared.system.ActivityManagerWrapper
+
+/** Utility class for preloading overview */
+object ActivityPreloadUtil {
+
+ @JvmStatic
+ fun preloadOverviewForSUWAllSet(ctx: Context) {
+ preloadOverview(ctx, fromInit = false, forSUWAllSet = true)
+ }
+
+ @JvmStatic
+ fun preloadOverviewForTIS(ctx: Context, fromInit: Boolean) {
+ preloadOverview(ctx, fromInit = fromInit, forSUWAllSet = false)
+ }
+
+ private fun preloadOverview(ctx: Context, fromInit: Boolean, forSUWAllSet: Boolean) {
+ Trace.beginSection("preloadOverview(fromInit=$fromInit, forSUWAllSet=$forSUWAllSet)")
+
+ try {
+ if (!LockedUserState.get(ctx).isUserUnlocked) return
+
+ val deviceState = RecentsAnimationDeviceState.INSTANCE[ctx]
+ val overviewCompObserver = OverviewComponentObserver.INSTANCE[ctx]
+
+ // Prevent the overview from being started before the real home on first boot
+ if (deviceState.isButtonNavMode && !overviewCompObserver.isHomeAndOverviewSame) return
+
+ // Preloading while a restore is pending may cause launcher to start the restore too
+ // early
+ if ((RestoreDbTask.isPending(ctx) && !forSUWAllSet) || !deviceState.isUserSetupComplete)
+ return
+
+ // The activity has been created before the initialization of overview service. It is
+ // usually happens when booting or launcher is the top activity, so we should already
+ // have the latest state.
+ if (fromInit && overviewCompObserver.containerInterface.createdContainer != null) return
+
+ ActiveGestureProtoLogProxy.logPreloadRecentsAnimation()
+ val overviewIntent = Intent(overviewCompObserver.overviewIntentIgnoreSysUiState)
+ Executors.UI_HELPER_EXECUTOR.execute {
+ ActivityManagerWrapper.getInstance().preloadRecentsActivity(overviewIntent)
+ }
+ } finally {
+ Trace.endSection()
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 202574b..c524286 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -678,7 +678,7 @@
}
@Override
- public void startAnimation(IBinder transition, TransitionInfo transitionInfo,
+ public void startAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishedCallback) {
final Runnable finishAdapter = () -> {
@@ -708,7 +708,7 @@
null /* nonApps */,
mStateManager,
mDepthController,
- transitionInfo, t, () -> {
+ info, t, () -> {
finishAdapter.run();
cleanup(true /*success*/);
},
@@ -920,7 +920,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
StatsLogManager.LauncherEvent launcherDesktopSplitEvent =
mSplitPosition == STAGE_POSITION_BOTTOM_OR_RIGHT ?
LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM :
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 32c4b90..425c4fe 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -30,7 +30,6 @@
import android.app.ActivityOptions;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.window.TransitionInfo;
import androidx.annotation.BinderThread;
@@ -115,7 +114,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
mController.setInitialTaskSelect(mRunningTaskInfo,
mLeftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT,
null /* itemInfo */,
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index bb88818..401eccc 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -19,12 +19,9 @@
import android.util.FloatProperty;
import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.window.TransitionInfo;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
-import com.android.window.flags.Flags;
public class TransformParams {
@@ -59,7 +56,6 @@
private float mTargetAlpha;
private float mCornerRadius;
private RemoteAnimationTargets mTargetSet;
- private TransitionInfo mTransitionInfo;
private SurfaceTransactionApplier mSyncTransactionApplier;
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
@@ -111,14 +107,6 @@
}
/**
- * Provides the {@code TransitionInfo} of the transition that this transformation stems from.
- */
- public TransformParams setTransitionInfo(TransitionInfo transitionInfo) {
- mTransitionInfo = transitionInfo;
- return this;
- }
-
- /**
* Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
* are computed based on these TransformParams.
*/
@@ -164,9 +152,6 @@
builder.setAlpha(getTargetAlpha());
}
targetProxy.onBuildTargetParams(builder, app, this);
- // Override the corner radius for {@code app} with the leash used by Shell, so that it
- // doesn't interfere with the window clip and corner radius applied here.
- overrideChangeLeashCornerRadiusToZero(app, transaction.getTransaction());
}
// always put wallpaper layer to bottom.
@@ -178,28 +163,6 @@
return transaction;
}
- private void overrideChangeLeashCornerRadiusToZero(
- RemoteAnimationTarget app, SurfaceControl.Transaction transaction) {
- if (!Flags.enableDesktopRecentsTransitionsCornersBugfix()) {
- return;
- }
- SurfaceControl changeLeash = getChangeLeashForApp(app);
- if (changeLeash != null) {
- transaction.setCornerRadius(changeLeash, 0);
- }
- }
-
- private SurfaceControl getChangeLeashForApp(RemoteAnimationTarget app) {
- if (mTransitionInfo == null) return null;
- for (TransitionInfo.Change change : mTransitionInfo.getChanges()) {
- if (change.getTaskInfo() == null) continue;
- if (change.getTaskInfo().taskId == app.taskId) {
- return change.getLeash();
- }
- }
- return null;
- }
-
// Pubic getters so outside packages can read the values.
public float getProgress() {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 9a4933a..045b823 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -5870,8 +5870,7 @@
if (recentsAnimationTargets.hasDesktopTasks(mContext)) {
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
true /* forDesktop */);
- mRemoteTargetHandles = gluer.assignTargetsForDesktop(
- recentsAnimationTargets, /* transitionInfo= */ null);
+ mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
} else {
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
false);
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt
index 3ca36ec..da362bd 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt
@@ -94,7 +94,9 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync {
bubbleAnimator.animateNewAndRemoveOld(
selectedBubbleIndex = 3,
- removedBubbleIndex = 2,
+ newlySelectedBubbleIndex = 2,
+ removedBubbleIndex = 1,
+ addedBubbleIndex = 3,
listener,
)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index 542eb64..f16e193 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -364,7 +364,7 @@
private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
- mRecentsAnimationController, mRecentsAnimationTargets, /* transitionInfo= */null));
+ mRecentsAnimationController, mRecentsAnimationTargets));
}
protected static void runOnMainSync(Runnable runnable) {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index e065dba..88be752 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -165,7 +165,6 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/355466672
public void testPrivateSpaceLockingBehaviour() throws IOException {
assumeFalse(mLauncher.isTablet()); // b/367258373
// Scroll to the bottom of All Apps
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 6e2d357..a526b89 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -24,25 +24,38 @@
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.ModelDbController;
+import com.android.launcher3.util.LayoutImportExportHelper;
import com.android.launcher3.widget.LauncherWidgetHolder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.function.ToIntFunction;
public class LauncherProvider extends ContentProvider {
private static final String TAG = "LauncherProvider";
+ // Method API For Provider#call method.
+ private static final String METHOD_EXPORT_LAYOUT_XML = "EXPORT_LAYOUT_XML";
+ private static final String METHOD_IMPORT_LAYOUT_XML = "IMPORT_LAYOUT_XML";
+ private static final String KEY_RESULT = "KEY_RESULT";
+ private static final String KEY_LAYOUT = "KEY_LAYOUT";
+ private static final String SUCCESS = "success";
+ private static final String FAILURE = "failure";
+
/**
* $ adb shell dumpsys activity provider com.android.launcher3
*/
@@ -142,6 +155,43 @@
return executeControllerTask(c -> c.update(args.table, values, args.where, args.args));
}
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ Bundle b = new Bundle();
+
+ // The caller must have the read or write permission for this content provider to
+ // access the "call" method at all. We also enforce the appropriate per-method permissions.
+ switch(method) {
+ case METHOD_EXPORT_LAYOUT_XML:
+ if (getContext().checkCallingOrSelfPermission(getReadPermission())
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller doesn't have read permission");
+ }
+
+ CompletableFuture<String> resultFuture = LayoutImportExportHelper.INSTANCE
+ .exportModelDbAsXmlFuture(getContext());
+ try {
+ b.putString(KEY_LAYOUT, resultFuture.get());
+ b.putString(KEY_RESULT, SUCCESS);
+ } catch (ExecutionException | InterruptedException e) {
+ b.putString(KEY_RESULT, FAILURE);
+ }
+ return b;
+
+ case METHOD_IMPORT_LAYOUT_XML:
+ if (getContext().checkCallingOrSelfPermission(getWritePermission())
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller doesn't have write permission");
+ }
+
+ LayoutImportExportHelper.INSTANCE.importModelFromXml(getContext(), arg);
+ b.putString(KEY_RESULT, SUCCESS);
+ return b;
+ default:
+ return null;
+ }
+ }
+
private int executeControllerTask(ToIntFunction<ModelDbController> task) {
if (Binder.getCallingPid() == Process.myPid()) {
throw new IllegalArgumentException("Same process should call model directly");
diff --git a/src/com/android/launcher3/util/LayoutImportExportHelper.kt b/src/com/android/launcher3/util/LayoutImportExportHelper.kt
new file mode 100644
index 0000000..4033f60
--- /dev/null
+++ b/src/com/android/launcher3/util/LayoutImportExportHelper.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util
+
+import android.app.blob.BlobHandle.createWithSha256
+import android.app.blob.BlobStoreManager
+import android.content.Context
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream
+import android.provider.Settings.Secure
+import com.android.launcher3.AutoInstallsLayout
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+import com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL
+import com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG
+import com.android.launcher3.LauncherSettings.Settings.LAYOUT_PROVIDER_KEY
+import com.android.launcher3.LauncherSettings.Settings.createBlobProviderKey
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.MODEL_EXECUTOR
+import com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR
+import java.nio.charset.StandardCharsets
+import java.security.MessageDigest
+import java.util.concurrent.CompletableFuture
+
+object LayoutImportExportHelper {
+ fun exportModelDbAsXmlFuture(context: Context): CompletableFuture<String> {
+ val future = CompletableFuture<String>()
+ exportModelDbAsXml(context) { xmlString -> future.complete(xmlString) }
+ return future
+ }
+
+ fun exportModelDbAsXml(context: Context, callback: (String) -> Unit) {
+ val model = LauncherAppState.getInstance(context).model
+
+ model.enqueueModelUpdateTask { _, dataModel, _ ->
+ val builder = LauncherLayoutBuilder()
+ dataModel.workspaceItems.forEach { info ->
+ val loc =
+ when (info.container) {
+ CONTAINER_DESKTOP ->
+ builder.atWorkspace(info.cellX, info.cellY, info.screenId)
+
+ CONTAINER_HOTSEAT -> builder.atHotseat(info.screenId)
+ else -> return@forEach
+ }
+ loc.addItem(context, info)
+ }
+ dataModel.appWidgets.forEach { info ->
+ builder.atWorkspace(info.cellX, info.cellY, info.screenId).addItem(context, info)
+ }
+
+ val layoutXml = builder.build()
+ callback(layoutXml)
+ }
+ }
+
+ fun importModelFromXml(context: Context, xmlString: String) {
+ importModelFromXml(context, xmlString.toByteArray(StandardCharsets.UTF_8))
+ }
+
+ fun importModelFromXml(context: Context, data: ByteArray) {
+ val model = LauncherAppState.getInstance(context).model
+
+ val digest = MessageDigest.getInstance("SHA-256").digest(data)
+ val handle = createWithSha256(digest, LAYOUT_DIGEST_LABEL, 0, LAYOUT_DIGEST_TAG)
+ val blobManager = context.getSystemService(BlobStoreManager::class.java)!!
+
+ val resolver = context.contentResolver
+
+ blobManager.openSession(blobManager.createSession(handle)).use { session ->
+ AutoCloseOutputStream(session.openWrite(0, -1)).use { it.write(data) }
+ session.allowPublicAccess()
+
+ session.commit(ORDERED_BG_EXECUTOR) {
+ Secure.putString(resolver, LAYOUT_PROVIDER_KEY, createBlobProviderKey(digest))
+
+ MODEL_EXECUTOR.submit { model.modelDbController.createEmptyDB() }.get()
+ MAIN_EXECUTOR.submit { model.forceReload() }.get()
+ MODEL_EXECUTOR.submit {}.get()
+ Secure.putString(resolver, LAYOUT_PROVIDER_KEY, null)
+ }
+ }
+ }
+
+ private fun LauncherLayoutBuilder.ItemTarget.addItem(context: Context, info: ItemInfo) {
+ val userType: String? =
+ when (UserCache.INSTANCE.get(context).getUserInfo(info.user).type) {
+ UserIconInfo.TYPE_WORK -> AutoInstallsLayout.USER_TYPE_WORK
+ UserIconInfo.TYPE_CLONED -> AutoInstallsLayout.USER_TYPE_CLONED
+ else -> null
+ }
+ when (info.itemType) {
+ ITEM_TYPE_APPLICATION ->
+ info.targetComponent?.let { c -> putApp(c.packageName, c.className, userType) }
+ ITEM_TYPE_DEEP_SHORTCUT ->
+ ShortcutKey.fromItemInfo(info).let { key ->
+ putShortcut(key.packageName, key.id, userType)
+ }
+ ITEM_TYPE_FOLDER ->
+ (info as FolderInfo).let { folderInfo ->
+ putFolder(folderInfo.title?.toString() ?: "").also { folderBuilder ->
+ folderInfo.getContents().forEach { folderContent ->
+ folderBuilder.addItem(context, folderContent)
+ }
+ }
+ }
+ ITEM_TYPE_APPWIDGET ->
+ putWidget(
+ (info as LauncherAppWidgetInfo).providerName.packageName,
+ info.providerName.className,
+ info.spanX,
+ info.spanY,
+ userType,
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt b/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt
deleted file mode 100644
index a6de607..0000000
--- a/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.tablet
-
-import android.platform.test.rule.AllowedDevices
-import android.platform.test.rule.DeviceProduct
-import com.android.launcher3.Launcher
-import com.android.launcher3.ui.AbstractLauncherUiTest
-import junit.framework.TestCase.assertFalse
-import junit.framework.TestCase.assertTrue
-import org.junit.Test
-
-class TaplIsTabletTest : AbstractLauncherUiTest<Launcher>() {
-
- /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */
- @Test
- @AllowedDevices(
- DeviceProduct.CF_FOLDABLE,
- DeviceProduct.CF_TABLET,
- DeviceProduct.TANGORPRO,
- DeviceProduct.FELIX,
- DeviceProduct.COMET,
- )
- fun isTabletShouldBeTrue() {
- assertTrue(mLauncher.isTablet)
- }
-
- /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */
- @Test
- @AllowedDevices(DeviceProduct.CF_PHONE, DeviceProduct.CHEETAH)
- fun isTabletShouldBeFalse() {
- assertFalse(mLauncher.isTablet)
- }
-}
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 460ffc4..3e3e643 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -51,7 +51,6 @@
@Test
@PortraitLandscape
public void testDragIcon() throws Throwable {
- mLauncher.enableDebugTracing(); // b/289161193
commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
@@ -72,7 +71,6 @@
TestUtil.DEFAULT_UI_TIMEOUT);
assertNotNull("Widget not found on the workspace", widget);
widget.launch(getAppPackageName());
- mLauncher.disableDebugTracing(); // b/289161193
}
/**