Merge "Fix issue where pointer id was being used to set as action index" into ub-launcher3-master
diff --git a/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
index 4d56786..35f46cf 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
@@ -84,7 +84,8 @@
}
if (action == ACTION_MOVE) {
float dy = ev.getY() - mTranslator.getDownY();
- if (dy > mTouchSlop) {
+ float dx = ev.getX() - mTranslator.getDownX();
+ if (dy > mTouchSlop && dy > Math.abs(dx)) {
mTranslator.dispatchDownEvents(ev);
mTranslator.processMotionEvent(ev);
return true;
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index 9432256..3420767 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -67,6 +67,7 @@
private int mQuickScrubSection;
private boolean mStartedFromHome;
private boolean mFinishedTransitionToQuickScrub;
+ private int mLaunchingTaskId;
private Runnable mOnFinishedTransitionToQuickScrubRunnable;
private ActivityControlHelper mActivityControlHelper;
private TouchInteractionLog mTouchInteractionLog;
@@ -105,6 +106,7 @@
if (taskView != null) {
mWaitingForTaskLaunch = true;
mTouchInteractionLog.launchTaskStart();
+ mLaunchingTaskId = taskView.getTask().key.id;
taskView.launchTask(true, (result) -> {
mTouchInteractionLog.launchTaskEnd(result);
if (!result) {
@@ -146,6 +148,7 @@
mActivityControlHelper = null;
mOnFinishedTransitionToQuickScrubRunnable = null;
mRecentsView.setNextPageSwitchRunnable(null);
+ mLaunchingTaskId = 0;
}
/**
@@ -211,6 +214,18 @@
}
}
+ public void onTaskRemoved(int taskId) {
+ if (mLaunchingTaskId == taskId) {
+ // The task has been removed mid-launch, break out of quickscrub and return the user
+ // to where they were before (and notify the launch failed)
+ TaskView taskView = mRecentsView.getTaskView(taskId);
+ if (taskView != null) {
+ taskView.notifyTaskLaunchFailed(TAG);
+ }
+ breakOutOfQuickScrub();
+ }
+ }
+
public void snapToNextTaskIfAvailable() {
if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b9f95cc..cded799 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -19,7 +19,7 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
-import static android.view.MotionEvent.ACTION_POINTER_UP;
+import static android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.systemui.shared.system.ActivityManagerWrapper
@@ -52,6 +52,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ChoreographerCompat;
import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -299,7 +300,7 @@
mActivityHelper = activityHelper;
mActivity = activity;
mTarget = activity.getDragLayer();
- mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
+ mTouchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
mStartingInActivityBounds = startingInActivityBounds;
mQuickScrubController = mActivity.<RecentsView>getOverviewPanel()
@@ -324,12 +325,6 @@
mDownPos.set(ev.getX(), ev.getY());
} else if (!mTrackingStarted) {
switch (action) {
- case ACTION_POINTER_UP:
- case ACTION_POINTER_DOWN:
- if (!mTrackingStarted) {
- mInvalidated = true;
- }
- break;
case ACTION_CANCEL:
case ACTION_UP:
startTouchTracking(ev, true /* updateLocationOffset */);
@@ -359,15 +354,26 @@
}
// Send down touch event
- MotionEvent down = MotionEvent.obtain(ev);
+ MotionEvent down = MotionEvent.obtainNoHistory(ev);
down.setAction(ACTION_DOWN);
sendEvent(down);
- down.recycle();
mTrackingStarted = true;
+ // Send pointer down for remaining pointers.
+ int pointerCount = ev.getPointerCount();
+ for (int i = 1; i < pointerCount; i++) {
+ down.setAction(ACTION_POINTER_DOWN | (i << ACTION_POINTER_INDEX_SHIFT));
+ sendEvent(down);
+ }
+
+ down.recycle();
}
private void sendEvent(MotionEvent ev) {
+ if (!mTarget.verifyTouchDispatch(this, ev)) {
+ mInvalidated = true;
+ return;
+ }
int flags = ev.getEdgeFlags();
ev.setEdgeFlags(flags | TouchInteractionService.EDGE_NAV_BAR);
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index f3dec9a..bff3025 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -183,6 +183,10 @@
if (!mHandleTaskStackChanges) {
return;
}
+
+ // Notify the quick scrub controller that a particular task has been removed
+ mQuickScrubController.onTaskRemoved(taskId);
+
BackgroundExecutor.get().submit(() -> {
TaskView taskView = getTaskView(taskId);
if (taskView == null) {
@@ -396,9 +400,6 @@
final int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
- if (mShowEmptyMessage) {
- onAllTasksRemoved();
- }
if (mTouchDownToStartHome) {
startHome();
}
@@ -409,7 +410,8 @@
break;
case MotionEvent.ACTION_MOVE:
// Passing the touch slop will not allow dismiss to home
- if (mTouchDownToStartHome && Math.hypot(mDownX - x, mDownY - y) > mTouchSlop) {
+ if (mTouchDownToStartHome &&
+ (isHandlingTouch() || Math.hypot(mDownX - x, mDownY - y) > mTouchSlop)) {
mTouchDownToStartHome = false;
}
break;
@@ -417,12 +419,17 @@
// Touch down anywhere but the deadzone around the visible clear all button and
// between the task views will start home on touch up
if (!isHandlingTouch()) {
- updateDeadZoneRects();
- final boolean clearAllButtonDeadZoneConsumed = mClearAllButton.getAlpha() == 1
- && mClearAllButtonDeadZoneRect.contains(x, y);
- if (!clearAllButtonDeadZoneConsumed
- && !mTaskViewDeadZoneRect.contains(x + getScrollX(), y)) {
+ if (mShowEmptyMessage) {
mTouchDownToStartHome = true;
+ } else {
+ updateDeadZoneRects();
+ final boolean clearAllButtonDeadZoneConsumed =
+ mClearAllButton.getAlpha() == 1
+ && mClearAllButtonDeadZoneRect.contains(x, y);
+ if (!clearAllButtonDeadZoneConsumed
+ && !mTaskViewDeadZoneRect.contains(x + getScrollX(), y)) {
+ mTouchDownToStartHome = true;
+ }
}
}
mDownX = x;
@@ -662,10 +669,6 @@
mHasVisibleTaskData.clear();
}
- protected void onAllTasksRemoved() {
- startHome();
- }
-
protected abstract void startHome();
public void reset() {
@@ -969,7 +972,7 @@
if (getTaskViewCount() == 0) {
removeView(mClearAllButton);
- onAllTasksRemoved();
+ startHome();
} else {
snapToPageImmediately(pageToSnapTo);
}
@@ -998,7 +1001,7 @@
// Remove all the task views now
ActivityManagerWrapper.getInstance().removeAllRecentTasks();
removeAllViews();
- onAllTasksRemoved();
+ startHome();
}
mPendingAnimation = null;
});
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
new file mode 100644
index 0000000..6854aa8
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.quickstep;
+
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
+/**
+ * Base class for all instrumentation tests that deal with Quickstep.
+ */
+public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
+ @Rule
+ public TestRule mQuickstepOnOffExecutor =
+ new QuickStepOnOffRule(mMainThreadExecutor, mLauncher);
+}
diff --git a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
new file mode 100644
index 0000000..6a149b7
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.quickstep;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.ui.TestHelpers;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.Executor;
+
+/**
+ * Test rule that allows executing a test with Quickstep on and then Quickstep off.
+ * The test should be annotated with @QuickstepOnOff.
+ */
+public class QuickStepOnOffRule implements TestRule {
+ // Annotation for tests that need to be run with quickstep enabled and disabled.
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public @interface QuickstepOnOff {
+ }
+
+ private final Executor mMainThreadExecutor;
+ private final LauncherInstrumentation mLauncher;
+
+ public QuickStepOnOffRule(Executor mainThreadExecutor, LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ this.mMainThreadExecutor = mainThreadExecutor;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ if (TestHelpers.isInLauncherProcess() &&
+ description.getAnnotation(QuickstepOnOff.class) != null) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ evaluateWithQuickstepOn();
+ evaluateWithQuickstepOff();
+ } finally {
+ overrideSwipeUpEnabled(null);
+ }
+ }
+
+ private void evaluateWithQuickstepOff() throws Throwable {
+ overrideSwipeUpEnabled(false);
+ base.evaluate();
+ }
+
+ private void evaluateWithQuickstepOn() throws Throwable {
+ overrideSwipeUpEnabled(true);
+ base.evaluate();
+ }
+
+ private void overrideSwipeUpEnabled(Boolean swipeUpEnabledOverride) {
+ mLauncher.overrideSwipeUpEnabled(swipeUpEnabledOverride);
+ mMainThreadExecutor.execute(() -> OverviewInteractionState.INSTANCE.get(
+ InstrumentationRegistry.getInstrumentation().getTargetContext()).
+ notifySwipeUpSettingChanged(mLauncher.isSwipeUpEnabled()));
+ }
+ };
+ } else {
+ return base;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index 80758c9..b2b05b1 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -2,11 +2,15 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Parcel;
+import android.os.UserHandle;
+
+import com.android.launcher3.icons.ComponentWithLabel;
/**
* This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
@@ -14,7 +18,8 @@
* (who's implementation is owned by the launcher). This object represents a widget type / class,
* as opposed to a widget instance, and so should not be confused with {@link LauncherAppWidgetInfo}
*/
-public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
+public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
+ implements ComponentWithLabel {
public static final String CLS_CUSTOM_WIDGET_PREFIX = "#custom-widget-";
@@ -102,4 +107,14 @@
return 0;
}
}
- }
+
+ @Override
+ public final ComponentName getComponent() {
+ return provider;
+ }
+
+ @Override
+ public final UserHandle getUser() {
+ return getProfile();
+ }
+}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 68abd68..5e09f8a 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -599,6 +599,19 @@
CacheDataUpdatedTask.OP_CACHE_UPDATE, user, updatedPackages));
}
+ /**
+ * Called when the labels for the widgets has updated in the icon cache.
+ */
+ public void onWidgetLabelsUpdated(HashSet<String> updatedPackages, UserHandle user) {
+ enqueueModelUpdateTask(new BaseModelUpdateTask() {
+ @Override
+ public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
+ dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, app);
+ bindUpdatedWidgets(dataModel);
+ }
+ });
+ }
+
public void enqueueModelUpdateTask(ModelUpdateTask task) {
task.init(mApp, this, sBgDataModel, mBgAllAppsList, mUiExecutor);
runOnWorkerThread(task);
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index ba0ac6e..b641391 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -200,7 +200,7 @@
pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0)) {
if (packageUser == null || packageUser.mPackageName
.equals(info.activityInfo.packageName)) {
- result.add(new ShortcutConfigActivityInfoVL(info.activityInfo, pm));
+ result.add(new ShortcutConfigActivityInfoVL(info.activityInfo));
}
}
return result;
diff --git a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
index d260e24..76eec6d 100644
--- a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
@@ -32,6 +32,7 @@
import android.util.Log;
import android.widget.Toast;
+import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
@@ -40,7 +41,7 @@
/**
* Wrapper class for representing a shortcut configure activity.
*/
-public abstract class ShortcutConfigActivityInfo {
+public abstract class ShortcutConfigActivityInfo implements ComponentWithLabel {
private static final String TAG = "SCActivityInfo";
@@ -52,10 +53,12 @@
mUser = user;
}
+ @Override
public ComponentName getComponent() {
return mCn;
}
+ @Override
public UserHandle getUser() {
return mUser;
}
@@ -64,8 +67,6 @@
return LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
}
- public abstract CharSequence getLabel();
-
public abstract Drawable getFullResIcon(IconCache cache);
/**
@@ -94,8 +95,8 @@
}
/**
- * Returns true if various properties ({@link #getLabel()}, {@link #getFullResIcon}) can
- * be safely persisted.
+ * Returns true if various properties ({@link #getLabel(PackageManager)},
+ * {@link #getFullResIcon}) can be safely persisted.
*/
public boolean isPersistable() {
return true;
@@ -104,18 +105,15 @@
static class ShortcutConfigActivityInfoVL extends ShortcutConfigActivityInfo {
private final ActivityInfo mInfo;
- private final PackageManager mPm;
-
- public ShortcutConfigActivityInfoVL(ActivityInfo info, PackageManager pm) {
+ public ShortcutConfigActivityInfoVL(ActivityInfo info) {
super(new ComponentName(info.packageName, info.name), Process.myUserHandle());
mInfo = info;
- mPm = pm;
}
@Override
- public CharSequence getLabel() {
- return mInfo.loadLabel(mPm);
+ public CharSequence getLabel(PackageManager pm) {
+ return mInfo.loadLabel(pm);
}
@Override
@@ -135,7 +133,7 @@
}
@Override
- public CharSequence getLabel() {
+ public CharSequence getLabel(PackageManager pm) {
return mInfo.getLabel();
}
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 278eefd..daf7dc6 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -32,6 +32,7 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.view.MotionEvent;
@@ -46,6 +47,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherModel;
import com.android.launcher3.R;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
@@ -54,6 +56,8 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.InstantAppResolver;
+import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.Provider;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
@@ -78,7 +82,6 @@
// Widget request specific options.
private LauncherAppWidgetHost mAppWidgetHost;
private AppWidgetManagerCompat mAppWidgetManager;
- private PendingAddWidgetInfo mPendingWidgetInfo;
private int mPendingBindWidgetId;
private Bundle mWidgetOptions;
@@ -189,10 +192,9 @@
private void setupShortcut() {
PinShortcutRequestActivityInfo shortcutInfo =
new PinShortcutRequestActivityInfo(mRequest, this);
- WidgetItem item = new WidgetItem(shortcutInfo);
mWidgetCell.getWidgetView().setTag(new PendingAddShortcutInfo(shortcutInfo));
- mWidgetCell.applyFromCellItem(item, mApp.getWidgetCache());
- mWidgetCell.ensurePreview();
+ applyWidgetItemAsync(
+ () -> new WidgetItem(shortcutInfo, mApp.getIconCache(), getPackageManager()));
}
private boolean setupWidget() {
@@ -207,18 +209,32 @@
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
mAppWidgetHost = new LauncherAppWidgetHost(this);
- mPendingWidgetInfo = new PendingAddWidgetInfo(widgetInfo);
- mPendingWidgetInfo.spanX = Math.min(mIdp.numColumns, widgetInfo.spanX);
- mPendingWidgetInfo.spanY = Math.min(mIdp.numRows, widgetInfo.spanY);
- mWidgetOptions = WidgetHostViewLoader.getDefaultOptionsForWidget(this, mPendingWidgetInfo);
+ PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(widgetInfo);
+ pendingInfo.spanX = Math.min(mIdp.numColumns, widgetInfo.spanX);
+ pendingInfo.spanY = Math.min(mIdp.numRows, widgetInfo.spanY);
+ mWidgetOptions = WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
+ mWidgetCell.getWidgetView().setTag(pendingInfo);
- WidgetItem item = new WidgetItem(widgetInfo, getPackageManager(), mIdp);
- mWidgetCell.getWidgetView().setTag(mPendingWidgetInfo);
- mWidgetCell.applyFromCellItem(item, mApp.getWidgetCache());
- mWidgetCell.ensurePreview();
+ applyWidgetItemAsync(() -> new WidgetItem(widgetInfo, mIdp, mApp.getIconCache()));
return true;
}
+ private void applyWidgetItemAsync(final Provider<WidgetItem> itemProvider) {
+ new AsyncTask<Void, Void, WidgetItem>() {
+ @Override
+ protected WidgetItem doInBackground(Void... voids) {
+ return itemProvider.get();
+ }
+
+ @Override
+ protected void onPostExecute(WidgetItem item) {
+ mWidgetCell.applyFromCellItem(item, mApp.getWidgetCache());
+ mWidgetCell.ensurePreview();
+ }
+ }.executeOnExecutor(new LooperExecutor(LauncherModel.getWorkerLooper()));
+ // TODO: Create a worker looper executor and reuse that everywhere.
+ }
+
/**
* Called when the cancel button is clicked.
*/
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index bd919bc..64655cc 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -65,7 +66,7 @@
}
@Override
- public CharSequence getLabel() {
+ public CharSequence getLabel(PackageManager pm) {
return mInfo.getShortLabel();
}
diff --git a/src/com/android/launcher3/icons/BaseIconCache.java b/src/com/android/launcher3/icons/BaseIconCache.java
index f7e2be1..6433103 100644
--- a/src/com/android/launcher3/icons/BaseIconCache.java
+++ b/src/com/android/launcher3/icons/BaseIconCache.java
@@ -226,12 +226,12 @@
entry = new CacheEntry();
cachingLogic.loadIcon(mContext, this, object, entry);
}
- entry.title = cachingLogic.getLabel(object);
+ entry.title = cachingLogic.getLabel(object, mPackageManager);
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
mCache.put(key, entry);
- ContentValues values = newContentValues(entry.icon, entry.color,
- entry.title.toString(), componentName.getPackageName());
+ ContentValues values = newContentValues(entry, entry.title.toString(),
+ componentName.getPackageName());
addIconToDB(values, componentName, info, userSerial);
}
@@ -280,16 +280,25 @@
* This method is not thread safe, it must be called from a synchronized method.
*/
protected <T> CacheEntry cacheLocked(
- @NonNull ComponentName componentName,
- @NonNull Provider<T> infoProvider,
- @NonNull CachingLogic<T> cachingLogic,
- UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
+ @NonNull ComponentName componentName, @NonNull UserHandle user,
+ @NonNull Provider<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
+ boolean usePackageIcon, boolean useLowResIcon) {
+ return cacheLocked(componentName, user, infoProvider, cachingLogic, usePackageIcon,
+ useLowResIcon, true);
+ }
+
+ protected <T> CacheEntry cacheLocked(
+ @NonNull ComponentName componentName, @NonNull UserHandle user,
+ @NonNull Provider<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
+ boolean usePackageIcon, boolean useLowResIcon, boolean addToMemCache) {
Preconditions.assertWorkerThread();
ComponentKey cacheKey = new ComponentKey(componentName, user);
CacheEntry entry = mCache.get(cacheKey);
if (entry == null || (entry.isLowRes() && !useLowResIcon)) {
entry = new CacheEntry();
- mCache.put(cacheKey, entry);
+ if (addToMemCache) {
+ mCache.put(cacheKey, entry);
+ }
// Check the DB first.
T object = null;
@@ -327,7 +336,7 @@
providerFetchedOnce = true;
}
if (object != null) {
- entry.title = cachingLogic.getLabel(object);
+ entry.title = cachingLogic.getLabel(object, mPackageManager);
entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
}
}
@@ -413,8 +422,8 @@
// Add the icon in the DB here, since these do not get written during
// package updates.
- ContentValues values = newContentValues(iconInfo.icon, entry.color,
- entry.title.toString(), packageName);
+ ContentValues values = newContentValues(
+ iconInfo, entry.title.toString(), packageName);
addIconToDB(values, cacheKey.componentName, info,
mUserManager.getSerialNumberForUser(user));
@@ -515,11 +524,11 @@
}
}
- private ContentValues newContentValues(Bitmap icon, int iconColor, String label,
- String packageName) {
+ private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, String packageName) {
ContentValues values = new ContentValues();
- values.put(IconDB.COLUMN_ICON, Utilities.flattenBitmap(icon));
- values.put(IconDB.COLUMN_ICON_COLOR, iconColor);
+ values.put(IconDB.COLUMN_ICON,
+ bitmapInfo.isLowRes() ? null : Utilities.flattenBitmap(bitmapInfo.icon));
+ values.put(IconDB.COLUMN_ICON_COLOR, bitmapInfo.color);
values.put(IconDB.COLUMN_LABEL, label);
values.put(IconDB.COLUMN_SYSTEM_STATE, mIconProvider.getIconSystemState(packageName));
diff --git a/src/com/android/launcher3/icons/CachingLogic.java b/src/com/android/launcher3/icons/CachingLogic.java
index 13fdc6a..24186ef 100644
--- a/src/com/android/launcher3/icons/CachingLogic.java
+++ b/src/com/android/launcher3/icons/CachingLogic.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageManager;
import android.os.UserHandle;
public interface CachingLogic<T> {
@@ -26,7 +27,7 @@
UserHandle getUser(T object);
- CharSequence getLabel(T object);
+ CharSequence getLabel(T object, PackageManager pm);
void loadIcon(Context context, BaseIconCache cache, T object, BitmapInfo target);
@@ -44,7 +45,7 @@
}
@Override
- public CharSequence getLabel(LauncherActivityInfo object) {
+ public CharSequence getLabel(LauncherActivityInfo object, PackageManager pm) {
return object.getLabel();
}
@@ -57,4 +58,30 @@
li.recycle();
}
};
+
+ CachingLogic<ComponentWithLabel> COMPONENT_WITH_LABEL =
+ new CachingLogic<ComponentWithLabel>() {
+
+ @Override
+ public ComponentName getComponent(ComponentWithLabel object) {
+ return object.getComponent();
+ }
+
+ @Override
+ public UserHandle getUser(ComponentWithLabel object) {
+ return object.getUser();
+ }
+
+ @Override
+ public CharSequence getLabel(ComponentWithLabel object, PackageManager pm) {
+ return object.getLabel(pm);
+ }
+
+ @Override
+ public void loadIcon(Context context, BaseIconCache cache,
+ ComponentWithLabel object, BitmapInfo target) {
+ // Do not load icon.
+ target.icon = BitmapInfo.LOW_RES_ICON;
+ }
+ };
}
diff --git a/src/com/android/launcher3/icons/ComponentWithLabel.java b/src/com/android/launcher3/icons/ComponentWithLabel.java
new file mode 100644
index 0000000..2badb4c
--- /dev/null
+++ b/src/com/android/launcher3/icons/ComponentWithLabel.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons;
+
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+public interface ComponentWithLabel {
+
+ ComponentName getComponent();
+
+ UserHandle getUser();
+
+ CharSequence getLabel(PackageManager pm);
+}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index eae6f01..4349455 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -16,6 +16,7 @@
package com.android.launcher3.icons;
+import static com.android.launcher3.icons.CachingLogic.COMPONENT_WITH_LABEL;
import static com.android.launcher3.icons.CachingLogic.LAUNCHER_ACTIVITY_INFO;
import android.content.Context;
@@ -114,8 +115,8 @@
*/
public synchronized void updateTitleAndIcon(AppInfo application) {
CacheEntry entry = cacheLocked(application.componentName,
- Provider.of(null), LAUNCHER_ACTIVITY_INFO,
- application.user, false, application.usingLowResIcon());
+ application.user, Provider.of(null), LAUNCHER_ACTIVITY_INFO,
+ false, application.usingLowResIcon());
if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
applyCacheEntry(entry, application);
}
@@ -148,6 +149,13 @@
}
}
+ public synchronized String getTitleNoCache(ComponentWithLabel info) {
+ CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), Provider.of(info),
+ COMPONENT_WITH_LABEL, false /* usePackageIcon */, true /* useLowResIcon */,
+ false /* addToMemCache */);
+ return Utilities.trim(entry.title);
+ }
+
/**
* Fill in {@param shortcutInfo} with the icon and label for {@param info}
*/
@@ -155,8 +163,9 @@
@NonNull ItemInfoWithIcon infoInOut,
@NonNull Provider<LauncherActivityInfo> activityInfoProvider,
boolean usePkgIcon, boolean useLowResIcon) {
- CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), activityInfoProvider,
- LAUNCHER_ACTIVITY_INFO, infoInOut.user, usePkgIcon, useLowResIcon);
+ CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
+ activityInfoProvider,
+ LAUNCHER_ACTIVITY_INFO, usePkgIcon, useLowResIcon);
applyCacheEntry(entry, infoInOut);
}
diff --git a/src/com/android/launcher3/icons/IconCacheUpdateHandler.java b/src/com/android/launcher3/icons/IconCacheUpdateHandler.java
index 64e3fbf..8b3af01 100644
--- a/src/com/android/launcher3/icons/IconCacheUpdateHandler.java
+++ b/src/com/android/launcher3/icons/IconCacheUpdateHandler.java
@@ -25,15 +25,17 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseBooleanArray;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BaseIconCache.IconDB;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
@@ -44,12 +46,28 @@
private static final String TAG = "IconCacheUpdateHandler";
+ /**
+ * In this mode, all invalid icons are marked as to-be-deleted in {@link #mItemsToDelete}.
+ * This mode is used for the first run.
+ */
+ private static final boolean MODE_SET_INVALID_ITEMS = true;
+
+ /**
+ * In this mode, any valid icon is removed from {@link #mItemsToDelete}. This is used for all
+ * subsequent runs, which essentially acts as set-union of all valid items.
+ */
+ private static final boolean MODE_CLEAR_VALID_ITEMS = false;
+
private static final Object ICON_UPDATE_TOKEN = new Object();
private final HashMap<String, PackageInfo> mPkgInfoMap;
private final BaseIconCache mIconCache;
+
private final HashMap<UserHandle, Set<String>> mPackagesToIgnore = new HashMap<>();
+ private final SparseBooleanArray mItemsToDelete = new SparseBooleanArray();
+ private boolean mFilterMode = MODE_SET_INVALID_ITEMS;
+
IconCacheUpdateHandler(BaseIconCache cache) {
mIconCache = cache;
@@ -77,24 +95,43 @@
* the DB and are updated.
* @return The set of packages for which icons have updated.
*/
- public <T> void updateIcons(List<T> apps, CachingLogic<T> cachingLogic) {
- if (apps.isEmpty()) {
- return;
+ public <T> void updateIcons(List<T> apps, CachingLogic<T> cachingLogic,
+ OnUpdateCallback onUpdateCallback) {
+ // Filter the list per user
+ HashMap<UserHandle, HashMap<ComponentName, T>> userComponentMap = new HashMap<>();
+ int count = apps.size();
+ for (int i = 0; i < count; i++) {
+ T app = apps.get(i);
+ UserHandle userHandle = cachingLogic.getUser(app);
+ HashMap<ComponentName, T> componentMap = userComponentMap.get(userHandle);
+ if (componentMap == null) {
+ componentMap = new HashMap<>();
+ userComponentMap.put(userHandle, componentMap);
+ }
+ componentMap.put(cachingLogic.getComponent(app), app);
}
- UserHandle user = cachingLogic.getUser(apps.get(0));
+ for (Entry<UserHandle, HashMap<ComponentName, T>> entry : userComponentMap.entrySet()) {
+ updateIconsPerUser(entry.getKey(), entry.getValue(), cachingLogic, onUpdateCallback);
+ }
+
+ // From now on, clear every valid item from the global valid map.
+ mFilterMode = MODE_CLEAR_VALID_ITEMS;
+ }
+
+ /**
+ * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
+ * the DB and are updated.
+ * @return The set of packages for which icons have updated.
+ */
+ private <T> void updateIconsPerUser(UserHandle user, HashMap<ComponentName, T> componentMap,
+ CachingLogic<T> cachingLogic, OnUpdateCallback onUpdateCallback) {
Set<String> ignorePackages = mPackagesToIgnore.get(user);
if (ignorePackages == null) {
ignorePackages = Collections.emptySet();
}
-
long userSerial = mIconCache.mUserManager.getSerialNumberForUser(user);
- HashMap<ComponentName, T> componentMap = new HashMap<>();
- for (T app : apps) {
- componentMap.put(cachingLogic.getComponent(app), app);
- }
- HashSet<Integer> itemsToRemove = new HashSet<>();
Stack<T> appsToUpdate = new Stack<>();
try (Cursor c = mIconCache.mIconDb.query(
@@ -114,10 +151,15 @@
String cn = c.getString(indexComponent);
ComponentName component = ComponentName.unflattenFromString(cn);
PackageInfo info = mPkgInfoMap.get(component.getPackageName());
+
+ int rowId = c.getInt(rowIndex);
if (info == null) {
if (!ignorePackages.contains(component.getPackageName())) {
- mIconCache.remove(component, user);
- itemsToRemove.add(c.getInt(rowIndex));
+
+ if (mFilterMode == MODE_SET_INVALID_ITEMS) {
+ mIconCache.remove(component, user);
+ mItemsToDelete.put(rowId, true);
+ }
}
continue;
}
@@ -132,11 +174,17 @@
if (version == info.versionCode && updateTime == info.lastUpdateTime &&
TextUtils.equals(c.getString(systemStateIndex),
mIconCache.mIconProvider.getIconSystemState(info.packageName))) {
+
+ if (mFilterMode == MODE_CLEAR_VALID_ITEMS) {
+ mItemsToDelete.put(rowId, false);
+ }
continue;
}
if (app == null) {
- mIconCache.remove(component, user);
- itemsToRemove.add(c.getInt(rowIndex));
+ if (mFilterMode == MODE_SET_INVALID_ITEMS) {
+ mIconCache.remove(component, user);
+ mItemsToDelete.put(rowId, true);
+ }
} else {
appsToUpdate.add(app);
}
@@ -145,17 +193,28 @@
Log.d(TAG, "Error reading icon cache", e);
// Continue updating whatever we have read so far
}
- if (!itemsToRemove.isEmpty()) {
- mIconCache.mIconDb.delete(
- Utilities.createDbSelectionQuery(IconDB.COLUMN_ROWID, itemsToRemove), null);
- }
// Insert remaining apps.
if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
Stack<T> appsToAdd = new Stack<>();
appsToAdd.addAll(componentMap.values());
- new SerializedIconUpdateTask(userSerial, user, appsToAdd, appsToUpdate, cachingLogic)
- .scheduleNext();
+ new SerializedIconUpdateTask(userSerial, user, appsToAdd, appsToUpdate, cachingLogic,
+ onUpdateCallback).scheduleNext();
+ }
+ }
+
+ public void finish() {
+ // Commit all deletes
+ ArrayList<Integer> deleteIds = new ArrayList<>();
+ int count = mItemsToDelete.size();
+ for (int i = 0; i < count; i++) {
+ if (mItemsToDelete.valueAt(i)) {
+ deleteIds.add(mItemsToDelete.keyAt(i));
+ }
+ }
+ if (!deleteIds.isEmpty()) {
+ mIconCache.mIconDb.delete(
+ Utilities.createDbSelectionQuery(IconDB.COLUMN_ROWID, deleteIds), null);
}
}
@@ -172,14 +231,17 @@
private final Stack<T> mAppsToUpdate;
private final CachingLogic<T> mCachingLogic;
private final HashSet<String> mUpdatedPackages = new HashSet<>();
+ private final OnUpdateCallback mOnUpdateCallback;
SerializedIconUpdateTask(long userSerial, UserHandle userHandle,
- Stack<T> appsToAdd, Stack<T> appsToUpdate, CachingLogic<T> cachingLogic) {
+ Stack<T> appsToAdd, Stack<T> appsToUpdate, CachingLogic<T> cachingLogic,
+ OnUpdateCallback onUpdateCallback) {
mUserHandle = userHandle;
mUserSerial = userSerial;
mAppsToAdd = appsToAdd;
mAppsToUpdate = appsToUpdate;
mCachingLogic = cachingLogic;
+ mOnUpdateCallback = onUpdateCallback;
}
@Override
@@ -193,9 +255,8 @@
mUpdatedPackages.add(pkg);
if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
- // No more app to update. Notify model.
- LauncherAppState.getInstance(mIconCache.mContext).getModel()
- .onPackageIconsUpdated(mUpdatedPackages, mUserHandle);
+ // No more app to update. Notify callback.
+ mOnUpdateCallback.onPackageIconsUpdated(mUpdatedPackages, mUserHandle);
}
// Let it run one more time.
@@ -221,4 +282,9 @@
SystemClock.uptimeMillis() + 1);
}
}
+
+ public interface OnUpdateCallback {
+
+ void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandle user);
+ }
}
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index b4cbf65..244654b 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -30,6 +30,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -311,59 +312,49 @@
* @param scale the scale to apply before drawing {@param icon} on the canvas
*/
private Bitmap createIconBitmap(Drawable icon, float scale) {
- int width = mIconBitmapSize;
- int height = mIconBitmapSize;
-
- if (icon instanceof PaintDrawable) {
- PaintDrawable painter = (PaintDrawable) icon;
- painter.setIntrinsicWidth(width);
- painter.setIntrinsicHeight(height);
- } else if (icon instanceof BitmapDrawable) {
- // Ensure the bitmap has a density.
- BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
- Bitmap bitmap = bitmapDrawable.getBitmap();
- if (bitmap != null && bitmap.getDensity() == Bitmap.DENSITY_NONE) {
- bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics());
- }
- }
-
- int sourceWidth = icon.getIntrinsicWidth();
- int sourceHeight = icon.getIntrinsicHeight();
- if (sourceWidth > 0 && sourceHeight > 0) {
- // Scale the icon proportionally to the icon dimensions
- final float ratio = (float) sourceWidth / sourceHeight;
- if (sourceWidth > sourceHeight) {
- height = (int) (width / ratio);
- } else if (sourceHeight > sourceWidth) {
- width = (int) (height * ratio);
- }
- }
- // no intrinsic size --> use default size
- int textureWidth = mIconBitmapSize;
- int textureHeight = mIconBitmapSize;
-
- Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
+ Bitmap bitmap = Bitmap.createBitmap(mIconBitmapSize, mIconBitmapSize,
Bitmap.Config.ARGB_8888);
mCanvas.setBitmap(bitmap);
-
- final int left = (textureWidth-width) / 2;
- final int top = (textureHeight-height) / 2;
-
mOldBounds.set(icon.getBounds());
+
if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
- int offset = Math.max((int) Math.ceil(BLUR_FACTOR * textureWidth), Math.max(left, top));
- int size = Math.max(width, height);
- icon.setBounds(offset, offset, size - offset, size - offset);
+ int offset = Math.max((int) Math.ceil(BLUR_FACTOR * mIconBitmapSize),
+ Math.round(mIconBitmapSize * (1 - scale) / 2 ));
+ icon.setBounds(offset, offset, mIconBitmapSize - offset, mIconBitmapSize - offset);
+ icon.draw(mCanvas);
} else {
- icon.setBounds(left, top, left+width, top+height);
+ if (icon instanceof BitmapDrawable) {
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap b = bitmapDrawable.getBitmap();
+ if (bitmap != null && b.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics());
+ }
+ }
+ int width = mIconBitmapSize;
+ int height = mIconBitmapSize;
+
+ int intrinsicWidth = icon.getIntrinsicWidth();
+ int intrinsicHeight = icon.getIntrinsicHeight();
+ if (intrinsicWidth > 0 && intrinsicHeight > 0) {
+ // Scale the icon proportionally to the icon dimensions
+ final float ratio = (float) intrinsicWidth / intrinsicHeight;
+ if (intrinsicWidth > intrinsicHeight) {
+ height = (int) (width / ratio);
+ } else if (intrinsicHeight > intrinsicWidth) {
+ width = (int) (height * ratio);
+ }
+ }
+ final int left = (mIconBitmapSize - width) / 2;
+ final int top = (mIconBitmapSize - height) / 2;
+ icon.setBounds(left, top, left + width, top + height);
+ mCanvas.save();
+ mCanvas.scale(scale, scale, mIconBitmapSize / 2, mIconBitmapSize / 2);
+ icon.draw(mCanvas);
+ mCanvas.restore();
+
}
- mCanvas.save();
- mCanvas.scale(scale, scale, textureWidth / 2, textureHeight / 2);
- icon.draw(mCanvas);
- mCanvas.restore();
icon.setBounds(mOldBounds);
mCanvas.setBitmap(null);
-
return bitmap;
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index d6b7b0f..e0da6b1 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+import static com.android.launcher3.icons.CachingLogic.COMPONENT_WITH_LABEL;
import static com.android.launcher3.icons.CachingLogic.LAUNCHER_ACTIVITY_INFO;
import static com.android.launcher3.model.LoaderResults.filterCurrentWorkspaceItems;
@@ -44,6 +45,7 @@
import com.android.launcher3.AllAppsList;
import com.android.launcher3.AppInfo;
import com.android.launcher3.FolderInfo;
+import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCacheUpdateHandler;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InstallShortcutReceiver;
@@ -184,7 +186,7 @@
// second step
TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
- List<List<LauncherActivityInfo>> activityListPerUser = loadAllApps();
+ List<LauncherActivityInfo> allActivityList = loadAllApps();
TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
verifyNotStopped();
@@ -194,7 +196,8 @@
TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache");
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
setIgnorePackages(updateHandler);
- updateIconCacheForApps(updateHandler, activityListPerUser);
+ updateHandler.updateIcons(allActivityList, LAUNCHER_ACTIVITY_INFO,
+ mApp.getModel()::onPackageIconsUpdated);
// Take a break
TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle");
@@ -216,12 +219,21 @@
// fourth step
TraceHelper.partitionSection(TAG, "step 4.1: loading widgets");
- mBgDataModel.widgetsModel.update(mApp, null);
+ List<ComponentWithLabel> allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null);
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets");
mResults.bindWidgets();
+ verifyNotStopped();
+ TraceHelper.partitionSection(TAG, "step 4.3: Update icon cache");
+ updateHandler.updateIcons(allWidgetsList, COMPONENT_WITH_LABEL,
+ mApp.getModel()::onWidgetLabelsUpdated);
+
+ verifyNotStopped();
+ TraceHelper.partitionSection(TAG, "step 5: Finish icon cache update");
+ updateHandler.finish();
+
transaction.commit();
} catch (CancellationException e) {
// Loader stopped, ignore
@@ -799,17 +811,9 @@
updateHandler.setPackagesToIgnore(Process.myUserHandle(), packagesToIgnore);
}
- private void updateIconCacheForApps(IconCacheUpdateHandler updateHandler,
- List<List<LauncherActivityInfo>> activityListPerUser) {
- int userCount = activityListPerUser.size();
- for (int i = 0; i < userCount; i++) {
- updateHandler.updateIcons(activityListPerUser.get(i), LAUNCHER_ACTIVITY_INFO);
- }
- }
-
- private List<List<LauncherActivityInfo>> loadAllApps() {
+ private List<LauncherActivityInfo> loadAllApps() {
final List<UserHandle> profiles = mUserManager.getUserProfiles();
- List<List<LauncherActivityInfo>> activityListPerUser = new ArrayList<>();
+ List<LauncherActivityInfo> allActivityList = new ArrayList<>();
// Clear the list of apps
mBgAllAppsList.clear();
for (UserHandle user : profiles) {
@@ -818,7 +822,7 @@
// Fail if we don't have any apps
// TODO: Fix this. Only fail for the current user.
if (apps == null || apps.isEmpty()) {
- return activityListPerUser;
+ return allActivityList;
}
boolean quietMode = mUserManager.isQuietModeEnabled(user);
// Create the ApplicationInfos
@@ -827,7 +831,7 @@
// This builds the icon bitmaps.
mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}
- activityListPerUser.add(apps);
+ allActivityList.addAll(apps);
}
if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
@@ -840,7 +844,7 @@
}
mBgAllAppsList.added = new ArrayList<>();
- return activityListPerUser;
+ return allActivityList;
}
private void loadDeepShortcuts() {
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index 1e96dec..e38529b 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -9,6 +9,7 @@
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.util.ComponentKey;
import java.text.Collator;
@@ -29,11 +30,11 @@
public final String label;
public final int spanX, spanY;
- public WidgetItem(LauncherAppWidgetProviderInfo info, PackageManager pm,
- InvariantDeviceProfile idp) {
+ public WidgetItem(LauncherAppWidgetProviderInfo info,
+ InvariantDeviceProfile idp, IconCache iconCache) {
super(info.provider, info.getProfile());
- label = Utilities.trim(info.getLabel(pm));
+ label = iconCache.getTitleNoCache(info);
widgetInfo = info;
activityInfo = null;
@@ -41,9 +42,10 @@
spanY = Math.min(info.spanY, idp.numRows);
}
- public WidgetItem(ShortcutConfigActivityInfo info) {
+ public WidgetItem(ShortcutConfigActivityInfo info, IconCache iconCache, PackageManager pm) {
super(info.getComponent(), info.getUser());
- label = Utilities.trim(info.getLabel());
+ label = info.isPersistable() ? iconCache.getTitleNoCache(info) :
+ Utilities.trim(info.getLabel(pm));
widgetInfo = null;
activityInfo = info;
spanX = spanY = 1;
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 82f4fe1..9a17ec6 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -11,6 +11,7 @@
import android.util.Log;
import com.android.launcher3.AppFilter;
+import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
@@ -31,7 +32,10 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import androidx.annotation.Nullable;
@@ -76,26 +80,32 @@
* @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
* only widgets and shortcuts associated with the package/user are.
*/
- public void update(LauncherAppState app, @Nullable PackageUserKey packageUser) {
+ public List<ComponentWithLabel> update(LauncherAppState app, @Nullable PackageUserKey packageUser) {
Preconditions.assertWorkerThread();
Context context = app.getContext();
final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
+ List<ComponentWithLabel> updatedItems = new ArrayList<>();
try {
- PackageManager pm = context.getPackageManager();
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
+ PackageManager pm = app.getContext().getPackageManager();
// Widgets
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context);
for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
- widgetsAndShortcuts.add(new WidgetItem(LauncherAppWidgetProviderInfo
- .fromProviderInfo(context, widgetInfo), pm, idp));
+ LauncherAppWidgetProviderInfo launcherWidgetInfo =
+ LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
+
+ widgetsAndShortcuts.add(new WidgetItem(
+ launcherWidgetInfo, idp, app.getIconCache()));
+ updatedItems.add(launcherWidgetInfo);
}
// Shortcuts
for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context)
.getCustomShortcutActivityList(packageUser)) {
- widgetsAndShortcuts.add(new WidgetItem(info));
+ widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm));
+ updatedItems.add(info);
}
setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
} catch (Exception e) {
@@ -110,6 +120,7 @@
}
app.getWidgetCache().removeObsoletePreviews(widgetsAndShortcuts, packageUser);
+ return updatedItems;
}
private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
@@ -204,4 +215,26 @@
iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
}
}
+
+ public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
+ LauncherAppState app) {
+ for (Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
+ if (packageNames.contains(entry.getKey().packageName)) {
+ ArrayList<WidgetItem> items = entry.getValue();
+ int count = items.size();
+ for (int i = 0; i < count; i++) {
+ WidgetItem item = items.get(i);
+ if (item.user.equals(user)) {
+ if (item.activityInfo != null) {
+ items.set(i, new WidgetItem(item.activityInfo, app.getIconCache(),
+ app.getContext().getPackageManager()));
+ } else {
+ items.set(i, new WidgetItem(item.widgetInfo,
+ app.getInvariantDeviceProfile(), app.getIconCache()));
+ }
+ }
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/touch/TouchEventTranslator.java b/src/com/android/launcher3/touch/TouchEventTranslator.java
index 55a88ee..bf0c84c 100644
--- a/src/com/android/launcher3/touch/TouchEventTranslator.java
+++ b/src/com/android/launcher3/touch/TouchEventTranslator.java
@@ -19,7 +19,6 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.util.SparseLongArray;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
@@ -37,13 +36,15 @@
private class DownState {
long timeStamp;
+ float downX;
float downY;
- public DownState(long timeStamp, float downY) {
+ public DownState(long timeStamp, float downX, float downY) {
this.timeStamp = timeStamp;
+ this.downX = downX;
this.downY = downY;
}
};
- private final DownState ZERO = new DownState(0, 0f);
+ private final DownState ZERO = new DownState(0, 0f, 0f);
private final Consumer<MotionEvent> mListener;
@@ -65,12 +66,16 @@
mFingers.clear();
}
+ public float getDownX() {
+ return mDownEvents.get(0).downX;
+ }
+
public float getDownY() {
return mDownEvents.get(0).downY;
}
public void setDownParameters(int idx, MotionEvent e) {
- DownState ev = new DownState(e.getEventTime(), e.getY(idx));
+ DownState ev = new DownState(e.getEventTime(), e.getX(idx), e.getY(idx));
mDownEvents.append(idx, ev);
}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 1faca15..5b8df13 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -16,6 +16,10 @@
package com.android.launcher3.views;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
import android.content.Context;
@@ -79,6 +83,9 @@
protected TouchController mActiveController;
private TouchCompleteListener mTouchCompleteListener;
+ // Object controlling the current touch interaction
+ private Object mCurrentTouchOwner;
+
public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
super(context, attrs);
mActivity = (T) ActivityContext.lookupContext(context);
@@ -94,7 +101,7 @@
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
@@ -177,7 +184,7 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
@@ -192,6 +199,37 @@
}
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ return verifyTouchDispatch(this, ev) && super.dispatchTouchEvent(ev);
+ }
+
+ /**
+ * Returns true if the {@param caller} is allowed to dispatch {@param ev} on this view,
+ * false otherwise.
+ */
+ public boolean verifyTouchDispatch(Object caller, MotionEvent ev) {
+ int action = ev.getAction();
+ if (action == ACTION_DOWN) {
+ if (mCurrentTouchOwner != null) {
+ // Another touch in progress.
+ ev.setAction(ACTION_CANCEL);
+ super.dispatchTouchEvent(ev);
+ ev.setAction(action);
+ }
+ mCurrentTouchOwner = caller;
+ return true;
+ }
+ if (mCurrentTouchOwner != caller) {
+ // Someone else is controlling the touch
+ return false;
+ }
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mCurrentTouchOwner = null;
+ }
+ return true;
+ }
+
/**
* Determine the rect of the descendant in this DragLayer's coordinates
*
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index 1e56439..8503547 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -205,9 +205,9 @@
@Override
protected <T> CacheEntry cacheLocked(
@NonNull ComponentName componentName,
- @NonNull Provider<T> infoProvider,
+ UserHandle user, @NonNull Provider<T> infoProvider,
@NonNull CachingLogic<T> cachingLogic,
- UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
+ boolean usePackageIcon, boolean useLowResIcon) {
CacheEntry entry = mCache.get(new ComponentKey(componentName, user));
if (entry == null) {
entry = new CacheEntry();
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 9cbab5e..fc8e1c5 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -32,6 +32,7 @@
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.Surface;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
@@ -59,7 +60,13 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -83,22 +90,66 @@
protected final LauncherInstrumentation mLauncher;
protected Context mTargetContext;
protected String mTargetPackage;
- protected final boolean mIsInLauncherProcess;
private static final String TAG = "AbstractLauncherUiTest";
protected AbstractLauncherUiTest() {
- final Instrumentation instrumentation = getInstrumentation();
+ final Instrumentation instrumentation =TestHelpers.getInstrumentation();
mDevice = UiDevice.getInstance(instrumentation);
+ try {
+ mDevice.setOrientationNatural();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
mLauncher = new LauncherInstrumentation(instrumentation);
-
- mIsInLauncherProcess = instrumentation.getTargetContext().getPackageName().equals(
- mDevice.getLauncherPackageName());
}
@Rule
public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ // Annotation for tests that need to be run in portrait and landscape modes.
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ protected @interface PortraitLandscape {
+ }
+
+ @Rule
+ public TestRule mPortraitLandscapeExecutor =
+ (base, description) -> false && description.getAnnotation(PortraitLandscape.class)
+ != null ? new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ // Create launcher activity if necessary and bring it to the front.
+ mDevice.pressHome();
+ waitForLauncherCondition(launcher -> launcher != null);
+
+ executeOnLauncher(launcher ->
+ launcher.getRotationHelper().forceAllowRotationForTesting(true));
+
+ evaluateInPortrait();
+ evaluateInLandscape();
+ } finally {
+ mDevice.setOrientationNatural();
+ executeOnLauncher(launcher ->
+ launcher.getRotationHelper().forceAllowRotationForTesting(false));
+ mLauncher.setExpectedRotation(Surface.ROTATION_0);
+ }
+ }
+
+ private void evaluateInPortrait() throws Throwable {
+ mDevice.setOrientationNatural();
+ mLauncher.setExpectedRotation(Surface.ROTATION_0);
+ base.evaluate();
+ }
+
+ private void evaluateInLandscape() throws Throwable {
+ mDevice.setOrientationLeft();
+ mLauncher.setExpectedRotation(Surface.ROTATION_90);
+ base.evaluate();
+ }
+ } : base;
+
@Before
public void setUp() throws Exception {
mTargetContext = InstrumentationRegistry.getTargetContext();
@@ -119,10 +170,6 @@
}
}
- protected Instrumentation getInstrumentation() {
- return InstrumentationRegistry.getInstrumentation();
- }
-
/**
* Opens all apps and returns the recycler view
*/
@@ -231,7 +278,7 @@
protected void sendPointer(int action, Point point) {
MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), action, point.x, point.y, 0);
- getInstrumentation().sendPointerSync(event);
+ TestHelpers.getInstrumentation().sendPointerSync(event);
event.recycle();
}
@@ -271,7 +318,7 @@
}
protected <T> T getFromLauncher(Function<Launcher, T> f) {
- if (!mIsInLauncherProcess) return null;
+ if (!TestHelpers.isInLauncherProcess()) return null;
return getOnUiThread(() -> f.apply(mActivityMonitor.getActivity()));
}
@@ -298,7 +345,7 @@
// flakiness.
protected boolean waitForLauncherCondition(
Function<Launcher, Boolean> condition, long timeout) {
- if (!mIsInLauncherProcess) return true;
+ if (!TestHelpers.isInLauncherProcess()) return true;
return Wait.atMost(() -> getFromLauncher(condition), timeout);
}
@@ -311,7 +358,7 @@
getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
@Override
public LauncherAppWidgetProviderInfo call() throws Exception {
- ComponentName cn = new ComponentName(getInstrumentation().getContext(),
+ ComponentName cn = new ComponentName(TestHelpers.getInstrumentation().getContext(),
hasConfigureScreen ? AppWidgetWithConfig.class : AppWidgetNoConfig.class);
Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
return AppWidgetManagerCompat.getInstance(mTargetContext)
diff --git a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
index a50a8b1..a0f4620 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
@@ -13,6 +13,7 @@
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ShellCommandRule;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -27,12 +28,14 @@
@Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
@Test
+ @Ignore
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
@Test
+ @Ignore
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
index f8a7bf7..83a6734 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -17,6 +17,7 @@
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ShellCommandRule;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,12 +32,14 @@
@Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
@Test
+ @Ignore
public void testAppLauncher_portrait() throws Exception {
lockRotation(true);
performTest();
}
@Test
+ @Ignore
public void testAppLauncher_landscape() throws Exception {
lockRotation(false);
performTest();
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
index ff1dcf3..793bd8f 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -17,6 +17,7 @@
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ShellCommandRule;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,12 +32,14 @@
@Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
@Test
+ @Ignore
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
@Test
+ @Ignore
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
diff --git a/tests/src/com/android/launcher3/ui/TestHelpers.java b/tests/src/com/android/launcher3/ui/TestHelpers.java
new file mode 100644
index 0000000..da21a5d
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/TestHelpers.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.launcher3.ui;
+
+import android.app.Instrumentation;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
+public class TestHelpers {
+ private static final boolean IS_IN_LAUNCHER_PROCESS =
+ getInstrumentation().getTargetContext().getPackageName().equals(
+ UiDevice.getInstance(getInstrumentation()).getLauncherPackageName());
+
+ public static Instrumentation getInstrumentation() {
+ return InstrumentationRegistry.getInstrumentation();
+ }
+
+ public static boolean isInLauncherProcess() {
+ return IS_IN_LAUNCHER_PROCESS;
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 183e390..0635e11 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -34,12 +34,14 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.testcomponent.WidgetConfigActivity;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TestHelpers;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -82,6 +84,7 @@
}
@Test
+ @Ignore
public void testConfigCancelled_rotate() throws Throwable {
runTest(true, false);
}
@@ -131,7 +134,7 @@
private void setResult(boolean success) {
- getInstrumentation().getTargetContext().sendBroadcast(
+ TestHelpers.getInstrumentation().getTargetContext().sendBroadcast(
WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
success ? "clickOK" : "clickCancel"));
}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 050f046..d9fef81 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -33,6 +33,7 @@
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,12 +48,14 @@
@Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
@Test
+ @Ignore
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
@Test
+ @Ignore
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
diff --git a/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java b/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
index 307a53e..a31d8a6 100644
--- a/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
+++ b/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
@@ -22,7 +22,6 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -129,11 +128,10 @@
if (num <= 0) return result;
MultiHashMap<PackageItemInfo, WidgetItem> newMap = new MultiHashMap();
- PackageManager pm = mContext.getPackageManager();
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(mContext);
for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(null)) {
WidgetItem wi = new WidgetItem(LauncherAppWidgetProviderInfo
- .fromProviderInfo(mContext, widgetInfo), pm, mTestProfile);
+ .fromProviderInfo(mContext, widgetInfo), mTestProfile, mIconCache);
PackageItemInfo pInfo = new PackageItemInfo(wi.componentName.getPackageName());
pInfo.title = pInfo.packageName;