为了获取快捷方式,packageName和ID是Laucnher传递快捷方式的主要信息,而其载体则是Laucnher自己通过makeIntent创建的intent,详见上章最后。和7.0不同,快捷方式的信息有一半是保存在系统里,通过数据库是查阅不到快捷方式的实际地址。
下面看看快捷方式的信息是如何在Laucnher中转化成快捷方式图标的。
创建好intent后,来自intent的信息则放入了PendingInstallShortcutInfo中,随后将其放入创建列表。
public static void queueShortcut(ShortcutInfoCompat info, Context context) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
}
创建快捷方式,这里分为两步走,1:addToInstallQueue 2:flushInstallQueue 剩下的是判断是否创建快捷方式的流程,如果创建(也就是本流程的主要流程)。则走1、2两步
private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
// Queue the item up for adding if launcher has not loaded properly yet
LauncherAppState app = LauncherAppState.getInstance(context);
boolean launcherNotLoaded = app.getModel().getCallback() == null;
addToInstallQueue(Utilities.getPrefs(context), info);
if (!mUseInstallQueue && !launcherNotLoaded) {
flushInstallQueue(context);
}
}
第一步addToInstallQueue的工作是:将参数形成jSon包,放置到sharedPrefs的APPS_PENDING_INSTALL中。
本方法关注两个参数,一个是encoded 的内容,一个是关键词APPS_PENDING_INSTALL.
private static void addToInstallQueue(
SharedPreferences sharedPrefs, PendingInstallShortcutInfo info) {
synchronized(sLock) {
String encoded = info.encodeToString();
if (encoded != null) {
Set
strings = (strings != null) ? new HashSet<>(strings) : new HashSet
strings.add(encoded);
sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).apply();
}
}
}
Encoded的内容是PendingInstallShortcutInfo 的encodeToString生成的。从该方法中,创建快捷方式这一栏,是直接创建JSON,没有多余操作,创建的JSON中,涉及:
LAUNCH_INTENT_KEY:即shortcut生成的launchIntent,涉及外部传入参数activity、package和id。也就是,到目前为止,用于创建快捷方式的有用信息,仅此三个参数。
DEEPSHORTCUT_TYPE_KEY:一个boolean,用于确定是创建快捷方式
USER_HANDLE_KEY:暂不关注
生成的JSON
else if (shortcutInfo != null) {
// If it a launcher target, we only need component name, and user to
// recreate this.
return new JSONStringer()
.object()
.key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
.key(DEEPSHORTCUT_TYPE_KEY).value(true)
.key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
.getSerialNumberForUser(user))
.endObject().toString();
接下来是flushInstallQueue:其关键代码也是两个getAndClearInstallQueue和addAndBindAddedWorkspaceItems,是从installQueue中获取需要安装的快捷方式,然后放入workspace。
static void flushInstallQueue(Context context) {
ArrayList
if (!items.isEmpty()) {
LauncherAppState.getInstance(context).getModel().addAndBindAddedWorkspaceItems(
new LazyShortcutsProvider(context.getApplicationContext(), items));
}
}
getAndClearInstallQueue方法,从APPS_PENDING_INSTALL中获取之前生成的JSON参数,然后decode之后,获取PendingInstallShortcutInfo存入infos中。也就是,之前的PendingInstallShortcutInfo先生成JSON,再返还成PendingInstallShortcutInfo .
private static ArrayList
SharedPreferences sharedPrefs = Utilities.getPrefs(context);
synchronized(sLock) {
ArrayList
Set
if (strings == null) {
return infos;
}
for (String encoded : strings) {
PendingInstallShortcutInfo info = decode(encoded, context);
if (info != null) {
infos.add(info);
}
}
sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, new HashSet
return infos;
}
}
在decode中,关键是获取si这个ShortcutInfoCompat,是通过
DeepShortcutManager 的 queryForFullDetails方法,传入
launcherIntent的package和id以及自己生成的user。其中,package和id是源于外界传入的快捷方式信息。
} else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
List
decoder.launcherIntent.getPackage(),
Arrays.asList(decoder.launcherIntent.getStringExtra(
ShortcutInfoCompat.EXTRA_SHORTCUT_ID)),
decoder.user);
if (si.isEmpty()) {
return null;
} else {
return new PendingInstallShortcutInfo(si.get(0), context);
}
其核心是使用ShortcutQuery通过 packageName和 shortcutIds在手机中查找到 shortcutInfo对应的shortcutInfo值,这个值和一开始获取的shortcutInfo是一样的。他存放在手机中。
if (Utilities.ATLEAST_NOUGAT_MR1) {
ShortcutQuery q = new ShortcutQuery();
q.setQueryFlags(flags);
if (packageName != null) {
q.setPackage(packageName);
q.setActivity(activity);
q.setShortcutIds(shortcutIds);
}
List
try {
shortcutInfos = mLauncherApps.getShortcuts(q, user);
mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to query for shortcuts", e);
mWasLastCallSuccess = false;
}
if (shortcutInfos == null) {
return Collections.EMPTY_LIST;
}
List
for (ShortcutInfo shortcutInfo : shortcutInfos) {
shortcutInfoCompats.add(new ShortcutInfoCompat(shortcutInfo));
}
return shortcutInfoCompats;
} else {
return Collections.EMPTY_LIST;
}
}
总结,Launcher的快捷方式被用户确定需要创建是在第三方应用中,而实际创建则是回到桌面后再创建,所以会有一个放入Queue的过程,这个过程,在7.0中信息是保存在intent里,而8.0中,信息分为三部分,查询信息,系统中信息,基本信息。这三个信息分别放在不同的地方,三组信息都是必须的。
查询信息是用来查询系统中信息,且也是打开快捷方式的信息,最后用户在桌面点击快捷方式打开的时候,就是通过查询信息来确定打开哪个目标。
系统中信息,最主要的是icon信息。Icon信息是保存在手机里面,快捷方式使用什么图标,在绑定的时候,需要通过查询信息从系统中找。
基本信息,必须用的是快捷方式的名字,这个是伴随外界intent传入的。
在返回Launcher从Queue中创建快捷方式的时候,就需要查询一些信息也就是以上代码的功能。