Merge "Removing support for legacy shortcuts from default layouts" into udc-dev am: 8382546a11

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/22351739

Change-Id: I58e70b7f4beb76b5e096c71b465ca70972b797b7
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Sunny Goyal
2023-04-05 23:20:26 +00:00
committed by Automerger Merge Worker
4 changed files with 87 additions and 136 deletions
@@ -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<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 @@ 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));
}
}
}
@@ -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<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 @@ 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 <favorite> 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);
}
}
@@ -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();
}
@@ -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<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;
}