Android偏好设置及findPreferredActivity分析

时间:2022-11-28 05:33:27
在手机使用中,经常需要设置默认打开方式,比如安装了好几个浏览器的时候,在打开网页链接的时候,在第一次会弹框让用户进行应用的选择。
这里以浏览器为例进行说明。 如果之前设置了默认浏览器,再安装另外一个浏览器后,再次打开链接,会重新弹框要求用户选择打开方式,这样设计的目的是让新安装的应用有机会得到用户的选择使用。
在之前的文章中,已经知道了存储偏好设置的文件是package-restrictions.xml 现在来查看下package-restrictions.xml,把UC设置为默认浏览器 package-restrictions.xml         <item name="com.UCMobile/.main.UCMobile" match="200000" always="true" set="2">            <set name="com.UCMobile/.main.UCMobile" />            <set name="com.android.browser/.BrowserActivity" />            <filter>                <action name="android.intent.action.VIEW" />                <cat name="android.intent.category.DEFAULT" />                <scheme name="http" />            </filter>        </item>
安装另外一个浏览器后,调用到findPreferredActivity                             if (always && !pa.mPref.sameSet(query)) {
                                Slog.d(TAG, "===== pa.mPref.Set =" + pa.mPref.mSetPackages);                                for (String astr : pa.mPref.mSetPackages)                                {                                        Slog.d(TAG, "set[]=" + astr);                                }
                                Slog.i(TAG, "Result set changed, dropping preferred activity for "                                        + intent + " type " + resolvedType);                                if (DEBUG_PREFERRED) {                                    Slog.v(TAG, "Removing preferred activity since set changed "                                            + pa.mPref.mComponent);                                }
pa.mPref.mSetPackages 为package-restrictions.xml里set的内容,如             <set name="com.UCMobile/.main.UCMobile" />            <set name="com.android.browser/.BrowserActivity" />
query为实时从pms里查询得到的满足条件的activity相关信息
当发现两个数据不一致的时候,就认为系统里的ap发生了变化,走到 Slog.i(TAG, "Result set changed, dropping preferred activity for "                                        + intent + " type " + resolvedType);删除掉之前的默认设置。然后由ResolverActivity去处理,显示选择界面
基本处理流程是 点击url网络连接 -> findPreferredActivity, 查看是否有默认打开方式 如果有,直接打开 如果没有,ResolverActivity去处理,显示选择界面,这个时候,选择“总是”(always),ResolverActivity调用 pm.addPreferredActivity(filter, bestMatch, set, intent.getComponent());
去重新设置偏好。
可参考下图Android偏好设置及findPreferredActivity分析



值得注意的是,ResolverActivity里对activity的priority进行了处理,如果一个ap注册的时候,把intent-filter里的priority写为了负数,如下所示<intent-filter android:priority="-1" >  <category android:name="android.intent.category.DEFAULT" /> <action android:name="android.intent.action.VIEW" />  <data android:scheme="http" />


那么,在选择默认浏览器的时候,就不会显示出这个应用。因为在private void rebuildList() 里有这样的处理        for (int i=1; i<N; i++) {                    ResolveInfo ri = currentResolveList.get(i);                    if (DEBUG) Log.v(                        TAG,                        r0.activityInfo.name + "=" +                        r0.priority + "/" + r0.isDefault + " vs " +                        ri.activityInfo.name + "=" +                        ri.priority + "/" + ri.isDefault);                    if (r0.priority != ri.priority ||                        r0.isDefault != ri.isDefault) {                        while (i < N) {                            if (mOrigResolveList == currentResolveList) {                                mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);                            }                            currentResolveList.remove(i);

导致priority为负数的不会显示出来。
了解了这些,就可以去分析这个问题http://www.zhihu.com/question/27313953/answer/36308142

在6.0的版本上,对priority的处理有些变化,比如对于自定义的ap  Test,priority设置为大于0的数<intent-filter android:priority="3" >  <category android:name="android.intent.category.DEFAULT" /> <action android:name="android.intent.action.VIEW" />  <data android:scheme="http" />
之前手机上安装了3个浏览器(priority都为0的),其中UC设置为了默认浏览器,再安装Test,接着打开网络链接,会弹出选择界面,在L版本上会列出所有的浏览器,M上呢?
答案是只显示出UC和Test因为M里的做了些修改,查看PackageManagerService.java的queryIntentActivities可以很容易的找到

package-restrictions.xml        <item name="com.UCMobile/.main.UCMobile" match="200000" always="true" set="2">            <set name="com.UCMobile/.main.UCMobile" />            <set name="com.android.browser/.BrowserActivity" />            <filter>                <action name="android.intent.action.VIEW" />                <cat name="android.intent.category.DEFAULT" />                <scheme name="http" />            </filter>        </item>里match的来源这个查看过程非常复杂,这里直接说下结果,是IntentFilter.java里的matchData方法

附相关log,注意,pms里的DEBUG_PREFERRED开关需要打开

05-01 08:53:56.290: D/PackageManager(918): ===== findPreferredActivity called05-01 08:53:56.290: D/PackageManager(918): ===== begin =====05-01 08:53:56.290: D/PackageManager(918): com.android.server.pm.PackageManagerService.findPreferredActivity(PackageManagerService.java:3575)05-01 08:53:56.290: D/PackageManager(918): com.android.server.pm.PackageManagerService.chooseBestActivity(PackageManagerService.java:3494)05-01 08:53:56.290: D/PackageManager(918): com.android.server.pm.PackageManagerService.resolveIntent(PackageManagerService.java:3432)05-01 08:53:56.290: D/PackageManager(918): android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:507)05-01 08:53:56.290: D/PackageManager(918): com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:2264)05-01 08:53:56.290: D/PackageManager(918): android.os.Binder.execTransact(Binder.java:451)05-01 08:53:56.290: V/PackageManager(918): Looking for presistent preferred activities...05-01 08:53:56.290: V/PackageManager(918): Looking for preferred activities...05-01 08:53:56.290: D/IntentResolver(918): ===== queryIntent called05-01 08:53:56.290: V/IntentResolver(918): Resolving type=null scheme=http defaultOnly=true userId=0 of Intent { act=android.intent.action.VIEW dat=http://wap.uc.cn flg=0x8 }05-01 08:53:56.290: V/IntentResolver(918): Scheme list: [PreferredActivity{0x43bb27d com.UCMobile/.main.UCMobile}, null]05-01 08:53:56.290: D/IntentResolver(918): ===== buildResolveList called05-01 08:53:56.291: D/IntentResolver(918): ===== begin =====05-01 08:53:56.291: D/IntentResolver(918): com.android.server.IntentResolver.buildResolveList(IntentResolver.java:677)05-01 08:53:56.291: D/IntentResolver(918): com.android.server.IntentResolver.queryIntent(IntentResolver.java:458)05-01 08:53:56.291: D/IntentResolver(918): com.android.server.pm.PackageManagerService.findPreferredActivity(PackageManagerService.java:3597)05-01 08:53:56.291: D/IntentResolver(918): com.android.server.pm.PackageManagerService.chooseBestActivity(PackageManagerService.java:3494)05-01 08:53:56.291: D/IntentResolver(918): com.android.server.pm.PackageManagerService.resolveIntent(PackageManagerService.java:3432)05-01 08:53:56.291: D/IntentResolver(918): android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:507)05-01 08:53:56.291: D/IntentResolver(918): com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:2264)05-01 08:53:56.291: D/IntentResolver(918): android.os.Binder.execTransact(Binder.java:451)05-01 08:53:56.291: V/IntentResolver(918): Matching against filter PreferredActivity{0x43bb27d com.UCMobile/.main.UCMobile}05-01 08:53:56.291: D/IntentFilter(918): ===== matchData called05-01 08:53:56.291: D/IntentFilter(918): ===== match=20000005-01 08:53:56.291: V/IntentResolver(918):   Filter matched!  match=0x208000 hasDefault=true05-01 08:53:56.291: V/IntentResolver(918):     43bb27d com.UCMobile/.main.UCMobile05-01 08:53:56.292: V/IntentResolver(918):      mMatch=0x200000 mAlways=true05-01 08:53:56.292: V/IntentResolver(918):       Selected from:05-01 08:53:56.292: V/IntentResolver(918):         com.UCMobile/.main.UCMobile05-01 08:53:56.292: V/IntentResolver(918):         com.android.browser/.BrowserActivity05-01 08:53:56.292: V/IntentResolver(918):     Action: "android.intent.action.VIEW"05-01 08:53:56.292: V/IntentResolver(918):     Category: "android.intent.category.DEFAULT"05-01 08:53:56.292: V/IntentResolver(918):     Scheme: "http"05-01 08:53:56.292: V/IntentResolver(918): Final result list:05-01 08:53:56.292: V/IntentResolver(918):   PreferredActivity{0x43bb27d com.UCMobile/.main.UCMobile}05-01 08:53:56.292: V/PackageManager(918): Figuring out best match...05-01 08:53:56.292: V/PackageManager(918): Match for ActivityInfo{21f95286 com.android.browser.BrowserActivity}: 0x005-01 08:53:56.292: V/PackageManager(918): Match for ActivityInfo{7f12747 com.UCMobile.main.UCMobile}: 0x20800005-01 08:53:56.292: V/PackageManager(918): Match for ActivityInfo{38f8b74 com.taobao.browser.BrowserActivity}: 0x20800005-01 08:53:56.292: D/PackageManager(918): ===== query list is:05-01 08:53:56.292: D/PackageManager(918): ===== ResolveInfo{2e13ff6b com.android.browser/.BrowserActivity m=0x208000}05-01 08:53:56.292: D/PackageManager(918): ===== ResolveInfo{2e188ac8 com.UCMobile/.main.UCMobile m=0x208000}05-01 08:53:56.292: D/ResolveInfo(918): tos ===== priority=-105-01 08:53:56.292: D/PackageManager(918): ===== ResolveInfo{396c3761 com.taobao.taobao/com.taobao.browser.BrowserActivity p=-1 m=0x208000}05-01 08:53:56.292: V/PackageManager(918): Best match: 0x20800005-01 08:53:56.292: V/PackageManager(918): Checking PreferredActivity ds=http05-01 08:53:56.292: V/PackageManager(918):   component=ComponentInfo{com.UCMobile/com.UCMobile.main.UCMobile}05-01 08:53:56.292: V/PackageManager(918):   Action: "android.intent.action.VIEW"05-01 08:53:56.292: V/PackageManager(918):   Category: "android.intent.category.DEFAULT"05-01 08:53:56.292: V/PackageManager(918):   Scheme: "http"05-01 08:53:56.292: V/PackageManager(918): Found preferred activity:05-01 08:53:56.292: V/PackageManager(918):   name=com.UCMobile.main.UCMobile05-01 08:53:56.292: V/PackageManager(918):   packageName=com.UCMobile05-01 08:53:56.292: V/PackageManager(918):   labelRes=0x7f070004 nonLocalizedLabel=null icon=0x0 banner=0x005-01 08:53:56.292: V/PackageManager(918):   enabled=true exported=true processName=com.UCMobile05-01 08:53:56.292: V/PackageManager(918):   taskAffinity=com.UCMobile targetActivity=null persistableMode=PERSIST_ROOT_ONLY05-01 08:53:56.292: V/PackageManager(918):   launchMode=2 flags=0x8a theme=0x103000f05-01 08:53:56.292: V/PackageManager(918):   screenOrientation=-1 configChanges=0x400004a3 softInputMode=0x2005-01 08:53:56.292: V/PackageManager(918):   ApplicationInfo:05-01 08:53:56.292: V/PackageManager(918):     packageName=com.UCMobile05-01 08:53:56.292: V/PackageManager(918):     labelRes=0x7f070004 nonLocalizedLabel=null icon=0x7f020089 banner=0x005-01 08:53:56.292: V/PackageManager(918):     className=com.uc.browser.UCMobileApp05-01 08:53:56.292: V/PackageManager(918):     processName=com.UCMobile05-01 08:53:56.292: V/PackageManager(918):     taskAffinity=com.UCMobile05-01 08:53:56.292: V/PackageManager(918):     uid=10073 flags=0x883e44 theme=0x0 flagsEx=0x005-01 08:53:56.292: V/PackageManager(918):     requiresSmallestWidthDp=0 compatibleWidthLimitDp=0 largestWidthLimitDp=005-01 08:53:56.292: V/PackageManager(918):     sourceDir=/data/app/com.UCMobile-1/base.apk05-01 08:53:56.292: V/PackageManager(918):     seinfo=default05-01 08:53:56.292: V/PackageManager(918):     dataDir=/data/data/com.UCMobile05-01 08:53:56.292: V/PackageManager(918):     enabled=true targetSdkVersion=23 versionCode=64805-01 08:53:56.292: V/PackageManager(918):     manageSpaceActivityName=com.uc.application.cleaner.SystemManageData.ManageDataActivity05-01 08:53:56.292: V/PackageManager(918):     supportsRtl=false05-01 08:53:56.292: D/PackageManager(918): ===== pa.mPref.Set =[Ljava.lang.String;@1053e89d, always=true05-01 08:53:56.292: D/PackageManager(918): set[]=com.UCMobile05-01 08:53:56.292: D/PackageManager(918): set[]=com.android.browser05-01 08:53:56.292: D/PackageManager(918): ===== pa.mPref.Set =[Ljava.lang.String;@1053e89d05-01 08:53:56.292: D/PackageManager(918): set[]=com.UCMobile05-01 08:53:56.293: D/PackageManager(918): set[]=com.android.browser05-01 08:53:56.293: I/PackageManager(918): Result set changed, dropping preferred activity for Intent { act=android.intent.action.VIEW dat=http://wap.uc.cn flg=0x8 } type null05-01 08:53:56.293: V/PackageManager(918): Removing preferred activity since set changed ComponentInfo{com.UCMobile/com.UCMobile.main.UCMobile}05-01 08:53:56.293: V/IntentResolver(918): Removing filter: PreferredActivity{0x43bb27d com.UCMobile/.main.UCMobile}05-01 08:53:56.293: V/IntentResolver(918):       Action: "android.intent.action.VIEW"05-01 08:53:56.293: V/IntentResolver(918):       Category: "android.intent.category.DEFAULT"05-01 08:53:56.293: V/IntentResolver(918):       Scheme: "http"05-01 08:53:56.293: V/IntentResolver(918):     Cleaning Lookup Maps:05-01 08:53:56.293: V/IntentResolver(918):       Scheme: http05-01 08:53:56.293: V/IntentResolver(918): Adding filter: PreferredActivity{0xb081112 com.UCMobile/.main.UCMobile}05-01 08:53:56.293: V/IntentResolver(918):       Action: "android.intent.action.VIEW"05-01 08:53:56.293: V/IntentResolver(918):       Category: "android.intent.category.DEFAULT"05-01 08:53:56.293: V/IntentResolver(918):       Scheme: "http"05-01 08:53:56.293: V/IntentResolver(918):     Building Lookup Maps:05-01 08:53:56.293: V/IntentResolver(918):       Scheme: http05-01 08:53:56.293: V/PackageManager(918): Preferred activity bookkeeping changed; writing restrictions