Loading src/com/android/launcher3/AutoInstallsLayout.java +33 −68 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading @@ -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"; Loading @@ -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; Loading Loading @@ -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; Loading @@ -321,7 +326,7 @@ public class AutoInstallsLayout { 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; } Loading @@ -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; } Loading Loading @@ -420,60 +425,28 @@ 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); if (titleResId == 0 || iconId == 0) { if (LOGD) Log.d(TAG, "Ignoring shortcut"); return -1; } final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); final String shortcutId = getAttributeValue(parser, ATTR_SHORTCUT_ID); final Intent intent = parseIntent(parser); if (intent == null) { 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); } 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)); } } /** Loading Loading @@ -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)); } } } src/com/android/launcher3/DefaultLayoutParser.java +4 −69 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; /** Loading @@ -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"; Loading @@ -66,14 +59,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout { @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; } Loading @@ -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()); Loading Loading @@ -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 <favorite> nodes, and accepts the first successfully parsed node. */ Loading Loading @@ -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); } } Loading tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java +17 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -175,6 +184,14 @@ public class LauncherLayoutBuilder { 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; } Loading Loading
src/com/android/launcher3/AutoInstallsLayout.java +33 −68 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading @@ -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"; Loading @@ -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; Loading Loading @@ -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; Loading @@ -321,7 +326,7 @@ public class AutoInstallsLayout { 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; } Loading @@ -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; } Loading Loading @@ -420,60 +425,28 @@ 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); if (titleResId == 0 || iconId == 0) { if (LOGD) Log.d(TAG, "Ignoring shortcut"); return -1; } final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); final String shortcutId = getAttributeValue(parser, ATTR_SHORTCUT_ID); final Intent intent = parseIntent(parser); if (intent == null) { 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); } 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)); } } /** Loading Loading @@ -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)); } } }
src/com/android/launcher3/DefaultLayoutParser.java +4 −69 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; /** Loading @@ -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"; Loading @@ -66,14 +59,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout { @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; } Loading @@ -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()); Loading Loading @@ -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 <favorite> nodes, and accepts the first successfully parsed node. */ Loading Loading @@ -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); } } Loading
tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading
tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java +17 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -175,6 +184,14 @@ public class LauncherLayoutBuilder { 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; } Loading