summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-13 00:23:08 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-13 00:23:08 +0000
commit6fdc2fda19b1398b4affbd0c59701f77cfe190f9 (patch)
tree4634dcdf8970cec4554e42aa0eb08b9a62bdce92
parent24ddc4ec44ebdd8821cfa874f020b076d8bb1d2f (diff)
parentd48279bf1dfb4a6866cbdabc12a84703c438796d (diff)
downloadLauncher3-6fdc2fda19b1398b4affbd0c59701f77cfe190f9.tar.gz
Snap for 11211173 from d48279bf1dfb4a6866cbdabc12a84703c438796d to 24Q1-release
Change-Id: Ib0f855c521d9356b3b003c4945bfd1ef71ebcd59
-rw-r--r--quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java10
-rw-r--r--quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt81
-rw-r--r--quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java12
-rw-r--r--quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java4
-rw-r--r--quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java2
-rw-r--r--quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java5
-rw-r--r--quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java5
-rw-r--r--quickstep/src/com/android/quickstep/SystemUiProxy.java39
-rw-r--r--quickstep/src/com/android/quickstep/views/RecentsView.java23
-rw-r--r--quickstep/src/com/android/quickstep/views/TaskView.java63
-rw-r--r--quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java2
-rw-r--r--quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java2
-rw-r--r--quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt202
-rw-r--r--src/com/android/launcher3/AbstractFloatingView.java4
-rw-r--r--src/com/android/launcher3/AppWidgetsRestoredReceiver.java21
-rw-r--r--src/com/android/launcher3/InvariantDeviceProfile.java6
-rw-r--r--src/com/android/launcher3/model/LoaderTask.java22
-rw-r--r--src/com/android/launcher3/model/ModelDbController.java10
-rw-r--r--src/com/android/launcher3/provider/RestoreDbTask.java115
-rw-r--r--src/com/android/launcher3/shortcuts/ShortcutRequest.java5
-rw-r--r--tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java2
-rw-r--r--tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java13
-rw-r--r--tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java50
23 files changed, 501 insertions, 197 deletions
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index fc04d6c6b7..38ee4ac9ba 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -74,6 +74,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -183,6 +184,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
private DeviceProfile mPersistentTaskbarDeviceProfile;
+ private final LauncherPrefs mLauncherPrefs;
+
public TaskbarActivityContext(Context windowContext,
@Nullable Context navigationBarPanelContext, DeviceProfile launcherDp,
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
@@ -294,6 +297,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this),
bubbleControllersOptional);
+
+ mLauncherPrefs = LauncherPrefs.get(this);
}
/** Updates {@link DeviceProfile} instances for any Taskbar windows. */
@@ -411,6 +416,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
getDeviceProfile().toSmallString());
}
+ @NonNull
+ public LauncherPrefs getLauncherPrefs() {
+ return mLauncherPrefs;
+ }
+
/**
* Returns the View bounds of transient taskbar.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index cbfa0247e8..6cb28eee36 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -16,7 +16,9 @@
package com.android.launcher3.taskbar
import android.animation.AnimatorSet
+import android.annotation.SuppressLint
import android.view.View
+import androidx.annotation.VisibleForTesting
import androidx.core.animation.doOnEnd
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
@@ -31,46 +33,68 @@ class TaskbarPinningController(private val context: TaskbarActivityContext) :
private lateinit var controllers: TaskbarControllers
private lateinit var taskbarSharedState: TaskbarSharedState
- private val launcherPrefs = LauncherPrefs.get(context)
+ private lateinit var launcherPrefs: LauncherPrefs
private val statsLogManager = context.statsLogManager
- private var isAnimatingTaskbarPinning = false
+ @VisibleForTesting var isAnimatingTaskbarPinning = false
+ @VisibleForTesting lateinit var onCloseCallback: (preferenceChanged: Boolean) -> Unit
+ @SuppressLint("VisibleForTests")
fun init(taskbarControllers: TaskbarControllers, sharedState: TaskbarSharedState) {
controllers = taskbarControllers
taskbarSharedState = sharedState
+ launcherPrefs = context.launcherPrefs
+ onCloseCallback =
+ fun(didPreferenceChange: Boolean) {
+ statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
+ context.dragLayer.post { context.onPopupVisibilityChanged(false) }
+
+ if (!didPreferenceChange) {
+ return
+ }
+ val animateToValue =
+ if (!launcherPrefs.get(TASKBAR_PINNING)) {
+ PINNING_PERSISTENT
+ } else {
+ PINNING_TRANSIENT
+ }
+ taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
+ animateTaskbarPinning(animateToValue)
+ }
}
fun showPinningView(view: View) {
context.isTaskbarWindowFullscreen = true
-
view.post {
- val popupView = createAndPopulate(view, context)
+ val popupView = getPopupView(view)
popupView.requestFocus()
-
- popupView.onCloseCallback =
- callback@{ didPreferenceChange ->
- statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
- context.dragLayer.post { context.onPopupVisibilityChanged(false) }
-
- if (!didPreferenceChange) {
- return@callback
- }
- val animateToValue =
- if (!launcherPrefs.get(TASKBAR_PINNING)) {
- PINNING_PERSISTENT
- } else {
- PINNING_TRANSIENT
- }
- taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
- animateTaskbarPinning(animateToValue)
- }
+ popupView.onCloseCallback = onCloseCallback
context.onPopupVisibilityChanged(true)
popupView.show()
statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN)
}
}
- private fun animateTaskbarPinning(animateToValue: Float) {
+ @VisibleForTesting
+ fun getPopupView(view: View): TaskbarDividerPopupView<*> {
+ return createAndPopulate(view, context)
+ }
+
+ @VisibleForTesting
+ fun animateTaskbarPinning(animateToValue: Float) {
+ val taskbarViewController = controllers.taskbarViewController
+ val animatorSet =
+ getAnimatorSetForTaskbarPinningAnimation(animateToValue).apply {
+ doOnEnd { recreateTaskbarAndUpdatePinningValue() }
+ duration = PINNING_ANIMATION_DURATION
+ }
+ controllers.taskbarOverlayController.hideWindow()
+ updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
+ taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation()
+ animatorSet.start()
+ }
+
+ @VisibleForTesting
+ fun getAnimatorSetForTaskbarPinningAnimation(animateToValue: Float): AnimatorSet {
val animatorSet = AnimatorSet()
val taskbarViewController = controllers.taskbarViewController
val dragLayerController = controllers.taskbarDragLayerController
@@ -82,13 +106,7 @@ class TaskbarPinningController(private val context: TaskbarActivityContext) :
taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
)
- controllers.taskbarOverlayController.hideWindow()
-
- animatorSet.doOnEnd { recreateTaskbarAndUpdatePinningValue() }
- animatorSet.duration = PINNING_ANIMATION_DURATION
- updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
- taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation()
- animatorSet.start()
+ return animatorSet
}
private fun updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(isAnimating: Boolean) {
@@ -96,7 +114,8 @@ class TaskbarPinningController(private val context: TaskbarActivityContext) :
context.dragLayer.setAnimatingTaskbarPinning(isAnimating)
}
- private fun recreateTaskbarAndUpdatePinningValue() {
+ @VisibleForTesting
+ fun recreateTaskbarAndUpdatePinningValue() {
updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 176a8c5e51..1224b3f064 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -73,9 +73,17 @@ public class TaskbarSharedState {
};
// Allows us to shift translation logic when doing taskbar pinning animation.
- public Boolean startTaskbarVariantIsTransient = true;
+ public boolean startTaskbarVariantIsTransient = true;
// To track if taskbar was pinned using taskbar pinning feature at the time of recreate,
// so we can unstash transient taskbar when we un-pinning taskbar.
- public Boolean taskbarWasPinned = false;
+ private boolean mTaskbarWasPinned = false;
+
+ public boolean getTaskbarWasPinned() {
+ return mTaskbarWasPinned;
+ }
+
+ public void setTaskbarWasPinned(boolean taskbarWasPinned) {
+ mTaskbarWasPinned = taskbarWasPinned;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 9c532ec4f8..c74ddcbd21 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -307,7 +307,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_AUTO,
- isTransientTaskbar && !mTaskbarSharedState.taskbarWasPinned);
+ isTransientTaskbar && !mTaskbarSharedState.getTaskbarWasPinned());
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
updateStateForFlag(FLAG_IN_SETUP, isInSetup);
updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, isPhoneMode()
@@ -316,7 +316,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
// us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
updateStateForFlag(FLAG_IN_APP, true);
applyState(/* duration = */ 0);
- if (mTaskbarSharedState.taskbarWasPinned) {
+ if (mTaskbarSharedState.getTaskbarWasPinned()) {
tryStartTaskbarTimeout();
}
notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 5ce2a7a246..964d329066 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -222,7 +222,7 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = !mAppsView.shouldContainerScroll(ev)
|| getTopOpenViewWithType(
- mActivityContext, TYPE_ACCESSIBLE & ~TYPE_TASKBAR_OVERLAYS) != null;
+ mActivityContext, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null;
}
return super.onControllerInterceptTouchEvent(ev);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 8cbf2394ae..2c937b008e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -15,8 +15,7 @@
*/
package com.android.launcher3.uioverrides.touchcontrollers;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
+import static com.android.launcher3.AbstractFloatingView.TYPE_TOUCH_CONTROLLER_NO_INTERCEPT;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -84,7 +83,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
return false;
}
}
- if (getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE | TYPE_ALL_APPS_EDU) != null) {
+ if (getTopOpenViewWithType(mLauncher, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) {
return false;
}
return true;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 3d94857848..19bfe069c8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -15,7 +15,7 @@
*/
package com.android.launcher3.uioverrides.touchcontrollers;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
+import static com.android.launcher3.AbstractFloatingView.TYPE_TOUCH_CONTROLLER_NO_INTERCEPT;
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH;
@@ -112,7 +112,8 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
// If we are already animating from a previous state, we can intercept.
return true;
}
- if (AbstractFloatingView.getTopOpenViewWithType(mActivity, TYPE_ACCESSIBLE) != null) {
+ if (AbstractFloatingView.getTopOpenViewWithType(
+ mActivity, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) {
return false;
}
return isRecentsInteractive();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 27de20cec4..94ed5b9cb0 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -17,7 +17,6 @@ package com.android.quickstep;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
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.SplitConfigurationOptions.StagePosition;
@@ -102,6 +101,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
+import java.util.List;
/**
* Holds the reference to SystemUI.
@@ -147,6 +147,9 @@ public class SystemUiProxy implements ISystemUiProxy {
private IDesktopTaskListener mDesktopTaskListener;
private final LinkedHashMap<RemoteTransition, TransitionFilter> mRemoteTransitions =
new LinkedHashMap<>();
+
+ private final List<Runnable> mStateChangeCallbacks = new ArrayList<>();
+
private IBinder mOriginalTransactionToken = null;
private IOnBackInvokedCallback mBackToLauncherCallback;
private IRemoteAnimationRunner mBackToLauncherRunner;
@@ -268,6 +271,7 @@ public class SystemUiProxy implements ISystemUiProxy {
setDesktopTaskListener(mDesktopTaskListener);
setAssistantOverridesRequested(
AssistUtils.newInstance(mContext).getSysUiAssistOverrideInvocationTypes());
+ mStateChangeCallbacks.forEach(Runnable::run);
}
/**
@@ -278,6 +282,20 @@ public class SystemUiProxy implements ISystemUiProxy {
setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null);
}
+ /**
+ * Adds a callback to be notified whenever the active state changes
+ */
+ public void addOnStateChangeListener(Runnable callback) {
+ mStateChangeCallbacks.add(callback);
+ }
+
+ /**
+ * Removes a previously added state change callback
+ */
+ public void removeOnStateChangeListener(Runnable callback) {
+ mStateChangeCallbacks.remove(callback);
+ }
+
// TODO(141886704): Find a way to remove this
public void setLastSystemUiStateFlags(int stateFlags) {
mLastSystemUiStateFlags = stateFlags;
@@ -1082,6 +1100,25 @@ public class SystemUiProxy implements ISystemUiProxy {
}
/**
+ * Returns a surface which can be used to attach overlays to home task or null if
+ * the task doesn't exist or sysui is not connected
+ */
+ @Nullable
+ public SurfaceControl getHomeTaskOverlayContainer() {
+ // Use a local reference as this method can be called on a worker thread, which can lead
+ // to NullPointer exceptions if mShellTransitions is modified on the main thread.
+ IShellTransitions shellTransitions = mShellTransitions;
+ if (shellTransitions != null) {
+ try {
+ return mShellTransitions.getHomeTaskOverlayContainer();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call getOverlayContainerForTask", e);
+ }
+ }
+ return null;
+ }
+
+ /**
* Use SystemUI's transaction-queue instead of Launcher's independent one. This is necessary
* if Launcher and SystemUI need to coordinate transactions (eg. for shell transitions).
*/
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7e1034b16a..87cee63f9e 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2124,8 +2124,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
taskView.updateTaskSize();
- taskView.getPrimaryNonGridTranslationProperty().set(taskView, accumulatedTranslationX);
- taskView.getSecondaryNonGridTranslationProperty().set(taskView, 0f);
+ taskView.setNonGridTranslationX(accumulatedTranslationX);
taskView.setNonGridPivotTranslationX(translateXToMiddle);
// Compensate space caused by TaskView scaling.
float widthDiff =
@@ -2642,23 +2641,25 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
if (endState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) {
TaskView runningTaskView = getRunningTaskView();
float runningTaskPrimaryGridTranslation = 0;
+ float runningTaskSecondaryGridTranslation = 0;
if (runningTaskView != null) {
// Apply the grid translation to running task unless it's being snapped to
// and removes the current translation applied to the running task.
- runningTaskPrimaryGridTranslation = mOrientationHandler.getPrimaryValue(
- runningTaskView.getGridTranslationX(),
- runningTaskView.getGridTranslationY())
- - runningTaskView.getPrimaryNonGridTranslationProperty().get(
- runningTaskView);
+ runningTaskPrimaryGridTranslation = runningTaskView.getGridTranslationX()
+ - runningTaskView.getNonGridTranslationX();
+ runningTaskSecondaryGridTranslation = runningTaskView.getGridTranslationY();
}
for (TaskViewSimulator tvs : taskViewSimulators) {
if (animatorSet == null) {
setGridProgress(1);
tvs.taskPrimaryTranslation.value = runningTaskPrimaryGridTranslation;
+ tvs.taskSecondaryTranslation.value = runningTaskSecondaryGridTranslation;
} else {
animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
runningTaskPrimaryGridTranslation));
+ animatorSet.play(tvs.taskSecondaryTranslation.animateToValue(
+ runningTaskSecondaryGridTranslation));
}
}
}
@@ -3123,6 +3124,14 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
+ snappedTaskNonGridScrollAdjustment);
}
+ final TaskView runningTask = getRunningTaskView();
+ if (showAsGrid() && enableGridOnlyOverview() && runningTask != null) {
+ runActionOnRemoteHandles(
+ remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
+ .taskSecondaryTranslation.value = runningTask.getGridTranslationY()
+ );
+ }
+
mClearAllButton.setGridTranslationPrimary(
clearAllTotalTranslationX - snappedTaskGridTranslationX);
mClearAllButton.setGridScrollOffset(
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index af4f402f07..b42f0552cd 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -119,6 +119,8 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import kotlin.Unit;
+
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Collections;
@@ -127,8 +129,6 @@ import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
-import kotlin.Unit;
-
/**
* A task in the Recents view.
*/
@@ -304,32 +304,6 @@ public class TaskView extends FrameLayout implements Reusable {
}
};
- private static final FloatProperty<TaskView> NON_GRID_TRANSLATION_X =
- new FloatProperty<TaskView>("nonGridTranslationX") {
- @Override
- public void setValue(TaskView taskView, float v) {
- taskView.setNonGridTranslationX(v);
- }
-
- @Override
- public Float get(TaskView taskView) {
- return taskView.mNonGridTranslationX;
- }
- };
-
- private static final FloatProperty<TaskView> NON_GRID_TRANSLATION_Y =
- new FloatProperty<TaskView>("nonGridTranslationY") {
- @Override
- public void setValue(TaskView taskView, float v) {
- taskView.setNonGridTranslationY(v);
- }
-
- @Override
- public Float get(TaskView taskView) {
- return taskView.mNonGridTranslationY;
- }
- };
-
public static final FloatProperty<TaskView> GRID_END_TRANSLATION_X =
new FloatProperty<TaskView>("gridEndTranslationX") {
@Override
@@ -386,7 +360,6 @@ public class TaskView extends FrameLayout implements Reusable {
// Applied as a complement to gridTranslation, for adjusting the carousel overview and quick
// switch.
private float mNonGridTranslationX;
- private float mNonGridTranslationY;
private float mNonGridPivotTranslationX;
// Used when in SplitScreenSelectState
private float mSplitSelectTranslationY;
@@ -1323,7 +1296,7 @@ public class TaskView extends FrameLayout implements Reusable {
}
protected void resetPersistentViewTransforms() {
- mNonGridTranslationX = mNonGridTranslationY = mGridTranslationX =
+ mNonGridTranslationX = mGridTranslationX =
mGridTranslationY = mBoxTranslationY = mNonGridPivotTranslationX = 0f;
resetViewTransforms();
}
@@ -1494,14 +1467,16 @@ public class TaskView extends FrameLayout implements Reusable {
applyTranslationY();
}
- private void setNonGridTranslationX(float nonGridTranslationX) {
- mNonGridTranslationX = nonGridTranslationX;
- applyTranslationX();
+ public float getNonGridTranslationX() {
+ return mNonGridTranslationX;
}
- private void setNonGridTranslationY(float nonGridTranslationY) {
- mNonGridTranslationY = nonGridTranslationY;
- applyTranslationY();
+ /**
+ * Updates X coordinate of non-grid translation.
+ */
+ public void setNonGridTranslationX(float nonGridTranslationX) {
+ mNonGridTranslationX = nonGridTranslationX;
+ applyTranslationX();
}
public void setGridTranslationX(float gridTranslationX) {
@@ -1540,7 +1515,7 @@ public class TaskView extends FrameLayout implements Reusable {
if (gridEnabled) {
scrollAdjustment += mGridTranslationX;
} else {
- scrollAdjustment += getPrimaryNonGridTranslationProperty().get(this);
+ scrollAdjustment += getNonGridTranslationX();
}
return scrollAdjustment;
}
@@ -1586,9 +1561,7 @@ public class TaskView extends FrameLayout implements Reusable {
* change according to a temporary state (e.g. task offset).
*/
public float getPersistentTranslationY() {
- return mBoxTranslationY
- + getNonGridTrans(mNonGridTranslationY)
- + getGridTrans(mGridTranslationY);
+ return mBoxTranslationY + getGridTrans(mGridTranslationY);
}
public FloatProperty<TaskView> getPrimarySplitTranslationProperty() {
@@ -1626,16 +1599,6 @@ public class TaskView extends FrameLayout implements Reusable {
TASK_RESISTANCE_TRANSLATION_X, TASK_RESISTANCE_TRANSLATION_Y);
}
- public FloatProperty<TaskView> getPrimaryNonGridTranslationProperty() {
- return getPagedOrientationHandler().getPrimaryValue(
- NON_GRID_TRANSLATION_X, NON_GRID_TRANSLATION_Y);
- }
-
- public FloatProperty<TaskView> getSecondaryNonGridTranslationProperty() {
- return getPagedOrientationHandler().getSecondaryValue(
- NON_GRID_TRANSLATION_X, NON_GRID_TRANSLATION_Y);
- }
-
@Override
public boolean hasOverlappingRendering() {
// TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index eced5a9a41..8d54dce8ef 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -144,7 +144,7 @@ public class FallbackRecentsTest {
.around(new TestStabilityRule())
.around(new NavigationModeSwitchRule(mLauncher))
.around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
- .around(viewCaptureRule)
+ // .around(viewCaptureRule) b/315482167
.around(new TestIsolationRule(mLauncher, false))
.around(setLauncherCommand);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 0eec8b7a37..3465f23476 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -86,7 +86,7 @@ public class TaplTestsTrackpad extends AbstractQuickStepTest {
mLauncher.setTrackpadGestureType(TrackpadGestureType.THREE_FINGER);
startTestActivity(2);
- mLauncher.pressBack();
+ mLauncher.getLaunchedAppState().pressBackToWorkspace();
} finally {
instrumentation.getUiAutomation().dropShellPermissionIdentity();
}
diff --git a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
new file mode 100644
index 0000000000..dbe4624e45
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.taskbar.controllers
+
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarBaseTestCase
+import com.android.launcher3.taskbar.TaskbarDividerPopupView
+import com.android.launcher3.taskbar.TaskbarDragLayer
+import com.android.launcher3.taskbar.TaskbarPinningController
+import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_PERSISTENT
+import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_TRANSIENT
+import com.android.launcher3.taskbar.TaskbarSharedState
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TaskbarPinningControllerTest : TaskbarBaseTestCase() {
+ private val taskbarDragLayer = mock<TaskbarDragLayer>()
+ private val taskbarSharedState = mock<TaskbarSharedState>()
+ private val launcherPrefs = mock<LauncherPrefs> { on { get(TASKBAR_PINNING) } doReturn false }
+ private val statsLogger = mock<StatsLogManager.StatsLogger>()
+ private val statsLogManager = mock<StatsLogManager> { on { logger() } doReturn statsLogger }
+ private lateinit var pinningController: TaskbarPinningController
+
+ @Before
+ override fun setup() {
+ super.setup()
+ whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs)
+ whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer)
+ whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager)
+ pinningController = spy(TaskbarPinningController(taskbarActivityContext))
+ pinningController.init(taskbarControllers, taskbarSharedState)
+ }
+
+ @Test
+ fun testOnCloseCallback_whenClosingPopupView_shouldLogStatsForClosingPopupMenu() {
+ pinningController.onCloseCallback(false)
+ verify(statsLogger, times(1)).log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
+ }
+
+ @Test
+ fun testOnCloseCallback_whenClosingPopupView_shouldPostVisibilityChangedToDragLayer() {
+ val argumentCaptor = argumentCaptor<Runnable>()
+ pinningController.onCloseCallback(false)
+ verify(taskbarDragLayer, times(1)).post(argumentCaptor.capture())
+
+ val runnable = argumentCaptor.lastValue
+ assertThat(runnable).isNotNull()
+
+ runnable.run()
+ verify(taskbarActivityContext, times(1)).onPopupVisibilityChanged(false)
+ }
+
+ @Test
+ fun testOnCloseCallback_whenPreferenceUnchanged_shouldNotAnimateTaskbarPinning() {
+ pinningController.onCloseCallback(false)
+ verify(taskbarSharedState, never()).taskbarWasPinned = true
+ verify(pinningController, never()).animateTaskbarPinning(any())
+ }
+
+ @Test
+ fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToPinnedTaskbar() {
+ whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
+ doNothing().whenever(pinningController).animateTaskbarPinning(any())
+
+ pinningController.onCloseCallback(true)
+
+ verify(taskbarSharedState, times(1)).taskbarWasPinned = false
+ verify(pinningController, times(1)).animateTaskbarPinning(PINNING_PERSISTENT)
+ }
+
+ @Test
+ fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToTransientTaskbar() {
+ whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true)
+ doNothing().whenever(pinningController).animateTaskbarPinning(any())
+
+ pinningController.onCloseCallback(true)
+
+ verify(taskbarSharedState, times(1)).taskbarWasPinned = true
+ verify(pinningController, times(1)).animateTaskbarPinning(PINNING_TRANSIENT)
+ }
+
+ @Test
+ fun testShowPinningView_whenShowingPinningView_shouldSetTaskbarWindowFullscreenAndPostRunnableToView() {
+ val popupView =
+ mock<TaskbarDividerPopupView<TaskbarActivityContext>> {
+ on { requestFocus() } doReturn true
+ }
+ val view = mock<View>()
+ val argumentCaptor = argumentCaptor<Runnable>()
+ doReturn(popupView).whenever(pinningController).getPopupView(view)
+
+ pinningController.showPinningView(view)
+
+ verify(view, times(1)).post(argumentCaptor.capture())
+
+ val runnable = argumentCaptor.lastValue
+ assertThat(runnable).isNotNull()
+ runnable.run()
+
+ verify(pinningController, times(1)).getPopupView(view)
+ verify(popupView, times(1)).requestFocus()
+ verify(popupView, times(1)).onCloseCallback = any()
+ verify(taskbarActivityContext, times(1)).onPopupVisibilityChanged(true)
+ verify(popupView, times(1)).show()
+ verify(statsLogger, times(1)).log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN)
+ }
+
+ @Test
+ fun testAnimateTaskbarPinning_whenAnimationEnds_shouldInvokeCallbackDoOnEnd() {
+ val animatorSet = spy(AnimatorSet())
+ doReturn(animatorSet)
+ .whenever(pinningController)
+ .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT)
+ doNothing().whenever(animatorSet).start()
+ pinningController.animateTaskbarPinning(PINNING_PERSISTENT)
+ animatorSet.listeners[0].onAnimationEnd(ObjectAnimator())
+ verify(pinningController, times(1)).recreateTaskbarAndUpdatePinningValue()
+ }
+
+ @Test
+ fun testAnimateTaskbarPinning_whenAnimatingToPersistentTaskbar_shouldAnimateToPinnedTaskbar() {
+ val animatorSet = spy(AnimatorSet())
+ doReturn(animatorSet)
+ .whenever(pinningController)
+ .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT)
+ doNothing().whenever(animatorSet).start()
+ pinningController.animateTaskbarPinning(PINNING_PERSISTENT)
+
+ verify(taskbarOverlayController, times(1)).hideWindow()
+ verify(pinningController, times(1))
+ .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT)
+ verify(taskbarViewController, times(1))
+ .animateAwayNotificationDotsDuringTaskbarPinningAnimation()
+ verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(true)
+ assertThat(pinningController.isAnimatingTaskbarPinning).isTrue()
+ assertThat(animatorSet.listeners).isNotNull()
+ }
+
+ @Test
+ fun testAnimateTaskbarPinning_whenAnimatingToTransientTaskbar_shouldAnimateToTransientTaskbar() {
+ val animatorSet = spy(AnimatorSet())
+ doReturn(animatorSet)
+ .whenever(pinningController)
+ .getAnimatorSetForTaskbarPinningAnimation(PINNING_TRANSIENT)
+ doNothing().whenever(animatorSet).start()
+ pinningController.animateTaskbarPinning(PINNING_TRANSIENT)
+
+ verify(taskbarOverlayController, times(1)).hideWindow()
+ verify(pinningController, times(1))
+ .getAnimatorSetForTaskbarPinningAnimation(PINNING_TRANSIENT)
+ verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(true)
+ assertThat(pinningController.isAnimatingTaskbarPinning).isTrue()
+ verify(taskbarViewController, times(1))
+ .animateAwayNotificationDotsDuringTaskbarPinningAnimation()
+ assertThat(animatorSet.listeners).isNotNull()
+ }
+
+ @Test
+ fun testRecreateTaskbarAndUpdatePinningValue_whenAnimationEnds_shouldUpdateTaskbarPinningLauncherPref() {
+ pinningController.recreateTaskbarAndUpdatePinningValue()
+ verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(false)
+ assertThat(pinningController.isAnimatingTaskbarPinning).isFalse()
+ verify(launcherPrefs, times(1)).put(TASKBAR_PINNING, true)
+ }
+}
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index d78afd35d6..f72c55615c 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -135,6 +135,10 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_TASKBAR_OVERLAYS =
TYPE_TASKBAR_ALL_APPS | TYPE_TASKBAR_EDUCATION_DIALOG;
+ // Floating views that a TouchController should not try to intercept touches from.
+ public static final int TYPE_TOUCH_CONTROLLER_NO_INTERCEPT = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE
+ & ~TYPE_LISTENER & ~TYPE_TASKBAR_OVERLAYS;
+
public static final int TYPE_ALL_EXCEPT_ON_BOARD_POPUP = TYPE_ALL & ~TYPE_ON_BOARD_POPUP
& ~TYPE_PIN_IME_POPUP;
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index 641fd834e2..429978eeb4 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -9,9 +9,13 @@ import android.content.Context;
import android.content.Intent;
import android.util.Log;
+import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.widget.LauncherWidgetHolder;
+import java.util.Arrays;
+
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
private static final String TAG = "AppWidgetsRestoredReceiver";
@@ -20,8 +24,11 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent) {
if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) {
int hostId = intent.getIntExtra(AppWidgetManager.EXTRA_HOST_ID, 0);
- Log.d(TAG, "Widget ID map received for host:" + hostId);
+ Log.d(TAG, "onReceive: Widget ID map received for host:" + hostId);
if (hostId != LauncherWidgetHolder.APPWIDGET_HOST_ID) {
+ Log.w(TAG, "onReceive: hostId does not match Launcher."
+ + " Expected: " + LauncherWidgetHolder.APPWIDGET_HOST_ID
+ + ", Actual: " + hostId);
return;
}
@@ -31,8 +38,18 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
LauncherPrefs.get(context).putSync(
OLD_APP_WIDGET_IDS.to(IntArray.wrap(oldIds).toConcatString()),
APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString()));
+ FileLog.d(TAG, "onReceive: Valid Widget IDs received."
+ + " old IDs=" + Arrays.toString(oldIds)
+ + ", new IDs=" + Arrays.toString(newIds));
+ if (!RestoreDbTask.isPending(context)) {
+ FileLog.w(TAG, "onReceive: Restored App Widget Ids received but Launcher"
+ + " restore is not pending. New widget Ids might not get restored.");
+ }
} else {
- Log.e(TAG, "Invalid host restored received");
+ Log.e(TAG, "onReceive: Invalid widget ids received for Launcher"
+ + ", skipping restore of widget ids."
+ + " newIds=" + Arrays.toString(newIds)
+ + ", oldIds=" + Arrays.toString(oldIds));
}
}
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index dfbbcaabb4..5721ed3493 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -298,11 +298,15 @@ public class InvariantDeviceProfile {
* Reinitialize the current grid after a restore, where some grids might now be disabled.
*/
public void reinitializeAfterRestore(Context context) {
- FileLog.d(TAG, "Reinitializing grid after restore");
String currentGridName = getCurrentGridName(context);
String currentDbFile = dbFile;
String newGridName = initGrid(context, currentGridName);
String newDbFile = dbFile;
+ FileLog.d(TAG, "Reinitializing grid after restore."
+ + " currentGridName=" + currentGridName
+ + ", currentDbFile=" + currentDbFile
+ + ", newGridName=" + newGridName
+ + ", newDbFile=" + newDbFile);
if (!newDbFile.equals(currentDbFile)) {
FileLog.d(TAG, "Restored grid is disabled : " + currentGridName
+ ", migrating to: " + newGridName
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 6ea3e8ae5e..a98ec6484a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -411,7 +411,7 @@ public class LoaderTask implements Runnable {
mSessionHelper.getActiveSessions();
installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: "
- + installingPkgs.values());
+ + installingPkgs.keySet().stream().map(info -> info.mPackageName).toList());
final PackageUserKey tempPackageKey = new PackageUserKey(null, null);
mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
@@ -440,10 +440,15 @@ public class LoaderTask implements Runnable {
mShortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
shortcut);
}
+ if (pinnedShortcuts.isEmpty()) {
+ FileLog.d(TAG, "No pinned shortcuts found for user " + user);
+ }
} else {
// Shortcut manager can fail due to some race condition when the
// lock state changes too frequently. For the purpose of the loading
// shortcuts, consider the user is still locked.
+ FileLog.d(TAG, "Shortcut request failed for user "
+ + user + ", user may still be locked.");
userUnlocked = false;
}
}
@@ -590,17 +595,17 @@ public class LoaderTask implements Runnable {
// Package is not yet available but might be
// installed later.
FileLog.d(TAG, "package not yet restored: " + targetPkg);
-
tempPackageKey.update(targetPkg, c.user);
if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
// Restore has started once.
} else if (installingPkgs.containsKey(tempPackageKey)) {
// App restore has started. Update the flag
c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
- c.updater().put(Favorites.RESTORED,
- c.restoreFlag).commit();
+ FileLog.d(TAG, "restore started for installing app: " + targetPkg);
+ c.updater().put(Favorites.RESTORED, c.restoreFlag).commit();
} else {
- c.markDeleted("Unrestored app removed: " + targetPkg);
+ c.markDeleted("removing app that is not restored and not "
+ + "installing. package: " + targetPkg);
return;
}
} else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
@@ -611,7 +616,7 @@ public class LoaderTask implements Runnable {
} else if (!isSdCardReady) {
// SdCard is not ready yet. Package might get available,
// once it is ready.
- Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
+ Log.d(TAG, "Missing package, will check later: " + targetPkg);
mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
// Add the icon on the workspace anyway.
allowMissingTarget = true;
@@ -647,7 +652,8 @@ public class LoaderTask implements Runnable {
ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key);
if (pinnedShortcut == null) {
// The shortcut is no longer valid.
- c.markDeleted("Pinned shortcut not found");
+ c.markDeleted("Pinned shortcut not found for package: "
+ + key.getPackageName());
return;
}
info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
@@ -817,7 +823,7 @@ public class LoaderTask implements Runnable {
} else {
Log.v(TAG, "Widget restore pending id=" + c.id
+ " appWidgetId=" + appWidgetId
- + " status =" + c.restoreFlag);
+ + " status=" + c.restoreFlag);
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component);
appWidgetInfo.restoreStatus = c.restoreFlag;
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 139efc3d99..d2b7161697 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -62,6 +62,7 @@ import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
@@ -262,7 +263,7 @@ public class ModelDbController {
*/
public void tryMigrateDB() {
if (!migrateGridIfNeeded()) {
- Log.d(TAG, "Migration failed: resetting launcher database");
+ FileLog.d(TAG, "Migration failed: resetting launcher database");
createEmptyDB();
LauncherPrefs.get(mContext).putSync(
getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
@@ -282,15 +283,17 @@ public class ModelDbController {
createDbIfNotExists();
if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
// If we have already create a new DB, ignore migration
+ Log.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
return false;
}
InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
if (!GridSizeMigrationUtil.needsToMigrate(mContext, idp)) {
+ Log.d(TAG, "migrateGridIfNeeded: no grid migration needed");
return true;
}
String targetDbName = new DeviceGridState(idp).getDbFile();
if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
- Log.e(TAG, "migrateGridIfNeeded - target db is same as current: " + targetDbName);
+ Log.e(TAG, "migrateGridIfNeeded: target db is same as current: " + targetDbName);
return false;
}
DatabaseHelper oldHelper = mOpenHelper;
@@ -299,6 +302,9 @@ public class ModelDbController {
try {
return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper,
oldHelper.getWritableDatabase());
+ } catch (Exception e) {
+ FileLog.e(TAG, "Failed to migrate grid", e);
+ return false;
} finally {
if (mOpenHelper != oldHelper) {
oldHelper.close();
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index dbd13b38ad..dc8cd3af65 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -89,9 +89,9 @@ public class RestoreDbTask {
public static final String APPWIDGET_OLD_IDS = "appwidget_old_ids";
public static final String APPWIDGET_IDS = "appwidget_ids";
-
private static final String[] DB_COLUMNS_TO_LOG = {"profileId", "title", "itemType", "screen",
- "container", "cellX", "cellY", "spanX", "spanY", "intent"};
+ "container", "cellX", "cellY", "spanX", "spanY", "intent", "appWidgetProvider",
+ "appWidgetId", "restored"};
/**
* Tries to restore the backup DB if needed
@@ -141,16 +141,17 @@ public class RestoreDbTask {
* 4. If restored from a single display backup, remove gaps between screenIds
* 5. Override shortcuts that need to be replaced.
*
- * @return number of items deleted.
+ * @return number of items deleted
*/
@VisibleForTesting
protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db,
BackupManager backupManager) throws Exception {
- FileLog.d(TAG, "Old Launcher Database before sanitizing:");
+ logFavoritesTable(db, "Old Launcher Database before sanitizing:", null, null);
// Primary user ids
long myProfileId = controller.getSerialNumberForUser(myUserHandle());
long oldProfileId = getDefaultProfileId(db);
- FileLog.d(TAG, "sanitizeDB: myProfileId=" + myProfileId + " oldProfileId=" + oldProfileId);
+ FileLog.d(TAG, "sanitizeDB: myProfileId= " + myProfileId
+ + ", oldProfileId= " + oldProfileId);
LongSparseArray<Long> oldManagedProfileIds = getManagedProfileIds(db, oldProfileId);
LongSparseArray<Long> profileMapping = new LongSparseArray<>(oldManagedProfileIds.size()
+ 1);
@@ -182,7 +183,7 @@ public class RestoreDbTask {
final String[] args = new String[profileIds.length];
Arrays.fill(args, "?");
final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
- logUnrestoredItems(db, where, profileIds);
+ logFavoritesTable(db, "items to delete from unrestored profiles:", where, profileIds);
int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
FileLog.d(TAG, itemsDeletedCount + " total items from unrestored user(s) were deleted");
@@ -242,47 +243,6 @@ public class RestoreDbTask {
}
/**
- * Queries and logs the items we will delete from unrestored profiles in the launcher db.
- * This is to understand why items might be missing during the restore process for Launcher.
- * @param database the Launcher db to query from.
- * @param where the SELECT statement to query items that will be deleted.
- * @param profileIds the profile ID's the user will be migrating to.
- */
- private void logUnrestoredItems(SQLiteDatabase database, String where, String[] profileIds) {
- try (Cursor itemsToDelete = database.query(
- /* table */ Favorites.TABLE_NAME,
- /* columns */ DB_COLUMNS_TO_LOG,
- /* selection */ where,
- /* selection args */ profileIds,
- /* groupBy */ null,
- /* having */ null,
- /* orderBy */ null
- )) {
- if (itemsToDelete.moveToFirst()) {
- String[] columnNames = itemsToDelete.getColumnNames();
- StringBuilder stringBuilder = new StringBuilder(
- "items to be deleted from the Favorites Table during restore:\n"
- );
- do {
- for (String columnName : columnNames) {
- stringBuilder.append(columnName)
- .append("=")
- .append(itemsToDelete.getString(
- itemsToDelete.getColumnIndex(columnName)))
- .append(" ");
- }
- stringBuilder.append("\n");
- } while (itemsToDelete.moveToNext());
- FileLog.d(TAG, stringBuilder.toString());
- } else {
- FileLog.d(TAG, "logDeletedItems: No items found to delete");
- }
- } catch (Exception e) {
- FileLog.e(TAG, "logDeletedItems: Error reading from database", e);
- }
- }
-
- /**
* Remove gaps between screenIds to make sure no empty pages are left in between.
*
* e.g. [0, 3, 4, 6, 7] -> [0, 1, 2, 3, 4]
@@ -396,7 +356,7 @@ public class RestoreDbTask {
IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
host);
} else {
- FileLog.d(TAG, "No app widget ids to restore.");
+ FileLog.d(TAG, "No app widget ids were received from backup to restore.");
}
lp.remove(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS);
@@ -409,16 +369,16 @@ public class RestoreDbTask {
private void restoreAppWidgetIds(Context context, ModelDbController controller,
int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
if (WidgetsModel.GO_DISABLE_WIDGETS) {
- Log.e(TAG, "Skipping widget ID remap as widgets not supported");
+ FileLog.e(TAG, "Skipping widget ID remap as widgets not supported");
host.deleteHost();
return;
}
if (!RestoreDbTask.isPending(context)) {
// Someone has already gone through our DB once, probably LoaderTask. Skip any further
// modifications of the DB.
- Log.e(TAG, "Skipping widget ID remap as DB already in use");
+ FileLog.e(TAG, "Skipping widget ID remap as DB already in use");
for (int widgetId : newWidgetIds) {
- Log.d(TAG, "Deleting widgetId: " + widgetId);
+ FileLog.d(TAG, "Deleting widgetId: " + widgetId);
host.deleteAppWidgetId(widgetId);
}
return;
@@ -426,7 +386,7 @@ public class RestoreDbTask {
final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
- Log.d(TAG, "restoreAppWidgetIds: "
+ FileLog.d(TAG, "restoreAppWidgetIds: "
+ "oldWidgetIds=" + IntArray.wrap(oldWidgetIds).toConcatString()
+ ", newWidgetIds=" + IntArray.wrap(newWidgetIds).toConcatString());
@@ -434,7 +394,7 @@ public class RestoreDbTask {
logDatabaseWidgetInfo(controller);
for (int i = 0; i < oldWidgetIds.length; i++) {
- Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
+ FileLog.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
final int state;
@@ -454,7 +414,7 @@ public class RestoreDbTask {
final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?";
String profileId = Long.toString(mainProfileId);
final String[] args = new String[] { oldWidgetId, profileId };
- Log.d(TAG, "restoreAppWidgetIds: querying profile id=" + profileId
+ FileLog.d(TAG, "restoreAppWidgetIds: querying profile id=" + profileId
+ " with controller profile ID=" + controllerProfileId);
int result = new ContentWriter(context,
new ContentWriter.CommitParams(controller, where, args))
@@ -463,7 +423,7 @@ public class RestoreDbTask {
.commit();
if (result == 0) {
// TODO(b/234700507): Remove the logs after the bug is fixed
- Log.e(TAG, "restoreAppWidgetIds: remapping failed since the widget is not in"
+ FileLog.e(TAG, "restoreAppWidgetIds: remapping failed since the widget is not in"
+ " the database anymore");
try (Cursor cursor = controller.getDb().query(
Favorites.TABLE_NAME,
@@ -471,7 +431,7 @@ public class RestoreDbTask {
"appWidgetId=?", new String[]{oldWidgetId}, null, null, null)) {
if (!cursor.moveToFirst()) {
// The widget no long exists.
- Log.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
+ FileLog.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
+ oldWidgetId);
host.deleteAppWidgetId(newWidgetIds[i]);
}
@@ -523,7 +483,7 @@ public class RestoreDbTask {
}
builder.append("]");
Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
- + builder.toString());
+ + builder);
} catch (Exception ex) {
Log.e(TAG, "Getting widget ids from the database failed", ex);
}
@@ -572,4 +532,45 @@ public class RestoreDbTask {
Collectors.joining(" OR "));
}
+ /**
+ * Queries and logs the items from the Favorites table in the launcher db.
+ * This is to understand why items might be missing during the restore process for Launcher.
+ * @param database The Launcher db to query from.
+ * @param logHeader First line in log statement, used to explain what is being logged.
+ * @param where The SELECT statement to query items.
+ * @param profileIds The profile ID's for each user profile.
+ */
+ public static void logFavoritesTable(SQLiteDatabase database, @NonNull String logHeader,
+ String where, String[] profileIds) {
+ try (Cursor itemsToDelete = database.query(
+ /* table */ Favorites.TABLE_NAME,
+ /* columns */ DB_COLUMNS_TO_LOG,
+ /* selection */ where,
+ /* selection args */ profileIds,
+ /* groupBy */ null,
+ /* having */ null,
+ /* orderBy */ null
+ )) {
+ if (itemsToDelete.moveToFirst()) {
+ String[] columnNames = itemsToDelete.getColumnNames();
+ StringBuilder stringBuilder = new StringBuilder(logHeader + "\n");
+ do {
+ for (String columnName : columnNames) {
+ stringBuilder.append(columnName)
+ .append("=")
+ .append(itemsToDelete.getString(
+ itemsToDelete.getColumnIndex(columnName)))
+ .append(" ");
+ }
+ stringBuilder.append("\n");
+ } while (itemsToDelete.moveToNext());
+ FileLog.d(TAG, stringBuilder.toString());
+ } else {
+ FileLog.d(TAG, "logFavoritesTable: No items found from query for"
+ + "\"" + logHeader + "\"");
+ }
+ } catch (Exception e) {
+ FileLog.e(TAG, "logFavoritesTable: Error reading from database", e);
+ }
+ }
}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutRequest.java b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
index 5291ce4620..21efceb0fd 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutRequest.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
@@ -24,10 +24,11 @@ import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
-import android.util.Log;
import androidx.annotation.Nullable;
+import com.android.launcher3.logging.FileLog;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -101,7 +102,7 @@ public class ShortcutRequest {
return new QueryResult(mContext.getSystemService(LauncherApps.class)
.getShortcuts(mQuery, mUserHandle));
} catch (SecurityException | IllegalStateException e) {
- Log.e(TAG, "Failed to query for shortcuts", e);
+ FileLog.e(TAG, "Failed to query for shortcuts", e);
return QueryResult.DEFAULT;
}
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 95ed401636..79d8c60049 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -257,7 +257,7 @@ public abstract class AbstractLauncherUiTest {
final RuleChain inner = RuleChain
.outerRule(new PortraitLandscapeRunner(this))
.around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
- .around(viewCaptureRule)
+ // .around(viewCaptureRule) // b/315482167
.around(new TestIsolationRule(mLauncher, true));
return TestHelpers.isInLauncherProcess()
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 6d58a3562f..184ece74f5 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -340,4 +340,17 @@ public final class LaunchedAppState extends Background {
}
}
}
+
+ /** Send the "back" gesture to go to workspace. */
+ public Workspace pressBackToWorkspace() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to press back from launched app to workspace")) {
+ mLauncher.executeAndWaitForWallpaperAnimation(
+ () -> mLauncher.pressBackImpl(),
+ "pressing back"
+ );
+ return new Workspace(mLauncher);
+ }
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 0db6eb7412..91ef472ee4 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1121,30 +1121,34 @@ public final class LauncherInstrumentation {
*/
public void pressBack() {
try (Closable e = eventsCheck(); Closable c = addContextLayer("want to press back")) {
- waitForLauncherInitialized();
- final boolean launcherVisible =
- isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
- boolean isThreeFingerTrackpadGesture =
- mTrackpadGestureType == TrackpadGestureType.THREE_FINGER;
- if (getNavigationModel() == NavigationModel.ZERO_BUTTON
- || isThreeFingerTrackpadGesture) {
- final Point displaySize = getRealDisplaySize();
- // TODO(b/225505986): change startY and endY back to displaySize.y / 2 once the
- // issue is solved.
- int startX = isThreeFingerTrackpadGesture ? displaySize.x / 4 : 0;
- int endX = isThreeFingerTrackpadGesture ? displaySize.x * 3 / 4 : displaySize.x / 2;
- linearGesture(startX, displaySize.y / 4, endX, displaySize.y / 4,
- 10, false, GestureScope.DONT_EXPECT_PILFER);
+ pressBackImpl();
+ }
+ }
+
+ void pressBackImpl() {
+ waitForLauncherInitialized();
+ final boolean launcherVisible =
+ isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
+ boolean isThreeFingerTrackpadGesture =
+ mTrackpadGestureType == TrackpadGestureType.THREE_FINGER;
+ if (getNavigationModel() == NavigationModel.ZERO_BUTTON
+ || isThreeFingerTrackpadGesture) {
+ final Point displaySize = getRealDisplaySize();
+ // TODO(b/225505986): change startY and endY back to displaySize.y / 2 once the
+ // issue is solved.
+ int startX = isThreeFingerTrackpadGesture ? displaySize.x / 4 : 0;
+ int endX = isThreeFingerTrackpadGesture ? displaySize.x * 3 / 4 : displaySize.x / 2;
+ linearGesture(startX, displaySize.y / 4, endX, displaySize.y / 4,
+ 10, false, GestureScope.DONT_EXPECT_PILFER);
+ } else {
+ waitForNavigationUiObject("back").click();
+ }
+ if (launcherVisible) {
+ if (getContext().getApplicationInfo().isOnBackInvokedCallbackEnabled()) {
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ON_BACK_INVOKED);
} else {
- waitForNavigationUiObject("back").click();
- }
- if (launcherVisible) {
- if (getContext().getApplicationInfo().isOnBackInvokedCallbackEnabled()) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ON_BACK_INVOKED);
- } else {
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_DOWN);
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_UP);
- }
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_DOWN);
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_UP);
}
}
}