电信A库要求android系统中有多个Browser时,开机自动设置一个默认浏览器,而不用弹出选择框让用户手动选择。
监听开机广播Intent.ACTION_BOOT_COMPLETED, 用PackageManager调用addPreferredActivity来设置默认Browser。因为要有系统权限才能设置成功,所以在Package/apps/Settings模块中添加代码实现。(系统通过校验发起调用PackageManager.addPreferredActivity程序的Uid来判断是否有权限)
1 public class BootCompletedReceiver extends BroadcastReceiver { 2 3 private final static String PKG_NAME = "com.android.browser"; 4 private final static String CLASS_NAME = "com.android.browser.BrowserActivity"; 5 6 private final static String[] SCHEME = new String[] { "http", "https", "about", "javascript", }; 7 8 @Override 9 public void onReceive(Context c, Intent paramIntent) { 10 try { 11 Log.d("antoon", paramIntent.getAction()); 12 setDefaultBrowser(c); 13 } catch (Exception e) { 14 e.printStackTrace(); 15 } 16 } 17 18 private void setDefaultBrowser(Context c) { 19 20 long start = System.currentTimeMillis(); 21 22 Intent intent = new Intent(Intent.ACTION_VIEW); 23 intent.setData(Uri.parse("http://"));//这里如果配置 “file://” pm.queryIntentActivities得到的list为空,不知为何 24 25 final int flags = PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER; 26 27 PackageManager pm = c.getPackageManager(); 28 List<ResolveInfo> list = pm.queryIntentActivities(intent, flags); 29 30 final int N = list == null ? 0 : list.size(); 31 if (N == 0) 32 return; 33 34 int bestmatch = 0; 35 int uid = -1; 36 ComponentName matchComponentName = null; 37 ComponentName[] set = new ComponentName[N]; 38 39 ComponentName defaultComponentName = new ComponentName(PKG_NAME, CLASS_NAME); 40 for (int i = 0; i < N; i++) { 41 ResolveInfo r = list.get(i); 42 ComponentName cp = new ComponentName(r.activityInfo.packageName, r.activityInfo.name); 43 set[i] = cp; 44 if (cp.equals(defaultComponentName)) { 45 bestmatch = r.match; 46 matchComponentName = cp; 47 uid = r.activityInfo.applicationInfo.uid; 48 } 49 Log.d("antoon", i + " -- " + cp); 50 } 51 52 if (matchComponentName == null) { 53 Log.d("antoon", "matchComponentName is null"); 54 matchComponentName = set[0]; 55 bestmatch = list.get(0).match; 56 } 57 58 Log.d("antoon", "bestmatch = " + bestmatch + " matchComponentName = " 59 + matchComponentName); 60 61 // List<IntentFilter> filterList = filterList(); 62 //for (IntentFilter filter : filterList) { 63 // pm.addPreferredActivity(filter, bestmatch, set, matchComponentName);//用下面的方法也可以,系统权限的校验就是根据CallingUserId来判断 64 // pm.addPreferredActivity(filter, bestmatch, set, matchComponentName, android.os.UserHandle.getCallingUserId()); 65 //}
pm.addPreferredActivity(getFilterViewHttp(), bestmatch, set, matchComponentName, android.os.UserHandle.getCallingUserId()); 66 Log.d("antoon", "used time :" + (System.currentTimeMillis() - start)+"ms"); 67 } 68 69
/*没必要针对每个scheme创建filter,在一个filter中加入所有scheme就可以,与Browser中AndroidManifest.xml中的配置对应。
public List<IntentFilter> filterList() { 70 ArrayList<IntentFilter> list = new ArrayList<IntentFilter>(); 71 for (String sche : SCHEME) { 72 IntentFilter filter = new IntentFilter(); 73 filter.addAction(Intent.ACTION_VIEW); 74 filter.addCategory(Intent.CATEGORY_BROWSABLE); 75 filter.addCategory(Intent.CATEGORY_DEFAULT); 76 filter.addDataScheme(sche); 77 list.add(filter); 78 } 79 return list; 80 }
*/
public IntentFilter getFilterViewHttp() { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_VIEW); filter.addCategory(Intent.CATEGORY_BROWSABLE); filter.addCategory(Intent.CATEGORY_DEFAULT); filter.addDataScheme("http"); return filter; }
81 82 }
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <receiver android:name=".BootCompletedReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
看看系统Browser的配置
<activity android:name="BrowserActivity" android:alwaysRetainTaskState="true" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/application_name" android:launchMode="singleTask" android:theme="@style/BrowserTheme" android:windowSoftInputMode="adjustResize" > <intent-filter> <action android:name="android.speech.action.VOICE_SEARCH_RESULTS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <!-- For these schemes were not particular MIME type has been supplied, we are a good candidate. --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:scheme="about" /> <data android:scheme="javascript" /> </intent-filter> <!-- For these schemes where any of these particular MIME types have been supplied, we are a good candidate. --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:scheme="inline" /> <data android:mimeType="text/html" /> <data android:mimeType="text/plain" /> <data android:mimeType="application/xhtml+xml" /> <data android:mimeType="application/vnd.wap.xhtml+xml" /> </intent-filter> <!-- For viewing saved web archives. --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:scheme="file" /> <data android:mimeType="application/x-webarchive-xml" /> </intent-filter> <!-- Accept inbound NFC URLs at a low priority --> <intent-filter android:priority="-101" > <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> <data android:scheme="https" /> </intent-filter> <!-- We are also the main entry point of the browser. --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.APP_BROWSER" /> </intent-filter> <!-- The maps app is a much better experience, so it's not worth having this at all... especially for a demo! <intent-filter android:label="Map In Browser"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/postal-address" /> </intent-filter> --> <intent-filter> <action android:name="android.intent.action.WEB_SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.WEB_SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="" /> <data android:scheme="http" /> <data android:scheme="https" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.MEDIA_SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" /> </activity>
参考:http://www.apkbus.com/forum.php?mod=viewthread&tid=225694&page=1#pid3159981