Android奇技淫巧:隐藏APP图标

背景

最近碰到个需求,需要在桌面隐藏APP的图标。

介绍

我在网上查查了,发现有几种方式

  1. AndroidManifest.xml文件中在入口Activity的intent-filter里去掉category android:name=”android.intent.category.LAUNCHER或者将LAUNCHER改为DEFAULT
  2. 在程序中加入下面的代码
    PackageManager p = getPackageManager();
    p.setComponentEnabledSetting(getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
  3. 去掉android:icon=”@drawable/ic_launcher”中的资源啊

然而试了之后,发现这几种方法并没有什么卵用,会带来启动不了程序,程序无法正常使用的问题~~

最后发现了一种完美解决方法

在manifest的入口activity里面intent-filter中设置data

1
<data android:host=”ruijun.com” android:scheme=”http” />

原理

研究过Launcher的童鞋应该都知道LoaderTask.loadAllAppsByBatch有那么一段

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
private class LoaderTask implements Runnable {
......

private void loadAllAppsByBatch() {
......

// 此处是关键代码
// 设置Intent的action为ACTION_MAIN,category为CATEGORY_LAUNCHER
// 这样就过滤出桌面上显示的启动项了
// 注意这里是没有匹配data的
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

final PackageManager packageManager = mContext.getPackageManager();
List<ResolveInfo> apps = null;

int N = Integer.MAX_VALUE;

int startIndex;
int i=0;
int batchSize = -1;
while (i < N && !mStopped) {
if (i == 0) {
mAllAppsList.clear();
......
// 查询得到结果
apps = packageManager.queryIntentActivities(mainIntent, 0);

......

Collections.sort(apps,
new ResolveInfo.DisplayNameComparator(packageManager));
}

startIndex = i;
for (int j=0; i<N && j<batchSize; j++) {
// This builds the icon bitmaps.
mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache));
i++;
}

final boolean first = i <= batchSize;
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
final ArrayList<ApplicationInfo> added = mAllAppsList.added;
mAllAppsList.added = new ArrayList<ApplicationInfo>();

mHandler.post(new Runnable() {
public void run() {
final long t = SystemClock.uptimeMillis();
if (callbacks != null) {
if (first) {
callbacks.bindAllApplications(added);
} else {
callbacks.bindAppsAdded(added);
}
......
} else {
......
}
}
});

......
}

......
}

......
}

因为入口Activity加入了data,这里只是匹配了Action,Category。所以就匹配不了该Activity了,下面的apps就不含这个该Activity的信息。

Launcher还有那么一段:Launcher.bindAllApplications

1
2
3
4
5
6
7
8
9
10
/**
* A package was installed.
*
* Implementation of the method from LauncherModel.Callbacks.
*/

public void bindAppsAdded(ArrayList<ApplicationInfo> apps) {
setLoadOnResume();
removeDialog(DIALOG_CREATE_SHORTCUT);
mAllAppsGrid.addApps(apps);
}

由于满足不了上面的过滤匹配条件,mAllAppsGrid.setApps(apps)apps中不含有该入口Activity,桌面也就看不到我们的APP图标了。

参考

关于Launcher分析,可以看下这几篇文章
Android系统默认Home应用程序(Launcher)的启动过程源代码分析
Android M Launcher3主流程源码浅析
Android 4.0 Launcher2源码分析——Launcher内容加载详细过程