Full screen default app fragment

Fix: 34280137
Test: make RunSettingsRoboTests
Change-Id: Ib44e39589781d68c7952a2c16a44682791a422f1
This commit is contained in:
Fan Zhang
2017-01-13 16:01:14 -08:00
parent d9d463be8b
commit 35692cf439
47 changed files with 2654 additions and 1007 deletions

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.os.UserHandle;
/**
* Data model representing an app in DefaultAppPicker UI.
*/
class DefaultAppInfo {
public final int userId;
public final ComponentName componentName;
public final PackageItemInfo packageItemInfo;
public final String summary;
public DefaultAppInfo(int uid, ComponentName cn, String summary) {
packageItemInfo = null;
userId = uid;
componentName = cn;
this.summary = summary;
}
public DefaultAppInfo(PackageItemInfo info) {
userId = UserHandle.myUserId();
packageItemInfo = info;
componentName = null;
summary = null;
}
public CharSequence loadLabel(PackageManager pm) {
if (componentName != null) {
try {
final ActivityInfo actInfo = AppGlobals.getPackageManager().getActivityInfo(
componentName, 0, userId);
if (actInfo != null) {
return actInfo.loadLabel(pm);
} else {
final ApplicationInfo appInfo = pm.getApplicationInfoAsUser(
componentName.getPackageName(), 0, userId);
return appInfo.loadLabel(pm);
}
} catch (RemoteException | PackageManager.NameNotFoundException e) {
return null;
}
} else if (packageItemInfo != null) {
return packageItemInfo.loadLabel(pm);
} else {
return null;
}
}
public Drawable loadIcon(PackageManager pm) {
if (componentName != null) {
try {
final ActivityInfo actInfo = AppGlobals.getPackageManager().getActivityInfo(
componentName, 0, userId);
if (actInfo != null) {
return actInfo.loadIcon(pm);
} else {
final ApplicationInfo appInfo = pm.getApplicationInfoAsUser(
componentName.getPackageName(), 0, userId);
return appInfo.loadIcon(pm);
}
} catch (RemoteException | PackageManager.NameNotFoundException e) {
return null;
}
}
if (packageItemInfo != null) {
return packageItemInfo.loadIcon(pm);
} else {
return null;
}
}
public String getKey() {
if (componentName != null) {
return componentName.flattenToString();
} else if (packageItemInfo != null) {
return packageItemInfo.packageName;
} else {
return null;
}
}
}

View File

