Add user selectable Default Browser feature

- add Default Apps section in Apps / Advanced
- follow UX spec

This change depends on a Framework change which adds new APIs in PackageMaager
for setting and getting the default Browser App package name.

See bug #20144393

Change-Id: I2ff456eeaced9f740f4dd6fb6bccea6de6ea1308
This commit is contained in:
Fabrice Di Meglio
2015-04-09 19:02:18 -07:00
parent c2ab934117
commit 2eb901a4e8
6 changed files with 227 additions and 1 deletions

View File

@@ -5657,6 +5657,7 @@
<string name="keywords_emergency_app">emergency ice app default</string> <string name="keywords_emergency_app">emergency ice app default</string>
<string name="keywords_all_apps">apps download applications system</string> <string name="keywords_all_apps">apps download applications system</string>
<string name="keywords_app_permissions">apps permissions security</string> <string name="keywords_app_permissions">apps permissions security</string>
<string name="keywords_default_apps">apps default</string>
<!-- Search keywords for different screen unlock modes : slide to unlock, password, pattern and PIN [CHAR LIMIT=none] --> <!-- Search keywords for different screen unlock modes : slide to unlock, password, pattern and PIN [CHAR LIMIT=none] -->
<string name="keywords_lockscreen">slide password pattern pin</string> <string name="keywords_lockscreen">slide password pattern pin</string>
@@ -6212,4 +6213,13 @@
<item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> apps can open their domain URLs</item> <item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> apps can open their domain URLs</item>
</plurals> </plurals>
<!-- Title for Default Apps settings [CHAR LIMIT=30] -->
<string name="default_apps_title">Default Apps</string>
<!-- Title for Default Browser settings [CHAR LIMIT=30] -->
<string name="default_browser_title">Default Browser</string>
<!-- Summary for No Default Browser settings [CHAR LIMIT=45] -->
<string name="default_browser_title_none">No default Browser</string>
</resources> </resources>

View File

@@ -19,6 +19,12 @@
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:key="applications_settings"> android:key="applications_settings">
<PreferenceScreen
android:key="default_apps"
android:fragment="com.android.settings.applications.ManageDefaultApps"
android:title="@string/default_apps_title"
settings:keywords="@string/keywords_default_apps" />
<PreferenceScreen <PreferenceScreen
android:key="manage_perms" android:key="manage_perms"
android:fragment="com.android.settings.applications.ManagePermissions" android:fragment="com.android.settings.applications.ManagePermissions"

28
res/xml/default_apps.xml Normal file
View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:key="default_apps">
<com.android.settings.applications.DefaultBrowserPreference
android:key="default_browser"
android:title="@string/default_browser_title"
android:summary="@string/default_browser_title_none"
/>
</PreferenceScreen>

View File

@@ -23,9 +23,11 @@ import com.android.internal.logging.MetricsLogger;
* Instrumented fragment that logs visibility state. * Instrumented fragment that logs visibility state.
*/ */
public abstract class InstrumentedFragment extends PreferenceFragment { public abstract class InstrumentedFragment extends PreferenceFragment {
// Declare new temproary categories here, starting after this value. // Declare new temporary categories here, starting after this value.
public static final int VIEW_CATEGORY_UNDECLARED = 100000; public static final int VIEW_CATEGORY_UNDECLARED = 100000;
public static final int VIEW_CATEGORY_DEFAULT_APPS = VIEW_CATEGORY_UNDECLARED + 1;
/** /**
* Declare the view of this category. * Declare the view of this category.
* *

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.UserHandle;
import android.preference.ListPreference;
import android.util.ArrayMap;
import android.util.AttributeSet;
import com.android.settings.R;
import java.util.List;
public class DefaultBrowserPreference extends ListPreference {
final private PackageManager mPm;
public DefaultBrowserPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mPm = context.getPackageManager();
loadBrowserApps();
}
private void loadBrowserApps() {
ArrayMap<String, CharSequence> browsers = resolveBrowserApps();
setEntries(browsers.values().toArray(new CharSequence[browsers.size()]));
setEntryValues(browsers.keySet().toArray(new String[browsers.size()]));
}
private ArrayMap<String, CharSequence> resolveBrowserApps() {
ArrayMap<String, CharSequence> result = new ArrayMap<>();
// Create an Intent that will match ALL Browser Apps
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse("http:"));
// Resolve that intent and check that the handleAllWebDataURI boolean is set
PackageManager packageManager = getContext().getPackageManager();
List<ResolveInfo> list = packageManager.queryIntentActivitiesAsUser(intent, 0,
UserHandle.myUserId());
final int count = list.size();
for (int i=0; i<count; i++) {
ResolveInfo info = list.get(i);
if (info.activityInfo == null || result.containsKey(info.activityInfo.packageName)
|| !info.handleAllWebDataURI) {
continue;
}
String packageName = info.activityInfo.packageName;
CharSequence label = info.activityInfo.applicationInfo.loadLabel(packageManager);
result.put(packageName, label);
}
return result;
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.preference.Preference;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import com.android.settings.InstrumentedFragment;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.R;
public class ManageDefaultApps extends SettingsPreferenceFragment
implements Preference.OnPreferenceClickListener {
private static final String TAG = ManageDefaultApps.class.getSimpleName();
private static final String KEY_DEFAULT_BROWSER = "default_browser";
private DefaultBrowserPreference mDefaultBrowserPreference;
private PackageManager mPm;
private int myUserId;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.default_apps);
mPm = getPackageManager();
myUserId = UserHandle.myUserId();
mDefaultBrowserPreference = (DefaultBrowserPreference) findPreference(KEY_DEFAULT_BROWSER);
mDefaultBrowserPreference.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
final CharSequence packageName = mDefaultBrowserPreference.getValue();
if (TextUtils.isEmpty(packageName)) {
return false;
}
return mPm.setDefaultBrowserPackageName(packageName.toString(), myUserId);
}
});
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String packageName = getPackageManager().getDefaultBrowserPackageName(
UserHandle.myUserId());
if (!TextUtils.isEmpty(packageName)) {
// Check if the package is still there
Intent intent = new Intent();
intent.setPackage(packageName);
ResolveInfo info = mPm.resolveActivityAsUser(intent, 0, myUserId);
if (info != null) {
mDefaultBrowserPreference.setValue(packageName);
} else {
// Otherwise select the first one
mDefaultBrowserPreference.setValueIndex(0);
}
} else {
Log.d(TAG, "Cannot set empty default Browser value!");
}
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.VIEW_CATEGORY_DEFAULT_APPS;
}
@Override
public boolean onPreferenceClick(Preference preference) {
return false;
}
}