Merge "Add margin to all apps recycler container view b/29509347 > Last row inside recycler view was obstructed by nav bar making it difficult to interact with before." into ub-launcher3-calgary
diff --git a/build.gradle b/build.gradle
index 899767f..f98021c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,7 +18,7 @@
defaultConfig {
applicationId "com.android.launcher3"
minSdkVersion 21
- targetSdkVersion 23
+ targetSdkVersion 'N'
versionCode 1
versionName "1.0"
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 8ebc303..27ff789 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -36,7 +36,8 @@
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="center" />
+ android:layout_gravity="center"
+ launcher:pageIndicator="@id/page_indicator" />
<!-- DO NOT CHANGE THE ID -->
<include layout="@layout/hotseat"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9f011e5..4e5fcff 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -38,7 +38,7 @@
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
- <string name="long_press_widget_to_add">Tap & hold to pick up a widget.</string>
+ <string name="long_press_widget_to_add">Touch & hold to pick up a widget.</string>
<!-- Accessibility spoken hint message in widget picker, which allows user to add a widget. Custom action is the label for additional accessibility actions available in this mode [CHAR_LIMIT=100] -->
<string name="long_accessible_way_to_add">Double-tap & hold to pick up a widget or use custom actions.</string>
<!-- The format string for the dimensions of a widget in the drawer -->
@@ -135,7 +135,7 @@
<!-- The title text for workspace longpress action [CHAR_LIMIT=40] -->
<string name="workspace_cling_longpress_title">Wallpapers, widgets, & settings</string>
<!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
- <string name="workspace_cling_longpress_description">Tap & hold background to customize</string>
+ <string name="workspace_cling_longpress_description">Touch & hold background to customize</string>
<!-- The description of the button to dismiss the cling [CHAR_LIMIT=30] -->
<string name="workspace_cling_longpress_dismiss">GOT IT</string>
@@ -162,6 +162,8 @@
<string name="settings_button_text">Settings</string>
<!-- Message shown when a feature is disabled by the administrator -->
<string name="msg_disabled_by_admin">Disabled by your admin</string>
+ <!-- Text for custom accessibility action to go to the overview mode, where users can look and change the overall UI of the launcher. -->
+ <string name="accessibility_action_overview">Overview</string>
<!-- Strings for settings -->
<!-- Title for Allow Rotation setting. [CHAR LIMIT=50] -->
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 3287015..1762ca4 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -158,7 +158,7 @@
if (info.isDisabled()) {
iconDrawable.setState(FastBitmapDrawable.State.DISABLED);
}
- setIcon(iconDrawable, mIconSize);
+ setIcon(iconDrawable);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
}
@@ -175,7 +175,7 @@
if (info.isDisabled()) {
iconDrawable.setState(FastBitmapDrawable.State.DISABLED);
}
- setIcon(iconDrawable, mIconSize);
+ setIcon(iconDrawable);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
@@ -188,7 +188,7 @@
}
public void applyFromPackageItemInfo(PackageItemInfo info) {
- setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
+ setIcon(mLauncher.createIconDrawable(info.iconBitmap));
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
@@ -205,7 +205,7 @@
*/
public void applyDummyInfo() {
ColorDrawable d = new ColorDrawable();
- setIcon(mLauncher.resizeIconDrawable(d), mIconSize);
+ setIcon(mLauncher.resizeIconDrawable(d));
setText("");
}
@@ -477,7 +477,7 @@
preloadDrawable = (PreloadIconDrawable) mIcon;
} else {
preloadDrawable = new PreloadIconDrawable(mIcon, getPreloaderTheme());
- setIcon(preloadDrawable, mIconSize);
+ setIcon(preloadDrawable);
}
preloadDrawable.setLevel(progressLevel);
@@ -506,10 +506,10 @@
* Sets the icon for this view based on the layout direction.
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- private Drawable setIcon(Drawable icon, int iconSize) {
+ public void setIcon(Drawable icon) {
mIcon = icon;
- if (iconSize != -1) {
- mIcon.setBounds(0, 0, iconSize, iconSize);
+ if (mIconSize != -1) {
+ mIcon.setBounds(0, 0, mIconSize, mIconSize);
}
if (mLayoutHorizontal) {
if (Utilities.ATLEAST_JB_MR1) {
@@ -520,7 +520,6 @@
} else {
setCompoundDrawables(null, mIcon, null, null);
}
- return icon;
}
@Override
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 286a7f1..f54a2d4 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -32,7 +32,7 @@
/**
* Intent extra to store the profile. Format: UserHandle
*/
- static final String EXTRA_PROFILE = "profile";
+ public static final String EXTRA_PROFILE = "profile";
public static final int NO_ID = -1;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 271c69b..d25eca0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -119,6 +119,7 @@
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.TestingUtils;
import com.android.launcher3.util.Thunk;
@@ -150,7 +151,6 @@
static final boolean DEBUG_WIDGETS = false;
static final boolean DEBUG_STRICT_MODE = false;
static final boolean DEBUG_RESUME_TIME = false;
- static final boolean DEBUG_LOGGING = false;
private static final int REQUEST_CREATE_SHORTCUT = 1;
private static final int REQUEST_CREATE_APPWIDGET = 5;
@@ -235,7 +235,6 @@
@Thunk Workspace mWorkspace;
private View mLauncherView;
- private PageIndicator mPageIndicator;
@Thunk DragLayer mDragLayer;
private DragController mDragController;
@@ -294,6 +293,9 @@
private boolean mHasFocus = false;
private boolean mAttached = false;
+ /** Maps launcher activity components to their list of shortcut ids. */
+ private MultiHashMap<ComponentKey, String> mDeepShortcutMap = new MultiHashMap<>();
+
private LauncherClings mClings;
private View.OnTouchListener mHapticFeedbackTouchListener;
@@ -510,9 +512,7 @@
if (mExtractedColors != null && Utilities.isNycOrAbove()) {
mExtractedColors.load(this);
mHotseat.updateColor(mExtractedColors, !mPaused);
- if (mPageIndicator != null) {
- mPageIndicator.updateColor(mExtractedColors);
- }
+ mWorkspace.getPageIndicator().updateColor(mExtractedColors);
}
}
@@ -626,29 +626,6 @@
}
}
- /**
- * Logger object is a singleton and does not have to be coupled with the foreground activity.
- * Since most user event logging is done on the UI, the object is retrieved from the
- * callback for convenience.
- */
- private UserEventDispatcher createUserEventDispatcher() {
- return new UserEventDispatcher() {
- @Override
- public void dispatchUserEvent(LauncherLogProto.LauncherEvent ev, Intent intent) {
- if (!DEBUG_LOGGING) {
- return;
- }
- Log.d("UserEvent", String.format(Locale.US,
- "action:%s\nchild:%s\nparent:%s\nelapsed container %d ms session %d ms",
- LoggerUtils.getActionStr(ev.action),
- LoggerUtils.getTargetStr(ev.srcTarget[0]),
- LoggerUtils.getTargetStr(ev.srcTarget[1]),
- ev.elapsedContainerMillis,
- ev.elapsedSessionMillis));
- }
- };
- }
-
public UserEventDispatcher getUserEventDispatcher() {
if (mLauncherCallbacks != null) {
UserEventDispatcher dispatcher = mLauncherCallbacks.getUserEventDispatcher();
@@ -657,8 +634,11 @@
}
}
+ // Logger object is a singleton and does not have to be coupled with the foreground
+ // activity. Since most user event logging is done on the UI, the object is retrieved
+ // from the callback for convenience.
if (mUserEventDispatcher == null) {
- mUserEventDispatcher = createUserEventDispatcher();
+ mUserEventDispatcher = new UserEventDispatcher();
}
return mUserEventDispatcher;
}
@@ -1346,9 +1326,8 @@
mLauncherView = findViewById(R.id.launcher);
mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
-
mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
- mPageIndicator = (PageIndicator) mDragLayer.findViewById(R.id.page_indicator);
+ mWorkspace.initParentViews(mDragLayer);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
@@ -1468,7 +1447,7 @@
}
public View getStartViewForAllAppsRevealAnimation() {
- return FeatureFlags.NO_ALL_APPS_ICON ? mPageIndicator : mAllAppsButton;
+ return FeatureFlags.NO_ALL_APPS_ICON ? mWorkspace.getPageIndicator() : mAllAppsButton;
}
public View getWidgetsButton() {
@@ -2354,7 +2333,7 @@
* @param itemInfo the {@link ItemInfo} for this view.
* @param deleteFromDb whether or not to delete this item from the db.
*/
- public boolean removeItem(View v, ItemInfo itemInfo, boolean deleteFromDb) {
+ public boolean removeItem(View v, final ItemInfo itemInfo, boolean deleteFromDb) {
if (itemInfo instanceof ShortcutInfo) {
// Remove the shortcut from the folder before removing it from launcher
View folderIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
@@ -2382,7 +2361,6 @@
if (deleteFromDb) {
deleteWidgetInfo(widgetInfo);
}
-
} else {
return false;
}
@@ -2701,7 +2679,7 @@
* Event handler for the (Add) Widgets button that appears after a long press
* on the home screen.
*/
- protected void onClickAddWidgetButton(View view) {
+ public void onClickAddWidgetButton(View view) {
if (LOGD) Log.d(TAG, "onClickAddWidgetButton");
if (mIsSafeModeEnabled) {
Toast.makeText(this, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
@@ -2714,7 +2692,7 @@
* Event handler for the wallpaper picker button that appears after a long press
* on the home screen.
*/
- protected void onClickWallpaperPicker(View v) {
+ public void onClickWallpaperPicker(View v) {
if (!Utilities.isWallapaperAllowed(this)) {
Toast.makeText(this, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show();
return;
@@ -2737,7 +2715,7 @@
* Event handler for a click on the settings button that appears after a long press
* on the home screen.
*/
- private void onClickSettingsButton(View v) {
+ public void onClickSettingsButton(View v) {
if (LOGD) Log.d(TAG, "onClickSettingsButton");
startActivity(new Intent(Utilities.ACTION_APPLICATION_PREFERENCES)
.setPackage(getPackageName()));
@@ -2819,8 +2797,16 @@
// is enabled by default on NYC.
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
.penaltyLog().build());
- // Could be launching some bookkeeping activity
- startActivity(intent, optsBundle);
+
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ String id = ((ShortcutInfo) info).getDeepShortcutId();
+ String packageName = intent.getPackage();
+ LauncherAppsCompat.getInstance(this).startShortcut(
+ packageName, id, intent.getSourceBounds(), optsBundle, info.user);
+ } else {
+ // Could be launching some bookkeeping activity
+ startActivity(intent, optsBundle);
+ }
} finally {
StrictMode.setVmPolicy(oldPolicy);
}
@@ -2896,8 +2882,9 @@
new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight()));
}
try {
- if (Utilities.ATLEAST_MARSHMALLOW &&
- item != null && item.itemType == Favorites.ITEM_TYPE_SHORTCUT) {
+ if (Utilities.ATLEAST_MARSHMALLOW && item != null
+ && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
+ || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
@@ -3271,7 +3258,7 @@
/**
* Shows the overview button.
*/
- void showOverviewMode(boolean animated) {
+ public void showOverviewMode(boolean animated) {
showOverviewMode(animated, false);
}
@@ -3709,6 +3696,7 @@
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
ShortcutInfo info = (ShortcutInfo) item;
view = createShortcut(info);
break;
@@ -4065,6 +4053,16 @@
}
/**
+ * Copies LauncherModel's map of activities to shortcut ids to Launcher's. This is necessary
+ * because LauncherModel's map is updated in the background, while Launcher runs on the UI.
+ */
+ @Override
+ public void bindDeepShortcutMap(MultiHashMap<ComponentKey, String> deepShortcutMapCopy) {
+ mDeepShortcutMap = deepShortcutMapCopy;
+ if (LOGD) Log.d(TAG, "bindDeepShortcutMap: " + mDeepShortcutMap);
+ }
+
+ /**
* A package was updated.
*
* Implementation of the method from LauncherModel.Callbacks.
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index fe65b31..4bc76fb 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -28,6 +28,8 @@
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutCache;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.TestingUtils;
import com.android.launcher3.util.Thunk;
@@ -42,6 +44,7 @@
@Thunk final LauncherModel mModel;
private final IconCache mIconCache;
private final WidgetPreviewLoader mWidgetCache;
+ private final DeepShortcutManager mDeepShortcutManager;
@Thunk boolean mWallpaperChangedSinceLastCheck;
@@ -95,9 +98,10 @@
mInvariantDeviceProfile = new InvariantDeviceProfile(sContext);
mIconCache = new IconCache(sContext, mInvariantDeviceProfile);
mWidgetCache = new WidgetPreviewLoader(sContext, mIconCache);
+ mDeepShortcutManager = new DeepShortcutManager(sContext, new ShortcutCache());
mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class));
- mModel = new LauncherModel(this, mIconCache, mAppFilter);
+ mModel = new LauncherModel(this, mIconCache, mAppFilter, mDeepShortcutManager);
LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
@@ -168,6 +172,10 @@
return mWidgetCache;
}
+ public DeepShortcutManager getShortcutManager() {
+ return mDeepShortcutManager;
+ }
+
public boolean hasWallpaperChangedSinceLastCheck() {
boolean result = mWallpaperChangedSinceLastCheck;
mWallpaperChangedSinceLastCheck = false;
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index bca2ffb..e987a9b 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -560,7 +560,8 @@
// Don't backup apps in other profiles for now.
String where = "(" + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION + " OR " +
- Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT + ") AND " +
+ Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT + " OR " +
+ Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_DEEP_SHORTCUT + ") AND " +
getUserSelectionArg();
Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
where, null, null);
@@ -798,7 +799,8 @@
return favorite.container == Favorites.CONTAINER_HOTSEAT
&& favorite.intent != null
&& (favorite.itemType == Favorites.ITEM_TYPE_APPLICATION
- || favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT);
+ || favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT
+ || favorite.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT);
}
/** Serialize a Favorite for persistence, including a checksum wrapper. */
@@ -835,7 +837,8 @@
if (!TextUtils.isEmpty(appWidgetProvider)) {
favorite.appWidgetProvider = appWidgetProvider;
}
- } else if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT) {
+ } else if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT
+ || favorite.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
String iconPackage = c.getString(ICON_PACKAGE_INDEX);
String iconResource = c.getString(ICON_RESOURCE_INDEX);
if (!TextUtils.isEmpty(iconPackage) && !TextUtils.isEmpty(iconResource)) {
@@ -897,7 +900,8 @@
values.put(Favorites.SPANY, favorite.spanY);
values.put(Favorites.RANK, favorite.rank);
- if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT) {
+ if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT
+ || favorite.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
values.put(Favorites.ICON_PACKAGE, favorite.iconPackage);
values.put(Favorites.ICON_RESOURCE, favorite.iconResource);
values.put(Favorites.ICON, favorite.icon);
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 68a9c7e..8e404a7 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -42,6 +42,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.LongSparseArray;
+import android.util.MutableInt;
import android.util.Pair;
import com.android.launcher3.compat.AppWidgetManagerCompat;
@@ -60,6 +61,9 @@
import com.android.launcher3.model.GridSizeMigrationTask;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.provider.LauncherDbUtils;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.CursorIconInfo;
import com.android.launcher3.util.FlagOp;
@@ -69,6 +73,7 @@
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.StringFilter;
+import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -83,6 +88,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -119,8 +125,9 @@
// We start off with everything not loaded. After that, we assume that
// our monitoring of the package manager provides all updates and we never
// need to do a requery. These are only ever touched from the loader thread.
- @Thunk boolean mWorkspaceLoaded;
- @Thunk boolean mAllAppsLoaded;
+ private boolean mWorkspaceLoaded;
+ private boolean mAllAppsLoaded;
+ private boolean mDeepShortcutsLoaded;
/**
* Set of runnables to be called on the background thread after the workspace binding
@@ -135,6 +142,9 @@
// Entire list of widgets.
private final WidgetsModel mBgWidgetsModel;
+ // Maps all launcher activities to the id's of their shortcuts (if they have any).
+ private final MultiHashMap<ComponentKey, String> mBgDeepShortcutMap = new MultiHashMap<>();
+
// The lock that must be acquired before referencing any static bg data structures. Unlike
// other locks, this one can generally be held long-term because we never expect any of these
// static data structures to be referenced outside of the worker thread except on the first
@@ -160,16 +170,21 @@
// sBgWorkspaceScreens is the ordered set of workspace screens.
static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
+ // sBgPinnedShortcutCounts is the ComponentKey representing a pinned shortcut to the number of
+ // times it is pinned.
+ static final Map<ShortcutKey, MutableInt> sBgPinnedShortcutCounts = new HashMap<>();
+
// sPendingPackages is a set of packages which could be on sdcard and are not available yet
static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =
new HashMap<UserHandleCompat, HashSet<String>>();
// </ only access in worker thread >
- @Thunk IconCache mIconCache;
+ private IconCache mIconCache;
+ private DeepShortcutManager mDeepShortcutManager;
- @Thunk final LauncherAppsCompat mLauncherApps;
- @Thunk final UserManagerCompat mUserManager;
+ private final LauncherAppsCompat mLauncherApps;
+ private final UserManagerCompat mUserManager;
public interface Callbacks {
public boolean setLoadOnResume();
@@ -199,18 +214,21 @@
public void bindWidgetsModel(WidgetsModel model);
public void onPageBoundSynchronously(int page);
public void executeOnNextDraw(ViewOnDrawExecutor executor);
+ public void bindDeepShortcutMap(MultiHashMap<ComponentKey, String> deepShortcutMap);
}
public interface ItemInfoFilter {
public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);
}
- LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
+ LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter,
+ DeepShortcutManager deepShortcutManager) {
Context context = app.getContext();
mApp = app;
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter);
mIconCache = iconCache;
+ mDeepShortcutManager = deepShortcutManager;
mLauncherApps = LauncherAppsCompat.getInstance(context);
mUserManager = UserManagerCompat.getInstance(context);
@@ -679,6 +697,7 @@
switch (modelItem.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
if (!sBgWorkspaceItems.contains(modelItem)) {
sBgWorkspaceItems.add(modelItem);
@@ -892,6 +911,7 @@
// Fall through
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
sBgWorkspaceItems.add(item);
@@ -903,6 +923,14 @@
Log.e(TAG, msg);
}
}
+ if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ ShortcutInfo shortcutInfo = (ShortcutInfo) item;
+ ShortcutKey shortcutToPin = new ShortcutKey(
+ shortcutInfo.intent.getPackage(),
+ shortcutInfo.user,
+ shortcutInfo.getDeepShortcutId());
+ incrementPinnedShortcutCount(shortcutToPin, true /* shouldPin */);
+ }
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
sBgAppWidgets.add((LauncherAppWidgetInfo) item);
@@ -969,6 +997,14 @@
}
sBgWorkspaceItems.remove(item);
break;
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+ ShortcutInfo shortcutInfo = ((ShortcutInfo) item);
+ ShortcutKey pinnedShortcut = new ShortcutKey(
+ shortcutInfo.intent.getPackage(),
+ shortcutInfo.user,
+ shortcutInfo.getDeepShortcutId());
+ decrementPinnedShortcutCount(pinnedShortcut);
+ // Fall through.
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
sBgWorkspaceItems.remove(item);
@@ -986,6 +1022,39 @@
}
/**
+ * Decrement the count for the given pinned shortcut, unpinning it if the count becomes 0.
+ */
+ private static void decrementPinnedShortcutCount(final ShortcutKey pinnedShortcut) {
+ synchronized (sBgLock) {
+ MutableInt count = sBgPinnedShortcutCounts.get(pinnedShortcut);
+ if (count == null || --count.value == 0) {
+ LauncherAppState.getInstance().getShortcutManager().unpinShortcut(pinnedShortcut);
+ }
+ }
+ }
+
+ /**
+ * Increment the count for the given shortcut, pinning it if the count becomes 1.
+ *
+ * As an optimization, the caller can pass shouldPin == false to avoid
+ * unnecessary RPC's if the shortcut is already pinned.
+ */
+ private static void incrementPinnedShortcutCount(ShortcutKey pinnedShortcut, boolean shouldPin) {
+ synchronized (sBgLock) {
+ MutableInt count = sBgPinnedShortcutCounts.get(pinnedShortcut);
+ if (count == null) {
+ count = new MutableInt(1);
+ sBgPinnedShortcutCounts.put(pinnedShortcut, count);
+ } else {
+ count.value++;
+ }
+ if (shouldPin && count.value == 1) {
+ LauncherAppState.getInstance().getShortcutManager().pinShortcut(pinnedShortcut);
+ }
+ }
+ }
+
+ /**
* Update the order of the workspace screens in the database. The array list contains
* a list of screen ids in the order that they should appear.
*/
@@ -1077,28 +1146,28 @@
@Override
public void onPackageChanged(String packageName, UserHandleCompat user) {
int op = PackageUpdatedTask.OP_UPDATE;
- enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ enqueueItemUpdatedTask(new PackageUpdatedTask(op, new String[] { packageName },
user));
}
@Override
public void onPackageRemoved(String packageName, UserHandleCompat user) {
int op = PackageUpdatedTask.OP_REMOVE;
- enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ enqueueItemUpdatedTask(new PackageUpdatedTask(op, new String[] { packageName },
user));
}
@Override
public void onPackageAdded(String packageName, UserHandleCompat user) {
int op = PackageUpdatedTask.OP_ADD;
- enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ enqueueItemUpdatedTask(new PackageUpdatedTask(op, new String[] { packageName },
user));
}
@Override
public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,
boolean replacing) {
- enqueuePackageUpdated(
+ enqueueItemUpdatedTask(
new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, packageNames, user));
}
@@ -1106,7 +1175,7 @@
public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,
boolean replacing) {
if (!replacing) {
- enqueuePackageUpdated(new PackageUpdatedTask(
+ enqueueItemUpdatedTask(new PackageUpdatedTask(
PackageUpdatedTask.OP_UNAVAILABLE, packageNames,
user));
}
@@ -1114,18 +1183,24 @@
@Override
public void onPackagesSuspended(String[] packageNames, UserHandleCompat user) {
- enqueuePackageUpdated(new PackageUpdatedTask(
+ enqueueItemUpdatedTask(new PackageUpdatedTask(
PackageUpdatedTask.OP_SUSPEND, packageNames,
user));
}
@Override
public void onPackagesUnsuspended(String[] packageNames, UserHandleCompat user) {
- enqueuePackageUpdated(new PackageUpdatedTask(
+ enqueueItemUpdatedTask(new PackageUpdatedTask(
PackageUpdatedTask.OP_UNSUSPEND, packageNames,
user));
}
+ @Override
+ public void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
+ UserHandleCompat user) {
+ enqueueItemUpdatedTask(new ShortcutsChangedTask(packageName, shortcuts, user));
+ }
+
/**
* Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
* ACTION_PACKAGE_CHANGED.
@@ -1146,7 +1221,7 @@
LauncherAppsCompat.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
UserHandleCompat user = UserHandleCompat.fromIntent(intent);
if (user != null) {
- enqueuePackageUpdated(new PackageUpdatedTask(
+ enqueueItemUpdatedTask(new PackageUpdatedTask(
PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE,
new String[0], user));
}
@@ -1171,6 +1246,8 @@
stopLoaderLocked();
if (resetAllAppsLoaded) mAllAppsLoaded = false;
if (resetWorkspaceLoaded) mWorkspaceLoaded = false;
+ // Always reset deep shortcuts loaded.
+ mDeepShortcutsLoaded = false;
}
}
@@ -1257,6 +1334,7 @@
* - workspace icons
* - widgets
* - all apps icons
+ * - deep shortcuts within apps
*/
private class LoaderTask implements Runnable {
private Context mContext;
@@ -1388,6 +1466,12 @@
// second step
if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
loadAndBindAllApps();
+
+ waitForIdle();
+
+ // third step
+ if (DEBUG_LOADERS) Log.d(TAG, "step 3: loading deep shortcuts");
+ loadAndBindDeepShortcuts();
}
// Clear out this reference, otherwise we end up holding it until all of the
@@ -1539,6 +1623,7 @@
sBgFolders.clear();
sBgItemsIdMap.clear();
sBgWorkspaceScreens.clear();
+ sBgPinnedShortcutCounts.clear();
}
}
@@ -1585,6 +1670,7 @@
final ArrayList<Long> itemsToRemove = new ArrayList<>();
final ArrayList<Long> restoredRows = new ArrayList<>();
+ Map<ShortcutKey, ShortcutInfoCompat> shortcutKeyToPinnedShortcuts = new HashMap<>();
final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);
final Cursor c = contentResolver.query(contentUri, null, null, null, null);
@@ -1635,6 +1721,13 @@
long serialNo = mUserManager.getSerialNumberForUser(user);
allUsers.put(serialNo, user);
quietMode.put(serialNo, mUserManager.isQuietModeEnabled(user));
+
+ List<ShortcutInfoCompat> pinnedShortcuts = mDeepShortcutManager
+ .queryForPinnedShortcuts(null, user);
+ for (ShortcutInfoCompat shortcut : pinnedShortcuts) {
+ shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
+ shortcut);
+ }
}
ShortcutInfo info;
@@ -1657,6 +1750,7 @@
switch (itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
id = c.getLong(idIndex);
intentDescription = c.getString(intentIndex);
serialNumber = c.getInt(profileIdIndex);
@@ -1819,7 +1913,37 @@
info = getAppShortcutInfo(intent, user, context, c,
cursorIconInfo.iconIndex, titleIndex,
allowMissingTarget, useLowResIcon);
- } else {
+ } else if (itemType ==
+ LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ String shortcutId = intent.getStringExtra(
+ ShortcutInfoCompat.EXTRA_SHORTCUT_ID);
+ String packageName = intent.getPackage();
+ ShortcutKey key = new ShortcutKey(intent.getPackage(),
+ user, shortcutId);
+ ShortcutInfoCompat pinnedShortcut =
+ shortcutKeyToPinnedShortcuts.get(key);
+ boolean shouldPin = false; // It's already pinned.
+ if (pinnedShortcut == null) {
+ // It shouldn't be possible for a shortcut to be on the
+ // workspace without being pinned, but if one somehow is,
+ // we should pin it now to get back to a good state.
+ Log.w(TAG, "Shortcut was on workspace but wasn't pinned");
+ // Get full details; incrementing the count will pin it.
+ List<ShortcutInfoCompat> fullDetails = mDeepShortcutManager
+ .queryForFullDetails(packageName,
+ Collections.singletonList(shortcutId), user);
+ if (fullDetails == null || fullDetails.isEmpty()) {
+ itemsToRemove.add(id);
+ continue;
+ } else {
+ pinnedShortcut = fullDetails.get(0);
+ shouldPin = true;
+ }
+ }
+ incrementPinnedShortcutCount(key, shouldPin);
+ info = ShortcutInfo.fromDeepShortcutInfo(pinnedShortcut,
+ context, launcherApps);
+ } else { // item type == ITEM_TYPE_SHORTCUT
info = getShortcutInfo(c, context, titleIndex, cursorIconInfo);
// Shortcuts are only available on the primary profile
@@ -2098,6 +2222,15 @@
}
}
+ // Unpin shortcuts that don't exist on the workspace.
+ for (ShortcutKey key : shortcutKeyToPinnedShortcuts.keySet()) {
+ MutableInt numTimesPinned = sBgPinnedShortcutCounts.get(key);
+ if (numTimesPinned == null || numTimesPinned.value == 0) {
+ // Shortcut is pinned but doesn't exist on the workspace; unpin it.
+ mDeepShortcutManager.unpinShortcut(key);
+ }
+ }
+
// Sort all the folder items and make sure the first 3 items are high resolution.
for (FolderInfo folder : sBgFolders) {
Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
@@ -2629,6 +2762,27 @@
}
}
+ private void loadAndBindDeepShortcuts() {
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "loadAndBindDeepShortcuts mDeepShortcutsLoaded=" + mDeepShortcutsLoaded);
+ }
+ if (!mDeepShortcutsLoaded) {
+ mBgDeepShortcutMap.clear();
+ for (UserHandleCompat user : mUserManager.getUserProfiles()) {
+ List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
+ .queryForAllShortcuts(user);
+ updateDeepShortcutMap(null, shortcuts);
+ }
+ synchronized (LoaderTask.this) {
+ if (mStopped) {
+ return;
+ }
+ mDeepShortcutsLoaded = true;
+ }
+ }
+ bindDeepShortcutMapOnMainThread();
+ }
+
public void dumpState() {
synchronized (sBgLock) {
Log.d(TAG, "mLoaderTask.mContext=" + mContext);
@@ -2639,6 +2793,40 @@
}
}
+ // Clear all the shortcuts for the given package, and re-add the new shortcuts.
+ private void updateDeepShortcutMap(String packageName, List<ShortcutInfoCompat> shortcuts) {
+ // Remove all keys associated with the given package.
+ if (packageName != null) {
+ Iterator<ComponentKey> keysIter = mBgDeepShortcutMap.keySet().iterator();
+ while (keysIter.hasNext()) {
+ if (keysIter.next().componentName.getPackageName().equals(packageName)) {
+ keysIter.remove();
+ }
+ }
+ }
+
+ // Now add the new shortcuts to the map.
+ for (ShortcutInfoCompat shortcut : shortcuts) {
+ ComponentKey targetComponent
+ = new ComponentKey(shortcut.getActivity(), shortcut.getUserHandle());
+ mBgDeepShortcutMap.addToList(targetComponent, shortcut.getId());
+ }
+ }
+
+ private void bindDeepShortcutMapOnMainThread() {
+ final MultiHashMap<ComponentKey, String> shortcutMapCopy = new MultiHashMap<>();
+ shortcutMapCopy.putAll(mBgDeepShortcutMap);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Callbacks callbacks = getCallback();
+ if (callbacks != null) {
+ callbacks.bindDeepShortcutMap(shortcutMapCopy);
+ }
+ }
+ });
+ }
+
/**
* Called when the icons for packages have been updated in the icon cache.
*/
@@ -2664,19 +2852,7 @@
mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);
}
- if (!updatedShortcuts.isEmpty()) {
- final UserHandleCompat userFinal = user;
- mHandler.post(new Runnable() {
-
- public void run() {
- Callbacks cb = getCallback();
- if (cb != null && callbacks == cb) {
- cb.bindShortcutsChanged(updatedShortcuts,
- new ArrayList<ShortcutInfo>(), userFinal);
- }
- }
- });
- }
+ bindUpdatedShortcuts(updatedShortcuts, user);
if (!updatedApps.isEmpty()) {
mHandler.post(new Runnable() {
@@ -2691,7 +2867,25 @@
}
}
- void enqueuePackageUpdated(PackageUpdatedTask task) {
+ private void bindUpdatedShortcuts(final ArrayList<ShortcutInfo> updatedShortcuts,
+ UserHandleCompat user) {
+ if (!updatedShortcuts.isEmpty()) {
+ final Callbacks callbacks = getCallback();
+ final UserHandleCompat userFinal = user;
+ mHandler.post(new Runnable() {
+
+ public void run() {
+ Callbacks cb = getCallback();
+ if (cb != null && callbacks == cb) {
+ cb.bindShortcutsChanged(updatedShortcuts,
+ new ArrayList<ShortcutInfo>(), userFinal);
+ }
+ }
+ });
+ }
+ }
+
+ void enqueueItemUpdatedTask(Runnable task) {
sWorker.post(task);
}
@@ -2719,11 +2913,11 @@
}
}
if (!packagesRemoved.isEmpty()) {
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,
+ enqueueItemUpdatedTask(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,
packagesRemoved.toArray(new String[packagesRemoved.size()]), user));
}
if (!packagesUnavailable.isEmpty()) {
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,
+ enqueueItemUpdatedTask(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,
packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user));
}
}
@@ -3081,6 +3275,60 @@
}
}
+ private class ShortcutsChangedTask implements Runnable {
+ private String mPackageName;
+ private List<ShortcutInfoCompat> mShortcuts;
+ private UserHandleCompat mUser;
+
+ public ShortcutsChangedTask(String packageName, List<ShortcutInfoCompat> shortcuts,
+ UserHandleCompat user) {
+ mPackageName = packageName;
+ mShortcuts = shortcuts;
+ mUser = user;
+ }
+
+ @Override
+ public void run() {
+ mDeepShortcutManager.onShortcutsChanged(mShortcuts);
+
+ Map<String, ShortcutInfoCompat> idsToShortcuts = new HashMap<>();
+ for (ShortcutInfoCompat shortcut : mShortcuts) {
+ idsToShortcuts.put(shortcut.getId(), shortcut);
+ }
+
+ // Find ShortcutInfo's that have changed on the workspace.
+ MultiHashMap<String, ShortcutInfo> idsToWorkspaceShortcutInfos = new MultiHashMap<>();
+ for (ItemInfo itemInfo : sBgItemsIdMap) {
+ if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ ShortcutInfo si = (ShortcutInfo) itemInfo;
+ String shortcutId = si.getDeepShortcutId();
+ if (idsToShortcuts.containsKey(shortcutId)) {
+ idsToWorkspaceShortcutInfos.addToList(shortcutId, si);
+ }
+ }
+ }
+
+ // Update the workspace to reflect the changes to updated shortcuts residing on it.
+ List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager.queryForFullDetails(
+ mPackageName, new ArrayList<>(idsToWorkspaceShortcutInfos.keySet()), mUser);
+ ArrayList<ShortcutInfo> updatedShortcutInfos = new ArrayList<>();
+ Context context = LauncherAppState.getInstance().getContext();
+ for (ShortcutInfoCompat fullDetails : shortcuts) {
+ List<ShortcutInfo> shortcutInfos = idsToWorkspaceShortcutInfos
+ .get(fullDetails.getId());
+ for (ShortcutInfo shortcutInfo : shortcutInfos) {
+ shortcutInfo.updateFromDeepShortcutInfo(fullDetails, context, mLauncherApps);
+ updatedShortcutInfos.add(shortcutInfo);
+ }
+ }
+ bindUpdatedShortcuts(updatedShortcutInfos, mUser);
+
+ // Update the deep shortcut map, in case the list of ids has changed for an activity.
+ updateDeepShortcutMap(mPackageName, mShortcuts);
+ bindDeepShortcutMapOnMainThread();
+ }
+ }
+
private void bindWidgetsModel(final Callbacks callbacks, final WidgetsModel model) {
mHandler.post(new Runnable() {
@Override
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 52668d7..c213c8d 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -211,6 +211,11 @@
public static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5;
/**
+ * The gesture is an application created deep shortcut
+ */
+ public static final int ITEM_TYPE_DEEP_SHORTCUT = 6;
+
+ /**
* The appWidgetId of the widget
*
* <P>Type: INTEGER</P>
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 9266793..5ac3f0b 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -154,7 +154,7 @@
// Page Indicator
@Thunk int mPageIndicatorViewId;
- @Thunk PageIndicator mPageIndicator;
+ protected PageIndicator mPageIndicator;
// The viewport whether the pages are to be contained (the actual view may be larger than the
// viewport)
@ViewDebug.ExportedProperty(category = "launcher")
@@ -247,39 +247,14 @@
mScroller.setInterpolator(mDefaultInterpolator);
}
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- // Hook up the page indicator
- ViewGroup parent = (ViewGroup) getParent();
- ViewGroup grandParent = (ViewGroup) parent.getParent();
- if (mPageIndicator == null && mPageIndicatorViewId > -1) {
- mPageIndicator = (PageIndicator) grandParent.findViewById(mPageIndicatorViewId);
+ public void initParentViews(View parent) {
+ if (mPageIndicatorViewId > -1) {
+ mPageIndicator = (PageIndicator) parent.findViewById(mPageIndicatorViewId);
mPageIndicator.setMarkersCount(getChildCount());
-
- OnClickListener listener = getPageIndicatorClickListener();
- if (listener != null) {
- mPageIndicator.setOnClickListener(listener);
- }
- mPageIndicator.setContentDescription(getPageIndicatorDescription());
+ mPageIndicator.setContentDescription(getCurrentPageDescription());
}
}
- protected String getPageIndicatorDescription() {
- return getCurrentPageDescription();
- }
-
- protected OnClickListener getPageIndicatorClickListener() {
- return null;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- // Unhook the page indicator
- mPageIndicator = null;
- }
-
// Convenience methods to map points from self to parent and vice versa
private float[] mapPointFromViewToParent(View v, float x, float y) {
sTmpPoint[0] = x;
@@ -467,7 +442,7 @@
private void updatePageIndicator() {
// Update the page indicator (when we aren't reordering)
if (mPageIndicator != null) {
- mPageIndicator.setContentDescription(getPageIndicatorDescription());
+ mPageIndicator.setContentDescription(getCurrentPageDescription());
if (!isReordering(false)) {
mPageIndicator.setActiveMarker(getNextPage());
}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index d051665..63f49e0 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -16,20 +16,23 @@
package com.android.launcher3;
+import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.util.Log;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.text.TextUtils;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.folder.FolderIcon;
-
-import java.util.ArrayList;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
/**
* Represents a launchable icon on the workspaces and in folders.
@@ -274,6 +277,46 @@
return shortcut;
}
+ /**
+ * Creates a {@link ShortcutInfo} from a {@link ShortcutInfoCompat}. Pardon the overloaded name.
+ */
+ @TargetApi(Build.VERSION_CODES.N)
+ public static ShortcutInfo fromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo,
+ Context context, LauncherAppsCompat launcherApps) {
+ ShortcutInfo si = new ShortcutInfo();
+ si.user = shortcutInfo.getUserHandle();
+ si.itemType = LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+ si.intent = shortcutInfo.makeIntent(context);
+ si.flags = 0;
+ si.updateFromDeepShortcutInfo(shortcutInfo, context, launcherApps);
+ return si;
+ }
+
+ public void updateFromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo,
+ Context context, LauncherAppsCompat launcherApps) {
+ title = shortcutInfo.getShortLabel();
+
+ CharSequence label = shortcutInfo.getLongLabel();
+ if (TextUtils.isEmpty(label)) {
+ label = shortcutInfo.getShortLabel();
+ }
+ this.contentDescription = UserManagerCompat.getInstance(context)
+ .getBadgedLabelForUser(label, user);
+
+ LauncherAppState launcherAppState = LauncherAppState.getInstance();
+ Drawable unbadgedIcon = launcherApps.getShortcutIconDrawable(shortcutInfo, launcherAppState
+ .getInvariantDeviceProfile().fillResIconDpi);
+ Bitmap icon = unbadgedIcon == null ? null
+ : Utilities.createBadgedIconBitmap(unbadgedIcon, user, context);
+ setIcon(icon != null ? icon : launcherAppState.getIconCache().getDefaultIcon(user));
+ }
+
+ /** Returns the ShortcutInfo id associated with the deep shortcut. */
+ public String getDeepShortcutId() {
+ return itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT ?
+ intent.getStringExtra(ShortcutInfoCompat.EXTRA_SHORTCUT_ID) : null;
+ }
+
@Override
public boolean isDisabled() {
return isDisabled != 0;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 24736d4..416da3a 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -59,8 +59,8 @@
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
import com.android.launcher3.UninstallDropTarget.DropTargetSource;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
+import com.android.launcher3.accessibility.OverviewAccessibilityDelegate;
import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.compat.AppWidgetManagerCompat;
@@ -458,6 +458,12 @@
setEdgeGlowColor(getResources().getColor(R.color.workspace_edge_effect_color));
}
+ @Override
+ public void initParentViews(View parent) {
+ super.initParentViews(parent);
+ mPageIndicator.setAccessibilityDelegate(new OverviewAccessibilityDelegate());
+ }
+
private int getDefaultPage() {
return numCustomPages();
}
@@ -1445,10 +1451,9 @@
mHotseatAlpha[direction.ordinal()] = alpha;
float finalAlpha = mHotseatAlpha[0] * mHotseatAlpha[1];
- View pageIndicator = getPageIndicator();
- if (pageIndicator != null) {
- property.set(pageIndicator, translation);
- pageIndicator.setAlpha(finalAlpha);
+ if (mPageIndicator != null) {
+ property.set(mPageIndicator, translation);
+ mPageIndicator.setAlpha(alpha);
}
property.set(mLauncher.getHotseat(), translation);
@@ -1647,8 +1652,8 @@
mLauncher.getHotseat().setTranslationX(translationX);
}
- if (getPageIndicator() != null) {
- getPageIndicator().setTranslationX(translationX);
+ if (mPageIndicator != null) {
+ mPageIndicator.setTranslationX(translationX);
}
if (mCustomContentCallbacks != null) {
@@ -1657,21 +1662,6 @@
}
@Override
- protected OnClickListener getPageIndicatorClickListener() {
- AccessibilityManager am = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (!am.isTouchExplorationEnabled()) {
- return null;
- }
- return new OnClickListener() {
- @Override
- public void onClick(View arg0) {
- mLauncher.showOverviewMode(true);
- }
- };
- }
-
- @Override
protected void screenScrolled(int screenCenter) {
updatePageAlphaValues(screenCenter);
updateStateForCustomContent(screenCenter);
@@ -1692,15 +1682,6 @@
}
protected void onResume() {
- if (getPageIndicator() != null) {
- // In case accessibility state has changed, we need to perform this on every
- // attach to window
- OnClickListener listener = getPageIndicatorClickListener();
- if (listener != null) {
- getPageIndicator().setOnClickListener(listener);
- }
- }
-
// Update wallpaper dimensions if they were changed since last onResume
// (we also always set the wallpaper dimensions in the constructor)
if (LauncherAppState.getInstance().hasWallpaperChangedSinceLastCheck()) {
@@ -2086,10 +2067,13 @@
IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
page.setContentDescription(getPageDescription(pageNo));
- if (mPagesAccessibilityDelegate == null) {
- mPagesAccessibilityDelegate = new OverviewScreenAccessibilityDelegate(this);
+ // No custom action for the first page.
+ if (!FeatureFlags.QSB_ON_FIRST_SCREEN || pageNo > 0) {
+ if (mPagesAccessibilityDelegate == null) {
+ mPagesAccessibilityDelegate = new OverviewScreenAccessibilityDelegate(this);
+ }
+ page.setAccessibilityDelegate(mPagesAccessibilityDelegate);
}
- page.setAccessibilityDelegate(mPagesAccessibilityDelegate);
} else {
int accessible = mState == State.NORMAL ?
IMPORTANT_FOR_ACCESSIBILITY_AUTO :
@@ -2118,7 +2102,7 @@
@Override
public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
- if (mPageIndicator instanceof PageIndicator) {
+ if (mPageIndicator != null) {
boolean isNewStateSpringLoaded = mState == State.SPRING_LOADED;
mPageIndicator.setShouldAutoHide(!isNewStateSpringLoaded);
if (isNewStateSpringLoaded) {
@@ -2575,7 +2559,8 @@
boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
boolean willBecomeShortcut =
(info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
+ info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
+ info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT);
return (aboveShortcut && willBecomeShortcut);
}
@@ -3509,6 +3494,7 @@
switch (info.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
if (info.container == NO_ID && info instanceof AppInfo) {
// Came from all apps -- make a copy
info = ((AppInfo) info).makeShortcut();
@@ -4195,7 +4181,7 @@
public interface ItemOperator {
/**
- * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}.
+ * Process the next itemInfo, possibly with side-effect on the next item.
*
* @param info info for the shortcut
* @param view view for the shortcut
@@ -4379,11 +4365,7 @@
exitWidgetResizeMode();
}
- protected String getPageIndicatorDescription() {
- String settings = getResources().getString(R.string.settings_button_text);
- return getCurrentPageDescription() + ", " + settings;
- }
-
+ @Override
protected String getCurrentPageDescription() {
if (hasCustomContent() && getNextPage() == 0) {
return mCustomContentDescription;
diff --git a/src/com/android/launcher3/accessibility/OverviewAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/OverviewAccessibilityDelegate.java
new file mode 100644
index 0000000..64559f2
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/OverviewAccessibilityDelegate.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 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.accessibility;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+/**
+ * Accessibility delegate with actions pointing to various Overview entry points.
+ */
+public class OverviewAccessibilityDelegate extends AccessibilityDelegate {
+
+ private static final int OVERVIEW = R.string.accessibility_action_overview;
+ private static final int WALLPAPERS = R.string.wallpaper_button_text;
+ private static final int WIDGETS = R.string.widget_button_text;
+ private static final int SETTINGS = R.string.settings_button_text;
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+
+ Context context = host.getContext();
+ info.addAction(new AccessibilityAction(OVERVIEW, context.getText(OVERVIEW)));
+
+ if (Utilities.isWallapaperAllowed(context)) {
+ info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS)));
+ }
+ info.addAction(new AccessibilityAction(WIDGETS, context.getText(WIDGETS)));
+ info.addAction(new AccessibilityAction(SETTINGS, context.getText(SETTINGS)));
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ Launcher launcher = (Launcher) host.getContext();
+ if (action == OVERVIEW) {
+ launcher.showOverviewMode(true);
+ return true;
+ } else if (action == WALLPAPERS) {
+ launcher.onClickWallpaperPicker(host);
+ return true;
+ } else if (action == WIDGETS) {
+ launcher.onClickAddWidgetButton(host);
+ return true;
+ } else if (action == SETTINGS) {
+ launcher.onClickSettingsButton(host);
+ return true;
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+}
diff --git a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
index c5b52de..5f68f90 100644
--- a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
@@ -28,6 +28,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
+import com.android.launcher3.config.FeatureFlags;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class OverviewScreenAccessibilityDelegate extends AccessibilityDelegate {
@@ -88,7 +89,9 @@
if (index < mWorkspace.getChildCount() - 1) {
info.addAction(mActions.get(MOVE_FORWARD));
}
- if (index > mWorkspace.numCustomPages()) {
+
+ int startIndex = mWorkspace.numCustomPages() + (FeatureFlags.QSB_ON_FIRST_SCREEN ? 1 : 0);
+ if (index > startIndex) {
info.addAction(mActions.get(MOVE_BACKWARD));
}
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 237a9e9..3381064 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -19,10 +19,13 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherApps;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import com.android.launcher3.Utilities;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import java.util.List;
@@ -45,6 +48,8 @@
void onPackagesUnavailable(String[] packageNames, UserHandleCompat user, boolean replacing);
void onPackagesSuspended(String[] packageNames, UserHandleCompat user);
void onPackagesUnsuspended(String[] packageNames, UserHandleCompat user);
+ void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
+ UserHandleCompat user);
}
protected LauncherAppsCompat() {
@@ -56,7 +61,9 @@
public static LauncherAppsCompat getInstance(Context context) {
synchronized (sInstanceLock) {
if (sInstance == null) {
- if (Utilities.ATLEAST_LOLLIPOP) {
+ if (Utilities.isNycOrAbove()) {
+ sInstance = new LauncherAppsCompatVNMR1(context.getApplicationContext());
+ } else if (Utilities.ATLEAST_LOLLIPOP) {
sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
} else {
sInstance = new LauncherAppsCompatV16(context.getApplicationContext());
@@ -79,4 +86,11 @@
public abstract boolean isActivityEnabledForProfile(ComponentName component,
UserHandleCompat user);
public abstract boolean isPackageSuspendedForProfile(String packageName, UserHandleCompat user);
+ public abstract List<ShortcutInfoCompat> getShortcuts(LauncherApps.ShortcutQuery q,
+ UserHandleCompat userHandle);
+ public abstract void pinShortcuts(String packageName, List<String> pinnedIds,
+ UserHandleCompat userHandle);
+ public abstract void startShortcut(String packageName, String id, Rect sourceBounds,
+ Bundle startActivityOptions, UserHandleCompat user);
+ public abstract Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density);
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
index 4e2fc05..1a144e8 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
@@ -22,15 +22,18 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import com.android.launcher3.Utilities;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Thunk;
@@ -130,6 +133,29 @@
return false;
}
+ @Override
+ public List<ShortcutInfoCompat> getShortcuts(LauncherApps.ShortcutQuery q,
+ UserHandleCompat userHandle) {
+ return null;
+ }
+
+ @Override
+ public void pinShortcuts(String packageName, List<String> pinnedIds,
+ UserHandleCompat userHandle) {
+ // Not supported, so do nothing.
+ }
+
+ @Override
+ public void startShortcut(String packageName, String id, Rect sourceBounds,
+ Bundle startActivityOptions, UserHandleCompat user) {
+ // Not supported, so do nothing.
+ }
+
+ @Override
+ public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
+ return null;
+ }
+
private void unregisterForPackageIntents() {
mContext.unregisterReceiver(mPackageMonitor);
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index 7270d02..d97bf2f 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -22,11 +22,14 @@
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -34,7 +37,7 @@
import java.util.Map;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class LauncherAppsCompatVL extends LauncherAppsCompat {
+public class LauncherAppsCompatVL extends LauncherAppsCompatV16 {
protected LauncherApps mLauncherApps;
@@ -42,7 +45,7 @@
= new HashMap<OnAppsChangedCallbackCompat, WrappedCallback>();
LauncherAppsCompatVL(Context context) {
- super();
+ super(context);
mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
}
@@ -146,6 +149,18 @@
public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
mCallback.onPackagesUnsuspended(packageNames, UserHandleCompat.fromUser(user));
}
+
+ @Override
+ public void onShortcutsChanged(String packageName, List<ShortcutInfo> shortcuts,
+ UserHandle user) {
+ List<ShortcutInfoCompat> shortcutInfoCompats = new ArrayList<>(shortcuts.size());
+ for (ShortcutInfo shortcutInfo : shortcuts) {
+ shortcutInfoCompats.add(new ShortcutInfoCompat(shortcutInfo));
+ }
+
+ mCallback.onShortcutsChanged(packageName, shortcutInfoCompats,
+ UserHandleCompat.fromUser(user));
+ }
}
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVNMR1.java b/src/com/android/launcher3/compat/LauncherAppsCompatVNMR1.java
new file mode 100644
index 0000000..0c1db13
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVNMR1.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 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.compat;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@TargetApi(Build.VERSION_CODES.N)
+public class LauncherAppsCompatVNMR1 extends LauncherAppsCompatVL {
+
+ LauncherAppsCompatVNMR1(Context context) {
+ super(context);
+ }
+
+ @Override
+ public List<ShortcutInfoCompat> getShortcuts(LauncherApps.ShortcutQuery q,
+ UserHandleCompat userHandle) {
+ List<ShortcutInfo> shortcutInfos = mLauncherApps.getShortcuts(q, userHandle.getUser());
+ if (shortcutInfos == null) {
+ return null;
+ }
+ List<ShortcutInfoCompat> shortcutInfoCompats = new ArrayList<>(shortcutInfos.size());
+ for (ShortcutInfo shortcutInfo : shortcutInfos) {
+ shortcutInfoCompats.add(new ShortcutInfoCompat(shortcutInfo));
+ }
+ return shortcutInfoCompats;
+ }
+
+ @Override
+ public void pinShortcuts(String packageName, List<String> pinnedIds,
+ UserHandleCompat userHandle) {
+ mLauncherApps.pinShortcuts(packageName, pinnedIds, userHandle.getUser());
+ }
+
+ @Override
+ public void startShortcut(String packageName, String id, Rect sourceBounds,
+ Bundle startActivityOptions, UserHandleCompat user) {
+ mLauncherApps.startShortcut(packageName, id, sourceBounds,
+ startActivityOptions, user.getUser());
+ }
+
+ @Override
+ public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
+ return mLauncherApps.getShortcutIconDrawable(shortcutInfo.getShortcutInfo(), density);
+ }
+
+ private static class WrappedCallback extends LauncherApps.Callback {
+ private OnAppsChangedCallbackCompat mCallback;
+
+ public WrappedCallback(OnAppsChangedCallbackCompat callback) {
+ mCallback = callback;
+ }
+
+ public void onPackageRemoved(String packageName, UserHandle user) {
+ mCallback.onPackageRemoved(packageName, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackageAdded(String packageName, UserHandle user) {
+ mCallback.onPackageAdded(packageName, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackageChanged(String packageName, UserHandle user) {
+ mCallback.onPackageChanged(packageName, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
+ mCallback.onPackagesAvailable(packageNames, UserHandleCompat.fromUser(user), replacing);
+ }
+
+ public void onPackagesUnavailable(String[] packageNames, UserHandle user,
+ boolean replacing) {
+ mCallback.onPackagesUnavailable(packageNames, UserHandleCompat.fromUser(user),
+ replacing);
+ }
+
+ public void onPackagesSuspended(String[] packageNames, UserHandle user) {
+ mCallback.onPackagesSuspended(packageNames, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
+ mCallback.onPackagesUnsuspended(packageNames, UserHandleCompat.fromUser(user));
+ }
+
+ @Override
+ public void onShortcutsChanged(String packageName, List<ShortcutInfo> shortcuts,
+ UserHandle user) {
+ List<ShortcutInfoCompat> shortcutInfoCompats = new ArrayList<>(shortcuts.size());
+ for (ShortcutInfo shortcutInfo : shortcuts) {
+ shortcutInfoCompats.add(new ShortcutInfoCompat(shortcutInfo));
+ }
+
+ mCallback.onShortcutsChanged(packageName, shortcutInfoCompats,
+ UserHandleCompat.fromUser(user));
+ }
+ }
+}
+
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 93238de..2035f99 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -510,7 +510,7 @@
}
// This is set to true in close(), but isn't reset to false until onDropCompleted(). This
- // leads to an consistent state if you drag out of the folder and drag back in without
+ // leads to an inconsistent state if you drag out of the folder and drag back in without
// dropping. One resulting issue is that replaceFolderWithFinalItem() can be called twice.
mDeleteFolderOnDropCompleted = false;
@@ -737,7 +737,8 @@
final ItemInfo item = d.dragInfo;
final int itemType = item.itemType;
return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
+ itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
+ itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) &&
!isFull());
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index d7952c5..d08cf54 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -213,7 +213,8 @@
private boolean willAcceptItem(ItemInfo item) {
final int itemType = item.itemType;
return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
+ itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
+ itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) &&
!mFolder.isFull() && item != mInfo && !mInfo.opened);
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index c56e4e5..c6fc4cb 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -120,6 +120,7 @@
mFolder = folder;
mKeyListener = new PagedFolderKeyEventListener(folder);
mPageIndicator = (PageIndicator) folder.findViewById(R.id.folder_page_indicator);
+ initParentViews(folder);
}
/**
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index e9a897e..0deee57 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Intent;
+import android.util.Log;
import android.view.View;
import android.view.ViewParent;
@@ -28,11 +29,14 @@
import com.android.launcher3.util.ComponentKey;
import java.util.List;
+import java.util.Locale;
/**
* Manages the creation of {@link LauncherEvent}.
*/
-public abstract class UserEventDispatcher {
+public class UserEventDispatcher {
+
+ private static final boolean DEBUG_LOGGING = false;
private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
/**
@@ -155,7 +159,17 @@
mActionDurationMillis = System.currentTimeMillis();
}
- public abstract void dispatchUserEvent(LauncherEvent ev, Intent intent);
+ public void dispatchUserEvent(LauncherEvent ev, Intent intent) {
+ if (DEBUG_LOGGING) {
+ Log.d("UserEvent", String.format(Locale.US,
+ "action:%s\nchild:%s\nparent:%s\nelapsed container %d ms session %d ms",
+ LoggerUtils.getActionStr(ev.action),
+ LoggerUtils.getTargetStr(ev.srcTarget[0]),
+ LoggerUtils.getTargetStr(ev.srcTarget[1]),
+ ev.elapsedContainerMillis,
+ ev.elapsedSessionMillis));
+ }
+ }
public int getPredictedRank(ComponentKey key) {
if (mPredictedApps == null) return -1;
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index 8e8e551..cb1acaa 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -150,7 +150,7 @@
protected boolean migrateHotseat() throws Exception {
ArrayList<DbEntry> items = loadHotseatEntries();
- int requiredCount = mDestHotseatSize - 1;
+ int requiredCount = FeatureFlags.NO_ALL_APPS_ICON ? mDestHotseatSize : mDestHotseatSize - 1;
while (items.size() > requiredCount) {
// Pick the center item by default.
@@ -641,10 +641,11 @@
// calculate weight
switch (entry.itemType) {
case Favorites.ITEM_TYPE_SHORTCUT:
+ case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case Favorites.ITEM_TYPE_APPLICATION: {
verifyIntent(c.getString(indexIntent));
- entry.weight = entry.itemType == Favorites.ITEM_TYPE_SHORTCUT
- ? WT_SHORTCUT : WT_APPLICATION;
+ entry.weight = entry.itemType == Favorites.ITEM_TYPE_APPLICATION ?
+ WT_APPLICATION : WT_SHORTCUT;
break;
}
case Favorites.ITEM_TYPE_FOLDER: {
@@ -715,10 +716,11 @@
// calculate weight
switch (entry.itemType) {
case Favorites.ITEM_TYPE_SHORTCUT:
+ case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case Favorites.ITEM_TYPE_APPLICATION: {
verifyIntent(c.getString(indexIntent));
- entry.weight = entry.itemType == Favorites.ITEM_TYPE_SHORTCUT
- ? WT_SHORTCUT : WT_APPLICATION;
+ entry.weight = entry.itemType == Favorites.ITEM_TYPE_APPLICATION ?
+ WT_APPLICATION : WT_SHORTCUT;
break;
}
case Favorites.ITEM_TYPE_APPWIDGET: {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
new file mode 100644
index 0000000..e2e06af
--- /dev/null
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 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.shortcuts;
+
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.os.Build;
+import android.os.Process;
+import android.util.Log;
+
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class DeepShortcutManager {
+ private static final int FLAG_GET_ALL = ShortcutQuery.FLAG_GET_DYNAMIC
+ | ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_MANIFEST;
+
+ private final LauncherAppsCompat mLauncherApps;
+
+ public DeepShortcutManager(Context context, ShortcutCache shortcutCache) {
+ mLauncherApps = LauncherAppsCompat.getInstance(context);
+ }
+
+ public void onShortcutsChanged(List<ShortcutInfoCompat> shortcuts) {
+ // mShortcutCache.removeShortcuts(shortcuts);
+ }
+
+ /**
+ * Queries for the shortcuts with the package name and provided ids.
+ *
+ * This method is intended to get the full details for shortcuts when they are added or updated,
+ * because we only get "key" fields in onShortcutsChanged().
+ */
+ public List<ShortcutInfoCompat> queryForFullDetails(String packageName,
+ List<String> shortcutIds, UserHandleCompat user) {
+ return query(FLAG_GET_ALL, packageName, null, shortcutIds, user);
+ }
+
+ /**
+ * Gets all the shortcuts associated with the given package and user.
+ */
+ public List<ShortcutInfoCompat> queryForAllAppShortcuts(ComponentName activity,
+ List<String> ids, UserHandleCompat user) {
+ return query(FLAG_GET_ALL, activity.getPackageName(), activity, ids, user);
+ }
+
+ /**
+ * Removes the given shortcut from the current list of pinned shortcuts.
+ * (Runs on background thread)
+ */
+ public void unpinShortcut(final ShortcutKey key) {
+ String packageName = key.componentName.getPackageName();
+ String id = key.id;
+ UserHandleCompat user = key.user;
+ List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
+ pinnedIds.remove(id);
+ mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
+ }
+
+ /**
+ * Adds the given shortcut to the current list of pinned shortcuts.
+ * (Runs on background thread)
+ */
+ public void pinShortcut(final ShortcutKey key) {
+ String packageName = key.componentName.getPackageName();
+ String id = key.id;
+ UserHandleCompat user = key.user;
+ List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
+ pinnedIds.add(id);
+ mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
+ }
+
+ /**
+ * Returns the id's of pinned shortcuts associated with the given package and user.
+ *
+ * If packageName is null, returns all pinned shortcuts regardless of package.
+ */
+ public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName,
+ UserHandleCompat user) {
+ return query(ShortcutQuery.FLAG_GET_PINNED, packageName, null, null, user);
+ }
+
+ public List<ShortcutInfoCompat> queryForAllShortcuts(UserHandleCompat user) {
+ return query(FLAG_GET_ALL, null, null, null, user);
+ }
+
+ private List<String> extractIds(List<ShortcutInfoCompat> shortcuts) {
+ List<String> shortcutIds = new ArrayList<>(shortcuts.size());
+ for (ShortcutInfoCompat shortcut : shortcuts) {
+ shortcutIds.add(shortcut.getId());
+ }
+ return shortcutIds;
+ }
+
+ /**
+ * Query the system server for all the shortcuts matching the given parameters.
+ * If packageName == null, we query for all shortcuts with the passed flags, regardless of app.
+ *
+ * TODO: Use the cache to optimize this so we don't make an RPC every time.
+ */
+ private List<ShortcutInfoCompat> query(int flags, String packageName,
+ ComponentName activity, List<String> shortcutIds, UserHandleCompat user) {
+ ShortcutQuery q = new ShortcutQuery();
+ q.setQueryFlags(flags);
+ if (packageName != null) {
+ q.setPackage(packageName);
+ q.setActivity(activity);
+ q.setShortcutIds(shortcutIds);
+ }
+ return mLauncherApps.getShortcuts(q, user);
+ }
+}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutCache.java b/src/com/android/launcher3/shortcuts/ShortcutCache.java
new file mode 100644
index 0000000..fc118a8
--- /dev/null
+++ b/src/com/android/launcher3/shortcuts/ShortcutCache.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 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.shortcuts;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.LruCache;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Loads {@link ShortcutInfoCompat}s on demand (e.g. when launcher
+ * loads for pinned shortcuts and on long-press for dynamic shortcuts), and caches them
+ * for handful of apps in an LruCache while launcher lives.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class ShortcutCache {
+ private static final String TAG = "ShortcutCache";
+ private static final boolean LOGD = false;
+
+ private static final int CACHE_SIZE = 30; // Max number shortcuts we cache.
+
+ private LruCache<ShortcutKey, ShortcutInfoCompat> mCachedShortcuts;
+ // We always keep pinned shortcuts in the cache.
+ private HashMap<ShortcutKey, ShortcutInfoCompat> mPinnedShortcuts;
+
+ public ShortcutCache() {
+ mCachedShortcuts = new LruCache<>(CACHE_SIZE);
+ mPinnedShortcuts = new HashMap<>();
+ }
+
+ /**
+ * Removes shortcuts from the cache when shortcuts change for a given package.
+ *
+ * Returns a map of ids to their evicted shortcuts.
+ *
+ * @see android.content.pm.LauncherApps.Callback#onShortcutsChanged(String, List, UserHandle).
+ */
+ public void removeShortcuts(List<ShortcutInfoCompat> shortcuts) {
+ for (ShortcutInfoCompat shortcut : shortcuts) {
+ ShortcutKey key = ShortcutKey.fromInfo(shortcut);
+ mCachedShortcuts.remove(key);
+ }
+ }
+
+ public ShortcutInfoCompat get(ShortcutKey key) {
+ if (mPinnedShortcuts.containsKey(key)) {
+ return mPinnedShortcuts.get(key);
+ }
+ return mCachedShortcuts.get(key);
+ }
+
+ public void put(ShortcutKey key, ShortcutInfoCompat shortcut) {
+ if (shortcut.isPinned()) {
+ mPinnedShortcuts.put(key, shortcut);
+ } else {
+ mCachedShortcuts.put(key, shortcut);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
new file mode 100644
index 0000000..8dbeaa7
--- /dev/null
+++ b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 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.shortcuts;
+
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.os.Build;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.ComponentKey;
+
+/**
+ * Wrapper class for {@link android.content.pm.ShortcutInfo}, representing deep shortcuts into apps.
+ *
+ * Not to be confused with {@link com.android.launcher3.ShortcutInfo}.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class ShortcutInfoCompat {
+ private static final String INTENT_CATEGORY = "com.android.launcher3.DEEP_SHORTCUT";
+ public static final String EXTRA_SHORTCUT_ID = "shortcut_id";
+
+ private ShortcutInfo mShortcutInfo;
+
+ public ShortcutInfoCompat(ShortcutInfo shortcutInfo) {
+ mShortcutInfo = shortcutInfo;
+ }
+
+ @TargetApi(Build.VERSION_CODES.N)
+ public Intent makeIntent(Context context) {
+ long serialNumber = UserManagerCompat.getInstance(context)
+ .getSerialNumberForUser(getUserHandle());
+ return new Intent(Intent.ACTION_MAIN)
+ .addCategory(INTENT_CATEGORY)
+ .setComponent(getActivity())
+ .setPackage(getPackage())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+ .putExtra(ItemInfo.EXTRA_PROFILE, serialNumber)
+ .putExtra(EXTRA_SHORTCUT_ID, getId());
+ }
+
+ public ShortcutInfo getShortcutInfo() {
+ return mShortcutInfo;
+ }
+
+ public String getPackage() {
+ return mShortcutInfo.getPackage();
+ }
+
+ public String getId() {
+ return mShortcutInfo.getId();
+ }
+
+ public CharSequence getShortLabel() {
+ return mShortcutInfo.getShortLabel();
+ }
+
+ public CharSequence getLongLabel() {
+ return mShortcutInfo.getLongLabel();
+ }
+
+ public long getLastChangedTimestamp() {
+ return mShortcutInfo.getLastChangedTimestamp();
+ }
+
+ public ComponentName getActivity() {
+ return mShortcutInfo.getActivity();
+ }
+
+ public UserHandleCompat getUserHandle() {
+ return UserHandleCompat.fromUser(mShortcutInfo.getUserHandle());
+ }
+
+ public boolean hasKeyFieldsOnly() {
+ return mShortcutInfo.hasKeyFieldsOnly();
+ }
+
+ public boolean isPinned() {
+ return mShortcutInfo.isPinned();
+ }
+
+ @Override
+ public String toString() {
+ return mShortcutInfo.toString();
+ }
+}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java
new file mode 100644
index 0000000..c9d66eb
--- /dev/null
+++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java
@@ -0,0 +1,30 @@
+package com.android.launcher3.shortcuts;
+
+import android.content.ComponentName;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.ComponentKey;
+
+/**
+ * A key that uniquely identifies a shortcut using its package, id, and user handle.
+ */
+public class ShortcutKey extends ComponentKey {
+ final String id;
+
+ public ShortcutKey(String packageName, UserHandleCompat user, String id) {
+ // Use the id as the class name.
+ super(new ComponentName(packageName, id), user);
+ this.id = id;
+ }
+
+ public static ShortcutKey fromInfo(ShortcutInfoCompat shortcutInfo) {
+ return new ShortcutKey(shortcutInfo.getPackage(), shortcutInfo.getUserHandle(),
+ shortcutInfo.getId());
+ }
+
+ @Override
+ public String toString() {
+ return flattenToString(LauncherAppState.getInstance().getContext());
+ }
+}
diff --git a/src/com/android/launcher3/util/CachedPackageTracker.java b/src/com/android/launcher3/util/CachedPackageTracker.java
index d55d573..293714e 100644
--- a/src/com/android/launcher3/util/CachedPackageTracker.java
+++ b/src/com/android/launcher3/util/CachedPackageTracker.java
@@ -170,7 +170,7 @@
*/
protected abstract void onLauncherPackageRemoved(String packageName, UserHandleCompat user);
- protected static class LauncherActivityInstallInfo
+ public static class LauncherActivityInstallInfo
implements Comparable<LauncherActivityInstallInfo> {
public final LauncherActivityInfoCompat info;
public final long installTime;
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index df23abe..7dbc0e7a 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -29,6 +29,7 @@
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
@@ -180,6 +181,12 @@
saveWorkFolderShortcuts(workFolder.id, 0, workFolderApps);
}
}
+
+ @Override
+ public void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
+ UserHandleCompat user) {
+ // Do nothing
+ }
}
/**
diff --git a/src/com/android/launcher3/util/MultiHashMap.java b/src/com/android/launcher3/util/MultiHashMap.java
new file mode 100644
index 0000000..f54ab88
--- /dev/null
+++ b/src/com/android/launcher3/util/MultiHashMap.java
@@ -0,0 +1,20 @@
+package com.android.launcher3.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A utility map from keys to an ArrayList of values.
+ */
+public class MultiHashMap<K, V> extends HashMap<K, ArrayList<V>> {
+ public void addToList(K key, V value) {
+ ArrayList<V> list = get(key);
+ if (list == null) {
+ list = new ArrayList<>();
+ list.add(value);
+ put(key, list);
+ } else {
+ list.add(value);
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index 08a81f0..c250cb2 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -10,6 +10,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.util.TestLauncherProvider;
@@ -61,8 +62,13 @@
mIdp.numHotseatIcons = 3;
new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, 5, 3)
.migrateHotseat();
- // First & last items are dropped as they have the least weight.
- verifyHotseat(hotseatItems[1], -1, hotseatItems[3]);
+ if (FeatureFlags.NO_ALL_APPS_ICON) {
+ // First item is dropped as it has the least weight.
+ verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
+ } else {
+ // First & last items are dropped as they have the least weight.
+ verifyHotseat(hotseatItems[1], -1, hotseatItems[3]);
+ }
}
public void testHotseatMigration_shortcuts_dropped() throws Exception {
@@ -77,8 +83,13 @@
mIdp.numHotseatIcons = 3;
new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, 5, 3)
.migrateHotseat();
- // First & third items are dropped as they have the least weight.
- verifyHotseat(hotseatItems[1], -1, hotseatItems[4]);
+ if (FeatureFlags.NO_ALL_APPS_ICON) {
+ // First item is dropped as it has the least weight.
+ verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
+ } else {
+ // First & third items are dropped as they have the least weight.
+ verifyHotseat(hotseatItems[1], -1, hotseatItems[4]);
+ }
}
private void verifyHotseat(long... sortedIds) {