【学以致用】android功能实现6---android8.0 Launcher获取快捷方式源码分析(2)

为了获取快捷方式,packageNameIDLaucnher传递快捷方式的主要信息,而其载体则是Laucnher自己通过makeIntent创建的intent,详见上章最后。和7.0不同,快捷方式的信息有一半是保存在系统里,通过数据库是查阅不到快捷方式的实际地址。

下面看看快捷方式的信息是如何在Laucnher中转化成快捷方式图标的。

创建好intent后,来自intent的信息则放入了PendingInstallShortcutInfo中,随后将其放入创建列表。

 

public static void queueShortcut(ShortcutInfoCompat info, Context context) {
    queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
}

 

创建快捷方式,这里分为两步走,1addToInstallQueue 2flushInstallQueue 剩下的是判断是否创建快捷方式的流程,如果创建(也就是本流程的主要流程)。则走12两步

 

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包,放置到sharedPrefsAPPS_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 = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
            strings = (strings != null) ? new HashSet<>(strings) : new HashSet(1);
            strings.add(encoded);
            sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).apply();
        }
    }
}

 

Encoded的内容是PendingInstallShortcutInfo encodeToString生成的。从该方法中,创建快捷方式这一栏,是直接创建JSON,没有多余操作,创建的JSON中,涉及

 

LAUNCH_INTENT_KEY:即shortcut生成的launchIntent,涉及外部传入参数activitypackageid。也就是,到目前为止,用于创建快捷方式的有用信息,仅此三个参数。

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:其关键代码也是两个getAndClearInstallQueueaddAndBindAddedWorkspaceItems,是从installQueue中获取需要安装的快捷方式,然后放入workspace

static void flushInstallQueue(Context context) {
    ArrayList items = getAndClearInstallQueue(context);
    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 getAndClearInstallQueue(Context context) {
    SharedPreferences sharedPrefs = Utilities.getPrefs(context);
    synchronized(sLock) {
        ArrayList infos = new ArrayList<>();
        Set strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
         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()).apply();
        return infos;
    }
}

 

decode中,关键是获取si这个ShortcutInfoCompat,是通过

   DeepShortcutManager  queryForFullDetails方法,传入

launcherIntentpackageid以及自己生成的user。其中,packageid是源于外界传入的快捷方式信息。

 

} else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
    DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
    List si = sm.queryForFullDetails(
            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 shortcutInfos = null;
        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 shortcutInfoCompats = new ArrayList<>(shortcutInfos.size());
        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传入的。

在返回LauncherQueue中创建快捷方式的时候,就需要查询一些信息也就是以上代码的功能。

 

 

 

你可能感兴趣的:(学以致用)