DO Disclosures: detailed application lists
Add UI that lists enterprise set default apps for handling important intents
(opening browser, using camera, phone, etc).
Bug: 32692748
Test: m RunSettingsRoboTests
Merged-In: I75bb97d1b3728b1dcb90981b24d12edf510c4b04
Change-Id: I7d0041e4fada48bc56f6a6637614ac4471dba65a
(cherry picked from commit f0a61dd1126f4b21fb15f1c3d9611ef86fc291a7)
diff --git a/res/xml/enterprise_privacy_settings.xml b/res/xml/enterprise_privacy_settings.xml
index c84a33d..dae3b42 100644
--- a/res/xml/enterprise_privacy_settings.xml
+++ b/res/xml/enterprise_privacy_settings.xml
@@ -62,6 +62,7 @@
android:key="enterprise_privacy_number_camera_access_packages"
android:title="@string/enterprise_privacy_camera_access"/>
<com.android.settings.DividerPreference
+ android:fragment="com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment"
android:key="number_enterprise_set_default_apps"
android:title="@string/enterprise_privacy_enterprise_set_default_apps"/>
<com.android.settings.DividerPreference
diff --git a/res/xml/enterprise_set_default_apps_settings.xml b/res/xml/enterprise_set_default_apps_settings.xml
new file mode 100644
index 0000000..b006f46
--- /dev/null
+++ b/res/xml/enterprise_set_default_apps_settings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+ android:key="enterprise_set_default_apps_settings">
+ <PreferenceCategory
+ android:key="dashboard_tile_placeholder"/>
+</PreferenceScreen>
diff --git a/src/com/android/settings/applications/ApplicationFeatureProvider.java b/src/com/android/settings/applications/ApplicationFeatureProvider.java
index e3ad4c9..3266fe0 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProvider.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProvider.java
@@ -16,14 +16,14 @@
package com.android.settings.applications;
-import com.android.settings.applications.instantapps.InstantAppButtonsController;
-
+import android.annotation.UserIdInt;
import android.app.Fragment;
import android.content.Intent;
import android.view.View;
+import com.android.settings.applications.instantapps.InstantAppButtonsController;
+
import java.util.List;
-import java.util.Set;
public interface ApplicationFeatureProvider {
@@ -80,16 +80,18 @@
void listAppsWithAdminGrantedPermissions(String[] permissions, ListOfAppsCallback callback);
/**
- * Return the persistent preferred activities configured by the admin for the current user and
- * all its managed profiles. A persistent preferred activity is an activity that the admin
- * configured to always handle a given intent (e.g. open browser), even if the user has other
- * apps installed that would also be able to handle the intent.
+ * Return the persistent preferred activities configured by the admin for the given user.
+ * A persistent preferred activity is an activity that the admin configured to always handle a
+ * given intent (e.g. open browser), even if the user has other apps installed that would also
+ * be able to handle the intent.
*
+ * @param userId ID of the user for which to find persistent preferred activities
* @param intent The intents for which to find persistent preferred activities
*
- * @return the persistent preferred activites for the given intent
+ * @return the persistent preferred activites for the given intents, ordered first by user id,
+ * then by package name
*/
- Set<PersistentPreferredActivityInfo> findPersistentPreferredActivities(Intent[] intents);
+ List<UserAppInfo> findPersistentPreferredActivities(@UserIdInt int userId, Intent[] intents);
/**
* Callback that receives the number of packages installed on the device.
@@ -104,30 +106,4 @@
interface ListOfAppsCallback {
void onListOfAppsResult(List<UserAppInfo> result);
}
-
- public static class PersistentPreferredActivityInfo {
- public final String packageName;
- public final int userId;
-
- public PersistentPreferredActivityInfo(String packageName, int userId) {
- this.packageName = packageName;
- this.userId = userId;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof PersistentPreferredActivityInfo)) {
- return false;
- }
- final PersistentPreferredActivityInfo otherActivityInfo
- = (PersistentPreferredActivityInfo) other;
- return otherActivityInfo.packageName.equals(packageName)
- && otherActivityInfo.userId == userId;
- }
-
- @Override
- public int hashCode() {
- return packageName.hashCode() ^ userId;
- }
- }
}
diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
index 353252d..a744792 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
@@ -22,6 +22,7 @@
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -31,6 +32,7 @@
import com.android.settings.applications.instantapps.InstantAppButtonsController;
import com.android.settings.enterprise.DevicePolicyManagerWrapper;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -103,36 +105,34 @@
}
@Override
- public Set<PersistentPreferredActivityInfo> findPersistentPreferredActivities(
- Intent[] intents) {
- final Set<PersistentPreferredActivityInfo> activities = new ArraySet<>();
- final List<UserHandle> users = mUm.getUserProfiles();
+ public List<UserAppInfo> findPersistentPreferredActivities(int userId, Intent[] intents) {
+ final List<UserAppInfo> preferredActivities = new ArrayList<>();
+ final Set<UserAppInfo> uniqueApps = new ArraySet<>();
+ final UserInfo userInfo = mUm.getUserInfo(userId);
for (final Intent intent : intents) {
- for (final UserHandle user : users) {
- final int userId = user.getIdentifier();
- try {
- final ResolveInfo resolveInfo = mPms.findPersistentPreferredActivity(intent,
- userId);
- if (resolveInfo != null) {
- ComponentInfo componentInfo = null;
- if (resolveInfo.activityInfo != null) {
- componentInfo = resolveInfo.activityInfo;
- } else if (resolveInfo.serviceInfo != null) {
- componentInfo = resolveInfo.serviceInfo;
- } else if (resolveInfo.providerInfo != null) {
- componentInfo = resolveInfo.providerInfo;
- }
- if (componentInfo != null) {
- activities.add(new PersistentPreferredActivityInfo(
- componentInfo.packageName, userId));
+ try {
+ final ResolveInfo resolveInfo =
+ mPms.findPersistentPreferredActivity(intent, userId);
+ if (resolveInfo != null) {
+ ComponentInfo componentInfo = null;
+ if (resolveInfo.activityInfo != null) {
+ componentInfo = resolveInfo.activityInfo;
+ } else if (resolveInfo.serviceInfo != null) {
+ componentInfo = resolveInfo.serviceInfo;
+ } else if (resolveInfo.providerInfo != null) {
+ componentInfo = resolveInfo.providerInfo;
+ }
+ if (componentInfo != null) {
+ UserAppInfo info = new UserAppInfo(userInfo, componentInfo.applicationInfo);
+ if (uniqueApps.add(info)) {
+ preferredActivities.add(info);
}
}
- } catch (RemoteException exception) {
}
+ } catch (RemoteException exception) {
}
-
}
- return activities;
+ return preferredActivities;
}
private static class CurrentUserAndManagedProfilePolicyInstalledAppCounter
diff --git a/src/com/android/settings/applications/EnterpriseDefaultApps.java b/src/com/android/settings/applications/EnterpriseDefaultApps.java
new file mode 100644
index 0000000..f48b955
--- /dev/null
+++ b/src/com/android/settings/applications/EnterpriseDefaultApps.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.MediaStore;
+
+/**
+ * UI grouping of important intents that can be configured by device and profile owners.
+ */
+public enum EnterpriseDefaultApps {
+ BROWSER(new Intent[] {
+ buildIntent(Intent.ACTION_VIEW, Intent.CATEGORY_BROWSABLE, "http:", null)}),
+ CALENDAR(new Intent[] {
+ buildIntent(Intent.ACTION_INSERT, null, null, "vnd.android.cursor.dir/event")}),
+ CAMERA(new Intent[] {
+ new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
+ new Intent(MediaStore.ACTION_VIDEO_CAPTURE)}),
+ CONTACTS(new Intent[] {
+ buildIntent(Intent.ACTION_PICK, null, null, ContactsContract.Contacts.CONTENT_TYPE)}),
+ EMAIL(new Intent[] {
+ new Intent(Intent.ACTION_SENDTO), new Intent(Intent.ACTION_SEND),
+ new Intent(Intent.ACTION_SEND_MULTIPLE)}),
+ MAP(new Intent[] {buildIntent(Intent.ACTION_VIEW, null, "geo:", null)}),
+ PHONE(new Intent[] {new Intent(Intent.ACTION_DIAL), new Intent(Intent.ACTION_CALL)});
+ private final Intent[] mIntents;
+
+ EnterpriseDefaultApps(Intent[] intents) {
+ mIntents = intents;
+ }
+
+ public Intent[] getIntents() {
+ return mIntents;
+ }
+
+ private static Intent buildIntent(String action, String category, String protocol,
+ String type) {
+ final Intent intent = new Intent(action);
+ if (category != null) {
+ intent.addCategory(category);
+ }
+ if (protocol != null) {
+ intent.setData(Uri.parse(protocol));
+ }
+ if (type != null) {
+ intent.setType(type);
+ }
+ return intent;
+ }
+
+}
diff --git a/src/com/android/settings/applications/InstalledAppLister.java b/src/com/android/settings/applications/InstalledAppLister.java
index 1c3b0e9..d8e7c58 100644
--- a/src/com/android/settings/applications/InstalledAppLister.java
+++ b/src/com/android/settings/applications/InstalledAppLister.java
@@ -22,8 +22,7 @@
public abstract class InstalledAppLister extends AppLister {
- public InstalledAppLister(PackageManagerWrapper packageManager,
- UserManager userManager) {
+ public InstalledAppLister(PackageManagerWrapper packageManager, UserManager userManager) {
super(packageManager, userManager);
}
diff --git a/src/com/android/settings/applications/UserAppInfo.java b/src/com/android/settings/applications/UserAppInfo.java
index 3af5f19..04fa713 100644
--- a/src/com/android/settings/applications/UserAppInfo.java
+++ b/src/com/android/settings/applications/UserAppInfo.java
@@ -43,9 +43,10 @@
if (other == null || getClass() != other.getClass()) {
return false;
}
-
final UserAppInfo that = (UserAppInfo) other;
+ // As UserInfo and AppInfo do not support hashcode/equals contract, assume
+ // equality based on corresponding identity fields.
return that.userInfo.id == userInfo.id && TextUtils.equals(that.appInfo.packageName,
appInfo.packageName);
}
diff --git a/src/com/android/settings/enterprise/ApplicationListFragment.java b/src/com/android/settings/enterprise/ApplicationListFragment.java
index 9a887d8..ff68a8b 100644
--- a/src/com/android/settings/enterprise/ApplicationListFragment.java
+++ b/src/com/android/settings/enterprise/ApplicationListFragment.java
@@ -39,11 +39,6 @@
static final String TAG = "EnterprisePrivacySettings";
@Override
- public int getMetricsCategory() {
- return MetricsEvent.ENTERPRISE_PRIVACY_SETTINGS;
- }
-
- @Override
protected String getLogTag() {
return TAG;
}
@@ -75,6 +70,11 @@
FeatureFactory.getFactory(context).getApplicationFeatureProvider(context)
.listAppsWithAdminGrantedPermissions(mPermissions, callback);
}
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.ENTERPRISE_PRIVACY_PERMISSIONS;
+ }
}
public static class AdminGrantedPermissionCamera extends AdminGrantedPermission {
@@ -101,6 +101,11 @@
}
@Override
+ public int getMetricsCategory() {
+ return MetricsEvent.ENTERPRISE_PRIVACY_INSTALLED_APPS;
+ }
+
+ @Override
public void buildApplicationList(Context context,
ApplicationFeatureProvider.ListOfAppsCallback callback) {
FeatureFactory.getFactory(context).getApplicationFeatureProvider(context).
diff --git a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java
index 5817cf2..46ecb7e 100644
--- a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java
+++ b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java
@@ -17,10 +17,8 @@
package com.android.settings.enterprise;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
diff --git a/src/com/android/settings/enterprise/EnterprisePrivacyPreferenceController.java b/src/com/android/settings/enterprise/EnterprisePrivacyPreferenceController.java
index 254940e..69e0416 100644
--- a/src/com/android/settings/enterprise/EnterprisePrivacyPreferenceController.java
+++ b/src/com/android/settings/enterprise/EnterprisePrivacyPreferenceController.java
@@ -14,7 +14,6 @@
package com.android.settings.enterprise;
import android.content.Context;
-import android.content.res.Resources;
import android.support.v7.preference.Preference;
import com.android.settings.R;
diff --git a/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListFragment.java b/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListFragment.java
new file mode 100644
index 0000000..6f173f1
--- /dev/null
+++ b/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListFragment.java
@@ -0,0 +1,59 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment for displaying a list of default applications set by profile or device admin.
+ */
+public class EnterpriseSetDefaultAppsListFragment extends DashboardFragment {
+ static final String TAG = "EnterprisePrivacySettings";
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.ENTERPRISE_PRIVACY_DEFAULT_APPS;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.enterprise_set_default_apps_settings;
+ }
+
+ @Override
+ protected List<PreferenceController> getPreferenceControllers(Context context) {
+ final List controllers = new ArrayList<PreferenceController>();
+ final EnterpriseSetDefaultAppsListPreferenceController controller =
+ new EnterpriseSetDefaultAppsListPreferenceController(
+ context, this, context.getPackageManager());
+ controllers.add(controller);
+ return controllers;
+ }
+}
diff --git a/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceController.java b/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceController.java
new file mode 100644
index 0000000..51b60b8
--- /dev/null
+++ b/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceController.java
@@ -0,0 +1,197 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.applications.EnterpriseDefaultApps;
+import com.android.settings.applications.UserAppInfo;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.users.UserFeatureProvider;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+
+
+/**
+ * PreferenceController that builds a dynamic list of default apps set by device or profile owner.
+ */
+public class EnterpriseSetDefaultAppsListPreferenceController extends PreferenceController {
+ private final PackageManager mPm;
+ private final SettingsPreferenceFragment mParent;
+ private final ApplicationFeatureProvider mApplicationFeatureProvider;
+ private final EnterprisePrivacyFeatureProvider mEnterprisePrivacyFeatureProvider;
+ private final UserFeatureProvider mUserFeatureProvider;
+
+ private List<UserInfo> mUsers = Collections.emptyList();
+ private List<EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>>> mApps =
+ Collections.emptyList();
+
+ public EnterpriseSetDefaultAppsListPreferenceController(Context context,
+ SettingsPreferenceFragment parent, PackageManager packageManager) {
+ super(context);
+ mPm = packageManager;
+ mParent = parent;
+ final FeatureFactory factory = FeatureFactory.getFactory(context);
+ mApplicationFeatureProvider = factory.getApplicationFeatureProvider(context);
+ mEnterprisePrivacyFeatureProvider = factory.getEnterprisePrivacyFeatureProvider(context);
+ mUserFeatureProvider = factory.getUserFeatureProvider(context);
+ buildAppList();
+ }
+
+ /**
+ * Builds data for UI. Updates mUsers and mApps so that they contain non-empty list.
+ */
+ private void buildAppList() {
+ mUsers = new ArrayList<>();
+ mApps = new ArrayList<>();
+ for (UserHandle user : mUserFeatureProvider.getUserProfiles()) {
+ boolean hasDefaultsForUser = false;
+ EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> userMap = null;
+
+ for (EnterpriseDefaultApps typeOfDefault : EnterpriseDefaultApps.values()) {
+ List<UserAppInfo> apps = mApplicationFeatureProvider.
+ findPersistentPreferredActivities(user.getIdentifier(),
+ typeOfDefault.getIntents());
+ if (apps.isEmpty()) {
+ continue;
+ }
+ if (!hasDefaultsForUser) {
+ hasDefaultsForUser = true;
+ mUsers.add(apps.get(0).userInfo);
+ userMap = new EnumMap<>(EnterpriseDefaultApps.class);
+ mApps.add(userMap);
+ }
+ ArrayList<ApplicationInfo> applicationInfos = new ArrayList<>();
+ for (UserAppInfo userAppInfo : apps) {
+ applicationInfos.add(userAppInfo.appInfo);
+ }
+ userMap.put(typeOfDefault, applicationInfos);
+ }
+ }
+ new Handler(mContext.getMainLooper()).post(() -> { updateUi(); });
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return null;
+ }
+
+ private void updateUi() {
+ final Context prefContext = mParent.getPreferenceManager().getContext();
+ final PreferenceScreen screen = mParent.getPreferenceScreen();
+ if (screen == null) {
+ return;
+ }
+ if (!mEnterprisePrivacyFeatureProvider.isInCompMode() && mUsers.size() == 1) {
+ createPreferences(prefContext, screen, mApps.get(0));
+ } else {
+ for (int i = 0; i < mUsers.size(); i++) {
+ final UserInfo userInfo = mUsers.get(i);
+ final PreferenceCategory category = new PreferenceCategory(prefContext);
+ screen.addPreference(category);
+ if (userInfo.isManagedProfile()) {
+ category.setTitle(R.string.managed_device_admin_title);
+ } else {
+ category.setTitle(R.string.personal_device_admin_title);
+ }
+ category.setOrder(i);
+ createPreferences(prefContext, category, mApps.get(i));
+ }
+ }
+ }
+
+ private void createPreferences(Context prefContext, PreferenceGroup group,
+ EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> apps) {
+ if (group == null) {
+ return;
+ }
+ for (EnterpriseDefaultApps typeOfDefault : EnterpriseDefaultApps.values()) {
+ final List<ApplicationInfo> appsForCategory = apps.get(typeOfDefault);
+ if (appsForCategory == null || appsForCategory.isEmpty()) {
+ continue;
+ }
+ final Preference preference = new Preference(prefContext);
+ preference.setTitle(getTitle(prefContext, typeOfDefault, appsForCategory.size()));
+ preference.setSummary(buildSummaryString(prefContext, appsForCategory));
+ preference.setOrder(typeOfDefault.ordinal());
+ preference.setSelectable(false);
+ group.addPreference(preference);
+ }
+ }
+
+ private CharSequence buildSummaryString(Context context, List<ApplicationInfo> apps) {
+ final CharSequence[] appNames = new String[apps.size()];
+ for (int i = 0; i < apps.size(); i++) {
+ appNames[i] = apps.get(i).loadLabel(mPm);
+ }
+ if (apps.size() == 1) {
+ return appNames[0];
+ } else if (apps.size() == 2) {
+ return context.getString(R.string.app_names_concatenation_template_2, appNames[0],
+ appNames[1]);
+ } else {
+ return context.getString(R.string.app_names_concatenation_template_3, appNames[0],
+ appNames[1], appNames[2]);
+ }
+ }
+
+ private String getTitle(Context context, EnterpriseDefaultApps typeOfDefault, int appCount) {
+ switch (typeOfDefault) {
+ case BROWSER:
+ return context.getString(R.string.default_browser_title);
+ case CALENDAR:
+ return context.getString(R.string.default_calendar_app_title);
+ case CONTACTS:
+ return context.getString(R.string.default_contacts_app_title);
+ case PHONE:
+ return context.getResources()
+ .getQuantityString(R.plurals.default_phone_app_title, appCount);
+ case MAP:
+ return context.getString(R.string.default_map_app_title);
+ case EMAIL:
+ return context.getResources()
+ .getQuantityString(R.plurals.default_email_app_title, appCount);
+ case CAMERA:
+ return context.getResources()
+ .getQuantityString(R.plurals.default_camera_app_title, appCount);
+ default:
+ throw new IllegalStateException("Unknown type of default " + typeOfDefault);
+ }
+ }
+
+}
diff --git a/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceController.java b/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceController.java
index ae76d63..2f43a61 100644
--- a/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceController.java
+++ b/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceController.java
@@ -14,28 +14,29 @@
package com.android.settings.enterprise;
import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import android.provider.MediaStore;
+import android.os.UserHandle;
import android.support.v7.preference.Preference;
import com.android.settings.R;
import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.applications.EnterpriseDefaultApps;
import com.android.settings.core.DynamicAvailabilityPreferenceController;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.users.UserFeatureProvider;
public class EnterpriseSetDefaultAppsPreferenceController
extends DynamicAvailabilityPreferenceController {
private static final String KEY_DEFAULT_APPS = "number_enterprise_set_default_apps";
- private final ApplicationFeatureProvider mFeatureProvider;
+ private final ApplicationFeatureProvider mApplicationFeatureProvider;
+ private final UserFeatureProvider mUserFeatureProvider;
public EnterpriseSetDefaultAppsPreferenceController(Context context, Lifecycle lifecycle) {
super(context, lifecycle);
- mFeatureProvider = FeatureFactory.getFactory(context)
- .getApplicationFeatureProvider(context);
+ final FeatureFactory factory = FeatureFactory.getFactory(context);
+ mApplicationFeatureProvider = factory.getApplicationFeatureProvider(context);
+ mUserFeatureProvider = factory.getUserFeatureProvider(context);
}
@Override
@@ -56,47 +57,14 @@
}
private int getNumberOfEnterpriseSetDefaultApps() {
- // Browser
- int num = mFeatureProvider.findPersistentPreferredActivities(new Intent[] {
- buildIntent(Intent.ACTION_VIEW, Intent.CATEGORY_BROWSABLE, "http:", null)}).size();
- // Camera
- num += mFeatureProvider.findPersistentPreferredActivities(new Intent[] {
- new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
- new Intent(MediaStore.ACTION_VIDEO_CAPTURE)}).size();
- // Map
- num += mFeatureProvider.findPersistentPreferredActivities(new Intent[] {
- buildIntent(Intent.ACTION_VIEW, null, "geo:", null)}).size();
- // E-mail
- num += mFeatureProvider.findPersistentPreferredActivities(new Intent[] {
- new Intent(Intent.ACTION_SENDTO), new Intent(Intent.ACTION_SEND),
- new Intent(Intent.ACTION_SEND_MULTIPLE)}).size();
- // Calendar
- num += mFeatureProvider.findPersistentPreferredActivities(new Intent[] {
- buildIntent(Intent.ACTION_INSERT, null, null, "vnd.android.cursor.dir/event")})
- .size();
- // Contacts
- num += mFeatureProvider.findPersistentPreferredActivities(new Intent[] {
- buildIntent(Intent.ACTION_PICK, null, null,
- ContactsContract.Contacts.CONTENT_TYPE)}).size();
- // Dialer
- num += mFeatureProvider.findPersistentPreferredActivities(new Intent[] {
- new Intent(Intent.ACTION_DIAL), new Intent(Intent.ACTION_CALL)}).size();
-
+ int num = 0;
+ for (UserHandle user : mUserFeatureProvider.getUserProfiles()) {
+ for (EnterpriseDefaultApps app : EnterpriseDefaultApps.values()) {
+ num += mApplicationFeatureProvider
+ .findPersistentPreferredActivities(user.getIdentifier(),
+ app.getIntents()).size();
+ }
+ }
return num;
}
-
- private static Intent buildIntent(String action, String category, String protocol,
- String type) {
- final Intent intent = new Intent(action);
- if (category != null) {
- intent.addCategory(category);
- }
- if (protocol != null) {
- intent.setData(Uri.parse(protocol));
- }
- if (type != null) {
- intent.setType(type);
- }
- return intent;
- }
}
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index dcd2b51..e7d5088 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -31,6 +31,7 @@
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.search2.SearchFeatureProvider;
+import com.android.settings.users.UserFeatureProvider;
/**
* Abstract class for creating feature controllers. Allows OEM implementations to define their own
@@ -94,6 +95,8 @@
public abstract SecurityFeatureProvider getSecurityFeatureProvider();
+ public abstract UserFeatureProvider getUserFeatureProvider(Context context);
+
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index 5b039b2..b39a2a0 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -45,6 +45,8 @@
import com.android.settings.search2.SearchFeatureProviderImpl;
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.security.SecurityFeatureProviderImpl;
+import com.android.settings.users.UserFeatureProvider;
+import com.android.settings.users.UserFeatureProviderImpl;
import com.android.settings.vpn2.ConnectivityManagerWrapperImpl;
/**
@@ -63,6 +65,7 @@
private SuggestionFeatureProvider mSuggestionFeatureProvider;
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
private AssistGestureFeatureProvider mAssistGestureFeatureProvider;
+ private UserFeatureProvider mUserFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -158,6 +161,14 @@
}
@Override
+ public UserFeatureProvider getUserFeatureProvider(Context context) {
+ if (mUserFeatureProvider == null) {
+ mUserFeatureProvider = new UserFeatureProviderImpl(context);
+ }
+ return mUserFeatureProvider;
+ }
+
+ @Override
public AssistGestureFeatureProvider getAssistGestureFeatureProvider() {
if (mAssistGestureFeatureProvider == null) {
mAssistGestureFeatureProvider = new AssistGestureFeatureProviderImpl();
diff --git a/src/com/android/settings/users/UserFeatureProvider.java b/src/com/android/settings/users/UserFeatureProvider.java
new file mode 100644
index 0000000..9853255
--- /dev/null
+++ b/src/com/android/settings/users/UserFeatureProvider.java
@@ -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.users;
+
+import android.os.UserHandle;
+
+import java.util.List;
+
+public interface UserFeatureProvider {
+ /**
+ * Returns a list of UserHandles for profiles associated with the user that the calling process
+ * is running on, including the user itself.
+ *
+ * @return A non-empty list of UserHandles associated with the calling user.
+ */
+ List<UserHandle> getUserProfiles();
+}
diff --git a/src/com/android/settings/users/UserFeatureProviderImpl.java b/src/com/android/settings/users/UserFeatureProviderImpl.java
new file mode 100644
index 0000000..b88c831
--- /dev/null
+++ b/src/com/android/settings/users/UserFeatureProviderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * 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.users;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import java.util.List;
+
+public class UserFeatureProviderImpl implements UserFeatureProvider {
+ UserManager mUm;
+
+ public UserFeatureProviderImpl(Context context) {
+ mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ }
+
+ @Override
+ public List<UserHandle> getUserProfiles() {
+ return mUm.getUserProfiles();
+ }
+}
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index c043f1b..767edf8 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -9,3 +9,4 @@
com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionLocation
com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMicrophone
com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
+com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
index cb68ccb..4c4ec46 100644
--- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
@@ -20,13 +20,13 @@
import android.content.Context;
import android.content.Intent;
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.os.UserHandle;
import android.os.UserManager;
-import android.util.ArraySet;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
@@ -42,9 +42,9 @@
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Set;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
@@ -200,8 +200,14 @@
@Test
public void testFindPersistentPreferredActivities() throws Exception {
+ final UserInfo mainUser = new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN);
+ final UserInfo managedUser = new UserInfo(MANAGED_PROFILE_ID, "managed",
+ UserInfo.FLAG_MANAGED_PROFILE);
+
when(mUserManager.getUserProfiles()).thenReturn(Arrays.asList(new UserHandle(MAIN_USER_ID),
new UserHandle(MANAGED_PROFILE_ID)));
+ when(mUserManager.getUserInfo(MAIN_USER_ID)).thenReturn(mainUser);
+ when(mUserManager.getUserInfo(MANAGED_PROFILE_ID)).thenReturn(managedUser);
final Intent viewIntent = new Intent(Intent.ACTION_VIEW);
final Intent editIntent = new Intent(Intent.ACTION_EDIT);
@@ -222,17 +228,21 @@
when(mPackageManagerService.findPersistentPreferredActivity(sendIntent, MANAGED_PROFILE_ID))
.thenReturn(null);
- final Set<ApplicationFeatureProvider.PersistentPreferredActivityInfo> expectedActivities
- = new ArraySet<>();
- expectedActivities.add(new ApplicationFeatureProvider.PersistentPreferredActivityInfo(APP_1,
- MAIN_USER_ID));
- expectedActivities.add(new ApplicationFeatureProvider.PersistentPreferredActivityInfo(APP_1,
- MANAGED_PROFILE_ID));
- expectedActivities.add(new ApplicationFeatureProvider.PersistentPreferredActivityInfo(APP_2,
- MANAGED_PROFILE_ID));
+ final List<UserAppInfo> expectedMainUserActivities = new ArrayList<>();
+ expectedMainUserActivities.add(new UserAppInfo(mainUser,
+ new ApplicationInfo(app1.activityInfo.applicationInfo)));
+ final List<UserAppInfo> expectedManagedUserActivities = new ArrayList<>();
+ expectedManagedUserActivities.add(new UserAppInfo(managedUser,
+ new ApplicationInfo(app1.activityInfo.applicationInfo)));
+ expectedManagedUserActivities.add(new UserAppInfo(managedUser,
+ new ApplicationInfo(app2.activityInfo.applicationInfo)));
- assertThat(mProvider.findPersistentPreferredActivities(
- new Intent[] {viewIntent, editIntent, sendIntent})).isEqualTo(expectedActivities);
+ assertThat(mProvider.findPersistentPreferredActivities(MAIN_USER_ID,
+ new Intent[] {viewIntent, editIntent, sendIntent}))
+ .isEqualTo(expectedMainUserActivities);
+ assertThat(mProvider.findPersistentPreferredActivities(MANAGED_PROFILE_ID,
+ new Intent[] {viewIntent, editIntent, sendIntent}))
+ .isEqualTo(expectedManagedUserActivities);
}
private void setUpUsersAndInstalledApps() {
@@ -254,8 +264,11 @@
}
private ResolveInfo createResolveInfo(String packageName) {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.packageName = packageName;
final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.packageName = packageName;
+ activityInfo.applicationInfo = applicationInfo;
final ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = activityInfo;
return resolveInfo;
diff --git a/tests/robotests/src/com/android/settings/applications/EnterpriseDefaultAppsTest.java b/tests/robotests/src/com/android/settings/applications/EnterpriseDefaultAppsTest.java
new file mode 100644
index 0000000..ad05c27
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/EnterpriseDefaultAppsTest.java
@@ -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;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import static junit.framework.Assert.assertTrue;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnterpriseDefaultAppsTest {
+ @Test
+ public void testNumberOfIntentsCorrelateWithUI() throws Exception {
+ final int concatenation_templates[] =
+ new int[]{0 /* no need for single app name */,
+ R.string.app_names_concatenation_template_2,
+ R.string.app_names_concatenation_template_3};
+ for (EnterpriseDefaultApps app : EnterpriseDefaultApps.values()) {
+ assertTrue("Number of intents should be limited by number of apps the UI can show",
+ app.getIntents().length <= concatenation_templates.length);
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/ApplicationListFragmentTest.java b/tests/robotests/src/com/android/settings/enterprise/ApplicationListFragmentTest.java
index 5fbaf51..1936f80 100644
--- a/tests/robotests/src/com/android/settings/enterprise/ApplicationListFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/ApplicationListFragmentTest.java
@@ -71,12 +71,6 @@
}
@Test
- public void getMetricsCategory() {
- assertThat(mFragment.getMetricsCategory())
- .isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_SETTINGS);
- }
-
- @Test
public void getLogTag() {
assertThat(mFragment.getLogTag())
.isEqualTo("EnterprisePrivacySettings");
@@ -98,6 +92,17 @@
ApplicationListPreferenceController.class);
}
+ @Test public void getCategories() {
+ assertThat(new ApplicationListFragment.AdminGrantedPermissionCamera().getMetricsCategory())
+ .isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_PERMISSIONS);
+ assertThat(new ApplicationListFragment.AdminGrantedPermissionLocation().
+ getMetricsCategory()).isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_PERMISSIONS);
+ assertThat(new ApplicationListFragment.AdminGrantedPermissionMicrophone().
+ getMetricsCategory()).isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_PERMISSIONS);
+ assertThat(new ApplicationListFragment.EnterpriseInstalledPackages().getMetricsCategory())
+ .isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_INSTALLED_APPS);
+ }
+
private static class ApplicationListFragmentTestable extends ApplicationListFragment {
private final PreferenceManager mPreferenceManager;
@@ -127,5 +132,10 @@
public PreferenceScreen getPreferenceScreen() {
return mPreferenceScreen;
}
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.VIEW_UNKNOWN;
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListFragmentTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListFragmentTest.java
new file mode 100644
index 0000000..e5c877f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListFragmentTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceController;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnterpriseSetDefaultAppsListFragmentTest {
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceScreen mScreen;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceManager mPreferenceManager;
+
+ private EnterpriseSetDefaultAppsListFragment mFragment;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ShadowApplication.getInstance().getApplicationContext();
+ when(mPreferenceManager.getContext()).thenReturn(mContext);
+ when(mScreen.getPreferenceManager()).thenReturn(mPreferenceManager);
+ mFragment = new EnterpriseSetDefaultAppsListFragmentTestable(mPreferenceManager, mScreen);
+ }
+
+ @Test
+ public void getMetricsCategory() {
+ assertThat(mFragment.getMetricsCategory())
+ .isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_DEFAULT_APPS);
+ }
+
+ @Test
+ public void getLogTag() {
+ assertThat(mFragment.getLogTag()).isEqualTo("EnterprisePrivacySettings");
+ }
+
+ @Test
+ public void getScreenResource() {
+ assertThat(mFragment.getPreferenceScreenResId())
+ .isEqualTo(R.xml.enterprise_set_default_apps_settings);
+ }
+
+ @Test
+ public void getPreferenceControllers() {
+ final List<PreferenceController> controllers = mFragment.getPreferenceControllers(mContext);
+ assertThat(controllers).isNotNull();
+ assertThat(controllers.size()).isEqualTo(1);
+ int position = 0;
+ assertThat(controllers.get(position++)).isInstanceOf(
+ EnterpriseSetDefaultAppsListPreferenceController.class);
+ }
+
+ private static class EnterpriseSetDefaultAppsListFragmentTestable extends
+ EnterpriseSetDefaultAppsListFragment {
+
+ private final PreferenceManager mPreferenceManager;
+ private final PreferenceScreen mPreferenceScreen;
+
+ public EnterpriseSetDefaultAppsListFragmentTestable(PreferenceManager preferenceManager,
+ PreferenceScreen screen) {
+ this.mPreferenceManager = preferenceManager;
+ this.mPreferenceScreen = screen;
+ }
+
+ @Override
+ public PreferenceManager getPreferenceManager() {
+ return mPreferenceManager;
+ }
+
+ @Override
+ public PreferenceScreen getPreferenceScreen() {
+ return mPreferenceScreen;
+ }
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceControllerTest.java
new file mode 100644
index 0000000..6a1a7f7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceControllerTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.applications.EnterpriseDefaultApps;
+import com.android.settings.applications.UserAppInfo;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.testutils.ApplicationTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnterpriseSetDefaultAppsListPreferenceControllerTest {
+ private static final int USER_ID = 0;
+ private static final int APP_UID = 0;
+
+ private static final String APP_1 = "APP_1";
+ private static final String APP_2 = "APP_2";
+ private static final String BROWSER_TITLE = "Browser app";
+ private static final String PHONE_TITLE = "Phone apps";
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceScreen mScreen;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceManager mPrefenceManager;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PackageManager mPackageManager;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private SettingsPreferenceFragment mFragment;
+
+ private Context mContext;
+ private FakeFeatureFactory mFeatureFactory;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowApplication shadowContext = ShadowApplication.getInstance();
+ mContext = spy(shadowContext.getApplicationContext());
+ FakeFeatureFactory.setupForTest(mContext);
+ mFeatureFactory = (FakeFeatureFactory) FeatureFactory.getFactory(mContext);
+ when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
+ when(mPrefenceManager.getContext()).thenReturn(mContext);
+ when(mFragment.getPreferenceManager()).thenReturn(mPrefenceManager);
+
+ when(mContext.getString(R.string.default_browser_title)).thenReturn(BROWSER_TITLE);
+ Resources resources = spy(mContext.getResources());
+ when(mContext.getResources()).thenReturn(resources);
+ when(resources.getQuantityString(R.plurals.default_phone_app_title, 2))
+ .thenReturn(PHONE_TITLE);
+ when(mContext.getString(R.string.app_names_concatenation_template_2))
+ .thenReturn("%1$s, %2$s");
+
+ when(mPackageManager.getText(eq(APP_1), anyInt(), any())).thenReturn(APP_1);
+ when(mPackageManager.getText(eq(APP_2), anyInt(), any())).thenReturn(APP_2);
+ }
+
+ @Test
+ public void testMultipleAppsForOneTypeOfDefault() {
+ final UserInfo user = new UserInfo(USER_ID, "main", UserInfo.FLAG_ADMIN);
+ final ApplicationInfo appInfo1 = ApplicationTestUtils.buildInfo(APP_UID, APP_1, 0, 0);
+ final ApplicationInfo appInfo2 = ApplicationTestUtils.buildInfo(APP_UID, APP_2, 0, 0);
+
+ when(mFeatureFactory.userFeatureProvider.getUserProfiles())
+ .thenReturn(Arrays.asList(new UserHandle(USER_ID)));
+ when(mFeatureFactory.enterprisePrivacyFeatureProvider.isInCompMode()).thenReturn(false);
+ when(mFeatureFactory.applicationFeatureProvider
+ .findPersistentPreferredActivities(anyInt(), any()))
+ .thenReturn(Collections.emptyList());
+ when(mFeatureFactory.applicationFeatureProvider
+ .findPersistentPreferredActivities(eq(USER_ID),
+ eq(EnterpriseDefaultApps.BROWSER.getIntents())))
+ .thenReturn(Arrays.asList(new UserAppInfo(user, appInfo1)));
+ when(mFeatureFactory.applicationFeatureProvider
+ .findPersistentPreferredActivities(eq(USER_ID),
+ eq(EnterpriseDefaultApps.PHONE.getIntents()))).thenReturn(
+ Arrays.asList(new UserAppInfo(user, appInfo1),
+ new UserAppInfo(user, appInfo2)));
+
+ new EnterpriseSetDefaultAppsListPreferenceController(mContext, mFragment, mPackageManager);
+ ShadowApplication.runBackgroundTasks();
+
+ ArgumentCaptor<Preference> apps = ArgumentCaptor.forClass(Preference.class);
+ verify(mScreen, times(2)).addPreference(apps.capture());
+
+ assertThat(apps.getAllValues().get(0).getTitle()).isEqualTo(BROWSER_TITLE);
+ assertThat(apps.getAllValues().get(0).getSummary()).isEqualTo(APP_1);
+
+ assertThat(apps.getAllValues().get(1).getTitle()).isEqualTo(PHONE_TITLE);
+ assertThat(apps.getAllValues().get(1).getSummary()).isEqualTo(APP_1 + ", " + APP_2);
+ }
+
+ @Test
+ public void isAvailable() {
+ when(mFeatureFactory.userFeatureProvider.getUserProfiles())
+ .thenReturn(Arrays.asList(new UserHandle(USER_ID)));
+ when(mFeatureFactory.applicationFeatureProvider
+ .findPersistentPreferredActivities(anyInt(), any()))
+ .thenReturn(Collections.emptyList());
+ final EnterpriseSetDefaultAppsListPreferenceController controller =
+ new EnterpriseSetDefaultAppsListPreferenceController(mContext, mFragment,
+ mPackageManager);
+ assertThat(controller.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void getPreferenceKey() {
+ when(mFeatureFactory.userFeatureProvider.getUserProfiles())
+ .thenReturn(Arrays.asList(new UserHandle(USER_ID)));
+ when(mFeatureFactory.applicationFeatureProvider
+ .findPersistentPreferredActivities(anyInt(), any()))
+ .thenReturn(Collections.emptyList());
+ final EnterpriseSetDefaultAppsListPreferenceController controller =
+ new EnterpriseSetDefaultAppsListPreferenceController(mContext, mFragment,
+ mPackageManager);
+ assertThat(controller.getPreferenceKey()).isNull();
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceControllerTest.java
index 3455e80..34d9b24 100644
--- a/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsPreferenceControllerTest.java
@@ -18,32 +18,35 @@
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import android.provider.MediaStore;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.support.v7.preference.Preference;
-import android.util.ArraySet;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
-import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.applications.EnterpriseDefaultApps;
+import com.android.settings.applications.UserAppInfo;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
import org.mockito.Answers;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.when;
@@ -56,6 +59,8 @@
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private UserManager mUm;
private FakeFeatureFactory mFeatureFactory;
private EnterpriseSetDefaultAppsPreferenceController mController;
@@ -69,50 +74,40 @@
null /* lifecycle */);
}
- private static Intent buildIntent(String action, String category, String protocol,
- String type) {
- final Intent intent = new Intent(action);
- if (category != null) {
- intent.addCategory(category);
+ private void setEnterpriseSetDefaultApps(Intent[] intents, int number) {
+ final ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = "app";
+ for (int i = 0; i < number; i++) {
+ final List<UserAppInfo> apps = new ArrayList<>(number);
+ apps.add(new UserAppInfo(new UserInfo(i, "user." + i, UserInfo.FLAG_ADMIN), appInfo));
+ when(mFeatureFactory.applicationFeatureProvider.findPersistentPreferredActivities(eq(i),
+ argThat(new MatchesIntents(intents)))).thenReturn(apps);
}
- if (protocol != null) {
- intent.setData(Uri.parse(protocol));
- }
- if (type != null) {
- intent.setType(type);
- }
- return intent;
}
- private void setEnterpriseSetDefaultApps(Intent[] intents, int number) {
- final Set<ApplicationFeatureProvider.PersistentPreferredActivityInfo> apps
- = new ArraySet<>(number);
- for (int i = 0; i < number; i++) {
- apps.add(new ApplicationFeatureProvider.PersistentPreferredActivityInfo("app", i));
+ private void configureUsers(int number) {
+ final List<UserHandle> users = new ArrayList<>(number);
+ for (int i = 0; i < 64; i++) {
+ users.add(new UserHandle(i));
}
- when(mFeatureFactory.applicationFeatureProvider.findPersistentPreferredActivities(
- argThat(new MatchesIntents(intents)))).thenReturn(apps);
+ when(mFeatureFactory.userFeatureProvider.getUserProfiles()).thenReturn(users);
}
@Test
public void testUpdateState() {
- setEnterpriseSetDefaultApps(new Intent[] {buildIntent(Intent.ACTION_VIEW,
- Intent.CATEGORY_BROWSABLE, "http:", null)}, 1);
- setEnterpriseSetDefaultApps(new Intent[] {new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
- new Intent(MediaStore.ACTION_VIDEO_CAPTURE)}, 2);
- setEnterpriseSetDefaultApps(new Intent[] {buildIntent(Intent.ACTION_VIEW, null, "geo:",
- null)}, 4);
- setEnterpriseSetDefaultApps(new Intent[] {new Intent(Intent.ACTION_SENDTO),
- new Intent(Intent.ACTION_SEND), new Intent(Intent.ACTION_SEND_MULTIPLE)}, 8);
- setEnterpriseSetDefaultApps(new Intent[] {buildIntent(Intent.ACTION_INSERT, null, null,
- "vnd.android.cursor.dir/event")}, 16);
- setEnterpriseSetDefaultApps(new Intent[] {buildIntent(Intent.ACTION_PICK, null, null,
- ContactsContract.Contacts.CONTENT_TYPE)}, 32);
- setEnterpriseSetDefaultApps(new Intent[] {new Intent(Intent.ACTION_DIAL),
- new Intent(Intent.ACTION_CALL)}, 64);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.BROWSER.getIntents(), 1);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.CAMERA.getIntents(), 2);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.MAP.getIntents(), 4);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.EMAIL.getIntents(), 8);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.CALENDAR.getIntents(), 16);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.CONTACTS.getIntents(), 32);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.PHONE.getIntents(), 64);
when(mContext.getResources().getQuantityString(R.plurals.enterprise_privacy_number_packages,
127, 127)).thenReturn("127 apps");
+ // As setEnterpriseSetDefaultApps uses fake Users, we need to list them via UserManager.
+ configureUsers(64);
+
final Preference preference = new Preference(mContext, null, 0, 0);
mController.updateState(preference);
assertThat(preference.getSummary()).isEqualTo("127 apps");
@@ -120,13 +115,12 @@
@Test
public void testIsAvailable() {
- when(mFeatureFactory.applicationFeatureProvider.findPersistentPreferredActivities(
- anyObject())).thenReturn(
- new ArraySet<ApplicationFeatureProvider.PersistentPreferredActivityInfo>());
+ when(mFeatureFactory.applicationFeatureProvider.findPersistentPreferredActivities(anyInt(),
+ anyObject())).thenReturn(new ArrayList<UserAppInfo>());
assertThat(mController.isAvailable()).isFalse();
- setEnterpriseSetDefaultApps(new Intent[] {buildIntent(Intent.ACTION_VIEW,
- Intent.CATEGORY_BROWSABLE, "http:", null)}, 1);
+ setEnterpriseSetDefaultApps(EnterpriseDefaultApps.BROWSER.getIntents(), 1);
+ configureUsers(1);
assertThat(mController.isAvailable()).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index f4f1c63..68333e7 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -30,6 +30,7 @@
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.search2.SearchFeatureProvider;
import com.android.settings.overlay.SurveyFeatureProvider;
+import com.android.settings.users.UserFeatureProvider;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
@@ -52,6 +53,7 @@
public final SurveyFeatureProvider surveyFeatureProvider;
public final SecurityFeatureProvider securityFeatureProvider;
public final SuggestionFeatureProvider suggestionsFeatureProvider;
+ public final UserFeatureProvider userFeatureProvider;
public final AssistGestureFeatureProvider assistGestureFeatureProvider;
/**
@@ -86,6 +88,7 @@
surveyFeatureProvider = mock(SurveyFeatureProvider.class);
securityFeatureProvider = mock(SecurityFeatureProvider.class);
suggestionsFeatureProvider = mock(SuggestionFeatureProvider.class);
+ userFeatureProvider = mock(UserFeatureProvider.class);
assistGestureFeatureProvider = mock(AssistGestureFeatureProvider.class);
}
@@ -145,6 +148,11 @@
}
@Override
+ public UserFeatureProvider getUserFeatureProvider(Context context) {
+ return userFeatureProvider;
+ }
+
+ @Override
public AssistGestureFeatureProvider getAssistGestureFeatureProvider() {
return assistGestureFeatureProvider;
}
diff --git a/tests/robotests/src/com/android/settings/users/UserFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/users/UserFeatureProviderImplTest.java
new file mode 100644
index 0000000..c794cdd
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/users/UserFeatureProviderImplTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.users;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UserFeatureProviderImplTest {
+ public static final int FIRST_USER_ID = 0;
+ public static final int SECOND_USER_ID = 4;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private UserManager mUserManager;
+
+ private UserFeatureProviderImpl mFeatureProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ mFeatureProvider = new UserFeatureProviderImpl(mContext);
+ }
+
+ @Test
+ public void getUserProfiles() {
+ final List<UserHandle> expected =
+ Arrays.asList(new UserHandle(FIRST_USER_ID), new UserHandle(SECOND_USER_ID));
+ when(mUserManager.getUserProfiles()).thenReturn(expected);
+ final List<UserHandle> userProfiles = mFeatureProvider.getUserProfiles();
+ assertThat(userProfiles).isEqualTo(expected);
+ }
+}