Android 7.1 允许 App 自定义 Shortcuts,类似 iOS 的 3D touch。通过在桌面长按 App 弹出 Shortcut 列表,点击某个 Shortcut 快速进入某项操作,同时 Shortcut 可以拖动到桌面进行固定。
目前仅 7.1 系统桌面支持该特性,三方桌面需要通过LauncherApps
这个 API 支持此功能,本文主要介绍三方桌面如何接入此特性。
可以下载ShortcutViewer
查看效果:Google Play,应用宝。截图如下:
关于 Shortcuts 的全面介绍可见:
第一篇:Android 7.1 新特性 Shortcuts 介绍
第二篇:Android 7.1 新特性 Shortcuts 一些实践和目前的问题
如果不了解 Shortcuts 基本使用建议先看上面第一篇。
1. Manifest 支持 Home category
在 AndroidManifest.xml 的 Main Launcher 对应的 Activity 内添加android.intent.category.HOME
这个 category,表示此应用为桌面,如下:
1 2 3 4 5 6 7 8 9 10 11 |
<application ……> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.HOME" /> </intent-filter> </activity> </application> |
必须在 Main Launcher 对应的 Activity 内设置,其中android.intent.category.HOME
表示这是个桌面程序。
2. 设置为默认桌面
Android SDK LauncherApps
API 要求必须是默认桌面才有权限获取到所有应用 Shortcuts 信息。
按 Home 键退到后台会提示是否将此应用设置为桌面,选择”始终”(某些手机可能是默认)。
或者通过设置-应用-配置应用-主屏幕应用
,选择自己的应用作为默认桌面。
3. 获取各个 App 的所有 Shortcuts 信息
通过LauncherApps.getShortcuts
获取各 App Shortcuts 信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); if (!launcherApps.hasShortcutHostPermission()) { // Don't have permission, you may need set this app as default desktop. return; } PackageManager packageManager = context.getPackageManager(); Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> resolveInfoList; if (packageManager == null || CollectionUtils .isEmpty(resolveInfoList = packageManager.queryIntentActivities(mainIntent, 0))) { // No Main&Launcher Activity return; } // Get ShortcutInfo for every app Set<String> packageNameSet = new HashSet<>(); for (ResolveInfo info : resolveInfoList) { ApplicationInfo applicationInfo; if (info == null || info.activityInfo == null || (applicationInfo = info.activityInfo.applicationInfo) == null || !applicationInfo.enabled || packageNameSet.contains(applicationInfo.packageName)) { continue; } packageNameSet.add(applicationInfo.packageName); int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED; List<ShortcutInfo> shortcutInfoList = launcherApps.getShortcuts( new ShortcutQuery().setPackage(applicationInfo.packageName).setQueryFlags(queryFlags), UserHandle.getUserHandleForUid(applicationInfo.uid)); …… } |
上面主要步骤包括:
(1) 通过LauncherApps.hasShortcutHostPermission()
判断是否拥有获取 shortcuts 信息的权限;
(2) 通过PackageManager.queryIntentActivities(…)
得到所有已安装应用,并且含有 ACTION_MAIN&CATEGORY_LAUNCHER Intent 的ResolveInfo
;
(3) 遍历每个符合条件的ResolveInfo
,通过LauncherApps.getShortcuts(…)
得到其 shortcuts 信息。
注意:这里也可以通过其他方式得到所有适合在桌面显示的ApplicationInfo
,而通过PackageManager.queryIntentActivities(…)
是性能最优的方式。
1 2 3 4 5 |
int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED; List<ShortcutInfo> shortcutInfoList = launcherApps.getShortcuts( new ShortcutQuery().setPackage(applicationInfo.packageName).setQueryFlags(queryFlags), UserHandle.getUserHandleForUid(applicationInfo.uid)); |
LauncherApps.getShortcuts(LauncherApps.ShortcutQuery query, UserHandle user)
的两个参数分别表示查询条件和查询的 App 对应的 UserHandle。
上面queryFlags
表示同时匹配动态 Shortcuts、静态 Shortcuts、固定的 Shortcuts。
当然这个特性仅对 Android SDK 7.1 及以上才有效,所以最好先判断下系统 API 版本才开始调用LauncherApps
相关 API。
Hello,
“Product” might be an oversight. You could quickly confirm using spellreport.com, or another spelling tool.
Best regards,
Ricardo Barry
I was looking at your website and noticed it appears the word “canot” is spelled wrong. I had similar problems on my site until someone mentioned it to me and I also now use software from SpellPerfect.com to keep my site error free.
It looks like you have a couple spelling errors on your website such as the word “canot”. Check out a service like SpellAce.com to help. We’ve used it in the past and liked it.
Greetings,
I’m not the best speller but I see the word “canot” is spelled incorrectly on your website. In the past I’ve used a service like SpellAlerts.com or SiteChecker.com to help keep mistakes off of my websites.
-Brenda
Your site looks great but I did notice that the word “canot” appears to be spelled incorrectly. I saw a couple small issues like this. I thought you would like to know!
In case you wanted to fix it, in the past we’ve used services from a websites like HelloSpell.com to keep our site error-free.
It looks like you’ve misspelled the word “canot” on your website. I thought you would like to know
. Silly mistakes can ruin your site’s credibility. I’ve used a tool called SpellScan.com in the past to keep mistakes off of my website.
-Kerri
Java
LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
if (!launcherApps.hasShortcutHostPermission()) {
// Don’t have permission, you may need set this app as default desktop.
return;
}
PackageManager packageManager = context.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List resolveInfoList;
if (packageManager == null || CollectionUtils
.isEmpty(resolveInfoList = packageManager.queryIntentActivities(mainIntent, 0))) {
// No Main&Launcher Activity
return;
}
// Get ShortcutInfo for every app
Set packageNameSet = new HashSet();
for (ResolveInfo info : resolveInfoList) {
ApplicationInfo applicationInfo;
if (info == null || info.activityInfo == null
|| (applicationInfo = info.activityInfo.applicationInfo) == null || !applicationInfo.enabled
|| packageNameSet.contains(applicationInfo.packageName)) {
continue;
}
packageNameSet.add(applicationInfo.packageName);
int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_MANIFEST
| ShortcutQuery.FLAG_MATCH_PINNED;
List shortcutInfoList = launcherApps.getShortcuts(
new ShortcutQuery().setPackage(applicationInfo.packageName).setQueryFlags(queryFlags),
UserHandle.getUserHandleForUid(applicationInfo.uid));
……
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
if (!launcherApps.hasShortcutHostPermission()) {
// Don’t have permission, you may need set this app as default desktop.
return;
}
PackageManager packageManager = context.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List resolveInfoList;
if (packageManager == null || CollectionUtils
.isEmpty(resolveInfoList = packageManager.queryIntentActivities(mainIntent, 0))) {
// No Main&Launcher Activity
return;
}
// Get ShortcutInfo for every app
Set packageNameSet = new HashSet();
for (ResolveInfo info : resolveInfoList) {
ApplicationInfo applicationInfo;
if (info == null || info.activityInfo == null
|| (applicationInfo = info.activityInfo.applicationInfo) == null || !applicationInfo.enabled
|| packageNameSet.contains(applicationInfo.packageName)) {
continue;
}
packageNameSet.add(applicationInfo.packageName);
int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_MANIFEST
| ShortcutQuery.FLAG_MATCH_PINNED;
List shortcutInfoList = launcherApps.getShortcuts(
new ShortcutQuery().setPackage(applicationInfo.packageName).setQueryFlags(queryFlags),
UserHandle.getUserHandleForUid(applicationInfo.uid));
……
}