Merge changes from topic "new-task-snapshots-ub-launcher3-master" into ub-launcher3-master
* changes:
Toggle loading state based on config_lowResTaskSnapshotScale
Add config to enable snapshot preloading
diff --git a/Android.bp b/Android.bp
index cb695df..e132854 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,3 +47,14 @@
},
static_libs: ["libprotobuf-java-lite"],
}
+
+java_library {
+ name: "LauncherPluginLib",
+
+ static_libs: ["PluginCoreLib"],
+
+ srcs: ["src_plugins/**/*.java"],
+
+ sdk_version: "current",
+ min_sdk_version: "28",
+}
diff --git a/Android.mk b/Android.mk
index c066a12..9cfcf17 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,24 +17,6 @@
LOCAL_PATH := $(call my-dir)
#
-# Build rule for plugin lib (needed to write a plugin).
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES:= PluginCoreLib
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src_plugins)
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 28
-LOCAL_MODULE := LauncherPluginLib
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-#
# Build rule for Launcher3 dependencies lib.
#
include $(CLEAR_VARS)
diff --git a/proguard.flags b/proguard.flags
index e556c94..37b8093 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -50,4 +50,13 @@
-dontwarn android.graphics.**
# Ignore warnings for hidden utility classes referenced from the shared lib
--dontwarn com.android.internal.util.**
\ No newline at end of file
+-dontwarn com.android.internal.util.**
+
+################ Do not optimize recents lib #############
+-keep class com.android.systemui.** {
+ *;
+}
+
+-keep class com.android.quickstep.** {
+ *;
+}
diff --git a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
index 7f1425b..a572cad 100644
--- a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
+++ b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
@@ -14,12 +14,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.views.LauncherRecentsView
+<com.android.launcher3.InsettableFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:theme="@style/HomeScreenElementTheme"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:accessibilityPaneTitle="@string/accessibility_recent_apps"
- android:visibility="invisible" />
\ No newline at end of file
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <com.android.quickstep.views.LauncherRecentsView
+ android:id="@+id/overview_panel_recents"
+ android:theme="@style/HomeScreenElementTheme"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:accessibilityPaneTitle="@string/accessibility_recent_apps"
+ android:visibility="invisible" />
+</com.android.launcher3.InsettableFrameLayout>
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
index 03862db..1f5228a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.isTouchOverHotseat;
import android.view.MotionEvent;
+import android.view.animation.Interpolator;
import com.android.launcher3.Launcher;
import com.android.launcher3.util.PendingAnimation;
@@ -74,12 +75,12 @@
* @param duration how long the animation should be
* @return the animation
*/
- PendingAnimation createSwipeDownToTaskAppAnimation(long duration) {
+ PendingAnimation createSwipeDownToTaskAppAnimation(long duration, Interpolator interpolator) {
mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
TaskView taskView = mRecentsView.getCurrentPageTaskView();
if (taskView == null) {
throw new IllegalStateException("There is no task view to animate to.");
}
- return mRecentsView.createTaskLauncherAnimation(taskView, duration);
+ return mRecentsView.createTaskLaunchAnimation(taskView, duration, interpolator);
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 32855d7..947a861 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -191,9 +191,8 @@
mEndDisplacement = -mTaskBeingDragged.getHeight();
} else {
- mPendingAnimation = mRecentsView.createTaskLauncherAnimation(
- mTaskBeingDragged, maxDuration);
- mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN);
+ mPendingAnimation = mRecentsView.createTaskLaunchAnimation(
+ mTaskBeingDragged, maxDuration, Interpolators.ZOOM_IN);
mTempCords[1] = mTaskBeingDragged.getHeight();
dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
@@ -203,8 +202,8 @@
if (mCurrentAnimation != null) {
mCurrentAnimation.setOnCancelRunnable(null);
}
- mCurrentAnimation = AnimatorPlaybackController
- .wrap(mPendingAnimation.anim, maxDuration, this::clearState);
+ mCurrentAnimation = AnimatorPlaybackController.wrap(
+ mPendingAnimation.anim, maxDuration, this::clearState);
onUserControlledAnimationCreated(mCurrentAnimation);
mCurrentAnimation.getTarget().addListener(this);
mCurrentAnimation.dispatchOnStart();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
index b71fede..5a9c2fe 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
@@ -70,9 +70,6 @@
// if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
// app window coordinates.
private final RectF mSourceWindowClipInsets = new RectF();
- // The insets to be used for clipping the app window. For live tile, we don't transform the clip
- // relative to the target rect.
- private final RectF mSourceWindowClipInsetsForLiveTile = new RectF();
// The clip rect in source app window coordinates. The app window surface will only be drawn
// within these bounds. This clip rect starts at the full mSourceStackBounds, and insets by
// mSourceWindowClipInsets as the transform progress goes to 1.
@@ -149,7 +146,6 @@
Math.max(scaledTargetRect.top, 0),
Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
- mSourceWindowClipInsetsForLiveTile.set(mSourceWindowClipInsets);
mSourceRect.set(scaledTargetRect);
}
@@ -252,14 +248,12 @@
private void updateClipRect(TransformParams params) {
// Don't clip past progress > 1.
float progress = Math.min(1, params.mProgress);
- final RectF sourceWindowClipInsets = params.mForLiveTile
- ? mSourceWindowClipInsetsForLiveTile : mSourceWindowClipInsets;
- mCurrentClipRectF.left = sourceWindowClipInsets.left * progress;
- mCurrentClipRectF.top = sourceWindowClipInsets.top * progress;
+ mCurrentClipRectF.left = mSourceWindowClipInsets.left * progress;
+ mCurrentClipRectF.top = mSourceWindowClipInsets.top * progress;
mCurrentClipRectF.right =
- mSourceStackBounds.width() - (sourceWindowClipInsets.right * progress);
+ mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress);
mCurrentClipRectF.bottom =
- mSourceStackBounds.height() - (sourceWindowClipInsets.bottom * progress);
+ mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress);
}
public RectF getCurrentRectWithInsets() {
@@ -400,7 +394,6 @@
private float mOffsetScale;
private @Nullable RectF mCurrentRect;
private float mTargetAlpha;
- private boolean mForLiveTile;
private float mCornerRadius;
private boolean mLauncherOnTop;
private RemoteAnimationTargets mTargetSet;
@@ -412,7 +405,6 @@
mOffsetScale = 1;
mCurrentRect = null;
mTargetAlpha = 1;
- mForLiveTile = false;
mCornerRadius = -1;
mLauncherOnTop = false;
}
@@ -477,16 +469,6 @@
}
/**
- * Specifies whether we should clip the source window based on
- * {@link AppWindowAnimationHelper#mSourceWindowClipInsetsForLiveTile} rather than
- * {@link AppWindowAnimationHelper#mSourceWindowClipInsets} as {@link #mProgress} goes to 1.
- */
- public TransformParams setForLiveTile(boolean forLiveTile) {
- mForLiveTile = forLiveTile;
- return this;
- }
-
- /**
* If true, sets the crop = null and layer = Integer.MAX_VALUE for targets that don't match
* {@link #mTargetSet}.targetMode. (Currently only does this when live tiles are enabled.)
*/
@@ -539,10 +521,6 @@
return mTargetAlpha;
}
- public boolean isForLiveTile() {
- return mForLiveTile;
- }
-
public float getCornerRadius() {
return mCornerRadius;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index d705cc0..3e106aa 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -201,8 +201,7 @@
if (tv.isRunningTask()) {
mTransformParams.setProgress(1 - progress)
.setCurrentRect(null)
- .setSyncTransactionApplier(mSyncTransactionApplier)
- .setForLiveTile(true);
+ .setSyncTransactionApplier(mSyncTransactionApplier);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
} else {
redrawLiveTile(true);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index fe78a84..e34e74c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -76,6 +76,7 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.Interpolator;
import android.widget.ListView;
import androidx.annotation.Nullable;
@@ -1599,7 +1600,8 @@
return anim;
}
- public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) {
+ public PendingAnimation createTaskLaunchAnimation(
+ TaskView tv, long duration, Interpolator interpolator) {
if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
throw new IllegalStateException("Another pending animation is still running");
}
@@ -1612,7 +1614,6 @@
int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
final boolean[] passedOverviewThreshold = new boolean[] {false};
ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
- progressAnim.setInterpolator(LINEAR);
progressAnim.addUpdateListener(animator -> {
// Once we pass a certain threshold, update the sysui flags to match the target
// tasks' flags
@@ -1638,7 +1639,7 @@
appWindowAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */);
AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, appWindowAnimationHelper);
anim.play(progressAnim);
- anim.setDuration(duration);
+ anim.setDuration(duration).setInterpolator(interpolator);
Consumer<Boolean> onTaskLaunchFinish = this::onTaskLaunched;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 8b7ce10..dce92ff 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
@@ -280,11 +281,10 @@
}
public AnimatorPlaybackController createLaunchAnimationForRunningTask() {
- final PendingAnimation pendingAnimation =
- getRecentsView().createTaskLauncherAnimation(this, RECENTS_LAUNCH_DURATION);
- pendingAnimation.anim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
- AnimatorPlaybackController currentAnimation = AnimatorPlaybackController
- .wrap(pendingAnimation.anim, RECENTS_LAUNCH_DURATION, null);
+ final PendingAnimation pendingAnimation = getRecentsView().createTaskLaunchAnimation(
+ this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR);
+ AnimatorPlaybackController currentAnimation = AnimatorPlaybackController.wrap(
+ pendingAnimation.anim, RECENTS_LAUNCH_DURATION);
currentAnimation.setEndAction(() -> {
pendingAnimation.finish(true, Touch.SWIPE);
launchTask(false);
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 15503b8..07d2381 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -194,7 +194,7 @@
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
// Overview is above all other launcher elements, including qsb, so move it to the top.
- getOverviewPanel().bringToFront();
+ getOverviewPanelContainer().bringToFront();
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index d5ce734..fe830d2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -228,15 +228,13 @@
// Reset the state manager, when changing the interaction mode
mLauncher.getStateManager().goToState(OVERVIEW, false /* animate */);
mPendingAnimation = mOverviewPortraitStateTouchHelper
- .createSwipeDownToTaskAppAnimation(maxAccuracy);
- mPendingAnimation.anim.setInterpolator(Interpolators.LINEAR);
-
+ .createSwipeDownToTaskAppAnimation(maxAccuracy, Interpolators.LINEAR);
Runnable onCancelRunnable = () -> {
cancelPendingAnim();
clearState();
};
- mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation.anim, maxAccuracy,
- onCancelRunnable);
+ mCurrentAnimation = AnimatorPlaybackController.wrap(
+ mPendingAnimation.anim, maxAccuracy, onCancelRunnable);
mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher,
mLauncher.getDeviceProfile());
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 00adfbe..21a4918 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -81,12 +81,9 @@
mWindowThresholdCrossed = windowThresholdCrossed;
UI_HELPER_EXECUTOR.execute(() -> {
mController.setAnimationTargetsBehindSystemBars(!windowThresholdCrossed);
- if (mShouldMinimizeSplitScreen && windowThresholdCrossed) {
- // NOTE: As a workaround for conflicting animations (Launcher animating the task
- // leash, and SystemUI resizing the docked stack, which resizes the task), we
- // currently only set the minimized mode, and not the inverse.
- // TODO: Synchronize the minimize animation with the launcher animation
- mController.setSplitScreenMinimized(windowThresholdCrossed);
+ SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
+ if (p != null && mShouldMinimizeSplitScreen) {
+ p.setSplitScreenMinimized(windowThresholdCrossed);
}
});
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 101bb07..458d6a9 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -295,4 +295,15 @@
}
}
}
+
+ @Override
+ public void setSplitScreenMinimized(boolean minimized) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.setSplitScreenMinimized(minimized);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call stopScreenPinning", e);
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index d8b10b6..7d52571 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_LSQ_VELOCITY_PROVIDER;
+
import android.content.Context;
import android.content.res.Resources;
import android.view.MotionEvent;
@@ -85,7 +87,8 @@
mForcePauseTimeout = new Alarm();
mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
mMakePauseHarderToTrigger = makePauseHarderToTrigger;
- mVelocityProvider = new LinearVelocityProvider(axis);
+ mVelocityProvider = ENABLE_LSQ_VELOCITY_PROVIDER.get()
+ ? new LSqVelocityProvider(axis) : new LinearVelocityProvider(axis);
}
/**
@@ -106,8 +109,6 @@
/**
* Computes velocity and acceleration to determine whether the motion is paused.
* @param ev The motion being tracked.
- *
- * TODO: Use historical positions as well, e.g. {@link MotionEvent#getHistoricalY(int, int)}.
*/
public void addPosition(MotionEvent ev) {
addPosition(ev, 0);
@@ -248,4 +249,137 @@
mPreviousPosition = null;
}
}
+
+ /**
+ * Java implementation of {@link android.view.VelocityTracker} using the Least Square (deg 2)
+ * algorithm.
+ */
+ private static class LSqVelocityProvider implements VelocityProvider {
+
+ // Maximum age of a motion event to be considered when calculating the velocity.
+ private static final long HORIZON_MS = 100;
+ // Number of samples to keep.
+ private static final int HISTORY_SIZE = 20;
+
+ // Position history are stored in a circular array
+ private final float[] mHistoricTimes = new float[HISTORY_SIZE];
+ private final float[] mHistoricPos = new float[HISTORY_SIZE];
+ private int mHistoryCount = 0;
+ private int mHistoryStart = 0;
+
+ private final int mAxis;
+
+ LSqVelocityProvider(int axis) {
+ mAxis = axis;
+ }
+
+ @Override
+ public void clear() {
+ mHistoryCount = mHistoryStart = 0;
+ }
+
+ private void addPositionAndTime(float eventTime, float eventPosition) {
+ mHistoricTimes[mHistoryStart] = eventTime;
+ mHistoricPos[mHistoryStart] = eventPosition;
+ mHistoryStart++;
+ if (mHistoryStart >= HISTORY_SIZE) {
+ mHistoryStart = 0;
+ }
+ mHistoryCount = Math.min(HISTORY_SIZE, mHistoryCount + 1);
+ }
+
+ @Override
+ public Float addMotionEvent(MotionEvent ev, int pointer) {
+ // Add all historic points
+ int historyCount = ev.getHistorySize();
+ for (int i = 0; i < historyCount; i++) {
+ addPositionAndTime(
+ ev.getHistoricalEventTime(i), ev.getHistoricalAxisValue(mAxis, pointer, i));
+ }
+
+ // Start index for the last position (about to be added)
+ int eventStartIndex = mHistoryStart;
+ addPositionAndTime(ev.getEventTime(), ev.getAxisValue(mAxis, pointer));
+ return solveUnweightedLeastSquaresDeg2(eventStartIndex);
+ }
+
+ /**
+ * Solves the instantaneous velocity.
+ * Based on solveUnweightedLeastSquaresDeg2 in VelocityTracker.cpp
+ */
+ private Float solveUnweightedLeastSquaresDeg2(final int pointPos) {
+ final float eventTime = mHistoricTimes[pointPos];
+
+ float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
+ int count = 0;
+ for (int i = 0; i < mHistoryCount; i++) {
+ int index = pointPos - i;
+ if (index < 0) {
+ index += HISTORY_SIZE;
+ }
+
+ float time = mHistoricTimes[index];
+ float age = eventTime - time;
+ if (age > HORIZON_MS) {
+ break;
+ }
+ count++;
+ float xi = -age;
+
+ float yi = mHistoricPos[index];
+ float xi2 = xi * xi;
+ float xi3 = xi2 * xi;
+ float xi4 = xi3 * xi;
+ float xiyi = xi * yi;
+ float xi2yi = xi2 * yi;
+
+ sxi += xi;
+ sxi2 += xi2;
+ sxiyi += xiyi;
+ sxi2yi += xi2yi;
+ syi += yi;
+ sxi3 += xi3;
+ sxi4 += xi4;
+ }
+
+ if (count < 3) {
+ // Too few samples
+ if (count == 2) {
+ int endPos = pointPos - 1;
+ if (endPos < 0) {
+ endPos += HISTORY_SIZE;
+ }
+ float denominator = eventTime - mHistoricTimes[endPos];
+ if (denominator != 0) {
+ return (eventTime - mHistoricPos[endPos]) / denominator;
+
+ }
+ }
+ return null;
+ }
+
+ float Sxx = sxi2 - sxi * sxi / count;
+ float Sxy = sxiyi - sxi * syi / count;
+ float Sxx2 = sxi3 - sxi * sxi2 / count;
+ float Sx2y = sxi2yi - sxi2 * syi / count;
+ float Sx2x2 = sxi4 - sxi2 * sxi2 / count;
+
+ float denominator = Sxx * Sx2x2 - Sxx2 * Sxx2;
+ if (denominator == 0) {
+ // division by 0 when computing velocity
+ return null;
+ }
+ // Compute a
+ // float numerator = Sx2y*Sxx - Sxy*Sxx2;
+
+ // Compute b
+ float numerator = Sxy * Sx2x2 - Sx2y * Sxx2;
+ float b = numerator / denominator;
+
+ // Compute c
+ // float c = syi/count - b * sxi/count - a * sxi2/count;
+
+ return b;
+ }
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 724af66..ecfdb55 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -45,7 +45,6 @@
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,21 +52,10 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TaplTestsQuickstep extends AbstractQuickStepTest {
- private int mLauncherPid;
-
@Before
public void setUp() throws Exception {
- mLauncherPid = 0;
super.setUp();
TaplTestsLauncher3.initialize(this);
- mLauncherPid = mLauncher.getPid();
- }
-
- @After
- public void teardown() {
- if (mLauncherPid != 0) {
- assertEquals("Launcher crashed, pid mismatch:", mLauncherPid, mLauncher.getPid());
- }
}
private void startTestApps() throws Exception {
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index cca899b..6c66897 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -44,9 +44,8 @@
layout="@layout/hotseat" />
<include
- android:id="@+id/overview_panel"
- layout="@layout/overview_panel"
- android:visibility="gone" />
+ android:id="@+id/overview_panel_container"
+ layout="@layout/overview_panel"/>
<!-- Keep these behind the workspace so that they are not visible when
we go into AllApps -->
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index bdd5d23..7fff711 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -14,7 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<Space
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/overview_panel_recents"
android:layout_width="0dp"
- android:layout_height="0dp" />
\ No newline at end of file
+ android:layout_height="0dp"
+ android:visibility="gone" />
\ No newline at end of file
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index 1ed4bca..c426dc5 100644
--- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -65,7 +65,7 @@
};
mIdp.numHotseatIcons = 3;
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, 5, 3)
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3)
.migrateHotseat();
// First item is dropped as it has the least weight.
verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
@@ -82,7 +82,7 @@
};
mIdp.numHotseatIcons = 3;
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, 5, 3)
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3)
.migrateHotseat();
// First item is dropped as it has the least weight.
verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
@@ -127,7 +127,7 @@
{ 5, 2, -1, 6},
}});
- new GridSizeMigrationTask(mContext, mDb, mValidPackages,
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Column 2 and row 2 got removed.
@@ -147,7 +147,7 @@
{ 5, 2, -1, 6},
}});
- new GridSizeMigrationTask(mContext, mDb, mValidPackages,
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Items in the second column get moved to new screen
@@ -172,7 +172,7 @@
{ 3, 1, -1, 4},
}});
- new GridSizeMigrationTask(mContext, mDb, mValidPackages,
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Items in the second column of the first screen should get placed on the 3rd
@@ -204,7 +204,7 @@
{ 5, 2, -1, 6},
}});
- new GridSizeMigrationTask(mContext, mDb, mValidPackages,
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Items in the second column of the first screen should get placed on a new screen.
@@ -235,7 +235,7 @@
{ 5, 2, 7, -1},
}}, 0);
- new GridSizeMigrationTask(mContext, mDb, mValidPackages,
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
new Point(4, 4), new Point(3, 4)).migrateWorkspace();
// Items in the second column of the first screen should get placed on a new screen.
@@ -262,7 +262,7 @@
{ 5, 6, 7, -1},
}}, 0);
- new GridSizeMigrationTask(mContext, mDb, mValidPackages,
+ new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Items in the second column of the first screen should get placed on a new screen.
@@ -282,7 +282,7 @@
* represent the workspace grid.
*/
private void verifyWorkspace(int[][][] ids) {
- IntArray allScreens = getWorkspaceScreenIds(mDb);
+ IntArray allScreens = getWorkspaceScreenIds(mDb, LauncherSettings.Favorites.TABLE_NAME);
assertEquals(ids.length, allScreens.size());
int total = 0;
@@ -351,7 +351,7 @@
private final LinkedList<Point> mPoints;
public MultiStepMigrationTaskVerifier(int... points) {
- super(null, null, null);
+ super(null, null, null, false);
mPoints = new LinkedList<>();
for (int i = 0; i < points.length; i += 2) {
diff --git a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 7fa3ee9..6e41a4f 100644
--- a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -52,6 +52,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LauncherRoboTestRunner;
@@ -91,7 +92,7 @@
SCREEN, CELLX, CELLY, RESTORED, INTENT
});
- mLoaderCursor = new LoaderCursor(mCursor, mApp);
+ mLoaderCursor = new LoaderCursor(mCursor, LauncherSettings.Favorites.CONTENT_URI, mApp);
mLoaderCursor.allUsers.put(0, Process.myUserHandle());
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 857db8e..2ad84b9 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -47,6 +47,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.DefaultDisplay;
import com.android.launcher3.util.DefaultDisplay.Info;
@@ -156,6 +157,11 @@
@TargetApi(23)
private InvariantDeviceProfile(Context context) {
+ if (context instanceof LauncherPreviewRenderer.PreviewContext) {
+ throw new IllegalArgumentException(
+ "PreviewContext is passed into this IDP constructor");
+ }
+
String gridName = Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)
? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null)
: null;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3fc8de2..33f5a95 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -80,6 +80,7 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
+import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -273,6 +274,7 @@
// UI and state for the overview panel
private View mOverviewPanel;
+ private FrameLayout mOverviewPanelContainer;
@Thunk
boolean mWorkspaceLoading = true;
@@ -1143,7 +1145,8 @@
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
mWorkspace = mDragLayer.findViewById(R.id.workspace);
mWorkspace.initParentViews(mDragLayer);
- mOverviewPanel = findViewById(R.id.overview_panel);
+ mOverviewPanel = findViewById(R.id.overview_panel_recents);
+ mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
mHotseat = findViewById(R.id.hotseat);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -1386,6 +1389,10 @@
return (T) mOverviewPanel;
}
+ public FrameLayout getOverviewPanelContainer() {
+ return mOverviewPanelContainer;
+ }
+
public DropTargetBar getDropTargetBar() {
return mDropTargetBar;
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index d77285d..2f38037 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -27,6 +27,8 @@
import android.os.Handler;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.IconProvider;
@@ -55,12 +57,12 @@
private final IconCache mIconCache;
private final WidgetPreviewLoader mWidgetCache;
private final InvariantDeviceProfile mInvariantDeviceProfile;
- private final SecureSettingsObserver mNotificationDotsObserver;
- private final InstallSessionTracker mInstallSessionTracker;
- private final SimpleBroadcastReceiver mModelChangeReceiver;
- private final SafeCloseable mCalendarChangeTracker;
- private final SafeCloseable mUserChangeListener;
+ private SecureSettingsObserver mNotificationDotsObserver;
+ private InstallSessionTracker mInstallSessionTracker;
+ private SimpleBroadcastReceiver mModelChangeReceiver;
+ private SafeCloseable mCalendarChangeTracker;
+ private SafeCloseable mUserChangeListener;
public static LauncherAppState getInstance(final Context context) {
return INSTANCE.get(context);
@@ -74,15 +76,8 @@
return mContext;
}
- private LauncherAppState(Context context) {
- Log.v(Launcher.TAG, "LauncherAppState initiated");
- Preconditions.assertUIThread();
- mContext = context;
-
- mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext);
- mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
- mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
- mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
+ public LauncherAppState(Context context) {
+ this(context, LauncherFiles.APP_ICONS_DB);
mModelChangeReceiver = new SimpleBroadcastReceiver(mModel::onBroadcastIntent);
@@ -123,6 +118,17 @@
}
}
+ public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
+ Log.v(Launcher.TAG, "LauncherAppState initiated");
+ Preconditions.assertUIThread();
+ mContext = context;
+
+ mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
+ mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName);
+ mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
+ mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
+ }
+
protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) {
if (areNotificationDotsEnabled) {
NotificationListener.requestRebind(new ComponentName(
@@ -148,11 +154,19 @@
* Call from Application.onTerminate(), which is not guaranteed to ever be called.
*/
public void onTerminate() {
- mContext.unregisterReceiver(mModelChangeReceiver);
+ if (mModelChangeReceiver != null) {
+ mContext.unregisterReceiver(mModelChangeReceiver);
+ }
mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel);
- mInstallSessionTracker.unregister();
- mCalendarChangeTracker.close();
- mUserChangeListener.close();
+ if (mInstallSessionTracker != null) {
+ mInstallSessionTracker.unregister();
+ }
+ if (mCalendarChangeTracker != null) {
+ mCalendarChangeTracker.close();
+ }
+ if (mUserChangeListener != null) {
+ mUserChangeListener.close();
+ }
CustomWidgetManager.INSTANCE.get(mContext).setWidgetRefreshCallback(null);
if (mNotificationDotsObserver != null) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index f618fe1..e61b7a8 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -153,7 +153,7 @@
public void onPackagesRemoved(UserHandle user, String... packages) {
int op = PackageUpdatedTask.OP_REMOVE;
- FileLog.d(TAG, "package removed received " + String.join("," + packages));
+ FileLog.d(TAG, "package removed received " + TextUtils.join(",", packages));
enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packages));
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 49831f6..216c221 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -93,15 +93,26 @@
public static final String TABLE_NAME = "favorites";
/**
- * Backup table created when when the favorites table is modified during grid migration
+ * Backup table created when the favorites table is modified during grid migration
*/
public static final String BACKUP_TABLE_NAME = "favorites_bakup";
/**
- * The content:// style URL for this table
+ * Temporary table used specifically for grid migrations during wallpaper preview
*/
- public static final Uri CONTENT_URI = Uri.parse("content://" +
- LauncherProvider.AUTHORITY + "/" + TABLE_NAME);
+ public static final String PREVIEW_TABLE_NAME = "favorites_preview";
+
+ /**
+ * The content:// style URL for "favorites" table
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://"
+ + LauncherProvider.AUTHORITY + "/" + TABLE_NAME);
+
+ /**
+ * The content:// style URL for "favorites_preview" table
+ */
+ public static final Uri PREVIEW_CONTENT_URI = Uri.parse("content://"
+ + LauncherProvider.AUTHORITY + "/" + PREVIEW_TABLE_NAME);
/**
* The content:// style URL for a given row, identified by its id.
@@ -111,8 +122,8 @@
* @return The unique content URL for the specified row.
*/
public static Uri getContentUri(int id) {
- return Uri.parse("content://" + LauncherProvider.AUTHORITY +
- "/" + TABLE_NAME + "/" + id);
+ return Uri.parse("content://" + LauncherProvider.AUTHORITY
+ + "/" + TABLE_NAME + "/" + id);
}
/**
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 16be391..36440c9 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -74,6 +74,10 @@
public static final int VERTICAL_SWIPE_INDICATOR = 1 << 5;
public static final int RECENTS_CLEAR_ALL_BUTTON = 1 << 6;
+ /** Mask of all the items that are contained in the apps view. */
+ public static final int APPS_VIEW_ITEM_MASK =
+ HOTSEAT_SEARCH_BOX | ALL_APPS_HEADER | ALL_APPS_HEADER_EXTRA | ALL_APPS_CONTENT;
+
protected static final int FLAG_MULTI_PAGE = 1 << 0;
protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 1;
protected static final int FLAG_DISABLE_RESTORE = 1 << 2;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 6aa3efc..e49ff30 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -2,6 +2,7 @@
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
+import static com.android.launcher3.LauncherState.APPS_VIEW_ITEM_MASK;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
@@ -203,6 +204,8 @@
boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0;
boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0;
+ boolean hasAnyVisibleItem = (visibleElements & APPS_VIEW_ITEM_MASK) != 0;
+
Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade);
@@ -213,6 +216,8 @@
setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA,
(visibleElements & VERTICAL_SWIPE_INDICATOR) != 0 ? 255 : 0, allAppsFade);
+
+ setter.setViewAlpha(mAppsView, hasAnyVisibleItem ? 1 : 0, allAppsFade);
}
public AnimatorListenerAdapter getProgressAnimatorListener() {
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index db4bef0..1d32d1d 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -40,8 +40,16 @@
return isAccessibilityEnabled(context);
}
- public static void sendCustomAccessibilityEvent(View target, int type, @Nullable String text) {
- if (isObservedEventType(target.getContext(), type)) {
+ /**
+ *
+ * @param target The view the accessibility event is initialized on.
+ * If null, this method has no effect.
+ * @param type See TYPE_ constants defined in {@link AccessibilityEvent}.
+ * @param text Optional text to add to the event, which will be announced to the user.
+ */
+ public static void sendCustomAccessibilityEvent(@Nullable View target, int type,
+ @Nullable String text) {
+ if (target != null && isObservedEventType(target.getContext(), type)) {
AccessibilityEvent event = AccessibilityEvent.obtain(type);
target.onInitializeAccessibilityEvent(event);
if (!TextUtils.isEmpty(text)) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6413044..3d8a9d7 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -135,6 +135,10 @@
"ENABLE_UNIVERSAL_SMARTSPACE", false,
"Replace Smartspace with a version rendered by System UI.");
+ public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag(
+ "ENABLE_LSQ_VELOCITY_PROVIDER", false,
+ "Use Least Square algorithm for motion pause detection.");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index ddb88dc..e33d89f 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -346,7 +346,7 @@
}
mInfo.title = newTitle;
- mInfo.setOption(FLAG_MANUAL_FOLDER_NAME, mFolderName.isEnteredCompose(),
+ mInfo.setOption(FLAG_MANUAL_FOLDER_NAME, getAcceptedSuggestionIndex() < 0,
mLauncher.getModelWriter());
mFolderIcon.onTitleChanged(newTitle);
mLauncher.getModelWriter().updateItemInDatabase(mInfo);
@@ -437,11 +437,11 @@
}
mItemsInvalidated = true;
mInfo.addListener(this);
+ mPreviousLabel = mInfo.title.toString();
+ mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
if (!isEmpty(mInfo.title)) {
mFolderName.setText(mInfo.title);
- mPreviousLabel = mInfo.title.toString();
- mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
mFolderName.setHint(null);
} else {
mFolderName.setText("");
diff --git a/src/com/android/launcher3/folder/FolderNameEditText.java b/src/com/android/launcher3/folder/FolderNameEditText.java
index 7e11b18..edf2c70 100644
--- a/src/com/android/launcher3/folder/FolderNameEditText.java
+++ b/src/com/android/launcher3/folder/FolderNameEditText.java
@@ -102,13 +102,6 @@
mEnteredCompose = value;
}
- protected boolean isEnteredCompose() {
- if (DEBUG) {
- Log.d(TAG, "isEnteredCompose " + mEnteredCompose);
- }
- return mEnteredCompose;
- }
-
private class FolderNameEditTextInputConnection extends InputConnectionWrapper {
FolderNameEditTextInputConnection(InputConnection target, boolean mutable) {
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index a429af2..0927b26 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -20,14 +20,19 @@
import static android.view.View.VISIBLE;
import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER;
+import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
+import static com.android.launcher3.model.GridSizeMigrationTask.needsToMigrate;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.annotation.TargetApi;
import android.app.Fragment;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.pm.ShortcutInfo;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -70,17 +75,31 @@
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.model.GridSizeMigrationTask;
+import com.android.launcher3.model.GridSizeMigrationTaskV2;
import com.android.launcher3.model.LoaderResults;
+import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -101,6 +120,81 @@
private static final String TAG = "LauncherPreviewRenderer";
+ /**
+ * Context used just for preview. It also provides a few objects (e.g. UserCache) just for
+ * preview purposes.
+ */
+ public static class PreviewContext extends ContextWrapper {
+
+ private static final Set<MainThreadInitializedObject> WHITELIST = new HashSet<>(
+ Arrays.asList(UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
+ LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE));
+
+ private final InvariantDeviceProfile mIdp;
+ private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
+ private final ConcurrentLinkedQueue<LauncherIconsForPreview> mIconPool =
+ new ConcurrentLinkedQueue<>();
+
+ public PreviewContext(Context base, InvariantDeviceProfile idp) {
+ super(base);
+ mIdp = idp;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
+
+ /**
+ * Find a cached object from mObjectMap if we have already created one. If not, generate
+ * an object using the provider.
+ */
+ public <T> T getObject(MainThreadInitializedObject<T> mainThreadInitializedObject,
+ MainThreadInitializedObject.ObjectProvider<T> provider) {
+ if (!WHITELIST.contains(mainThreadInitializedObject)) {
+ throw new IllegalStateException("Leaking unknown objects");
+ }
+ if (mainThreadInitializedObject == LauncherAppState.INSTANCE) {
+ throw new IllegalStateException(
+ "Should not use MainThreadInitializedObject to initialize this with "
+ + "PreviewContext");
+ }
+ if (mainThreadInitializedObject == InvariantDeviceProfile.INSTANCE) {
+ return (T) mIdp;
+ }
+ if (mObjectMap.containsKey(mainThreadInitializedObject)) {
+ return (T) mObjectMap.get(mainThreadInitializedObject);
+ }
+ T t = provider.get(this);
+ mObjectMap.put(mainThreadInitializedObject, t);
+ return t;
+ }
+
+ public LauncherIcons newLauncherIcons(Context context, boolean shapeDetection) {
+ LauncherIconsForPreview launcherIconsForPreview = mIconPool.poll();
+ if (launcherIconsForPreview != null) {
+ return launcherIconsForPreview;
+ }
+ return new LauncherIconsForPreview(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize,
+ -1 /* poolId */, shapeDetection);
+ }
+
+ private final class LauncherIconsForPreview extends LauncherIcons {
+
+ private LauncherIconsForPreview(Context context, int fillResIconDpi, int iconBitmapSize,
+ int poolId, boolean shapeDetection) {
+ super(context, fillResIconDpi, iconBitmapSize, poolId, shapeDetection);
+ }
+
+ @Override
+ public void recycle() {
+ // Clear any temporary state variables
+ clear();
+ mIconPool.offer(this);
+ }
+ }
+ }
+
private final Handler mUiHandler;
private final Context mContext;
private final InvariantDeviceProfile mIdp;
@@ -282,15 +376,28 @@
private void renderScreenShot(Canvas canvas) {
if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) {
- final LauncherModel launcherModel = LauncherAppState.getInstance(
- mContext).getModel();
- final WorkspaceItemsInfoFetcher fetcher = new WorkspaceItemsInfoFetcher();
- launcherModel.enqueueModelUpdateTask(fetcher);
- WorkspaceResult workspaceResult;
- try {
- workspaceResult = fetcher.mTask.get(5, TimeUnit.SECONDS);
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- Log.d(TAG, "Error fetching workspace items info", e);
+ boolean needsToMigrate = needsToMigrate(mContext, mIdp);
+ boolean success = false;
+ if (needsToMigrate) {
+ success = MULTI_DB_GRID_MIRATION_ALGO.get()
+ ? GridSizeMigrationTaskV2.migrateGridIfNeeded(mContext, mIdp)
+ : GridSizeMigrationTask.migrateGridIfNeeded(mContext, mIdp);
+ }
+
+ WorkspaceFetcher fetcher;
+ if (needsToMigrate && success) {
+ LauncherAppState appForPreview = new LauncherAppState(
+ new PreviewContext(mContext, mIdp), null /* iconCacheFileName */);
+ fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview);
+ MODEL_EXECUTOR.execute(fetcher);
+ } else {
+ fetcher = new WorkspaceItemsInfoFetcher();
+ LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask(
+ (LauncherModel.ModelUpdateTask) fetcher);
+ }
+ WorkspaceResult workspaceResult = fetcher.get();
+
+ if (workspaceResult == null) {
return;
}
@@ -379,8 +486,13 @@
}
}
- private static class WorkspaceItemsInfoFetcher implements Callable<WorkspaceResult>,
- LauncherModel.ModelUpdateTask {
+ private static void measureView(View view, int width, int height) {
+ view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
+ view.layout(0, 0, width, height);
+ }
+
+ private static class WorkspaceItemsInfoFetcher implements LauncherModel.ModelUpdateTask,
+ WorkspaceFetcher {
private final FutureTask<WorkspaceResult> mTask = new FutureTask<>(this);
@@ -399,6 +511,11 @@
}
@Override
+ public FutureTask<WorkspaceResult> getTask() {
+ return mTask;
+ }
+
+ @Override
public void run() {
mTask.run();
}
@@ -417,9 +534,45 @@
}
}
- private static void measureView(View view, int width, int height) {
- view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
- view.layout(0, 0, width, height);
+ private static class WorkspaceItemsInfoFromPreviewFetcher extends LoaderTask implements
+ WorkspaceFetcher {
+
+ private final FutureTask<WorkspaceResult> mTask = new FutureTask<>(this);
+
+ WorkspaceItemsInfoFromPreviewFetcher(LauncherAppState app) {
+ super(app, null, new BgDataModel(), null);
+ }
+
+ @Override
+ public FutureTask<WorkspaceResult> getTask() {
+ return mTask;
+ }
+
+ @Override
+ public void run() {
+ mTask.run();
+ }
+
+ @Override
+ public WorkspaceResult call() throws Exception {
+ List<ShortcutInfo> allShortcuts = new ArrayList<>();
+ loadWorkspace(allShortcuts, LauncherSettings.Favorites.PREVIEW_CONTENT_URI);
+ return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets,
+ mBgDataModel.widgetsModel);
+ }
+ }
+
+ private interface WorkspaceFetcher extends Runnable, Callable<WorkspaceResult> {
+ FutureTask<WorkspaceResult> getTask();
+
+ default WorkspaceResult get() {
+ try {
+ return getTask().get(5, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Log.d(TAG, "Error fetching workspace items info", e);
+ return null;
+ }
+ }
}
private static class WorkspaceResult {
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 804acc3..f27c9da 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -81,9 +81,13 @@
private int mPendingIconRequestCount = 0;
- public IconCache(Context context, InvariantDeviceProfile inv) {
- super(context, LauncherFiles.APP_ICONS_DB, MODEL_EXECUTOR.getLooper(),
- inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */);
+ public IconCache(Context context, InvariantDeviceProfile idp) {
+ this(context, idp, LauncherFiles.APP_ICONS_DB);
+ }
+
+ public IconCache(Context context, InvariantDeviceProfile idp, String dbFileName) {
+ super(context, dbFileName, MODEL_EXECUTOR.getLooper(),
+ idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */);
mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false);
mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context);
mShortcutCachingLogic = new ShortcutCachingLogic();
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index cbd7c53..bf7897e 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -19,8 +19,8 @@
import android.content.Context;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.graphics.LauncherPreviewRenderer;
/**
* Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
@@ -41,6 +41,11 @@
* avoid allocating new objects in many cases.
*/
public static LauncherIcons obtain(Context context, boolean shapeDetection) {
+ if (context instanceof LauncherPreviewRenderer.PreviewContext) {
+ return ((LauncherPreviewRenderer.PreviewContext) context).newLauncherIcons(context,
+ shapeDetection);
+ }
+
int poolId;
synchronized (sPoolSync) {
if (sPool != null) {
@@ -52,7 +57,7 @@
poolId = sPoolId;
}
- InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId,
shapeDetection);
}
@@ -68,7 +73,7 @@
private LauncherIcons next;
- private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId,
+ protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId,
boolean shapeDetection) {
super(context, fillResIconDpi, iconBitmapSize, shapeDetection);
mPoolId = poolId;
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 199d13f..afa3f6d 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -147,7 +147,7 @@
fillIntentInfo(event.srcTarget[0], intent, userHandle);
}
ItemInfo info = (ItemInfo) v.getTag();
- if (Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
+ if (info != null && Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
FileLog.d(TAG, "appLaunch: packageName:" + info.getTargetComponent().getPackageName()
+ ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals(
userHandle)) + ",launchLocation:" + info.container);
diff --git a/src/com/android/launcher3/model/GridBackupTable.java b/src/com/android/launcher3/model/GridBackupTable.java
index 07a7551..4a1bc4d 100644
--- a/src/com/android/launcher3/model/GridBackupTable.java
+++ b/src/com/android/launcher3/model/GridBackupTable.java
@@ -100,12 +100,24 @@
Process.myUserHandle()), 0);
return false;
}
+ return restoreIfBackupExists(Favorites.TABLE_NAME);
+ }
+
+ public boolean restoreToPreviewIfBackupExists() {
+ if (!tableExists(mDb, BACKUP_TABLE_NAME)) {
+ return false;
+ }
+
+ return restoreIfBackupExists(Favorites.PREVIEW_TABLE_NAME);
+ }
+
+ private boolean restoreIfBackupExists(String toTableName) {
if (loadDBProperties() != STATE_SANITIZED) {
return false;
}
long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
Process.myUserHandle());
- copyTable(mDb, BACKUP_TABLE_NAME, Favorites.TABLE_NAME, userSerial);
+ copyTable(mDb, BACKUP_TABLE_NAME, toTableName, userSerial);
Log.d(TAG, "Backup table found");
return true;
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index c35c4b9..3ba740d 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -3,6 +3,7 @@
import static com.android.launcher3.LauncherSettings.Settings.EXTRA_VALUE;
import static com.android.launcher3.Utilities.getPointString;
import static com.android.launcher3.Utilities.parsePoint;
+import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -14,6 +15,7 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
@@ -29,6 +31,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
@@ -69,6 +72,7 @@
private final SparseArray<ContentValues> mUpdateOperations = new SparseArray<>();
private final HashSet<String> mValidPackages;
+ private final String mTableName;
private final int mSrcX, mSrcY;
private final int mTrgX, mTrgY;
@@ -78,10 +82,12 @@
private final int mDestHotseatSize;
protected GridSizeMigrationTask(Context context, SQLiteDatabase db,
- HashSet<String> validPackages, Point sourceSize, Point targetSize) {
+ HashSet<String> validPackages, boolean usePreviewTable, Point sourceSize,
+ Point targetSize) {
mContext = context;
mDb = db;
mValidPackages = validPackages;
+ mTableName = usePreviewTable ? Favorites.PREVIEW_TABLE_NAME : Favorites.TABLE_NAME;
mSrcX = sourceSize.x;
mSrcY = sourceSize.y;
@@ -97,10 +103,12 @@
}
protected GridSizeMigrationTask(Context context, SQLiteDatabase db,
- HashSet<String> validPackages, int srcHotseatSize, int destHotseatSize) {
+ HashSet<String> validPackages, boolean usePreviewTable, int srcHotseatSize,
+ int destHotseatSize) {
mContext = context;
mDb = db;
mValidPackages = validPackages;
+ mTableName = usePreviewTable ? Favorites.PREVIEW_TABLE_NAME : Favorites.TABLE_NAME;
mSrcHotseatSize = srcHotseatSize;
@@ -120,7 +128,7 @@
// Update items
int updateCount = mUpdateOperations.size();
for (int i = 0; i < updateCount; i++) {
- mDb.update(Favorites.TABLE_NAME, mUpdateOperations.valueAt(i),
+ mDb.update(mTableName, mUpdateOperations.valueAt(i),
"_id=" + mUpdateOperations.keyAt(i), null);
}
@@ -128,8 +136,8 @@
if (DEBUG) {
Log.d(TAG, "Removing items: " + mEntryToRemove.toConcatString());
}
- mDb.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
- Favorites._ID, mEntryToRemove), null);
+ mDb.delete(mTableName, Utilities.createDbSelectionQuery(Favorites._ID, mEntryToRemove),
+ null);
}
return updateCount > 0 || !mEntryToRemove.isEmpty();
@@ -182,8 +190,8 @@
}
@VisibleForTesting
- static IntArray getWorkspaceScreenIds(SQLiteDatabase db) {
- return LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME, Favorites.SCREEN,
+ static IntArray getWorkspaceScreenIds(SQLiteDatabase db, String tableName) {
+ return LauncherDbUtils.queryIntArray(db, tableName, Favorites.SCREEN,
Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP,
Favorites.SCREEN, Favorites.SCREEN);
}
@@ -192,7 +200,7 @@
* @return true if any DB change was made
*/
protected boolean migrateWorkspace() throws Exception {
- IntArray allScreens = getWorkspaceScreenIds(mDb);
+ IntArray allScreens = getWorkspaceScreenIds(mDb, mTableName);
if (allScreens.isEmpty()) {
throw new Exception("Unable to get workspace screens");
}
@@ -244,12 +252,12 @@
/**
* Migrate a particular screen id.
* Strategy:
- * 1) For all possible combinations of row and column, pick the one which causes the least
- * data loss: {@link #tryRemove(int, int, int, ArrayList, float[])}
- * 2) Maintain a list of all lost items before this screen, and add any new item lost from
- * this screen to that list as well.
- * 3) If all those items from the above list can be placed on this screen, place them
- * (otherwise they are placed on a new screen).
+ * 1) For all possible combinations of row and column, pick the one which causes the least
+ * data loss: {@link #tryRemove(int, int, int, ArrayList, float[])}
+ * 2) Maintain a list of all lost items before this screen, and add any new item lost from
+ * this screen to that list as well.
+ * 3) If all those items from the above list can be placed on this screen, place them
+ * (otherwise they are placed on a new screen).
*/
protected void migrateScreen(int screenId) {
// If we are migrating the first screen, do not touch the first row.
@@ -362,9 +370,9 @@
/**
* Tries the remove the provided row and column.
*
- * @param items all the items on the screen under operation
+ * @param items all the items on the screen under operation
* @param outLoss array of size 2. The first entry is filled with weight loss, and the second
- * with the overall item movement.
+ * with the overall item movement.
*/
private ArrayList<DbEntry> tryRemove(int col, int row, int startY,
ArrayList<DbEntry> items, float[] outLoss) {
@@ -379,13 +387,13 @@
for (DbEntry item : items) {
if ((item.cellX <= col && (item.spanX + item.cellX) > col)
- || (item.cellY <= row && (item.spanY + item.cellY) > row)) {
+ || (item.cellY <= row && (item.spanY + item.cellY) > row)) {
removedItems.add(item);
- if (item.cellX >= col) item.cellX --;
- if (item.cellY >= row) item.cellY --;
+ if (item.cellX >= col) item.cellX--;
+ if (item.cellY >= row) item.cellY--;
} else {
- if (item.cellX > col) item.cellX --;
- if (item.cellY > row) item.cellY --;
+ if (item.cellX > col) item.cellX--;
+ if (item.cellY > row) item.cellY--;
finalItems.add(item);
occupied.markCells(item, true);
}
@@ -438,9 +446,9 @@
/**
* Recursively finds a placement for the provided items.
*
- * @param index the position in {@link #itemsToPlace} to start looking at.
- * @param weightLoss total weight loss upto this point
- * @param moveCost total move cost upto this point
+ * @param index the position in {@link #itemsToPlace} to start looking at.
+ * @param weightLoss total weight loss upto this point
+ * @param moveCost total move cost upto this point
* @param itemsPlaced all the items already placed upto this point
*/
public void find(int index, float weightLoss, float moveCost,
@@ -481,11 +489,11 @@
float newMoveCost = moveCost;
if (x != myX) {
me.cellX = x;
- newMoveCost ++;
+ newMoveCost++;
}
if (y != myY) {
me.cellY = y;
- newMoveCost ++;
+ newMoveCost++;
}
if (ignoreMove) {
newMoveCost = moveCost;
@@ -500,35 +508,35 @@
// Try resizing horizontally
if (myW > me.minSpanX && occupied.isRegionVacant(x, y, myW - 1, myH)) {
- me.spanX --;
+ me.spanX--;
occupied.markCells(me, true);
// 1 extra move cost
find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe);
occupied.markCells(me, false);
- me.spanX ++;
+ me.spanX++;
}
// Try resizing vertically
if (myH > me.minSpanY && occupied.isRegionVacant(x, y, myW, myH - 1)) {
- me.spanY --;
+ me.spanY--;
occupied.markCells(me, true);
// 1 extra move cost
find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe);
occupied.markCells(me, false);
- me.spanY ++;
+ me.spanY++;
}
// Try resizing horizontally & vertically
if (myH > me.minSpanY && myW > me.minSpanX &&
occupied.isRegionVacant(x, y, myW - 1, myH - 1)) {
- me.spanX --;
- me.spanY --;
+ me.spanX--;
+ me.spanY--;
occupied.markCells(me, true);
// 2 extra move cost
find(index + 1, weightLoss, newMoveCost + 2, itemsIncludingMe);
occupied.markCells(me, false);
- me.spanX ++;
- me.spanY ++;
+ me.spanX++;
+ me.spanY++;
}
me.cellX = myX;
me.cellY = myY;
@@ -565,11 +573,11 @@
float newMoveCost = moveCost;
if (newX != myX) {
me.cellX = newX;
- newMoveCost ++;
+ newMoveCost++;
}
if (newY != myY) {
me.cellY = newY;
- newMoveCost ++;
+ newMoveCost++;
}
if (ignoreMove) {
newMoveCost = moveCost;
@@ -602,7 +610,7 @@
}
private ArrayList<DbEntry> loadHotseatEntries() {
- Cursor c = queryWorkspace(
+ Cursor c = queryWorkspace(
new String[]{
Favorites._ID, // 0
Favorites.ITEM_TYPE, // 1
@@ -787,7 +795,7 @@
}
protected Cursor queryWorkspace(String[] columns, String where) {
- return mDb.query(Favorites.TABLE_NAME, columns, where, null, null, null, null);
+ return mDb.query(mTableName, columns, where, null, null, null, null);
}
/**
@@ -879,24 +887,44 @@
}
/**
- * Migrates the workspace and hotseat in case their sizes changed.
+ * Check given a new IDP, if migration is necessary.
+ */
+ public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) {
+ SharedPreferences prefs = Utilities.getPrefs(context);
+ String gridSizeString = getPointString(idp.numColumns, idp.numRows);
+
+ return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
+ || idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
+ idp.numHotseatIcons);
+ }
+
+ /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
+ public static boolean migrateGridIfNeeded(Context context) {
+ if (context instanceof LauncherPreviewRenderer.PreviewContext) {
+ return true;
+ }
+ return migrateGridIfNeeded(context, null);
+ }
+
+ /**
+ * Run the migration algorithm if needed. For preview, we provide the intended idp because it
+ * has not been changed. If idp is null, we read it from the context, for actual grid migration.
*
* @return false if the migration failed.
*/
- public static boolean migrateGridIfNeeded(Context context) {
- SharedPreferences prefs = Utilities.getPrefs(context);
- InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
+ public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) {
+ boolean migrateForPreview = idp != null;
+ if (!migrateForPreview) {
+ idp = LauncherAppState.getIDP(context);
+ }
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
-
- if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) &&
- idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
- idp.numHotseatIcons)) {
- // Skip if workspace and hotseat sizes have not changed.
+ if (!needsToMigrate(context, idp)) {
return true;
}
- long migrationStartTime = System.currentTimeMillis();
+ SharedPreferences prefs = Utilities.getPrefs(context);
+ String gridSizeString = getPointString(idp.numColumns, idp.numRows);
+ long migrationStartTime = SystemClock.elapsedRealtime();
try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call(
context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION)
.getBinder(Settings.EXTRA_VALUE)) {
@@ -907,33 +935,39 @@
KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString));
boolean dbChanged = false;
+ if (migrateForPreview) {
+ copyTable(transaction.getDb(), Favorites.TABLE_NAME, Favorites.PREVIEW_TABLE_NAME,
+ context);
+ }
GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(),
srcHotseatCount, sourceSize.x, sourceSize.y);
- if (backupTable.backupOrRestoreAsNeeded()) {
+ if (migrateForPreview ? backupTable.restoreToPreviewIfBackupExists()
+ : backupTable.backupOrRestoreAsNeeded()) {
dbChanged = true;
srcHotseatCount = backupTable.getRestoreHotseatAndGridSize(sourceSize);
}
HashSet<String> validPackages = getValidPackages(context);
- // Hotseat
+ // Hotseat.
if (srcHotseatCount != idp.numHotseatIcons) {
// Migrate hotseat.
- dbChanged = new GridSizeMigrationTask(context, transaction.getDb(),
- validPackages, srcHotseatCount, idp.numHotseatIcons).migrateHotseat();
+ dbChanged = new GridSizeMigrationTask(context, transaction.getDb(), validPackages,
+ migrateForPreview, srcHotseatCount, idp.numHotseatIcons).migrateHotseat();
}
// Grid size
Point targetSize = new Point(idp.numColumns, idp.numRows);
- if (new MultiStepMigrationTask(validPackages, context, transaction.getDb())
- .migrate(sourceSize, targetSize)) {
+ if (new MultiStepMigrationTask(validPackages, context, transaction.getDb(),
+ migrateForPreview).migrate(sourceSize, targetSize)) {
dbChanged = true;
}
if (dbChanged) {
// Make sure we haven't removed everything.
final Cursor c = context.getContentResolver().query(
- Favorites.CONTENT_URI, null, null, null, null);
+ migrateForPreview ? Favorites.PREVIEW_CONTENT_URI : Favorites.CONTENT_URI,
+ null, null, null, null);
boolean hasData = c.moveToNext();
c.close();
if (!hasData) {
@@ -942,21 +976,25 @@
}
transaction.commit();
- Settings.call(context.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
+ if (!migrateForPreview) {
+ Settings.call(context.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
+ }
return true;
} catch (Exception e) {
- Log.e(TAG, "Error during grid migration", e);
+ Log.e(TAG, "Error during preview grid migration", e);
return false;
} finally {
- Log.v(TAG, "Workspace migration completed in "
- + (System.currentTimeMillis() - migrationStartTime));
+ Log.v(TAG, "Preview workspace migration completed in "
+ + (SystemClock.elapsedRealtime() - migrationStartTime));
- // Save current configuration, so that the migration does not run again.
- prefs.edit()
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
- .apply();
+ if (!migrateForPreview) {
+ // Save current configuration, so that the migration does not run again.
+ prefs.edit()
+ .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
+ .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
+ .apply();
+ }
}
}
@@ -989,7 +1027,7 @@
.getBinder(Settings.EXTRA_VALUE)) {
GridSizeMigrationTask task = new GridSizeMigrationTask(
context, transaction.getDb(), getValidPackages(context),
- Integer.MAX_VALUE, Integer.MAX_VALUE);
+ false /* usePreviewTable */, Integer.MAX_VALUE, Integer.MAX_VALUE);
// Load all the valid entries
ArrayList<DbEntry> items = task.loadHotseatEntries();
@@ -1011,12 +1049,14 @@
private final HashSet<String> mValidPackages;
private final Context mContext;
private final SQLiteDatabase mDb;
+ private final boolean mUsePreviewTable;
public MultiStepMigrationTask(HashSet<String> validPackages, Context context,
- SQLiteDatabase db) {
+ SQLiteDatabase db, boolean usePreviewTable) {
mValidPackages = validPackages;
mContext = context;
mDb = db;
+ mUsePreviewTable = usePreviewTable;
}
public boolean migrate(Point sourceSize, Point targetSize) throws Exception {
@@ -1052,8 +1092,8 @@
}
protected boolean runStepTask(Point sourceSize, Point nextSize) throws Exception {
- return new GridSizeMigrationTask(mContext, mDb,
- mValidPackages, sourceSize, nextSize).migrateWorkspace();
+ return new GridSizeMigrationTask(mContext, mDb, mValidPackages, mUsePreviewTable,
+ sourceSize, nextSize).migrateWorkspace();
}
}
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 63b7191..197b29c 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import com.android.launcher3.InvariantDeviceProfile;
+
/**
* This class takes care of shrinking the workspace (by maximum of one row and one column), as a
* result of restoring from a larger device or device density change.
@@ -28,12 +30,19 @@
}
+ /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
+ public static boolean migrateGridIfNeeded(Context context) {
+ // To be implemented.
+ return true;
+ }
+
/**
- * Migrates the workspace and hotseat in case their sizes changed.
+ * Run the migration algorithm if needed. For preview, we provide the intended idp because it
+ * has not been changed. If idp is null, we read it from the context, for actual grid migration.
*
* @return false if the migration failed.
*/
- public static boolean migrateGridIfNeeded(Context context) {
+ public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) {
// To be implemented.
return true;
}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 4961432..2311dcc 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.CursorWrapper;
+import android.net.Uri;
import android.os.UserHandle;
import android.provider.BaseColumns;
import android.text.TextUtils;
@@ -64,6 +65,7 @@
public final LongSparseArray<UserHandle> allUsers = new LongSparseArray<>();
+ private final Uri mContentUri;
private final Context mContext;
private final PackageManager mPM;
private final IconCache mIconCache;
@@ -96,8 +98,10 @@
public int itemType;
public int restoreFlag;
- public LoaderCursor(Cursor c, LauncherAppState app) {
- super(c);
+ public LoaderCursor(Cursor cursor, Uri contentUri, LauncherAppState app) {
+ super(cursor);
+
+ mContentUri = contentUri;
mContext = app.getContext();
mIconCache = app.getIconCache();
mIDP = app.getInvariantDeviceProfile();
@@ -312,9 +316,8 @@
public boolean commitDeleted() {
if (itemsToRemove.size() > 0) {
// Remove dead items
- mContext.getContentResolver().delete(LauncherSettings.Favorites.CONTENT_URI,
- Utilities.createDbSelectionQuery(
- LauncherSettings.Favorites._ID, itemsToRemove), null);
+ mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery(
+ LauncherSettings.Favorites._ID, itemsToRemove), null);
return true;
}
return false;
@@ -339,7 +342,7 @@
// Update restored items that no longer require special handling
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.RESTORED, 0);
- mContext.getContentResolver().update(LauncherSettings.Favorites.CONTENT_URI, values,
+ mContext.getContentResolver().update(mContentUri, values,
Utilities.createDbSelectionQuery(
LauncherSettings.Favorites._ID, restoredRows), null);
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 6223a23..fbf01fc 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -36,6 +36,7 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.ShortcutInfo;
+import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
@@ -76,7 +77,6 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.LooperIdleLock;
@@ -106,7 +106,7 @@
private final LauncherAppState mApp;
private final AllAppsList mBgAllAppsList;
- private final BgDataModel mBgDataModel;
+ protected final BgDataModel mBgDataModel;
private FirstScreenBroadcast mFirstScreenBroadcast;
@@ -284,6 +284,10 @@
@VisibleForTesting
void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
+ loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI);
+ }
+
+ protected void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, Uri contentUri) {
final Context context = mApp.getContext();
final ContentResolver contentResolver = context.getContentResolver();
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -327,8 +331,8 @@
mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
Map<ShortcutKey, ShortcutInfo> shortcutKeyToPinnedShortcuts = new HashMap<>();
- final LoaderCursor c = new LoaderCursor(contentResolver.query(
- LauncherSettings.Favorites.CONTENT_URI, null, null, null, null), mApp);
+ final LoaderCursor c = new LoaderCursor(
+ contentResolver.query(contentUri, null, null, null, null), contentUri, mApp);
Map<ComponentKey, AppWidgetProviderInfo> widgetProvidersMap = null;
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index d9bd714..1c2acfd 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -32,6 +32,7 @@
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.util.AttributeSet;
+import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -358,6 +359,11 @@
}
}
+ @Override
+ protected Pair<View, String> getAccessibilityTarget() {
+ return Pair.create(this, "");
+ }
+
private void animateOpen() {
setVisibility(View.VISIBLE);
@@ -413,6 +419,8 @@
}
if (getOutlineProvider() instanceof RevealOutlineAnimation) {
((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect);
+ } else {
+ mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
}
if (mOpenCloseAnimator != null) {
mOpenCloseAnimator.cancel();
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 05ea694..445acca 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -37,7 +37,6 @@
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
-import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -330,11 +329,6 @@
}
@Override
- protected Pair<View, String> getAccessibilityTarget() {
- return Pair.create(this, "");
- }
-
- @Override
protected void getTargetObjectLocation(Rect outPos) {
getPopupContainer().getDescendantRectRelativeToSelf(mOriginalIcon, outPos);
outPos.top += mOriginalIcon.getPaddingTop();
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 2c843f9..f7ecc3f 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -22,10 +22,12 @@
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.os.Binder;
+import android.os.Process;
import android.util.Log;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.IntArray;
import java.util.Locale;
@@ -116,6 +118,15 @@
db.execSQL("DROP TABLE IF EXISTS " + tableName);
}
+ /** Copy from table to the to table. */
+ public static void copyTable(SQLiteDatabase db, String from, String to, Context context) {
+ long userSerial = UserCache.INSTANCE.get(context).getSerialNumberForUser(
+ Process.myUserHandle());
+ dropTable(db, to);
+ Favorites.addTableToDb(db, userSerial, false, to);
+ db.execSQL("INSERT INTO " + to + " SELECT * FROM " + from);
+ }
+
/**
* Utility class to simplify managing sqlite transactions
*/
diff --git a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
index 6d839f3..c0111b9 100644
--- a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
+++ b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
@@ -18,7 +18,6 @@
import android.content.ContentValues;
import android.content.Context;
-import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
@@ -43,7 +42,7 @@
protected LossyScreenMigrationTask(
Context context, InvariantDeviceProfile idp, SQLiteDatabase db) {
// Decrease the rows count by 1
- super(context, db, getValidPackages(context),
+ super(context, db, getValidPackages(context), false /* usePreviewTable */,
new Point(idp.numColumns, idp.numRows + 1),
new Point(idp.numColumns, idp.numRows));
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index 520a9ed..fc9f8f7 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -22,6 +22,7 @@
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext;
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import java.util.concurrent.ExecutionException;
@@ -39,6 +40,10 @@
}
public T get(Context context) {
+ if (context instanceof PreviewContext) {
+ return ((PreviewContext) context).getObject(this, mProvider);
+ }
+
if (mValue == null) {
if (Looper.myLooper() == Looper.getMainLooper()) {
mValue = TraceHelper.whitelistIpcs("main.thread.object",
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 4ffc251..5e98184 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -22,10 +22,9 @@
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static java.lang.System.exit;
-
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -38,7 +37,6 @@
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.RemoteException;
-import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
@@ -102,6 +100,7 @@
protected final LauncherInstrumentation mLauncher = new LauncherInstrumentation();
protected Context mTargetContext;
protected String mTargetPackage;
+ private int mLauncherPid;
protected AbstractLauncherUiTest() {
mLauncher.enableCheckEventsForSuccessfulGestures();
@@ -158,7 +157,7 @@
return TestHelpers.isInLauncherProcess()
? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher())
- .around(inner) :
+ .around(inner) :
inner;
}
@@ -175,17 +174,22 @@
@Before
public void setUp() throws Exception {
+ mLauncherPid = 0;
// Disable app tracker
AppLaunchTracker.INSTANCE.initializeForTesting(new AppLaunchTracker());
mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
+ mLauncherPid = mLauncher.getPid();
}
@After
public void verifyLauncherState() {
// Limits UI tests affecting tests running after them.
mLauncher.waitForLauncherInitialized();
+ if (mLauncherPid != 0) {
+ assertEquals("Launcher crashed, pid mismatch:", mLauncherPid, mLauncher.getPid());
+ }
}
protected void clearLauncherData() throws IOException, InterruptedException {
@@ -196,6 +200,7 @@
} else {
clearPackageData(mDevice.getLauncherPackageName());
mLauncher.enableDebugTracing();
+ mLauncherPid = mLauncher.getPid();
}
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 54caf1e..7475efe 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -40,7 +40,6 @@
import com.android.launcher3.widget.WidgetsFullSheet;
import com.android.launcher3.widget.WidgetsRecyclerView;
-import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -51,21 +50,10 @@
public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
private static final String APP_NAME = "LauncherTestApp";
- private int mLauncherPid;
-
@Before
public void setUp() throws Exception {
- mLauncherPid = 0;
super.setUp();
initialize(this);
- mLauncherPid = mLauncher.getPid();
- }
-
- @After
- public void teardown() {
- if (mLauncherPid != 0) {
- assertEquals("Launcher crashed, pid mismatch:", mLauncherPid, mLauncher.getPid());
- }
}
public static void initialize(AbstractLauncherUiTest test) throws Exception {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index b3b887d..6775521 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -145,7 +145,7 @@
private static final String WORKSPACE_RES_ID = "workspace";
private static final String APPS_RES_ID = "apps_view";
- private static final String OVERVIEW_RES_ID = "overview_panel";
+ private static final String OVERVIEW_RES_ID = "overview_panel_recents";
private static final String WIDGETS_RES_ID = "widgets_list_view";
private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
public static final int WAIT_TIME_MS = 10000;