Removing support for legacy shortcuts from default layouts
Launcher will only allow deep shortcuts to be pinned on homescreen.
Bug: 275875209
Test: Updated tests
Flag: N/A
Change-Id: I4f2674deb9cd81dd07d5d537f35a51b030a183da
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 27c41c2..2083726 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -24,30 +24,29 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Process;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Patterns;
import android.util.Xml;
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherProvider.SqlArguments;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.icons.GraphicsUtils;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.qsb.QsbContainerView;
+import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.Partner;
@@ -58,6 +57,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
@@ -135,6 +135,7 @@
private static final String ATTR_TITLE = "title";
private static final String ATTR_TITLE_TEXT = "titleText";
private static final String ATTR_SCREEN = "screen";
+ private static final String ATTR_SHORTCUT_ID = "shortcutId";
// x and y can be specified as negative integers, in which case -1 represents the
// last row / column, -2 represents the second last, and so on.
@@ -143,8 +144,6 @@
private static final String ATTR_SPAN_X = "spanX";
private static final String ATTR_SPAN_Y = "spanY";
- private static final String ATTR_ICON = "icon";
- private static final String ATTR_URL = "url";
// Attrs for "Include"
private static final String ATTR_WORKSPACE = "workspace";
@@ -156,10 +155,8 @@
private static final String HOTSEAT_CONTAINER_NAME =
Favorites.containerToString(Favorites.CONTAINER_HOTSEAT);
- @Thunk
- final Context mContext;
- @Thunk
- final LauncherWidgetHolder mAppWidgetHolder;
+ protected final Context mContext;
+ protected final LauncherWidgetHolder mAppWidgetHolder;
protected final LayoutParserCallback mCallback;
protected final PackageManager mPackageManager;
@@ -308,7 +305,15 @@
mValues.put(Favorites.SPANY, 1);
mValues.put(Favorites._ID, id);
- maybeReplaceShortcut(intent.getComponent().getPackageName(), type);
+ if (type == ITEM_TYPE_APPLICATION) {
+ ComponentName cn = intent.getComponent();
+ if (cn != null && mActivityOverride.containsKey(cn.getPackageName())) {
+ LauncherActivityInfo replacementInfo = mActivityOverride.get(cn.getPackageName());
+ mValues.put(Favorites.PROFILE_ID, UserCache.INSTANCE.get(mContext)
+ .getSerialNumberForUser(replacementInfo.getUser()));
+ mValues.put(Favorites.INTENT, AppInfo.makeLaunchIntent(replacementInfo).toUri(0));
+ }
+ }
if (mCallback.insertAndCheck(mDb, mValues) < 0) {
return -1;
@@ -321,7 +326,7 @@
ArrayMap<String, TagParser> parsers = new ArrayMap<>();
parsers.put(TAG_APP_ICON, new AppShortcutParser());
parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
- parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
return parsers;
}
@@ -332,7 +337,7 @@
parsers.put(TAG_FOLDER, new FolderParser());
parsers.put(TAG_APPWIDGET, new PendingWidgetParser());
parsers.put(TAG_SEARCH_WIDGET, new SearchWidgetParser());
- parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
return parsers;
}
@@ -420,59 +425,27 @@
}
/**
- * Parses a web shortcut. Required attributes url, icon, title
+ * Parses a deep shortcut. Required attributes packageName and shortcutId
*/
protected class ShortcutParser implements TagParser {
- private final Resources mIconRes;
-
- public ShortcutParser(Resources iconRes) {
- mIconRes = iconRes;
- }
-
@Override
public int parseAndAdd(XmlPullParser parser) {
- final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
- final int iconId = getAttributeResourceValue(parser, ATTR_ICON, 0);
+ final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
+ final String shortcutId = getAttributeValue(parser, ATTR_SHORTCUT_ID);
- if (titleResId == 0 || iconId == 0) {
- if (LOGD) Log.d(TAG, "Ignoring shortcut");
- return -1;
+ try {
+ LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
+ launcherApps.pinShortcuts(packageName, Collections.singletonList(shortcutId),
+ Process.myUserHandle());
+ Intent intent = ShortcutKey.makeIntent(shortcutId, packageName);
+ mValues.put(Favorites.RESTORED, WorkspaceItemInfo.FLAG_RESTORED_ICON);
+ return addShortcut(null, intent, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to pin the shortcut for shortcut id = " + shortcutId
+ + " and package name = " + packageName, e);
}
-
- final Intent intent = parseIntent(parser);
- if (intent == null) {
- return -1;
- }
-
- Drawable icon = mIconRes.getDrawable(iconId);
- if (icon == null) {
- if (LOGD) Log.d(TAG, "Ignoring shortcut, can't load icon");
- return -1;
- }
-
- // Auto installs should always support the current platform version.
- LauncherIcons li = LauncherIcons.obtain(mContext);
- mValues.put(LauncherSettings.Favorites.ICON, GraphicsUtils.flattenBitmap(
- li.createBadgedIconBitmap(icon).icon));
- li.recycle();
-
- mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
- mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId));
-
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- return addShortcut(mSourceRes.getString(titleResId),
- intent, Favorites.ITEM_TYPE_SHORTCUT);
- }
-
- protected Intent parseIntent(XmlPullParser parser) {
- final String url = getAttributeValue(parser, ATTR_URL);
- if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches()) {
- if (LOGD) Log.d(TAG, "Ignoring shortcut, invalid url: " + url);
- return null;
- }
- return new Intent(Intent.ACTION_VIEW, null).setData(Uri.parse(url));
+ return -1;
}
}
@@ -728,12 +701,4 @@
to.put(key, from.getAsInteger(key));
}
- private void maybeReplaceShortcut(String packageName, int type) {
- if (mActivityOverride.containsKey(packageName) && type == ITEM_TYPE_APPLICATION) {
- LauncherActivityInfo replacementInfo = mActivityOverride.get(packageName);
- mValues.put(Favorites.PROFILE_ID, UserCache.INSTANCE.get(mContext)
- .getSerialNumberForUser(replacementInfo.getUser()));
- mValues.put(Favorites.INTENT, AppInfo.makeLaunchIntent(replacementInfo).toUri(0));
- }
- }
}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index c69ae4d..c748693 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -6,19 +6,15 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Bundle;
-import android.os.Process;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherWidgetHolder;
@@ -28,7 +24,6 @@
import java.io.IOException;
import java.net.URISyntaxException;
-import java.util.Collections;
import java.util.List;
/**
@@ -49,8 +44,6 @@
private static final String ATTR_CONTAINER = "container";
private static final String ATTR_SCREEN = "screen";
private static final String ATTR_FOLDER_ITEMS = "folderItems";
- private static final String ATTR_SHORTCUT_ID = "shortcutId";
- private static final String ATTR_PACKAGE_NAME = "packageName";
public static final String RES_PARTNER_FOLDER = "partner_folder";
public static final String RES_PARTNER_DEFAULT_LAYOUT = "partner_default_layout";
@@ -66,14 +59,9 @@
@Override
protected ArrayMap<String, TagParser> getFolderElementsMap() {
- return getFolderElementsMap(mSourceRes);
- }
-
- @Thunk
- ArrayMap<String, TagParser> getFolderElementsMap(Resources res) {
ArrayMap<String, TagParser> parsers = new ArrayMap<>();
parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
- parsers.put(TAG_SHORTCUT, new UriShortcutParser(res));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
return parsers;
}
@@ -83,7 +71,7 @@
parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
parsers.put(TAG_APPWIDGET, new AppWidgetParser());
parsers.put(TAG_SEARCH_WIDGET, new SearchWidgetParser());
- parsers.put(TAG_SHORTCUT, new UriShortcutParser(mSourceRes));
+ parsers.put(TAG_SHORTCUT, new ShortcutParser());
parsers.put(TAG_RESOLVE, new ResolveParser());
parsers.put(TAG_FOLDER, new MyFolderParser());
parsers.put(TAG_PARTNER_FOLDER, new PartnerFolderParser());
@@ -190,57 +178,6 @@
}
/**
- * Shortcut parser which allows any uri and not just web urls.
- */
- public class UriShortcutParser extends ShortcutParser {
-
- public UriShortcutParser(Resources iconRes) {
- super(iconRes);
- }
-
- @Override
- public int parseAndAdd(XmlPullParser parser) {
- final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
- final String shortcutId = getAttributeValue(parser, ATTR_SHORTCUT_ID);
- if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(shortcutId)) {
- return parseAndAddDeepShortcut(shortcutId, packageName);
- }
- return super.parseAndAdd(parser);
- }
-
- /**
- * This method parses and adds a deep shortcut.
- * @return item id if the shortcut is successfully added else -1
- */
- private int parseAndAddDeepShortcut(String shortcutId, String packageName) {
- try {
- LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
- launcherApps.pinShortcuts(packageName, Collections.singletonList(shortcutId),
- Process.myUserHandle());
- Intent intent = ShortcutKey.makeIntent(shortcutId, packageName);
- mValues.put(Favorites.RESTORED, WorkspaceItemInfo.FLAG_RESTORED_ICON);
- return addShortcut(null, intent, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
- } catch (Exception e) {
- Log.e(TAG, "Unable to pin the shortcut for shortcut id = " + shortcutId
- + " and package name = " + packageName);
- }
- return -1;
- }
-
- @Override
- protected Intent parseIntent(XmlPullParser parser) {
- String uri = null;
- try {
- uri = getAttributeValue(parser, ATTR_URI);
- return Intent.parseUri(uri, 0);
- } catch (URISyntaxException e) {
- Log.w(TAG, "Shortcut has malformed uri: " + uri);
- return null; // Oh well
- }
- }
- }
-
- /**
* Contains a list of <favorite> nodes, and accepts the first successfully parsed node.
*/
public class ResolveParser implements TagParser {
@@ -284,11 +221,9 @@
if (partner != null) {
final int resId = partner.getXmlResId(RES_PARTNER_FOLDER);
if (resId != 0) {
- final Resources partnerRes = partner.getResources();
- final XmlPullParser partnerParser = partnerRes.getXml(resId);
+ final XmlPullParser partnerParser = partner.getResources().getXml(resId);
beginDocument(partnerParser, TAG_FOLDER);
-
- FolderParser folderParser = new FolderParser(getFolderElementsMap(partnerRes));
+ FolderParser folderParser = new FolderParser(getFolderElementsMap());
return folderParser.parseAndAdd(partnerParser);
}
}
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 004ed06..2b89321 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -20,8 +20,10 @@
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
@@ -127,6 +129,38 @@
assertEquals(2, info.spanY);
}
+ @Test
+ public void testCustomProfileLoaded_with_shortcut_on_hotseat() throws Exception {
+ assumeTrue(mTargetContext.getSystemService(LauncherApps.class).hasShortcutHostPermission());
+ writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0)
+ .putShortcut(TEST_PACKAGE, "shortcut2"));
+
+ // Verify one item in hotseat
+ assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
+ ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
+ assertEquals(LauncherSettings.Favorites.CONTAINER_HOTSEAT, info.container);
+ assertEquals(LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT, info.itemType);
+ }
+
+ @Test
+ public void testCustomProfileLoaded_with_shortcut_in_folder() throws Exception {
+ assumeTrue(mTargetContext.getSystemService(LauncherApps.class).hasShortcutHostPermission());
+ writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
+ .addApp(TEST_PACKAGE, TEST_ACTIVITY)
+ .addApp(TEST_PACKAGE, TEST_ACTIVITY)
+ .addShortcut(TEST_PACKAGE, "shortcut2")
+ .build());
+
+ // Verify folder
+ assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
+ FolderInfo info = (FolderInfo) mModelHelper.getBgDataModel().workspaceItems.get(0);
+ assertEquals(3, info.contents.size());
+
+ // Verify last icon
+ assertEquals(LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT,
+ info.contents.get(info.contents.size() - 1).itemType);
+ }
+
private void writeLayoutAndLoad(LauncherLayoutBuilder builder) throws Exception {
mModelHelper.setupDefaultLayoutProvider(builder).loadModelSync();
}
diff --git a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java b/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
index 4e21dce..ba01b04 100644
--- a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
+++ b/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
@@ -39,6 +39,7 @@
private static final String TAG_AUTO_INSTALL = "autoinstall";
private static final String TAG_FOLDER = "folder";
private static final String TAG_APPWIDGET = "appwidget";
+ private static final String TAG_SHORTCUT = "shortcut";
private static final String TAG_EXTRA = "extra";
private static final String ATTR_CONTAINER = "container";
@@ -49,6 +50,7 @@
private static final String ATTR_TITLE = "title";
private static final String ATTR_TITLE_TEXT = "titleText";
private static final String ATTR_SCREEN = "screen";
+ private static final String ATTR_SHORTCUT_ID = "shortcutId";
// x and y can be specified as negative integers, in which case -1 represents the
// last row / column, -2 represents the second last, and so on.
@@ -135,6 +137,13 @@
return LauncherLayoutBuilder.this;
}
+ public LauncherLayoutBuilder putShortcut(String packageName, String shortcutId) {
+ items.put(ATTR_PACKAGE_NAME, packageName);
+ items.put(ATTR_SHORTCUT_ID, shortcutId);
+ mNodes.add(Pair.create(TAG_SHORTCUT, items));
+ return LauncherLayoutBuilder.this;
+ }
+
public LauncherLayoutBuilder putWidget(String packageName, String className,
int spanX, int spanY) {
items.put(ATTR_PACKAGE_NAME, packageName);
@@ -175,6 +184,14 @@
return this;
}
+ public FolderBuilder addShortcut(String packageName, String shortcutId) {
+ HashMap<String, Object> items = new HashMap<>();
+ items.put(ATTR_PACKAGE_NAME, packageName);
+ items.put(ATTR_SHORTCUT_ID, shortcutId);
+ mChildren.add(Pair.create(TAG_SHORTCUT, items));
+ return this;
+ }
+
public LauncherLayoutBuilder build() {
return LauncherLayoutBuilder.this;
}