Merge "Fixing generation of fake app-to-recents events" into ub-launcher3-master
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 0956048..9b6c053 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -25,6 +25,9 @@
<dimen name="task_fade_length">20dp</dimen>
<dimen name="recents_page_spacing">10dp</dimen>
+ <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
+ loading full resolution screenshots. -->
+ <dimen name="recents_fast_fling_velocity">600dp</dimen>
<dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
<dimen name="quickstep_fling_min_velocity">250dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 5259e04..a5af173 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -500,10 +500,8 @@
mFloatingView = new View(mLauncher);
if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
// Create a copy of the app icon
- ItemInfoWithIcon info = (ItemInfoWithIcon) v.getTag();
- FastBitmapDrawable d = DrawableFactory.get(mLauncher).newIcon(info);
- d.setIsDisabled(info.isDisabled());
- mFloatingView.setBackground(d);
+ mFloatingView.setBackground(
+ DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag()));
}
// Position the floating view exactly on top of the original
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 7bd4366..71cdd10 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -29,6 +29,7 @@
import com.android.launcher3.graphics.BitmapRenderer;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.RecentsModel;
import com.android.quickstep.RecentsView;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -88,4 +89,18 @@
RecentsView recents = launcher.getOverviewPanel();
recents.reset();
}
+
+ public static void onStart(Launcher launcher) {
+ RecentsModel model = RecentsModel.getInstance(launcher);
+ if (model != null) {
+ model.onStart();
+ }
+ }
+
+ public static void onTrimMemory(Launcher launcher, int level) {
+ RecentsModel model = RecentsModel.getInstance(launcher);
+ if (model != null) {
+ model.onTrimMemory(level);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 7fe7751..90e857c 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -16,6 +16,8 @@
package com.android.quickstep;
import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -29,6 +31,7 @@
import android.util.LruCache;
import android.util.SparseArray;
+import com.android.launcher3.Launcher;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.util.Preconditions;
@@ -51,7 +54,6 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public class RecentsModel extends TaskStackChangeListener {
-
// We do not need any synchronization for this variable as its only written on UI thread.
private static RecentsModel INSTANCE;
@@ -83,10 +85,16 @@
private int mTaskChangeId;
private ISystemUiProxy mSystemUiProxy;
private boolean mClearAssistCacheOnStackChange = true;
+ private final boolean mPreloadTasksInBackground;
private RecentsModel(Context context) {
mContext = context;
+ ActivityManager activityManager =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mPreloadTasksInBackground = !activityManager.isLowRamDevice();
+ mMainThreadExecutor = new MainThreadExecutor();
+
Resources res = context.getResources();
mRecentsTaskLoader = new RecentsTaskLoader(mContext,
res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize),
@@ -100,8 +108,6 @@
}
};
mRecentsTaskLoader.startLoader(mContext);
-
- mMainThreadExecutor = new MainThreadExecutor();
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
mTaskChangeId = 1;
@@ -162,6 +168,31 @@
}
}
+ @Override
+ public void onTaskStackChangedBackground() {
+ int userId = UserHandle.myUserId();
+ if (!mPreloadTasksInBackground || !checkCurrentUserId(userId, false /* debug */)) {
+ // TODO: Only register this for the current user
+ return;
+ }
+
+ // Preload a fixed number of task icons/thumbnails in the background
+ ActivityManager.RunningTaskInfo runningTaskInfo =
+ ActivityManagerWrapper.getInstance().getRunningTask();
+ RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
+ launchOpts.numVisibleTasks = 2;
+ launchOpts.numVisibleTaskThumbnails = 2;
+ launchOpts.onlyLoadForCache = true;
+ launchOpts.onlyLoadPausedActivities = true;
+ launchOpts.loadThumbnails = true;
+ PreloadOptions preloadOpts = new PreloadOptions();
+ preloadOpts.loadTitles = false;
+ plan.preloadPlan(preloadOpts, mRecentsTaskLoader, -1, userId);
+ mRecentsTaskLoader.loadTasks(plan, launchOpts);
+ }
+
public boolean isLoadPlanValid(int resultId) {
return mTaskChangeId == resultId;
}
@@ -178,6 +209,19 @@
return mSystemUiProxy;
}
+ public void onStart() {
+ mRecentsTaskLoader.startLoader(mContext);
+ mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(true);
+ }
+
+ public void onTrimMemory(int level) {
+ if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
+ // We already stop the loader in UI_HIDDEN, so stop the high res loader as well
+ mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(false);
+ }
+ mRecentsTaskLoader.onTrimMemory(level);
+ }
+
@WorkerThread
public void preloadAssistData(int taskId, Bundle data) {
mMainThreadExecutor.execute(() -> {
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 9e07b49..42677c1 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -22,9 +22,11 @@
import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
import android.animation.LayoutTransition;
+import android.animation.LayoutTransition.TransitionListener;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
@@ -38,8 +40,10 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.launcher3.DeviceProfile;
@@ -82,6 +86,8 @@
private LayoutTransition mLayoutTransition;
private Runnable mNextPageSwitchRunnable;
+ private float mFastFlingVelocity;
+
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
*/
@@ -114,6 +120,7 @@
private boolean mScrimOnLeft;
private boolean mFirstTaskIconScaledDown = false;
+ private SparseBooleanArray mPrevVisibleTasks = new SparseBooleanArray();
public RecentsView(Context context) {
this(context, null);
@@ -167,19 +174,37 @@
private void setupLayoutTransition() {
// We want to show layout transitions when pages are deleted, to close the gap.
+ // TODO: We should this manually so we can control the animation (fill in the gap as the
+ // dismissing task is being tracked, and also so we can update the visible task data during
+ // the transition. For now, the workaround is to expand the visible tasks to load.
mLayoutTransition = new LayoutTransition();
mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);
mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
+ mLayoutTransition.addTransitionListener(new TransitionListener() {
+ @Override
+ public void startTransition(LayoutTransition layoutTransition, ViewGroup viewGroup,
+ View view, int i) {
+ loadVisibleTaskData();
+ }
+
+ @Override
+ public void endTransition(LayoutTransition layoutTransition, ViewGroup viewGroup,
+ View view, int i) {
+ loadVisibleTaskData();
+ }
+ });
setLayoutTransition(mLayoutTransition);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ Resources res = getResources();
mFirstTaskIndex = getPageCount();
+ mFastFlingVelocity = res.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
}
@Override
@@ -307,20 +332,25 @@
}
while (getChildCount() > requiredChildCount) {
final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
+ final Task task = taskView.getTask();
removeView(taskView);
- loader.unloadTaskData(taskView.getTask());
+ loader.unloadTaskData(task);
+ loader.getHighResThumbnailLoader().onTaskInvisible(task);
}
setLayoutTransition(mLayoutTransition);
// Rebind and reset all task views
for (int i = tasks.size() - 1; i >= 0; i--) {
+ final int pageIndex = tasks.size() - i - 1 + mFirstTaskIndex;
final Task task = tasks.get(i);
- final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex);
+ final TaskView taskView = (TaskView) getChildAt(pageIndex);
taskView.bind(task);
taskView.resetVisualProperties();
- loader.loadTaskData(task);
}
updateCurveProperties();
+ // Reload the set of visible task's data
+ mPrevVisibleTasks.clear();
+ loadVisibleTaskData();
applyIconScale(false /* animate */);
if (oldChildCount != getChildCount()) {
@@ -414,9 +444,24 @@
}
@Override
- public void computeScroll() {
- super.computeScroll();
+ protected boolean computeScrollHelper() {
+ boolean scrolling = super.computeScrollHelper();
+ boolean isFlingingFast = false;
updateCurveProperties();
+ if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) {
+ if (scrolling) {
+ // Check if we are flinging quickly to disable high res thumbnail loading
+ isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity;
+ }
+
+ // After scrolling, update the visible task's data
+ loadVisibleTaskData();
+ }
+
+ // Update the high res thumbnail loader
+ RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+ loader.getHighResThumbnailLoader().setFlingingFast(isFlingingFast);
+ return scrolling;
}
/**
@@ -444,6 +489,34 @@
}
}
+ /**
+ * Iterates through all thet asks, and loads the associated task data for newly visible tasks,
+ * and unloads the associated task data for tasks that are no longer visible.
+ */
+ private void loadVisibleTaskData() {
+ RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+ int centerPageIndex = getPageNearestToCenterOfScreen();
+ int lower = Math.max(mFirstTaskIndex, centerPageIndex - 2);
+ int upper = Math.min(centerPageIndex + 2, getChildCount() - 1);
+ for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
+ TaskView taskView = (TaskView) getChildAt(i);
+ Task task = taskView.getTask();
+ boolean visible = lower <= i && i <= upper;
+ if (visible) {
+ if (!mPrevVisibleTasks.get(i)) {
+ loader.loadTaskData(task);
+ loader.getHighResThumbnailLoader().onTaskVisible(task);
+ }
+ } else {
+ if (mPrevVisibleTasks.get(i)) {
+ loader.unloadTaskData(task);
+ loader.getHighResThumbnailLoader().onTaskInvisible(task);
+ }
+ }
+ mPrevVisibleTasks.put(i, visible);
+ }
+ }
+
public void onTaskDismissed(TaskView taskView) {
ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
removeView(taskView);
@@ -493,14 +566,16 @@
addView(taskView, mFirstTaskIndex);
setLayoutTransition(mLayoutTransition);
}
+ mRunningTaskId = runningTaskId;
+ setCurrentPage(mFirstTaskIndex);
if (!needsReload) {
needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
}
if (needsReload) {
mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
+ } else {
+ loadVisibleTaskData();
}
- mRunningTaskId = runningTaskId;
- setCurrentPage(mFirstTaskIndex);
if (mCurrentPage >= mFirstTaskIndex) {
getPageAt(mCurrentPage).setAlpha(0);
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index dbdb2dc..4f50d1a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -231,7 +231,6 @@
FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info);
mBadgeColor = IconPalette.getMutedColor(info.iconColor, 0.54f);
- iconDrawable.setIsDisabled(info.isDisabled());
setIcon(iconDrawable);
setText(info.title);
if (info.contentDescription != null) {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index ba55b36..ea52324 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -250,6 +250,14 @@
}
/**
+ * Inverse of {@link #getMultiWindowProfile(Context, Point)}
+ * @return device profile corresponding to the current orientation in non multi-window mode.
+ */
+ public DeviceProfile getFullScreenProfile() {
+ return isLandscape ? inv.landscapeProfile : inv.portraitProfile;
+ }
+
+ /**
* Adjusts the profile so that the labels on the Workspace are hidden.
* It is important to call this method after the All Apps variables have been set.
*/
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5ac53a8..38b0140 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -829,6 +829,7 @@
mScrimAnimator.start();
}
mShouldFadeInScrim = false;
+ UiFactory.onStart(this);
}
@Override
@@ -2171,6 +2172,7 @@
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onTrimMemory(level);
}
+ UiFactory.onTrimMemory(this, level);
}
@Override
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ca8039c..6ec209a 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -552,7 +552,6 @@
// Notify the user when the page changes
announceForAccessibility(getCurrentPageDescription());
}
- return true;
}
return false;
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index d8a9f63..416469f 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -131,7 +131,7 @@
mSnappedScrolledY = currentScrollY - mMaxTranslation;
} else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
mHeaderCollapsed = true;
- mSnappedScrolledY = currentScrollY;
+ mSnappedScrolledY = -mMaxTranslation;
}
}
}
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 32d9e41..3393469 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -65,7 +65,9 @@
* Returns a FastBitmapDrawable with the icon.
*/
public FastBitmapDrawable newIcon(ItemInfoWithIcon info) {
- return new FastBitmapDrawable(info);
+ FastBitmapDrawable drawable = new FastBitmapDrawable(info);
+ drawable.setIsDisabled(info.isDisabled());
+ return drawable;
}
/**
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
index 37e5efcb..3a24c3d 100644
--- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
@@ -44,7 +44,8 @@
mPaint = new TextPaint();
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
- mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
+ mLauncher.getDeviceProfile().getFullScreenProfile().iconTextSizePx,
+ getResources().getDisplayMetrics()));
setBackgroundResource(R.drawable.bg_deferred_app_widget);
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 64a29ea..a16ae48 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -64,4 +64,8 @@
public static void resetOverview(Launcher launcher) { }
public static void onLauncherStateOrFocusChanged(Launcher launcher) { }
+
+ public static void onStart(Launcher launcher) { }
+
+ public static void onTrimMemory(Launcher launcher, int level) { }
}