@@ -0,0 +1,228 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.PackageManagerWrapper;
import com.android.settings.applications.PackageManagerWrapperImpl;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.widget.RadioButtonPreference;
import java.util.List;
import java.util.Map;
/**
* A generic app picker fragment that shows a list of app as radio button group.
*/
public abstract class DefaultAppPickerFragment extends InstrumentedPreferenceFragment implements
RadioButtonPreference.OnClickListener {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
static final String EXTRA_FOR_WORK = "for_work";
private final Map<String, DefaultAppInfo> mCandidates = new ArrayMap<>();
protected PackageManagerWrapper mPm;
protected UserManager mUserManager;
protected int mUserId;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mPm = new PackageManagerWrapperImpl(context.getPackageManager());
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
final Bundle arguments = getArguments();
boolean mForWork = false;
if (arguments != null) {
mForWork = arguments.getBoolean(EXTRA_FOR_WORK);
}
final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
mUserId = mForWork && managedProfile != null
? managedProfile.getIdentifier()
: UserHandle.myUserId();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = super.onCreateView(inflater, container, savedInstanceState);
setHasOptionsMenu(true);
return view;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
addPreferencesFromResource(R.xml.app_picker_prefs);
mCandidates.clear();
final List<DefaultAppInfo> candidateList = getCandidates();
if (candidateList != null) {
for (DefaultAppInfo info : candidateList) {
mCandidates.put(info.getKey(), info);
}
}
final String defaultAppKey = getDefaultAppKey();
final String systemDefaultAppKey = getSystemDefaultAppKey();
final PreferenceScreen screen = getPreferenceScreen();
screen.removeAll();
if (shouldShowItemNone()) {
final RadioButtonPreference nonePref = new RadioButtonPreference(getPrefContext());
nonePref.setIcon(R.drawable.ic_remove_circle);
nonePref.setTitle(R.string.app_list_preference_none);
nonePref.setChecked(TextUtils.isEmpty(defaultAppKey));
nonePref.setOnClickListener(this);
screen.addPreference(nonePref);
}
for (Map.Entry<String, DefaultAppInfo> app : mCandidates.entrySet()) {
final RadioButtonPreference pref = new RadioButtonPreference(getPrefContext());
final String appKey = app.getKey();
pref.setTitle(app.getValue().loadLabel(mPm.getPackageManager()));
pref.setIcon(app.getValue().loadIcon(mPm.getPackageManager()));
pref.setKey(appKey);
if (TextUtils.equals(defaultAppKey, appKey)) {
pref.setChecked(true);
}
if (TextUtils.equals(systemDefaultAppKey, appKey)) {
pref.setSummary(R.string.system_app);
}
pref.setOnClickListener(this);
screen.addPreference(pref);
}
}
@Override
public void onRadioButtonClicked(RadioButtonPreference selected) {
final String selectedKey = selected.getKey();
final String confirmationMessage = getConfirmationMessage(mCandidates.get(selectedKey));
final Activity activity = getActivity();
if (TextUtils.isEmpty(confirmationMessage)) {
onRadioButtonConfirmed(selectedKey);
} else if (activity != null) {
final DialogFragment fragment = ConfirmationDialogFragment.newInstance(
this, selectedKey, confirmationMessage);
fragment.show(activity.getFragmentManager(), ConfirmationDialogFragment.TAG);
}
}
private void onRadioButtonConfirmed(String selectedKey) {
final boolean success = setDefaultAppKey(selectedKey);
if (success) {
final PreferenceScreen screen = getPreferenceScreen();
if (screen != null) {
final int count = screen.getPreferenceCount();
for (int i = 0; i < count; i++) {
final Preference pref = screen.getPreference(i);
if (pref instanceof RadioButtonPreference) {
final RadioButtonPreference radioPref = (RadioButtonPreference) pref;
final boolean newCheckedState =
TextUtils.equals(pref.getKey(), selectedKey);
if (radioPref.isChecked() != newCheckedState) {
radioPref.setChecked(TextUtils.equals(pref.getKey(), selectedKey));
}
}
}
}
}
}
protected boolean shouldShowItemNone() {
return false;
}
protected String getSystemDefaultAppKey() {
return null;
}
protected abstract List<DefaultAppInfo> getCandidates();
protected abstract String getDefaultAppKey();
protected abstract boolean setDefaultAppKey(String key);
protected String getConfirmationMessage(DefaultAppInfo appInfo) {
return null;
}
public static class ConfirmationDialogFragment extends InstrumentedDialogFragment
implements DialogInterface.OnClickListener {
public static final String TAG = "DefaultAppConfirm";
public static final String EXTRA_KEY = "extra_key";
public static final String EXTRA_MESSAGE = "extra_message";
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_APP_PICKER_CONFIRMATION_DIALOG;
}
public static ConfirmationDialogFragment newInstance(DefaultAppPickerFragment parent,
String key, String message) {
final ConfirmationDialogFragment fragment = new ConfirmationDialogFragment();
final Bundle argument = new Bundle();
argument.putString(EXTRA_KEY, key);
argument.putString(EXTRA_MESSAGE, message);
fragment.setArguments(argument);
fragment.setTargetFragment(parent, 0);
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Bundle bundle = getArguments();
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setMessage(bundle.getString(EXTRA_MESSAGE))
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
@Override
public void onClick(DialogInterface dialog, int which) {
final Fragment fragment = getTargetFragment();
if (fragment instanceof DefaultAppPickerFragment) {
final Bundle bundle = getArguments();
((DefaultAppPickerFragment) fragment).onRadioButtonConfirmed(
bundle.getString(EXTRA_KEY));
}
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.util.Log;
import com.android.settings.applications.PackageManagerWrapper;
import com.android.settings.applications.PackageManagerWrapperImpl;
import com.android.settings.core.PreferenceController;
public abstract class DefaultAppPreferenceController extends PreferenceController {
private static final String TAG = "DefaultAppPrefControl";
protected final PackageManagerWrapper mPackageManager;
protected final UserManager mUserManager;
protected int mUserId;
public DefaultAppPreferenceController(Context context) {
super(context);
mPackageManager = new PackageManagerWrapperImpl(context.getPackageManager());
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mUserId = UserHandle.myUserId();
}
@Override
public void updateState(Preference preference) {
final DefaultAppInfo app = getDefaultAppInfo();
CharSequence defaultAppLabel = null;
if (app != null) {
defaultAppLabel = app.loadLabel(mPackageManager.getPackageManager());
}
if (!TextUtils.isEmpty(defaultAppLabel)) {
preference.setSummary(defaultAppLabel);
} else {
Log.d(TAG, "No default app");
}
}
protected abstract DefaultAppInfo getDefaultAppInfo();
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import com.android.internal.logging.nano.MetricsProto;
import java.util.ArrayList;
import java.util.List;
/**
* Fragment for choosing default browser.
*/
public class DefaultBrowserPicker extends DefaultAppPickerFragment {
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_BROWSER_PICKER;
}
@Override
protected String getDefaultAppKey() {
return mPm.getDefaultBrowserPackageNameAsUser(mUserId);
}
@Override
protected boolean setDefaultAppKey(String packageName) {
return mPm.setDefaultBrowserPackageNameAsUser(packageName, mUserId);
}
@Override
protected List<DefaultAppInfo> getCandidates() {
final List<DefaultAppInfo> candidates = new ArrayList<>();
// Resolve that intent and check that the handleAllWebDataURI boolean is set
final List<ResolveInfo> list = mPm.queryIntentActivitiesAsUser(
DefaultBrowserPreferenceController.BROWSE_PROBE, PackageManager.MATCH_ALL, mUserId);
final int count = list.size();
for (int i = 0; i < count; i++) {
ResolveInfo info = list.get(i);
if (info.activityInfo == null || !info.handleAllWebDataURI) {
continue;
}
try {
candidates.add(new DefaultAppInfo(
mPm.getApplicationInfoAsUser(info.activityInfo.packageName, 0, mUserId)));
} catch (PackageManager.NameNotFoundException e) {
// Skip unknown packages.
}
}
return candidates;
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2017 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.defaultapps;
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.support.v7.preference.Preference;
import android.text.TextUtils;
import java.util.List;
public class DefaultBrowserPreferenceController extends DefaultAppPreferenceController {
static final Intent BROWSE_PROBE = new Intent()
.setAction(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_BROWSABLE)
.setData(Uri.parse("http:"));
public DefaultBrowserPreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return "default_browser";
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
final DefaultAppInfo defaultApp = getDefaultAppInfo();
final CharSequence defaultAppLabel = defaultApp != null
? defaultApp.loadLabel(mPackageManager.getPackageManager()) : null;
if (TextUtils.isEmpty(defaultAppLabel)) {
final String onlyAppLabel = getOnlyAppLabel();
if (!TextUtils.isEmpty(onlyAppLabel)) {
preference.setSummary(onlyAppLabel);
}
}
}
private String getOnlyAppLabel() {
// Resolve that intent and check that the handleAllWebDataURI boolean is set
final List<ResolveInfo> list = mPackageManager.queryIntentActivitiesAsUser(BROWSE_PROBE,
PackageManager.MATCH_ALL, mUserId);
if (list != null && list.size() == 1) {
return list.get(0).loadLabel(mPackageManager.getPackageManager()).toString();
}
return null;
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
try {
return new DefaultAppInfo(mPackageManager.getPackageManager().getApplicationInfo(
mPackageManager.getDefaultBrowserPackageNameAsUser(mUserId), 0));
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
/**
* Whether or not the pkg contains browser capability
*/
public static boolean hasBrowserPreference(String pkg, Context context) {
final Intent intent = new Intent(BROWSE_PROBE);
intent.setPackage(pkg);
final List<ResolveInfo> resolveInfos =
context.getPackageManager().queryIntentActivities(intent, 0);
return resolveInfos != null && resolveInfos.size() != 0;
}
/**
* Whether or not the pkg is the default browser
*/
public static boolean isBrowserDefault(String pkg, Context context) {
String defaultPackage = context.getPackageManager()
.getDefaultBrowserPackageNameAsUser(UserHandle.myUserId());
return defaultPackage != null && defaultPackage.equals(pkg);
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.ContentResolver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.Utils;
import java.util.ArrayList;
import java.util.List;
public class DefaultEmergencyPicker extends DefaultAppPickerFragment {
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_EMERGENCY_APP_PICKER;
}
@Override
protected List<DefaultAppInfo> getCandidates() {
final List<DefaultAppInfo> candidates = new ArrayList<>();
final List<ResolveInfo> infos = mPm.getPackageManager().queryIntentActivities(
DefaultEmergencyPreferenceController.QUERY_INTENT, 0);
PackageInfo bestMatch = null;
for (ResolveInfo info : infos) {
try {
final PackageInfo packageInfo =
mPm.getPackageManager().getPackageInfo(info.activityInfo.packageName, 0);
final ApplicationInfo appInfo = packageInfo.applicationInfo;
candidates.add(new DefaultAppInfo(appInfo));
// Get earliest installed system app.
if (isSystemApp(appInfo) && (bestMatch == null ||
bestMatch.firstInstallTime > packageInfo.firstInstallTime)) {
bestMatch = packageInfo;
}
} catch (PackageManager.NameNotFoundException e) {
// Skip unknown packages.
}
if (bestMatch != null) {
final String defaultKey = getDefaultAppKey();
if (TextUtils.isEmpty(defaultKey)) {
setDefaultAppKey(bestMatch.packageName);
}
}
}
return candidates;
}
@Override
protected String getConfirmationMessage(DefaultAppInfo info) {
return Utils.isPackageDirectBootAware(getContext(), info.getKey()) ? null
: getContext().getString(R.string.direct_boot_unaware_dialog_message);
}
@Override
protected String getDefaultAppKey() {
return Settings.Secure.getString(getContext().getContentResolver(),
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
}
@Override
protected boolean setDefaultAppKey(String key) {
final ContentResolver contentResolver = getContext().getContentResolver();
final String previousValue = Settings.Secure.getString(contentResolver,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
if (!TextUtils.isEmpty(key) && !TextUtils.equals(key, previousValue)) {
Settings.Secure.putString(contentResolver,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
key);
return true;
}
return false;
}
private boolean isSystemApp(ApplicationInfo info) {
return info != null && (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import java.util.List;
public class DefaultEmergencyPreferenceController extends DefaultAppPreferenceController {
private static final boolean DEFAULT_EMERGENCY_APP_IS_CONFIGURABLE = false;
public static final Intent QUERY_INTENT = new Intent(
TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
public DefaultEmergencyPreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
return DEFAULT_EMERGENCY_APP_IS_CONFIGURABLE
&& isCapable()
&& mPackageManager.getPackageManager().resolveActivity(QUERY_INTENT, 0) != null;
}
@Override
public String getPreferenceKey() {
return "default_emergency_app";
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
return null;
}
private boolean isCapable() {
return TelephonyManager.EMERGENCY_ASSISTANCE_ENABLED
&& mContext.getResources().getBoolean(
com.android.internal.R.bool.config_voice_capable);
}
public static boolean hasEmergencyPreference(String pkg, Context context) {
Intent i = new Intent(QUERY_INTENT);
i.setPackage(pkg);
final List<ResolveInfo> resolveInfos =
context.getPackageManager().queryIntentActivities(i, 0);
return resolveInfos != null && resolveInfos.size() != 0;
}
public static boolean isEmergencyDefault(String pkg, Context context) {
String defaultPackage = Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
return defaultPackage != null && defaultPackage.equals(pkg);
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.os.Build;
import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import java.util.ArrayList;
import java.util.List;
public class DefaultHomePicker extends DefaultAppPickerFragment {
private String mPackageName;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mPackageName = context.getPackageName();
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_HOME_PICKER;
}
@Override
protected List<DefaultAppInfo> getCandidates() {
final boolean mustSupportManagedProfile = hasManagedProfile();
final List<DefaultAppInfo> candidates = new ArrayList<>();
final List<ResolveInfo> homeActivities = new ArrayList<>();
mPm.getHomeActivities(homeActivities);
for (ResolveInfo resolveInfo : homeActivities) {
final ActivityInfo info = resolveInfo.activityInfo;
final ComponentName activityName = new ComponentName(info.packageName, info.name);
if (info.packageName.equals(mPackageName)) {
continue;
}
final String summary;
if (mustSupportManagedProfile && !launcherHasManagedProfilesFeature(resolveInfo)) {
summary = getContext().getString(R.string.home_work_profile_not_supported);
} else {
summary = null;
}
final DefaultAppInfo candidate = new DefaultAppInfo(mUserId, activityName, summary);
candidates.add(candidate);
}
return candidates;
}
@Override
protected String getDefaultAppKey() {
final ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
final ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
if (currentDefaultHome != null) {
return currentDefaultHome.flattenToString();
}
return null;
}
@Override
protected boolean setDefaultAppKey(String key) {
if (!TextUtils.isEmpty(key)) {
final ComponentName component = ComponentName.unflattenFromString(key);
final List<ResolveInfo> homeActivities = new ArrayList<>();
mPm.getHomeActivities(homeActivities);
final List<ComponentName> allComponents = new ArrayList<>();
for (ResolveInfo info : homeActivities) {
final ActivityInfo appInfo = info.activityInfo;
ComponentName activityName = new ComponentName(appInfo.packageName, appInfo.name);
allComponents.add(activityName);
}
mPm.replacePreferredActivity(
DefaultHomePreferenceController.HOME_FILTER,
IntentFilter.MATCH_CATEGORY_EMPTY,
allComponents.toArray(new ComponentName[0]),
component);
return true;
}
return false;
}
private boolean hasManagedProfile() {
final Context context = getContext();
List<UserInfo> profiles = mUserManager.getProfiles(context.getUserId());
for (UserInfo userInfo : profiles) {
if (userInfo.isManagedProfile()) {
return true;
}
}
return false;
}
private boolean launcherHasManagedProfilesFeature(ResolveInfo resolveInfo) {
try {
ApplicationInfo appInfo = mPm.getPackageManager().getApplicationInfo(
resolveInfo.activityInfo.packageName, 0 /* default flags */);
return versionNumberAtLeastL(appInfo.targetSdkVersion);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
private boolean versionNumberAtLeastL(int versionNumber) {
return versionNumber >= Build.VERSION_CODES.LOLLIPOP;
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
public class DefaultHomePreferenceController extends DefaultAppPreferenceController {
static final IntentFilter HOME_FILTER;
private final String mPackageName;
static {
HOME_FILTER = new IntentFilter(Intent.ACTION_MAIN);
HOME_FILTER.addCategory(Intent.CATEGORY_HOME);
HOME_FILTER.addCategory(Intent.CATEGORY_DEFAULT);
}
public DefaultHomePreferenceController(Context context) {
super(context);
mPackageName = mContext.getPackageName();
}
@Override
public String getPreferenceKey() {
return "default_home";
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
final DefaultAppInfo defaultApp = getDefaultAppInfo();
final CharSequence defaultAppLabel = defaultApp != null
? defaultApp.loadLabel(mPackageManager.getPackageManager()) : null;
if (TextUtils.isEmpty(defaultAppLabel)) {
final String onlyAppLabel = getOnlyAppLabel();
if (!TextUtils.isEmpty(onlyAppLabel)) {
preference.setSummary(onlyAppLabel);
}
}
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
final ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
final ComponentName currentDefaultHome = mPackageManager.getHomeActivities(homeActivities);
return new DefaultAppInfo(mUserId, currentDefaultHome, null /* summary */);
}
private String getOnlyAppLabel() {
final List<ResolveInfo> homeActivities = new ArrayList<>();
final List<ActivityInfo> appLabels = new ArrayList<>();
mPackageManager.getHomeActivities(homeActivities);
for (ResolveInfo candidate : homeActivities) {
final ActivityInfo info = candidate.activityInfo;
if (info.packageName.equals(mPackageName)) {
continue;
}
appLabels.add(info);
}
return appLabels.size() == 1
? appLabels.get(0).loadLabel(mPackageManager.getPackageManager()).toString()
: null;
}
public static boolean hasHomePreference(String pkg, Context context) {
ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
PackageManager pm = context.getPackageManager();
pm.getHomeActivities(homeActivities);
for (int i = 0; i < homeActivities.size(); i++) {
if (homeActivities.get(i).activityInfo.packageName.equals(pkg)) {
return true;
}
}
return false;
}
public static boolean isHomeDefault(String pkg, Context context) {
ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
PackageManager pm = context.getPackageManager();
ComponentName def = pm.getHomeActivities(homeActivities);
return def != null && def.getPackageName().equals(pkg);
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.provider.Settings;
import android.service.notification.NotificationAssistantService;
import android.util.Slog;
import com.android.settings.R;
import com.android.settings.utils.ManagedServiceSettings;
import java.util.ArrayList;
import java.util.List;
public class DefaultNotificationAssistantPicker extends DefaultAppPickerFragment {
private static final String TAG = "DefaultNotiAssist";
private final ManagedServiceSettings.Config mConfig = getConfig();
@Override
public int getMetricsCategory() {
return 0;
}
@Override
protected String getDefaultAppKey() {
return Settings.Secure.getString(getContext().getContentResolver(), mConfig.setting);
}
@Override
protected boolean setDefaultAppKey(String value) {
Settings.Secure.putString(getContext().getContentResolver(), mConfig.setting, value);
return true;
}
@Override
protected List<DefaultAppInfo> getCandidates() {
List<DefaultAppInfo> candidates = new ArrayList<>();
final int user = ActivityManager.getCurrentUser();
List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
new Intent(mConfig.intentAction),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
user);
for (int i = 0, count = installedServices.size(); i < count; i++) {
ResolveInfo resolveInfo = installedServices.get(i);
ServiceInfo info = resolveInfo.serviceInfo;
if (!mConfig.permission.equals(info.permission)) {
Slog.w(mConfig.tag, "Skipping " + mConfig.noun + " service "
+ info.packageName + "/" + info.name
+ ": it does not require the permission "
+ mConfig.permission);
continue;
}
candidates.add(new DefaultAppInfo(
mUserId, new ComponentName(info.packageName, info.name), null /* summary */));
}
return candidates;
}
@Override
protected boolean shouldShowItemNone() {
return true;
}
private ManagedServiceSettings.Config getConfig() {
final ManagedServiceSettings.Config c = new ManagedServiceSettings.Config();
c.tag = TAG;
c.setting = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
c.intentAction = NotificationAssistantService.SERVICE_INTERFACE;
c.permission = android.Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
c.noun = "notification assistant";
c.warningDialogTitle = R.string.notification_listener_security_warning_title;
c.warningDialogSummary = R.string.notification_listener_security_warning_summary;
c.emptyText = R.string.no_notification_listeners;
return c;
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.Context;
import android.content.pm.PackageManager;
import android.telecom.DefaultDialerManager;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto;
import java.util.ArrayList;
import java.util.List;
public class DefaultPhonePicker extends DefaultAppPickerFragment {
private DefaultKeyUpdater mDefaultKeyUpdater;
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_PHONE_PICKER;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mDefaultKeyUpdater = new DefaultKeyUpdater(
(TelecomManager) context.getSystemService(Context.TELECOM_SERVICE));
}
@Override
protected List<DefaultAppInfo> getCandidates() {
final List<DefaultAppInfo> candidates = new ArrayList<>();
final List<String> dialerPackages =
DefaultDialerManager.getInstalledDialerApplications(getContext(), mUserId);
for (String packageName : dialerPackages) {
try {
candidates.add(new DefaultAppInfo(
mPm.getApplicationInfoAsUser(packageName, 0, mUserId)));
} catch (PackageManager.NameNotFoundException e) {
// Skip unknown packages.
}
}
return candidates;
}
@Override
protected String getDefaultAppKey() {
return mDefaultKeyUpdater.getDefaultDialerApplication(getContext(), mUserId);
}
@Override
protected String getSystemDefaultAppKey() {
return mDefaultKeyUpdater.getSystemDialerPackage();
}
@Override
protected boolean setDefaultAppKey(String key) {
if (!TextUtils.isEmpty(key) && !TextUtils.equals(key, getDefaultAppKey())) {
return mDefaultKeyUpdater.setDefaultDialerApplication(getContext(), key, mUserId);
}
return false;
}
/**
* Wrapper class to handle default phone app update.
*/
static class DefaultKeyUpdater {
private final TelecomManager mTelecomManager;
public DefaultKeyUpdater(TelecomManager telecomManager) {
mTelecomManager = telecomManager;
}
public String getSystemDialerPackage() {
return mTelecomManager.getSystemDialerPackage();
}
public String getDefaultDialerApplication(Context context, int uid) {
return DefaultDialerManager.getDefaultDialerApplication(context, uid);
}
public boolean setDefaultDialerApplication(Context context, String key, int uid) {
return DefaultDialerManager.setDefaultDialerApplication(context, key, uid);
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.telecom.DefaultDialerManager;
import android.telephony.TelephonyManager;
import java.util.List;
public class DefaultPhonePreferenceController extends DefaultAppPreferenceController {
public DefaultPhonePreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
final TelephonyManager tm =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (!tm.isVoiceCapable()) {
return false;
}
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
final boolean hasUserRestriction =
um.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS);
return !hasUserRestriction;
}
@Override
public String getPreferenceKey() {
return "default_phone_app";
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
try {
return new DefaultAppInfo(mPackageManager.getPackageManager().getApplicationInfo(
DefaultDialerManager.getDefaultDialerApplication(mContext, mUserId), 0));
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
public static boolean hasPhonePreference(String pkg, Context context) {
List<String> dialerPackages =
DefaultDialerManager.getInstalledDialerApplications(context, UserHandle.myUserId());
return dialerPackages.contains(pkg);
}
public static boolean isPhoneDefault(String pkg, Context context) {
String def = DefaultDialerManager.getDefaultDialerApplication(context,
UserHandle.myUserId());
return def != null && def.equals(pkg);
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.telephony.SmsApplication;
import com.android.settings.R;
import com.android.settings.Utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class DefaultSmsPicker extends DefaultAppPickerFragment {
private DefaultKeyUpdater mDefaultKeyUpdater = new DefaultKeyUpdater();
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_SMS_PICKER;
}
@Override
protected List<DefaultAppInfo> getCandidates() {
final Collection<SmsApplication.SmsApplicationData> smsApplications =
SmsApplication.getApplicationCollection(getContext());
final List<DefaultAppInfo> candidates = new ArrayList<>(smsApplications.size());
for (SmsApplication.SmsApplicationData smsApplicationData : smsApplications) {
try {
candidates.add(new DefaultAppInfo(
mPm.getApplicationInfoAsUser(smsApplicationData.mPackageName, 0, mUserId)));
} catch (PackageManager.NameNotFoundException e) {
// Skip unknown packages.
}
}
return candidates;
}
@Override
protected String getDefaultAppKey() {
return mDefaultKeyUpdater.getDefaultApplication(getContext());
}
@Override
protected boolean setDefaultAppKey(String key) {
if (!TextUtils.isEmpty(key) && !TextUtils.equals(key, getDefaultAppKey())) {
mDefaultKeyUpdater.setDefaultApplication(getContext(), key);
return true;
}
return false;
}
@Override
protected String getConfirmationMessage(DefaultAppInfo info) {
return Utils.isPackageDirectBootAware(getContext(), info.getKey()) ? null
: getContext().getString(R.string.direct_boot_unaware_dialog_message);
}
/**
* Wrapper class to handle default phone app update.
*/
static class DefaultKeyUpdater {
public String getDefaultApplication(Context context) {
final ComponentName appName = SmsApplication.getDefaultSmsApplication(context, true);
if (appName != null) {
return appName.getPackageName();
}
return null;
}
public void setDefaultApplication(Context context, String key) {
SmsApplication.setDefaultApplication(key, context);
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.ComponentName;
import android.content.Context;
import android.telephony.TelephonyManager;
import com.android.internal.telephony.SmsApplication;
import java.util.Collection;
public class DefaultSmsPreferenceController extends DefaultAppPreferenceController {
public DefaultSmsPreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
boolean isRestrictedUser = mUserManager.getUserInfo(mUserId).isRestricted();
TelephonyManager tm =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
return !isRestrictedUser && tm.isSmsCapable();
}
@Override
public String getPreferenceKey() {
return "default_sms_app";
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
final ComponentName app = SmsApplication.getDefaultSmsApplication(mContext, true);
if (app != null) {
return new DefaultAppInfo(mUserId, app, null /* summary */);
}
return null;
}
public static boolean hasSmsPreference(String pkg, Context context) {
Collection<SmsApplication.SmsApplicationData> smsApplications =
SmsApplication.getApplicationCollection(context);
for (SmsApplication.SmsApplicationData data : smsApplications) {
if (data.mPackageName.equals(pkg)) {
return true;
}
}
return false;
}
public static boolean isSmsDefault(String pkg, Context context) {
ComponentName appName = SmsApplication.getDefaultSmsApplication(context, true);
return appName != null && appName.getPackageName().equals(pkg);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.Context;
import android.os.UserHandle;
import com.android.settings.Utils;
public class DefaultWorkBrowserPreferenceController extends DefaultBrowserPreferenceController {
public DefaultWorkBrowserPreferenceController(Context context) {
super(context);
final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
if (managedProfile != null) {
mUserId = managedProfile.getIdentifier();
}
}
@Override
public boolean isAvailable() {
return Utils.getManagedProfile(mUserManager) != null;
}
@Override
public String getPreferenceKey() {
return "work_default_browser";
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2017 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.defaultapps;
import android.content.Context;
public class DefaultWorkPhonePreferenceController extends DefaultPhonePreferenceController {
public DefaultWorkPhonePreferenceController(Context context) {
super(context);
}
@Override
public String getPreferenceKey() {
return "work_default_phone_app";
}
}