diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index 27c41c2fcd..2083726a05 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -24,30 +24,29 @@ import android.content.Context; 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.XmlPullParser; 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 @@ public class AutoInstallsLayout { 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 @@ public class AutoInstallsLayout { 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 @@ public class AutoInstallsLayout { 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 @@ public class AutoInstallsLayout { 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 @@ public class AutoInstallsLayout { ArrayMap 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 @@ public class AutoInstallsLayout { 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 @@ public class AutoInstallsLayout { } /** - * 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 @@ public class AutoInstallsLayout { 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 c69ae4dac8..c748693f9b 100644 --- a/src/com/android/launcher3/DefaultLayoutParser.java +++ b/src/com/android/launcher3/DefaultLayoutParser.java @@ -6,19 +6,15 @@ import android.content.Context; 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 org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.net.URISyntaxException; -import java.util.Collections; import java.util.List; /** @@ -49,8 +44,6 @@ public class DefaultLayoutParser extends AutoInstallsLayout { 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 @@ public class DefaultLayoutParser extends AutoInstallsLayout { @Override protected ArrayMap getFolderElementsMap() { - return getFolderElementsMap(mSourceRes); - } - - @Thunk - ArrayMap getFolderElementsMap(Resources res) { ArrayMap 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 @@ public class DefaultLayoutParser extends AutoInstallsLayout { 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()); @@ -189,57 +177,6 @@ public class DefaultLayoutParser extends AutoInstallsLayout { } } - /** - * 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 nodes, and accepts the first successfully parsed node. */ @@ -284,11 +221,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout { 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 004ed06b32..2b893211dc 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_ACTIVITY; 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 @@ public class DefaultLayoutProviderTest { 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 4e21dce021..ba01b043e7 100644 --- a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java +++ b/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java @@ -39,6 +39,7 @@ public class LauncherLayoutBuilder { 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 @@ public class LauncherLayoutBuilder { 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 @@ public class LauncherLayoutBuilder { 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 @@ public class LauncherLayoutBuilder { return this; } + public FolderBuilder addShortcut(String packageName, String shortcutId) { + HashMap 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; }