diff --git a/res/xml/app_list_disclosure_settings.xml b/res/xml/app_list_disclosure_settings.xml
new file mode 100644
index 00000000000..2aae95ee5e5
--- /dev/null
+++ b/res/xml/app_list_disclosure_settings.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/res/xml/enterprise_privacy_settings.xml b/res/xml/enterprise_privacy_settings.xml
index c2b77b5f37b..c84a33d1699 100644
--- a/res/xml/enterprise_privacy_settings.xml
+++ b/res/xml/enterprise_privacy_settings.xml
@@ -16,8 +16,8 @@
+ android:key="enterprise_privacy_settings"
+ android:title="@string/enterprise_privacy_settings">
> {
+ protected final PackageManagerWrapper mPm;
+ protected final UserManager mUm;
+
+ public AppLister(PackageManagerWrapper packageManager, UserManager userManager) {
+ mPm = packageManager;
+ mUm = userManager;
+ }
+
+ @Override
+ protected List doInBackground(Void... params) {
+ final List result = new ArrayList<>();
+ for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
+ final List list =
+ mPm.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
+ | (user.isAdmin() ? PackageManager.MATCH_ANY_USER : 0),
+ user.id);
+ for (ApplicationInfo info : list) {
+ if (includeInCount(info)) {
+ result.add(new UserAppInfo(user, info));
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(List list) {
+ onAppListBuilt(list);
+ }
+
+ protected abstract void onAppListBuilt(List list);
+ protected abstract boolean includeInCount(ApplicationInfo info);
+}
diff --git a/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounter.java b/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounter.java
index 52f1da5aace..c7d0a627268 100644
--- a/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounter.java
+++ b/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounter.java
@@ -31,7 +31,6 @@ import com.android.settings.enterprise.DevicePolicyManagerWrapper;
public abstract class AppWithAdminGrantedPermissionsCounter extends AppCounter {
private final String[] mPermissions;
- private final PackageManagerWrapper mPackageManager;
private final IPackageManagerWrapper mPackageManagerService;
private final DevicePolicyManagerWrapper mDevicePolicyManager;
@@ -40,18 +39,24 @@ public abstract class AppWithAdminGrantedPermissionsCounter extends AppCounter {
DevicePolicyManagerWrapper devicePolicyManager) {
super(context, packageManager);
mPermissions = permissions;
- mPackageManager = packageManager;
mPackageManagerService = packageManagerService;
mDevicePolicyManager = devicePolicyManager;
}
@Override
protected boolean includeInCount(ApplicationInfo info) {
+ return includeInCount(mPermissions, mDevicePolicyManager, mPm, mPackageManagerService,
+ info);
+ }
+
+ public static boolean includeInCount(String[] permissions,
+ DevicePolicyManagerWrapper devicePolicyManager, PackageManagerWrapper packageManager,
+ IPackageManagerWrapper packageManagerService, ApplicationInfo info) {
if (info.targetSdkVersion >= Build.VERSION_CODES.M) {
// The app uses run-time permissions. Check whether one or more of the permissions were
// granted by enterprise policy.
- for (final String permission : mPermissions) {
- if (mDevicePolicyManager.getPermissionGrantState(null /* admin */, info.packageName,
+ for (final String permission : permissions) {
+ if (devicePolicyManager.getPermissionGrantState(null /* admin */, info.packageName,
permission) == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED) {
return true;
}
@@ -61,14 +66,14 @@ public abstract class AppWithAdminGrantedPermissionsCounter extends AppCounter {
// The app uses install-time permissions. Check whether the app requested one or more of the
// permissions and was installed by enterprise policy, implicitly granting permissions.
- if (mPackageManager.getInstallReason(info.packageName,
+ if (packageManager.getInstallReason(info.packageName,
new UserHandle(UserHandle.getUserId(info.uid)))
!= PackageManager.INSTALL_REASON_POLICY) {
return false;
}
try {
- for (final String permission : mPermissions) {
- if (mPackageManagerService.checkUidPermission(permission, info.uid)
+ for (final String permission : permissions) {
+ if (packageManagerService.checkUidPermission(permission, info.uid)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
diff --git a/src/com/android/settings/applications/AppWithAdminGrantedPermissionsLister.java b/src/com/android/settings/applications/AppWithAdminGrantedPermissionsLister.java
new file mode 100644
index 00000000000..b21f31f3a7d
--- /dev/null
+++ b/src/com/android/settings/applications/AppWithAdminGrantedPermissionsLister.java
@@ -0,0 +1,46 @@
+/*
+ * 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.pm.ApplicationInfo;
+import android.os.UserManager;
+import com.android.settings.enterprise.DevicePolicyManagerWrapper;
+
+/**
+ * Lists installed apps across all users that have been granted one or more specific permissions by
+ * the admin.
+ */
+public abstract class AppWithAdminGrantedPermissionsLister extends AppLister {
+ private final String[] mPermissions;
+ private final IPackageManagerWrapper mPackageManagerService;
+ private final DevicePolicyManagerWrapper mDevicePolicyManager;
+
+ public AppWithAdminGrantedPermissionsLister(String[] permissions,
+ PackageManagerWrapper packageManager, IPackageManagerWrapper packageManagerService,
+ DevicePolicyManagerWrapper devicePolicyManager, UserManager userManager) {
+ super(packageManager, userManager);
+ mPermissions = permissions;
+ mPackageManagerService = packageManagerService;
+ mDevicePolicyManager = devicePolicyManager;
+ }
+
+ @Override
+ protected boolean includeInCount(ApplicationInfo info) {
+ return AppWithAdminGrantedPermissionsCounter.includeInCount(mPermissions,
+ mDevicePolicyManager, mPm, mPackageManagerService, info);
+ }
+}
diff --git a/src/com/android/settings/applications/ApplicationFeatureProvider.java b/src/com/android/settings/applications/ApplicationFeatureProvider.java
index 5e986db959c..e3ad4c9327c 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProvider.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProvider.java
@@ -22,6 +22,7 @@ import android.app.Fragment;
import android.content.Intent;
import android.view.View;
+import java.util.List;
import java.util.Set;
public interface ApplicationFeatureProvider {
@@ -48,6 +49,14 @@ public interface ApplicationFeatureProvider {
*/
void calculateNumberOfPolicyInstalledApps(boolean async, NumberOfAppsCallback callback);
+ /**
+ * Asynchronously builds the list of apps installed on the device via policy in the current user
+ * and all its managed profiles.
+ *
+ * @param callback The callback to invoke with the result
+ */
+ void listPolicyInstalledApps(ListOfAppsCallback callback);
+
/**
* Asynchronously calculates the total number of apps installed in the current user and all its
* managed profiles that have been granted one or more of the given permissions by the admin.
@@ -60,6 +69,16 @@ public interface ApplicationFeatureProvider {
void calculateNumberOfAppsWithAdminGrantedPermissions(String[] permissions, boolean async,
NumberOfAppsCallback callback);
+ /**
+ * Asynchronously builds the list of apps installed in the current user and all its
+ * managed profiles that have been granted one or more of the given permissions by the admin.
+ *
+ * @param permissions Only consider apps that have been granted one or more of these permissions
+ * by the admin, either at run-time or install-time
+ * @param callback The callback to invoke with the result
+ */
+ 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
@@ -79,6 +98,13 @@ public interface ApplicationFeatureProvider {
void onNumberOfAppsResult(int num);
}
+ /**
+ * Callback that receives the list of packages installed on the device.
+ */
+ interface ListOfAppsCallback {
+ void onListOfAppsResult(List result);
+ }
+
public static class PersistentPreferredActivityInfo {
public final String packageName;
public final int userId;
diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
index 417185787dd..353252d8572 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
@@ -73,6 +73,13 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
}
}
+ @Override
+ public void listPolicyInstalledApps(ListOfAppsCallback callback) {
+ final CurrentUserPolicyInstalledAppLister lister =
+ new CurrentUserPolicyInstalledAppLister(mPm, mUm, callback);
+ lister.execute();
+ }
+
@Override
public void calculateNumberOfAppsWithAdminGrantedPermissions(String[] permissions,
boolean async, NumberOfAppsCallback callback) {
@@ -86,6 +93,15 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
}
}
+ @Override
+ public void listAppsWithAdminGrantedPermissions(String[] permissions,
+ ListOfAppsCallback callback) {
+ final CurrentUserAppWithAdminGrantedPermissionsLister lister =
+ new CurrentUserAppWithAdminGrantedPermissionsLister(permissions, mPm, mPms, mDpm,
+ mUm, callback);
+ lister.execute();
+ }
+
@Override
public Set findPersistentPreferredActivities(
Intent[] intents) {
@@ -152,4 +168,39 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
mCallback.onNumberOfAppsResult(num);
}
}
+
+ private static class CurrentUserPolicyInstalledAppLister extends InstalledAppLister {
+ private ListOfAppsCallback mCallback;
+
+ CurrentUserPolicyInstalledAppLister(PackageManagerWrapper packageManager,
+ UserManager userManager, ListOfAppsCallback callback) {
+ super(packageManager, userManager);
+ mCallback = callback;
+ }
+
+ @Override
+ protected void onAppListBuilt(List list) {
+ mCallback.onListOfAppsResult(list);
+ }
+ }
+
+ private static class CurrentUserAppWithAdminGrantedPermissionsLister extends
+ AppWithAdminGrantedPermissionsLister {
+ private ListOfAppsCallback mCallback;
+
+ CurrentUserAppWithAdminGrantedPermissionsLister(String[] permissions,
+ PackageManagerWrapper packageManager, IPackageManagerWrapper packageManagerService,
+ DevicePolicyManagerWrapper devicePolicyManager, UserManager userManager,
+ ListOfAppsCallback callback) {
+ super(permissions, packageManager, packageManagerService, devicePolicyManager,
+ userManager);
+ mCallback = callback;
+ }
+
+ @Override
+ protected void onAppListBuilt(List list) {
+ mCallback.onListOfAppsResult(list);
+ }
+ }
+
}
diff --git a/src/com/android/settings/applications/InstalledAppCounter.java b/src/com/android/settings/applications/InstalledAppCounter.java
index 8065d490b42..932facee6f5 100644
--- a/src/com/android/settings/applications/InstalledAppCounter.java
+++ b/src/com/android/settings/applications/InstalledAppCounter.java
@@ -31,21 +31,24 @@ public abstract class InstalledAppCounter extends AppCounter {
public static final int IGNORE_INSTALL_REASON = -1;
private final int mInstallReason;
- private final PackageManagerWrapper mPackageManager;
public InstalledAppCounter(Context context, int installReason,
PackageManagerWrapper packageManager) {
super(context, packageManager);
mInstallReason = installReason;
- mPackageManager = packageManager;
}
@Override
protected boolean includeInCount(ApplicationInfo info) {
+ return includeInCount(mInstallReason, mPm, info);
+ }
+
+ public static boolean includeInCount(int installReason, PackageManagerWrapper pm,
+ ApplicationInfo info) {
final int userId = UserHandle.getUserId(info.uid);
- if (mInstallReason != IGNORE_INSTALL_REASON
- && mPackageManager.getInstallReason(info.packageName,
- new UserHandle(userId)) != mInstallReason) {
+ if (installReason != IGNORE_INSTALL_REASON
+ && pm.getInstallReason(info.packageName,
+ new UserHandle(userId)) != installReason) {
return false;
}
if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
@@ -57,7 +60,7 @@ public abstract class InstalledAppCounter extends AppCounter {
Intent launchIntent = new Intent(Intent.ACTION_MAIN, null)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(info.packageName);
- List intents = mPm.queryIntentActivitiesAsUser(
+ List intents = pm.queryIntentActivitiesAsUser(
launchIntent,
PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
diff --git a/src/com/android/settings/applications/InstalledAppLister.java b/src/com/android/settings/applications/InstalledAppLister.java
new file mode 100644
index 00000000000..1c3b0e9b28a
--- /dev/null
+++ b/src/com/android/settings/applications/InstalledAppLister.java
@@ -0,0 +1,34 @@
+/*
+ * 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.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.UserManager;
+
+public abstract class InstalledAppLister extends AppLister {
+
+ public InstalledAppLister(PackageManagerWrapper packageManager,
+ UserManager userManager) {
+ super(packageManager, userManager);
+ }
+
+ @Override
+ protected boolean includeInCount(ApplicationInfo info) {
+ return InstalledAppCounter.includeInCount(PackageManager.INSTALL_REASON_POLICY, mPm, info);
+ }
+}
diff --git a/src/com/android/settings/applications/UserAppInfo.java b/src/com/android/settings/applications/UserAppInfo.java
new file mode 100644
index 00000000000..3af5f19167f
--- /dev/null
+++ b/src/com/android/settings/applications/UserAppInfo.java
@@ -0,0 +1,57 @@
+/*
+ * 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.pm.ApplicationInfo;
+import android.content.pm.UserInfo;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * Simple class for bringing together information about application and user for which it was
+ * installed.
+ */
+public class UserAppInfo {
+ public final UserInfo userInfo;
+ public final ApplicationInfo appInfo;
+
+ public UserAppInfo(UserInfo mUserInfo, ApplicationInfo mAppInfo) {
+ this.userInfo = mUserInfo;
+ this.appInfo = mAppInfo;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+
+ final UserAppInfo that = (UserAppInfo) other;
+
+ return that.userInfo.id == userInfo.id && TextUtils.equals(that.appInfo.packageName,
+ appInfo.packageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(userInfo.id, appInfo.packageName);
+ }
+}
diff --git a/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerBase.java b/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerBase.java
index 0db9e15319c..f0aca01a1a5 100644
--- a/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerBase.java
+++ b/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerBase.java
@@ -16,7 +16,6 @@
package com.android.settings.enterprise;
import android.content.Context;
-import android.content.Intent;
import android.support.v7.preference.Preference;
import com.android.settings.R;
@@ -32,6 +31,7 @@ public abstract class AdminGrantedPermissionsPreferenceControllerBase
private final String mPermissionGroup;
private final ApplicationFeatureProvider mFeatureProvider;
private final boolean mAsync;
+ private boolean mHasApps;
public AdminGrantedPermissionsPreferenceControllerBase(Context context, Lifecycle lifecycle,
boolean async, String[] permissions, String permissionGroup) {
@@ -41,6 +41,7 @@ public abstract class AdminGrantedPermissionsPreferenceControllerBase
mFeatureProvider = FeatureFactory.getFactory(context)
.getApplicationFeatureProvider(context);
mAsync = async;
+ mHasApps = false;
}
@Override
@@ -50,11 +51,13 @@ public abstract class AdminGrantedPermissionsPreferenceControllerBase
(num) -> {
if (num == 0) {
preference.setVisible(false);
+ mHasApps = false;
} else {
preference.setVisible(true);
preference.setSummary(mContext.getResources().getQuantityString(
R.plurals.enterprise_privacy_number_packages_lower_bound,
num, num));
+ mHasApps = true;
}
});
}
@@ -76,7 +79,8 @@ public abstract class AdminGrantedPermissionsPreferenceControllerBase
final Boolean[] haveAppsWithAdminGrantedPermissions = { null };
mFeatureProvider.calculateNumberOfAppsWithAdminGrantedPermissions(mPermissions,
false /* async */, (num) -> haveAppsWithAdminGrantedPermissions[0] = num > 0);
- return haveAppsWithAdminGrantedPermissions[0];
+ mHasApps = haveAppsWithAdminGrantedPermissions[0];
+ return mHasApps;
}
@Override
@@ -84,9 +88,9 @@ public abstract class AdminGrantedPermissionsPreferenceControllerBase
if (!getPreferenceKey().equals(preference.getKey())) {
return false;
}
- final Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
- .putExtra(Intent.EXTRA_PERMISSION_NAME, mPermissionGroup);
- mContext.startActivity(intent);
- return true;
+ if (!mHasApps) {
+ return false;
+ }
+ return super.handlePreferenceTreeClick(preference);
}
}
diff --git a/src/com/android/settings/enterprise/ApplicationListFragment.java b/src/com/android/settings/enterprise/ApplicationListFragment.java
new file mode 100644
index 00000000000..9a887d8d10b
--- /dev/null
+++ b/src/com/android/settings/enterprise/ApplicationListFragment.java
@@ -0,0 +1,110 @@
+/*
+ * 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.Manifest;
+import android.content.Context;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base fragment for displaying a list of applications on a device.
+ * Inner static classes are concrete implementations.
+ */
+public abstract class ApplicationListFragment extends DashboardFragment
+ implements ApplicationListPreferenceController.ApplicationListBuilder {
+
+ static final String TAG = "EnterprisePrivacySettings";
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.ENTERPRISE_PRIVACY_SETTINGS;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.app_list_disclosure_settings;
+ }
+
+ @Override
+ protected List getPreferenceControllers(Context context) {
+ final List controllers = new ArrayList<>();
+ ApplicationListPreferenceController controller = new ApplicationListPreferenceController(
+ context, this, context.getPackageManager(), this);
+ controllers.add(controller);
+ return controllers;
+ }
+
+ private abstract static class AdminGrantedPermission extends ApplicationListFragment {
+ private final String[] mPermissions;
+
+ public AdminGrantedPermission(String[] permissions) {
+ mPermissions = permissions;
+ }
+
+ @Override
+ public void buildApplicationList(Context context,
+ ApplicationFeatureProvider.ListOfAppsCallback callback) {
+ FeatureFactory.getFactory(context).getApplicationFeatureProvider(context)
+ .listAppsWithAdminGrantedPermissions(mPermissions, callback);
+ }
+ }
+
+ public static class AdminGrantedPermissionCamera extends AdminGrantedPermission {
+ public AdminGrantedPermissionCamera() {
+ super(new String[] {Manifest.permission.CAMERA});
+ }
+ }
+
+ public static class AdminGrantedPermissionLocation extends AdminGrantedPermission {
+ public AdminGrantedPermissionLocation() {
+ super(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION});
+ }
+ }
+
+ public static class AdminGrantedPermissionMicrophone extends AdminGrantedPermission {
+ public AdminGrantedPermissionMicrophone() {
+ super(new String[] {Manifest.permission.RECORD_AUDIO});
+ }
+ }
+
+ public static class EnterpriseInstalledPackages extends ApplicationListFragment {
+ public EnterpriseInstalledPackages() {
+ }
+
+ @Override
+ public void buildApplicationList(Context context,
+ ApplicationFeatureProvider.ListOfAppsCallback callback) {
+ FeatureFactory.getFactory(context).getApplicationFeatureProvider(context).
+ listPolicyInstalledApps(callback);
+ }
+ }
+}
diff --git a/src/com/android/settings/enterprise/ApplicationListPreferenceController.java b/src/com/android/settings/enterprise/ApplicationListPreferenceController.java
new file mode 100644
index 00000000000..f9fefa1837b
--- /dev/null
+++ b/src/com/android/settings/enterprise/ApplicationListPreferenceController.java
@@ -0,0 +1,86 @@
+/*
+ * 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.PackageManager;
+import android.support.v7.preference.Preference;
+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.UserAppInfo;
+import com.android.settings.core.PreferenceController;
+
+import java.util.List;
+
+/**
+ * PreferenceController that builds a dynamic list of applications provided by
+ * {@link ApplicationListBuilder} instance.
+ */
+public class ApplicationListPreferenceController extends PreferenceController
+ implements ApplicationFeatureProvider.ListOfAppsCallback {
+ private final PackageManager mPm;
+ private SettingsPreferenceFragment mParent;
+
+ public ApplicationListPreferenceController(Context context, ApplicationListBuilder builder,
+ PackageManager packageManager, SettingsPreferenceFragment parent) {
+ super(context);
+ mPm = packageManager;
+ mParent = parent;
+ builder.buildApplicationList(context, this);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return null;
+ }
+
+ @Override
+ public void onListOfAppsResult(List result) {
+ final PreferenceScreen screen = mParent.getPreferenceScreen();
+ if (screen == null) {
+ return;
+ }
+ final Context prefContext = mParent.getPreferenceManager().getContext();
+ for (int position = 0; position < result.size(); position++) {
+ final UserAppInfo item = result.get(position);
+ final Preference preference = new Preference(prefContext);
+ preference.setLayoutResource(R.layout.preference_app);
+ preference.setTitle(item.appInfo.loadLabel(mPm));
+ preference.setIcon(item.appInfo.loadIcon(mPm));
+ preference.setOrder(position);
+ preference.setSelectable(false);
+ screen.addPreference(preference);
+ }
+ }
+
+ /**
+ * Simple interface for building application list within {
+ * @link ApplicationListPreferenceController}
+ */
+ public interface ApplicationListBuilder {
+ void buildApplicationList(Context context,
+ ApplicationFeatureProvider.ListOfAppsCallback callback);
+ }
+}
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index f5462b04dbc..c043f1bf54c 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -5,3 +5,7 @@ com.android.settings.fuelgauge.PowerUsageDetail
com.android.settings.fuelgauge.AdvancedPowerUsageDetail
com.android.settings.deviceinfo.StorageProfileFragment
com.android.settings.wifi.details.WifiNetworkDetailsFragment
+com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionCamera
+com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionLocation
+com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMicrophone
+com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
diff --git a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
index aeb38266b27..4a7dc8fa5e5 100644
--- a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
@@ -18,15 +18,18 @@ package com.android.settings.applications;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Build;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.enterprise.DevicePolicyManagerWrapper;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -83,102 +86,31 @@ public final class AppWithAdminGrantedPermissionsCounterTest {
@Mock private DevicePolicyManagerWrapper mDevicePolicyManager;
private int mAppCount = -1;
+ private ApplicationInfo mApp1;
+ private ApplicationInfo mApp2;
+ private ApplicationInfo mApp3;
+ private ApplicationInfo mApp4;
+ private ApplicationInfo mApp5;
+ private ApplicationInfo mApp6;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+
+ mApp1 = buildInfo(APP_1_UID, APP_1, 0 /* flags */, Build.VERSION_CODES.M);
+ mApp2 = buildInfo(APP_2_UID, APP_2, 0 /* flags */, Build.VERSION_CODES.M);
+ mApp3 = buildInfo(APP_3_UID, APP_3, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP);
+ mApp4 = buildInfo(APP_4_UID, APP_4, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP);
+ mApp5 = buildInfo(APP_5_UID, APP_5, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP);
+ mApp6 = buildInfo(APP_6_UID, APP_6, 0 /* flags */, Build.VERSION_CODES.M);
}
private void verifyCountInstalledApps(boolean async) throws Exception {
- // There are two users.
- when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
- new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),
- new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0)));
-
- // The first user has five apps installed:
- // * app1 uses run-time permissions. It has been granted one of the permissions by the
- // admin. It should be counted.
- // * app2 uses run-time permissions. It has not been granted any of the permissions by the
- // admin. It should not be counted.
- // * app3 uses install-time permissions. It was installed by the admin and requested one of
- // the permissions. It should be counted.
- // * app4 uses install-time permissions. It was not installed by the admin but did request
- // one of the permissions. It should not be counted.
- // * app5 uses install-time permissions. It was installed by the admin but did not request
- // any of the permissions. It should not be counted.
- when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
- | PackageManager.MATCH_ANY_USER,
- MAIN_USER_ID)).thenReturn(Arrays.asList(
- buildInfo(APP_1_UID, APP_1, 0 /* flags */, Build.VERSION_CODES.M),
- buildInfo(APP_2_UID, APP_2, 0 /* flags */, Build.VERSION_CODES.M),
- buildInfo(APP_3_UID, APP_3, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP),
- buildInfo(APP_4_UID, APP_4, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP),
- buildInfo(APP_5_UID, APP_5, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP)));
-
- // Grant run-time permissions as appropriate.
- when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_1))
- .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
- when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_2))
- .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_2), anyObject()))
- .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_3), anyObject()))
- .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_4), anyObject()))
- .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_5), anyObject()))
- .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
-
- // Grant install-time permissions as appropriate.
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_1_UID)))
- .thenReturn(PackageManager.PERMISSION_DENIED);
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_2_UID)))
- .thenReturn(PackageManager.PERMISSION_DENIED);
- when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_3_UID))
- .thenReturn(PackageManager.PERMISSION_DENIED);
- when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_3_UID))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
- when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_4_UID))
- .thenReturn(PackageManager.PERMISSION_DENIED);
- when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_4_UID))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_5_UID)))
- .thenReturn(PackageManager.PERMISSION_DENIED);
-
- // app3 and app5 were installed by enterprise policy.
- final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
- when(mPackageManager.getInstallReason(APP_1, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
- when(mPackageManager.getInstallReason(APP_2, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
- when(mPackageManager.getInstallReason(APP_3, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_POLICY);
- when(mPackageManager.getInstallReason(APP_4, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
- when(mPackageManager.getInstallReason(APP_5, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_POLICY);
-
- // The second user has one app installed. This app uses run-time permissions. It has been
- // granted both permissions by the admin. It should be counted.
- when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
- MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(
- buildInfo(APP_6_UID, APP_6, 0 /* flags */, Build.VERSION_CODES.M)));
-
- // Grant run-time permissions as appropriate.
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_6), anyObject()))
- .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
-
- // Grant install-time permissions as appropriate.
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_6_UID)))
- .thenReturn(PackageManager.PERMISSION_DENIED);
-
- // app6 was not installed by enterprise policy.
- final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
- when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
- .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ configureUserManager();
+ configurePackageManager();
+ configureRunTimePermissions();
+ configureInstallTimePermissions();
// Count the number of all apps installed that were granted on or more permissions by the
// admin.
@@ -200,6 +132,28 @@ public final class AppWithAdminGrantedPermissionsCounterTest {
verifyNoMoreInteractions(mPackageManager);
}
+ @Test
+ public void testIncludeInCount() throws Exception {
+ configurePackageManager();
+ configureRunTimePermissions();
+ configureInstallTimePermissions();
+
+ assertThat(AppWithAdminGrantedPermissionsCounter.includeInCount(PERMISSIONS,
+ mDevicePolicyManager, mPackageManager, mPackageManagerService, mApp1)).isTrue();
+
+ assertThat(AppWithAdminGrantedPermissionsCounter.includeInCount(PERMISSIONS,
+ mDevicePolicyManager, mPackageManager, mPackageManagerService, mApp2)).isFalse();
+
+ assertThat(AppWithAdminGrantedPermissionsCounter.includeInCount(PERMISSIONS,
+ mDevicePolicyManager, mPackageManager, mPackageManagerService, mApp3)).isTrue();
+
+ assertThat(AppWithAdminGrantedPermissionsCounter.includeInCount(PERMISSIONS,
+ mDevicePolicyManager, mPackageManager, mPackageManagerService, mApp4)).isFalse();
+
+ assertThat(AppWithAdminGrantedPermissionsCounter.includeInCount(PERMISSIONS,
+ mDevicePolicyManager, mPackageManager, mPackageManagerService, mApp5)).isFalse();
+ }
+
@Test
public void testCountInstalledAppsSync() throws Exception {
verifyCountInstalledApps(false /* async */);
@@ -210,6 +164,90 @@ public final class AppWithAdminGrantedPermissionsCounterTest {
verifyCountInstalledApps(true /* async */);
}
+ private void configureInstallTimePermissions() throws RemoteException {
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_1_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_2_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_3_UID))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_3_UID))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_4_UID))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_4_UID))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_5_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_6_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ }
+
+ private void configureRunTimePermissions() {
+ when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_1))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+ when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_2))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_2), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_3), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_4), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_5), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_6), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+ }
+
+ private void configurePackageManager() {
+ // The first user has five apps installed:
+ // * app1 uses run-time permissions. It has been granted one of the permissions by the
+ // admin. It should be counted.
+ // * app2 uses run-time permissions. It has not been granted any of the permissions by the
+ // admin. It should not be counted.
+ // * app3 uses install-time permissions. It was installed by the admin and requested one of
+ // the permissions. It should be counted.
+ // * app4 uses install-time permissions. It was not installed by the admin but did request
+ // one of the permissions. It should not be counted.
+ // * app5 uses install-time permissions. It was installed by the admin but did not request
+ // any of the permissions. It should not be counted.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_ANY_USER,
+ MAIN_USER_ID)).thenReturn(Arrays.asList(mApp1, mApp2, mApp3, mApp4, mApp5));
+ // The second user has one app installed. This app uses run-time permissions. It has been
+ // granted both permissions by the admin. It should be counted.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+ MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(mApp6));
+
+ // app3 and app5 were installed by enterprise policy.
+ final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
+ when(mPackageManager.getInstallReason(APP_1, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_2, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_3, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_4, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_5, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ // app6 was not installed by enterprise policy.
+ final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
+ when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+
+ }
+
+ private void configureUserManager() {
+ // There are two users.
+ when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
+ new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),
+ new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0)));
+ }
+
private class AppWithAdminGrantedPermissionsCounterTestable extends
AppWithAdminGrantedPermissionsCounter {
public AppWithAdminGrantedPermissionsCounterTestable(String[] permissions) {
diff --git a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
new file mode 100644
index 00000000000..73bba044c48
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
@@ -0,0 +1,223 @@
+/*
+ * 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.app.admin.DevicePolicyManager;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Build;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.enterprise.DevicePolicyManagerWrapper;
+
+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.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static com.android.settings.testutils.ApplicationTestUtils.buildInfo;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link AppWithAdminGrantedPermissionsLister}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class AppWithAdminGrantedPermissionsListerTest {
+
+ private final String APP_1 = "app1";
+ private final String APP_2 = "app2";
+ private final String APP_3 = "app3";
+ private final String APP_4 = "app4";
+ private final String APP_5 = "app5";
+ private final String APP_6 = "app6";
+
+ private final int MAIN_USER_ID = 0;
+ private final int MANAGED_PROFILE_ID = 10;
+
+ private final int PER_USER_UID_RANGE = 100000;
+ private final int APP_1_UID = MAIN_USER_ID * PER_USER_UID_RANGE + 1;
+ private final int APP_2_UID = MAIN_USER_ID * PER_USER_UID_RANGE + 2;
+ private final int APP_3_UID = MAIN_USER_ID * PER_USER_UID_RANGE + 3;
+ private final int APP_4_UID = MAIN_USER_ID * PER_USER_UID_RANGE + 4;
+ private final int APP_5_UID = MAIN_USER_ID * PER_USER_UID_RANGE + 5;
+ private final int APP_6_UID = MANAGED_PROFILE_ID * PER_USER_UID_RANGE + 1;
+
+ private final String PERMISSION_1 = "some.permission.1";
+ private final String PERMISSION_2 = "some.permission.2";
+ private final String[] PERMISSIONS = {PERMISSION_1, PERMISSION_2};
+
+ @Mock private UserManager mUserManager;
+ @Mock private PackageManagerWrapper mPackageManager;
+ @Mock private IPackageManagerWrapper mPackageManagerService;
+ @Mock private DevicePolicyManagerWrapper mDevicePolicyManager;
+
+ private List mAppList = Collections.emptyList();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void verifyListInstalledApps() throws Exception {
+ // There are two users.
+ when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
+ new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),
+ new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0)));
+
+ // The first user has five apps installed:
+ // * app1 uses run-time permissions. It has been granted one of the permissions by the
+ // admin. It should be listed.
+ // * app2 uses run-time permissions. It has not been granted any of the permissions by the
+ // admin. It should not be listed.
+ // * app3 uses install-time permissions. It was installed by the admin and requested one of
+ // the permissions. It should be listed.
+ // * app4 uses install-time permissions. It was not installed by the admin but did request
+ // one of the permissions. It should not be listed.
+ // * app5 uses install-time permissions. It was installed by the admin but did not request
+ // any of the permissions. It should not be listed.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_ANY_USER,
+ MAIN_USER_ID)).thenReturn(Arrays.asList(
+ buildInfo(APP_1_UID, APP_1, 0 /* flags */, Build.VERSION_CODES.M),
+ buildInfo(APP_2_UID, APP_2, 0 /* flags */, Build.VERSION_CODES.M),
+ buildInfo(APP_3_UID, APP_3, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP),
+ buildInfo(APP_4_UID, APP_4, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP),
+ buildInfo(APP_5_UID, APP_5, 0 /* flags */, Build.VERSION_CODES.LOLLIPOP)));
+
+ // Grant run-time permissions as appropriate.
+ when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_1))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+ when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_2))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_2), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_3), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_4), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_5), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+
+ // Grant install-time permissions as appropriate.
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_1_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_2_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_3_UID))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_3_UID))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_4_UID))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_4_UID))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_5_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ // app3 and app5 were installed by enterprise policy.
+ final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
+ when(mPackageManager.getInstallReason(APP_1, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_2, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_3, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_4, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_5, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+
+ // The second user has one app installed. This app uses run-time permissions. It has been
+ // granted both permissions by the admin. It should be listed.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+ MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(
+ buildInfo(APP_6_UID, APP_6, 0 /* flags */, Build.VERSION_CODES.M)));
+
+ // Grant run-time permissions as appropriate.
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_6), anyObject()))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+
+ // Grant install-time permissions as appropriate.
+ when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_6_UID)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ // app6 was not installed by enterprise policy.
+ final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
+ when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+
+ // List all apps installed that were granted one or more permissions by the
+ // admin.
+ (new AppWithAdminGrantedPermissionsListerTestable(PERMISSIONS)).execute();
+
+ // Wait for the background task to finish.
+ ShadowApplication.runBackgroundTasks();
+ assertThat(mAppList.size()).isEqualTo(3);
+ InstalledAppListerTest.verifyListUniqueness(mAppList);
+
+ assertThat(InstalledAppListerTest.checkAppFound(mAppList, APP_1, MAIN_USER_ID)).isTrue();
+ assertThat(InstalledAppListerTest.checkAppFound(mAppList, APP_2, MAIN_USER_ID)).isFalse();
+ assertThat(InstalledAppListerTest.checkAppFound(mAppList, APP_3, MAIN_USER_ID)).isTrue();
+ assertThat(InstalledAppListerTest.checkAppFound(mAppList, APP_4, MAIN_USER_ID)).isFalse();
+ assertThat(InstalledAppListerTest.checkAppFound(mAppList, APP_5, MAIN_USER_ID)).isFalse();
+ assertThat(InstalledAppListerTest.checkAppFound(mAppList, APP_6, MANAGED_PROFILE_ID)).
+ isTrue();
+
+ // Verify that installed packages were retrieved the current user and the user's managed
+ // profile only.
+ verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID));
+ verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(),
+ eq(MANAGED_PROFILE_ID));
+ verify(mPackageManager, atLeast(0)).getInstallReason(anyObject(), anyObject());
+ verifyNoMoreInteractions(mPackageManager);
+ }
+
+ private class AppWithAdminGrantedPermissionsListerTestable extends
+ AppWithAdminGrantedPermissionsLister {
+
+ public AppWithAdminGrantedPermissionsListerTestable(String[] permissions) {
+ super(permissions, mPackageManager, mPackageManagerService,
+ mDevicePolicyManager, mUserManager);
+ }
+
+ @Override
+ protected void onAppListBuilt(List list) {
+ mAppList = list;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
index f46bb902043..cb68ccb4f13 100644
--- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
@@ -33,6 +33,7 @@ import com.android.settings.TestConfig;
import com.android.settings.enterprise.DevicePolicyManagerWrapper;
import com.android.settings.testutils.ApplicationTestUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,6 +43,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import java.util.Arrays;
+import java.util.List;
import java.util.Set;
import static com.google.common.truth.Truth.assertThat;
@@ -76,6 +78,7 @@ public final class ApplicationFeatureProviderImplTest {
private ApplicationFeatureProvider mProvider;
private int mAppCount = -1;
+ private List mAppList = null;
@Before
public void setUp() {
@@ -105,6 +108,22 @@ public final class ApplicationFeatureProviderImplTest {
assertThat(mAppCount).isEqualTo(1);
}
+ @Test
+ public void testListPolicyInstalledApps() {
+ setUpUsersAndInstalledApps();
+
+ when(mPackageManager.getInstallReason(APP_1, new UserHandle(MAIN_USER_ID)))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_2, new UserHandle(MANAGED_PROFILE_ID)))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+
+ mAppList = null;
+ mProvider.listPolicyInstalledApps((list) -> mAppList = list);
+ assertThat(mAppList).isNotNull();
+ assertThat(mAppList.size()).isEqualTo(1);
+ assertThat(mAppList.get(0).appInfo.packageName).isEqualTo(APP_2);
+ }
+
@Test
public void testCalculateNumberOfInstalledAppsSync() {
verifyCalculateNumberOfPolicyInstalledApps(false /* async */);
@@ -139,7 +158,6 @@ public final class ApplicationFeatureProviderImplTest {
ShadowApplication.runBackgroundTasks();
}
assertThat(mAppCount).isEqualTo(2);
-
}
@Test
@@ -152,6 +170,34 @@ public final class ApplicationFeatureProviderImplTest {
verifyCalculateNumberOfAppsWithAdminGrantedPermissions(true /* async */);
}
+ @Test
+ public void testListAppsWithAdminGrantedPermissions()
+ throws Exception {
+ setUpUsersAndInstalledApps();
+
+ when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+ when(mDevicePolicyManager.getPermissionGrantState(null, APP_2, PERMISSION))
+ .thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION, APP_1_UID))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPackageManagerService.checkUidPermission(PERMISSION, APP_2_UID))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mPackageManager.getInstallReason(APP_1, new UserHandle(MAIN_USER_ID)))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_2, new UserHandle(MANAGED_PROFILE_ID)))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+
+ mAppList = null;
+ mProvider.listAppsWithAdminGrantedPermissions(new String[] {PERMISSION},
+ (list) -> mAppList = list);
+ assertThat(mAppList).isNotNull();
+ assertThat(mAppList.size()).isEqualTo(2);
+ assertThat(Arrays.asList(mAppList.get(0).appInfo.packageName,
+ mAppList.get(1).appInfo.packageName).containsAll(Arrays.asList(APP_1, APP_2)))
+ .isTrue();
+ }
+
@Test
public void testFindPersistentPreferredActivities() throws Exception {
when(mUserManager.getUserProfiles()).thenReturn(Arrays.asList(new UserHandle(MAIN_USER_ID),
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
index 46a3359c530..37fa9d70bb1 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
@@ -22,12 +22,14 @@ 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 com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.testutils.shadow.ShadowUserManager;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -75,16 +77,38 @@ public final class InstalledAppCounterTest {
private final int MAIN_USER_APP_UID = MAIN_USER_ID * PER_USER_UID_RANGE;
private final int MANAGED_PROFILE_APP_UID = MANAGED_PROFILE_ID * PER_USER_UID_RANGE;
- @Mock private UserManager mUserManager;
- @Mock private Context mContext;
- @Mock private PackageManagerWrapper mPackageManager;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private Context mContext;
+ @Mock
+ private PackageManagerWrapper mPackageManager;
private int mInstalledAppCount = -1;
+ private ApplicationInfo mApp1;
+ private ApplicationInfo mApp2;
+ private ApplicationInfo mApp3;
+ private ApplicationInfo mApp4;
+ private ApplicationInfo mApp5;
+ private ApplicationInfo mApp6;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+
+ mApp1 = buildInfo(MAIN_USER_APP_UID, APP_1,
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0 /* targetSdkVersion */);
+ mApp2 = buildInfo(MAIN_USER_APP_UID, APP_2, 0 /* flags */,
+ 0 /* targetSdkVersion */);
+ mApp3 = buildInfo(MAIN_USER_APP_UID, APP_3, ApplicationInfo.FLAG_SYSTEM,
+ 0 /* targetSdkVersion */);
+ mApp4 = buildInfo(MAIN_USER_APP_UID, APP_4, ApplicationInfo.FLAG_SYSTEM,
+ 0 /* targetSdkVersion */);
+ mApp5 = buildInfo(MANAGED_PROFILE_APP_UID, APP_5, 0 /* flags */,
+ 0 /* targetSdkVersion */);
+ mApp6 = buildInfo(MANAGED_PROFILE_APP_UID, APP_6, ApplicationInfo.FLAG_SYSTEM,
+ 0 /* targetSdkVersion */);
}
private void expectQueryIntentActivities(int userId, String packageName, boolean launchable) {
@@ -93,7 +117,7 @@ public final class InstalledAppCounterTest {
eq(PackageManager.GET_DISABLED_COMPONENTS | PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE),
eq(userId))).thenReturn(launchable ? Arrays.asList(new ResolveInfo())
- : new ArrayList());
+ : new ArrayList());
}
private void testCountInstalledAppsAcrossAllUsers(boolean async) {
@@ -101,58 +125,7 @@ public final class InstalledAppCounterTest {
when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),
new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0)));
-
- // The first user has four apps installed:
- // * app1 is an updated system app. It should be counted.
- // * app2 is a user-installed app. It should be counted.
- // * app3 is a system app that provides a launcher icon. It should be counted.
- // * app4 is a system app that provides no launcher icon. It should not be counted.
- when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
- | PackageManager.MATCH_ANY_USER,
- MAIN_USER_ID)).thenReturn(Arrays.asList(
- buildInfo(MAIN_USER_APP_UID, APP_1,
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0 /* targetSdkVersion */),
- buildInfo(MAIN_USER_APP_UID, APP_2, 0 /* flags */,
- 0 /* targetSdkVersion */),
- buildInfo(MAIN_USER_APP_UID, APP_3, ApplicationInfo.FLAG_SYSTEM,
- 0 /* targetSdkVersion */),
- buildInfo(MAIN_USER_APP_UID, APP_4, ApplicationInfo.FLAG_SYSTEM,
- 0 /* targetSdkVersion */)));
- // For system apps, InstalledAppCounter checks whether they handle the default launcher
- // intent to decide whether to include them in the count of installed apps or not.
- expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */);
- expectQueryIntentActivities(MAIN_USER_ID, APP_4, false /* launchable */);
-
- // app1, app3 and app4 are installed by enterprise policy.
- final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
- when(mPackageManager.getInstallReason(APP_1, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_POLICY);
- when(mPackageManager.getInstallReason(APP_2, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
- when(mPackageManager.getInstallReason(APP_3, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_POLICY);
- when(mPackageManager.getInstallReason(APP_4, mainUser))
- .thenReturn(PackageManager.INSTALL_REASON_POLICY);
-
- // The second user has two apps installed:
- // * app5 is a user-installed app. It should be counted.
- // * app6 is a system app that provides a launcher icon. It should be counted.
- when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
- MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(
- buildInfo(MANAGED_PROFILE_APP_UID, APP_5, 0 /* flags */,
- 0 /* targetSdkVersion */),
- buildInfo(MANAGED_PROFILE_APP_UID, APP_6, ApplicationInfo.FLAG_SYSTEM,
- 0 /* targetSdkVersion */)));
- expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */);
-
- // app5 is installed by enterprise policy.
- final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
- when(mPackageManager.getInstallReason(APP_5, managedProfileUser))
- .thenReturn(PackageManager.INSTALL_REASON_POLICY);
- when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
- .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ configurePackageManager();
// Count the number of all apps installed, irrespective of install reason.
count(InstalledAppCounter.IGNORE_INSTALL_REASON, async);
@@ -172,6 +145,36 @@ public final class InstalledAppCounterTest {
assertThat(mInstalledAppCount).isEqualTo(3);
}
+ @Test
+ public void testIncludeInCount() {
+ configurePackageManager();
+ assertThat(InstalledAppCounter.includeInCount(InstalledAppCounter.IGNORE_INSTALL_REASON,
+ mPackageManager, mApp1)).isTrue();
+ assertThat(InstalledAppCounter.includeInCount(InstalledAppCounter.IGNORE_INSTALL_REASON,
+ mPackageManager, mApp2)).isTrue();
+ assertThat(InstalledAppCounter.includeInCount(InstalledAppCounter.IGNORE_INSTALL_REASON,
+ mPackageManager, mApp3)).isTrue();
+ assertThat(InstalledAppCounter.includeInCount(InstalledAppCounter.IGNORE_INSTALL_REASON,
+ mPackageManager, mApp4)).isFalse();
+ assertThat(InstalledAppCounter.includeInCount(InstalledAppCounter.IGNORE_INSTALL_REASON,
+ mPackageManager, mApp5)).isTrue();
+ assertThat(InstalledAppCounter.includeInCount(InstalledAppCounter.IGNORE_INSTALL_REASON,
+ mPackageManager, mApp6)).isTrue();
+
+ assertThat(InstalledAppCounter.includeInCount(PackageManager.INSTALL_REASON_POLICY,
+ mPackageManager, mApp1)).isTrue();
+ assertThat(InstalledAppCounter.includeInCount(PackageManager.INSTALL_REASON_POLICY,
+ mPackageManager, mApp2)).isFalse();
+ assertThat(InstalledAppCounter.includeInCount(PackageManager.INSTALL_REASON_POLICY,
+ mPackageManager, mApp3)).isTrue();
+ assertThat(InstalledAppCounter.includeInCount(PackageManager.INSTALL_REASON_POLICY,
+ mPackageManager, mApp4)).isFalse();
+ assertThat(InstalledAppCounter.includeInCount(PackageManager.INSTALL_REASON_POLICY,
+ mPackageManager, mApp5)).isTrue();
+ assertThat(InstalledAppCounter.includeInCount(PackageManager.INSTALL_REASON_POLICY,
+ mPackageManager, mApp6)).isFalse();
+ }
+
@Test
public void testCountInstalledAppsAcrossAllUsersSync() {
testCountInstalledAppsAcrossAllUsers(false /* async */);
@@ -194,6 +197,48 @@ public final class InstalledAppCounterTest {
}
}
+ private void configurePackageManager() {
+ // The first user has four apps installed:
+ // * app1 is an updated system app. It should be counted.
+ // * app2 is a user-installed app. It should be counted.
+ // * app3 is a system app that provides a launcher icon. It should be counted.
+ // * app4 is a system app that provides no launcher icon. It should not be counted.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_ANY_USER,
+ MAIN_USER_ID)).thenReturn(Arrays.asList(mApp1, mApp2, mApp3, mApp4));
+ // For system apps, InstalledAppCounter checks whether they handle the default launcher
+ // intent to decide whether to include them in the count of installed apps or not.
+ expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */);
+ expectQueryIntentActivities(MAIN_USER_ID, APP_4, false /* launchable */);
+
+ // app1, app3 and app4 are installed by enterprise policy.
+ final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
+ when(mPackageManager.getInstallReason(APP_1, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_2, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_3, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_4, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+
+ // The second user has two apps installed:
+ // * app5 is a user-installed app. It should be counted.
+ // * app6 is a system app that provides a launcher icon. It should be counted.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,MANAGED_PROFILE_ID))
+ .thenReturn(Arrays.asList(mApp5, mApp6));
+ expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */);
+
+ // app5 is installed by enterprise policy.
+ final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
+ when(mPackageManager.getInstallReason(APP_5, managedProfileUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ }
+
private class InstalledAppCounterTestable extends InstalledAppCounter {
public InstalledAppCounterTestable(int installReason) {
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
new file mode 100644
index 00000000000..76421c25f88
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
@@ -0,0 +1,233 @@
+/*
+ * 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.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+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.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.android.settings.testutils.ApplicationTestUtils.buildInfo;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link InstalledAppLister}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class InstalledAppListerTest {
+
+ private final String APP_1 = "app1";
+ private final String APP_2 = "app2";
+ private final String APP_3 = "app3";
+ private final String APP_4 = "app4";
+ private final String APP_5 = "app5";
+ private final String APP_6 = "app6";
+
+ private final int MAIN_USER_ID = 0;
+ private final int MANAGED_PROFILE_ID = 10;
+
+ private final int PER_USER_UID_RANGE = 100000;
+ private final int MAIN_USER_APP_UID = MAIN_USER_ID * PER_USER_UID_RANGE;
+ private final int MANAGED_PROFILE_APP_UID = MANAGED_PROFILE_ID * PER_USER_UID_RANGE;
+
+ @Mock private UserManager mUserManager;
+ @Mock private PackageManagerWrapper mPackageManager;
+
+ private List mInstalledAppList = Collections.emptyList();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ private void expectQueryIntentActivities(int userId, String packageName, boolean launchable) {
+ when(mPackageManager.queryIntentActivitiesAsUser(
+ argThat(new IsLaunchIntentFor(packageName)),
+ eq(PackageManager.GET_DISABLED_COMPONENTS | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE),
+ eq(userId))).thenReturn(launchable ? Arrays.asList(new ResolveInfo())
+ : new ArrayList());
+ }
+
+ @Test
+ public void testCountInstalledAppsAcrossAllUsers() {
+ // There are two users.
+ when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
+ new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),
+ new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0)));
+
+ // The first user has four apps installed:
+ // * app1 is an updated system app. It should be listed.
+ // * app2 is a user-installed app. It should be listed.
+ // * app3 is a system app that provides a launcher icon. It should be listed.
+ // * app4 is a system app that provides no launcher icon. It should not be listed.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_ANY_USER,
+ MAIN_USER_ID)).thenReturn(Arrays.asList(
+ buildInfo(MAIN_USER_APP_UID, APP_1,
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0 /* targetSdkVersion */),
+ buildInfo(MAIN_USER_APP_UID, APP_2, 0 /* flags */,
+ 0 /* targetSdkVersion */),
+ buildInfo(MAIN_USER_APP_UID, APP_3, ApplicationInfo.FLAG_SYSTEM,
+ 0 /* targetSdkVersion */),
+ buildInfo(MAIN_USER_APP_UID, APP_4, ApplicationInfo.FLAG_SYSTEM,
+ 0 /* targetSdkVersion */)));
+ // For system apps, InstalledAppLister checks whether they handle the default launcher
+ // intent to decide whether to include them in the list of installed apps or not.
+ expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */);
+ expectQueryIntentActivities(MAIN_USER_ID, APP_4, false /* launchable */);
+
+ // app1, app3 and app4 are installed by enterprise policy.
+ final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
+ when(mPackageManager.getInstallReason(APP_1, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_2, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+ when(mPackageManager.getInstallReason(APP_3, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_4, mainUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+
+ // The second user has two apps installed:
+ // * app5 is a user-installed app. It should be listed.
+ // * app6 is a system app that provides a launcher icon. It should be listed.
+ when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+ MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(
+ buildInfo(MANAGED_PROFILE_APP_UID, APP_5, 0 /* flags */,
+ 0 /* targetSdkVersion */),
+ buildInfo(MANAGED_PROFILE_APP_UID, APP_6, ApplicationInfo.FLAG_SYSTEM,
+ 0 /* targetSdkVersion */)));
+ expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */);
+
+ // app5 is installed by enterprise policy.
+ final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
+ when(mPackageManager.getInstallReason(APP_5, managedProfileUser))
+ .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+ when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
+ .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+
+ // List apps, considering apps installed by enterprise policy only.
+ mInstalledAppList = Collections.emptyList();
+ final InstalledAppListerTestable counter = new InstalledAppListerTestable();
+ counter.execute();
+ // Wait for the background task to finish.
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(mInstalledAppList.size()).isEqualTo(3);
+
+ assertThat(checkAppFound(mInstalledAppList, APP_1, MAIN_USER_ID)).isTrue();
+ assertThat(checkAppFound(mInstalledAppList, APP_2, MAIN_USER_ID)).isFalse();
+ assertThat(checkAppFound(mInstalledAppList, APP_3, MAIN_USER_ID)).isTrue();
+ assertThat(checkAppFound(mInstalledAppList, APP_4, MAIN_USER_ID)).isFalse();
+ assertThat(checkAppFound(mInstalledAppList, APP_5, MANAGED_PROFILE_ID)).isTrue();
+ assertThat(checkAppFound(mInstalledAppList, APP_6, MANAGED_PROFILE_ID)).isFalse();
+
+ // Verify that installed packages were retrieved for the current user and the user's
+ // managed profile.
+ verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID));
+ verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(),
+ eq(MANAGED_PROFILE_ID));
+ verify(mPackageManager, atLeast(0)).queryIntentActivitiesAsUser(anyObject(), anyInt(),
+ anyInt());
+ }
+
+ public static boolean checkAppFound(List mInstalledAppList, String appId,
+ int userId) {
+ for (UserAppInfo info : mInstalledAppList) {
+ if (appId.equals(info.appInfo.packageName) && (info.userInfo.id == userId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void verifyListUniqueness(List list) {
+ assertThat((new HashSet<>(list)).size()).isEqualTo(list.size());
+ }
+
+ private class InstalledAppListerTestable extends InstalledAppLister {
+ public InstalledAppListerTestable() {
+ super(mPackageManager, mUserManager);
+ }
+
+ @Override
+ protected void onAppListBuilt(List list) {
+ mInstalledAppList = list;
+ }
+ }
+
+ private static class IsLaunchIntentFor extends ArgumentMatcher {
+ private final String mPackageName;
+
+ IsLaunchIntentFor(String packageName) {
+ mPackageName = packageName;
+ }
+
+ @Override
+ public boolean matches(Object i) {
+ final Intent intent = (Intent) i;
+ if (intent == null) {
+ return false;
+ }
+ if (!Intent.ACTION_MAIN.equals(intent.getAction())) {
+ return false;
+ }
+ final Set categories = intent.getCategories();
+ if (categories == null || categories.size() != 1 ||
+ !categories.contains(Intent.CATEGORY_LAUNCHER)) {
+ return false;
+ }
+ if (!mPackageName.equals(intent.getPackage())) {
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java b/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java
index f001bd1e73f..96ce081700d 100644
--- a/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java
+++ b/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java
@@ -17,8 +17,6 @@
package com.android.settings.enterprise;
import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
import android.support.v7.preference.Preference;
import com.android.settings.R;
@@ -28,24 +26,21 @@ import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Answers;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.anyObject;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Common base for testing subclasses of {@link AdminGrantedPermissionsPreferenceControllerBase}.
*/
public abstract class AdminGrantedPermissionsPreferenceControllerTestBase {
-
protected final String mKey;
protected final String[] mPermissions;
protected final String mPermissionGroup;
@@ -123,19 +118,8 @@ public abstract class AdminGrantedPermissionsPreferenceControllerTestBase {
@Test
public void testHandlePreferenceTreeClick() {
- final Preference preference = new Preference(mContext, null, 0, 0);
- preference.setKey(mKey);
-
- assertThat(mController.handlePreferenceTreeClick(preference)).isTrue();
-
- final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext).startActivity(argumentCaptor.capture());
-
- final Intent intent = argumentCaptor.getValue();
-
- assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_APPS);
- assertThat(intent.getStringExtra(Intent.EXTRA_PERMISSION_NAME)).
- isEqualTo(mPermissionGroup);
+ assertThat(mController.handlePreferenceTreeClick(new Preference(mContext, null, 0, 0)))
+ .isFalse();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/enterprise/ApplicationListFragmentTest.java b/tests/robotests/src/com/android/settings/enterprise/ApplicationListFragmentTest.java
new file mode 100644
index 00000000000..5fbaf51216e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/ApplicationListFragmentTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.UserInfo;
+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.applications.ApplicationFeatureProvider;
+import com.android.settings.applications.UserAppInfo;
+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.ArrayList;
+import java.util.List;
+
+import static com.android.settings.testutils.ApplicationTestUtils.buildInfo;
+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 ApplicationListFragmentTest {
+ private static final int USER_ID = 0;
+ private static final int USER_APP_UID = 0;
+
+ private static final String APP = "APP";
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceScreen mScreen;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceManager mPreferenceManager;
+
+ private ApplicationListFragment mFragment;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ShadowApplication.getInstance().getApplicationContext();
+ when(mPreferenceManager.getContext()).thenReturn(mContext);
+
+ mFragment = new ApplicationListFragmentTestable(mPreferenceManager, mScreen);
+ }
+
+ @Test
+ public void getMetricsCategory() {
+ assertThat(mFragment.getMetricsCategory())
+ .isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_SETTINGS);
+ }
+
+ @Test
+ public void getLogTag() {
+ assertThat(mFragment.getLogTag())
+ .isEqualTo("EnterprisePrivacySettings");
+ }
+
+ @Test
+ public void getScreenResource() {
+ assertThat(mFragment.getPreferenceScreenResId())
+ .isEqualTo(R.xml.app_list_disclosure_settings);
+ }
+
+ @Test
+ public void getPreferenceControllers() {
+ final List controllers = mFragment.getPreferenceControllers(mContext);
+ assertThat(controllers).isNotNull();
+ assertThat(controllers.size()).isEqualTo(1);
+ int position = 0;
+ assertThat(controllers.get(position++)).isInstanceOf(
+ ApplicationListPreferenceController.class);
+ }
+
+ private static class ApplicationListFragmentTestable extends ApplicationListFragment {
+
+ private final PreferenceManager mPreferenceManager;
+ private final PreferenceScreen mPreferenceScreen;
+
+ public ApplicationListFragmentTestable(PreferenceManager preferenceManager,
+ PreferenceScreen screen) {
+ this.mPreferenceManager = preferenceManager;
+ this.mPreferenceScreen = screen;
+ }
+
+ @Override
+ public void buildApplicationList(Context context,
+ ApplicationFeatureProvider.ListOfAppsCallback callback) {
+ final List apps = new ArrayList<>();
+ final UserInfo user = new UserInfo(USER_ID, "main", UserInfo.FLAG_ADMIN);
+ apps.add(new UserAppInfo(user, buildInfo(USER_APP_UID, APP, 0, 0)));
+ callback.onListOfAppsResult(apps);
+ }
+
+ @Override
+ public PreferenceManager getPreferenceManager() {
+ return mPreferenceManager;
+ }
+
+ @Override
+ public PreferenceScreen getPreferenceScreen() {
+ return mPreferenceScreen;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/ApplicationListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/ApplicationListPreferenceControllerTest.java
new file mode 100644
index 00000000000..56a6c62f605
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/ApplicationListPreferenceControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.PackageManager;
+import android.content.pm.UserInfo;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.applications.UserAppInfo;
+
+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.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.android.settings.testutils.ApplicationTestUtils.buildInfo;
+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.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 ApplicationListPreferenceControllerTest {
+
+ private static final int MAIN_USER_ID = 0;
+
+ private static final int MANAGED_PROFILE_ID = 10;
+ private static final int PER_USER_UID_RANGE = 100000;
+ private static final int MAIN_USER_APP_UID = MAIN_USER_ID * PER_USER_UID_RANGE;
+ private static final int MANAGED_PROFILE_APP_UID = MANAGED_PROFILE_ID * PER_USER_UID_RANGE;
+
+ private static final String APP_1 = "APP_1";
+ private static final String APP_2 = "APP_2";
+ private static final String APP_3 = "APP_3";
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceScreen mScreen;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PackageManager mPackageManager;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private SettingsPreferenceFragment mFragment;
+
+ private Context mContext;
+ private ApplicationListPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ final ShadowApplication shadowContext = ShadowApplication.getInstance();
+ mContext = shadowContext.getApplicationContext();
+ when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
+ when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
+ when(mPackageManager.getText(eq(APP_1), anyInt(), any())).thenReturn(APP_1);
+ when(mPackageManager.getText(eq(APP_2), anyInt(), any())).thenReturn(APP_2);
+ when(mPackageManager.getText(eq(APP_3), anyInt(), any())).thenReturn(APP_3);
+
+ mController = new ApplicationListPreferenceController(mContext, new ThreeAppsBuilder(),
+ mPackageManager, mFragment);
+ }
+
+ @Test
+ public void checkNumberAndTitlesOfApps() {
+ ArgumentCaptor apps = ArgumentCaptor.forClass(Preference.class);
+ verify(mScreen, times(3)).addPreference(apps.capture());
+ final Set expectedPackages = new HashSet<>(Arrays.asList(APP_1, APP_2, APP_3));
+ final Set packages = new HashSet<>();
+
+ for (Preference p : apps.getAllValues()) {
+ packages.add(p.getTitle().toString());
+ }
+ assertThat(packages).isEqualTo(expectedPackages);
+ }
+
+ @Test
+ public void isAvailable() {
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void getPreferenceKey() {
+ assertThat(mController.getPreferenceKey()).isNull();
+ }
+
+ private static class ThreeAppsBuilder
+ implements ApplicationListPreferenceController.ApplicationListBuilder {
+ @Override
+ public void buildApplicationList(Context context,
+ ApplicationFeatureProvider.ListOfAppsCallback callback) {
+ final List apps = new ArrayList<>();
+ final UserInfo user = new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN);
+ apps.add(new UserAppInfo(user, buildInfo(MAIN_USER_APP_UID, APP_1, 0, 0)));
+ apps.add(new UserAppInfo(user, buildInfo(MAIN_USER_APP_UID, APP_2, 0, 0)));
+ apps.add(new UserAppInfo(user, buildInfo(MANAGED_PROFILE_APP_UID, APP_3, 0, 0)));
+ callback.onListOfAppsResult(apps);
+ }
+ }
+}