该分析流程以Launcher菜单中设置壁纸为案例来进行,当前需求要求我们在应用选择器(即“选择壁纸来源”列表)中去除GMS包中的Photo应用。
那么这里的“选择壁纸来源”列表就是应用选择器,例如我们想要播放一段视频时,如果系统中安装了多个视频播放器,那么此时系统会列出系统中所安装的视频播放器以供我们选择自己所钟爱的一个。这是怎么实现的呢?我们想要播放一段视频的时候,会主动向系统发出请求,所有注册了该请求的应用均会去响应该请求。我们所看到的应用选择器其实是一个特殊Activity(ResolveActivity,官方对ResolveActivity的解释是,当系统存在多个匹配Intent请求的Activity时,该ResolveActivity会将这些匹配的多个Activity都显示出来让用户选择。),而Intent又是Android各组件交互的桥梁,那么我们将请求以Action的形式封装在Intent中,在我们startActivity时,PackageManagerService会从数据库中查找到所有在AndroidManifest.xml中已注册该Aciton的Activity,并提供给ResolveActivity进行显示。
首先来看下“设置壁纸”的函数,我们点击“壁纸”按钮进行壁纸的选择时,在Launcher应用的Launcher.java中调用了startWallpaper()函数,并在该函数中通过Intent.createChooser创建了一个带有选择器的Intent,如下:
private void startWallpaper() {//[Launcher.java]
enterEditMode(false);
showWorkspace(true);
final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
Intent chooser = Intent.createChooser(pickWallpaper, getText(R.string.chooser_wallpaper));
startActivityForResult(chooser, REQUEST_PICK_WALLPAPER);
}
那么上面有提到应用选择器中列出的应用都是由PMS从数据库查找到的对应的匹配项,那么如果想要在“选择壁纸来源”中屏蔽某个应用,只需要对PMS查找的匹配项进行二次处理即可,具体的实现如下:
private void rebuildList() {
try {
mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(
mIntent, mIntent.resolveTypeIfNeeded(getContentResolver()),
PackageManager.MATCH_DEFAULT_ONLY);
} catch (RemoteException re) {
Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
}
mList.clear();
if (mBaseResolveList != null) {
currentResolveList = mOrigResolveList = mBaseResolveList;
} else {
currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
mIntent, PackageManager.MATCH_DEFAULT_ONLY
| (mFilterLastUsed ? PackageManager.GET_RESOLVED_FILTER : 0));
// Filter out any activities that the launched uid does not
// have permission for. We don't do this when we have an explicit
// list of resolved activities, because that only happens when
// we are being subclassed, so we can safely launch whatever
// they gave us.
那么这里的“选择壁纸来源”列表就是应用选择器,例如我们想要播放一段视频时,如果系统中安装了多个视频播放器,那么此时系统会列出系统中所安装的视频播放器以供我们选择自己所钟爱的一个。这是怎么实现的呢?我们想要播放一段视频的时候,会主动向系统发出请求,所有注册了该请求的应用均会去响应该请求。我们所看到的应用选择器其实是一个特殊Activity(ResolveActivity,官方对ResolveActivity的解释是,当系统存在多个匹配Intent请求的Activity时,该ResolveActivity会将这些匹配的多个Activity都显示出来让用户选择。),而Intent又是Android各组件交互的桥梁,那么我们将请求以Action的形式封装在Intent中,在我们startActivity时,PackageManagerService会从数据库中查找到所有在AndroidManifest.xml中已注册该Aciton的Activity,并提供给ResolveActivity进行显示。
首先来看下“设置壁纸”的函数,我们点击“壁纸”按钮进行壁纸的选择时,在Launcher应用的Launcher.java中调用了startWallpaper()函数,并在该函数中通过Intent.createChooser创建了一个带有选择器的Intent,如下:
private void startWallpaper() {//[Launcher.java]
enterEditMode(false);
showWorkspace(true);
final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
Intent chooser = Intent.createChooser(pickWallpaper, getText(R.string.chooser_wallpaper));
startActivityForResult(chooser, REQUEST_PICK_WALLPAPER);
}
那么上面有提到应用选择器中列出的应用都是由PMS从数据库查找到的对应的匹配项,那么如果想要在“选择壁纸来源”中屏蔽某个应用,只需要对PMS查找的匹配项进行二次处理即可,具体的实现如下:
private void rebuildList() {
try {
mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(
mIntent, mIntent.resolveTypeIfNeeded(getContentResolver()),
PackageManager.MATCH_DEFAULT_ONLY);
} catch (RemoteException re) {
Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
}
mList.clear();
if (mBaseResolveList != null) {
currentResolveList = mOrigResolveList = mBaseResolveList;
} else {
currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
mIntent, PackageManager.MATCH_DEFAULT_ONLY
| (mFilterLastUsed ? PackageManager.GET_RESOLVED_FILTER : 0));
// Filter out any activities that the launched uid does not
// have permission for. We don't do this when we have an explicit
// list of resolved activities, because that only happens when
// we are being subclassed, so we can safely launch whatever
// they gave us.
//如果Action请求为设置壁纸,且匹配相中包含GMS应用photo,就从匹配列表中移除对应项。
if(mIntent.getAction().equals("android.intent.action.SET_WALLPAPER")){
int size=currentResolveList.size();
int index=-1;
android.util.Log.d("test","size-->"+size);
for (int i = 0; i <size; i++) {
int size=currentResolveList.size();
int index=-1;
android.util.Log.d("test","size-->"+size);
for (int i = 0; i <size; i++) {
ResolveInfo ri = currentResolveList.get(i);
android.util.Log.d("test","ri--->"+ri.toString());
ActivityInfo ai = ri.activityInfo;
android.util.Log.d("test","ai-->"+ai.toString()+";");
boolean hasPac = ai.packageName.equals("com.google.android.apps.photos");
android.util.Log.d("test","hasPac is "+hasPac+"; ");
if (hasPac) {
index=i;
}
}
currentResolveList.remove(index);
}
android.util.Log.d("test","ai-->"+ai.toString()+";");
boolean hasPac = ai.packageName.equals("com.google.android.apps.photos");
android.util.Log.d("test","hasPac is "+hasPac+"; ");
if (hasPac) {
index=i;
}
}
currentResolveList.remove(index);
}
if (currentResolveList != null) {
for (int i=currentResolveList.size()-1; i >= 0; i--) {
ActivityInfo ai = currentResolveList.get(i).activityInfo;
int granted = ActivityManager.checkComponentPermission(
ai.permission, mLaunchedFromUid,
ai.applicationInfo.uid, ai.exported);
if (granted != PackageManager.PERMISSION_GRANTED) {
// Access not allowed!
if (mOrigResolveList == currentResolveList) {
mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
}
currentResolveList.remove(i);
}
}
}
}
int N;
......
}
for (int i=currentResolveList.size()-1; i >= 0; i--) {
ActivityInfo ai = currentResolveList.get(i).activityInfo;
int granted = ActivityManager.checkComponentPermission(
ai.permission, mLaunchedFromUid,
ai.applicationInfo.uid, ai.exported);
if (granted != PackageManager.PERMISSION_GRANTED) {
// Access not allowed!
if (mOrigResolveList == currentResolveList) {
mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
}
currentResolveList.remove(i);
}
}
}
}
int N;
......
}