From fc7188d8222c45a5d86b518d9af1ef3168a5ac94 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Thu, 14 Jun 2018 13:17:51 -0700 Subject: [PATCH] Clean up DeviceAdminSetting: make it into DashboardFragment Change-Id: Ib5634f782daef15ab317175084c6813d6b8a8bb7 Fixes: 110207366 Test: robo --- res/layout/date_time_custom_list_item_2.xml | 42 -- res/layout/device_admin_item.xml | 86 ---- res/layout/device_admin_settings.xml | 43 -- res/values/bools.xml | 3 - res/xml/device_admin_settings.xml | 29 ++ res/xml/security_dashboard_settings.xml | 9 +- res/xml/special_access.xml | 3 +- .../deviceadmin/DeviceAdminListItem.java | 94 +++++ .../DeviceAdminListPreferenceController.java | 296 ++++++++++++++ .../deviceadmin/DeviceAdminSettings.java | 445 ++------------------- .../deviceadmin/DeviceAdminUtils.java | 58 +++ .../DeviceAdministratorsController.java | 36 -- .../datetime/DatePreferenceController.java | 5 +- .../ManageDeviceAdminPreferenceController.java | 30 +- .../settings/security/SecuritySettings.java | 2 - tests/robotests/res/values-mcc999/config.xml | 1 - .../deviceadmin/DeviceAdminListItemTest.java | 76 ++++ .../DeviceAdminListPreferenceControllerTest.java | 83 ++++ .../DeviceAdministratorsControllerTest.java | 56 --- .../ManageDeviceAdminPreferenceControllerTest.java | 18 +- 20 files changed, 689 insertions(+), 726 deletions(-) delete mode 100644 res/layout/date_time_custom_list_item_2.xml delete mode 100644 res/layout/device_admin_item.xml delete mode 100644 res/layout/device_admin_settings.xml create mode 100644 res/xml/device_admin_settings.xml create mode 100644 src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItem.java create mode 100644 src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java create mode 100644 src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java delete mode 100644 src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsController.java create mode 100644 tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java create mode 100644 tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceControllerTest.java delete mode 100644 tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsControllerTest.java diff --git a/res/layout/date_time_custom_list_item_2.xml b/res/layout/date_time_custom_list_item_2.xml deleted file mode 100644 index 4902758893..0000000000 --- a/res/layout/date_time_custom_list_item_2.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - diff --git a/res/layout/device_admin_item.xml b/res/layout/device_admin_item.xml deleted file mode 100644 index 875c734934..0000000000 --- a/res/layout/device_admin_item.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/layout/device_admin_settings.xml b/res/layout/device_admin_settings.xml deleted file mode 100644 index 1766138f1d..0000000000 --- a/res/layout/device_admin_settings.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/values/bools.xml b/res/values/bools.xml index fa57b29a51..b4066059aa 100644 --- a/res/values/bools.xml +++ b/res/values/bools.xml @@ -96,9 +96,6 @@ true - - true - true diff --git a/res/xml/device_admin_settings.xml b/res/xml/device_admin_settings.xml new file mode 100644 index 0000000000..999d7902bb --- /dev/null +++ b/res/xml/device_admin_settings.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index af15c082ae..8a3d10805c 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -48,7 +48,7 @@ android:key="fingerprint_settings" android:title="@string/security_settings_fingerprint_preference_title" android:summary="@string/summary_placeholder" - settings:keywords="@string/keywords_fingerprint_settings"/> + settings:keywords="@string/keywords_fingerprint_settings" /> @@ -75,7 +75,7 @@ android:key="visiblepattern_profile" android:summary="@string/summary_placeholder" android:title="@string/lockpattern_settings_enable_visible_pattern_title_profile" - settings:controller="com.android.settings.security.VisiblePatternProfilePreferenceController"/> + settings:controller="com.android.settings.security.VisiblePatternProfilePreferenceController" /> + settings:controller="com.android.settings.security.ShowPasswordPreferenceController" /> @@ -112,7 +112,8 @@ android:key="manage_device_admin" android:title="@string/manage_device_admin" android:summary="@string/summary_placeholder" - android:fragment="com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminSettings" /> + android:fragment="com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminSettings" + settings:controller="com.android.settings.enterprise.ManageDeviceAdminPreferenceController" /> + android:summary="@string/summary_placeholder" + settings:controller="com.android.settings.enterprise.ManageDeviceAdminPreferenceController" /> { + + private static final String TAG = "DeviceAdminListItem"; + + private final String mKey; + private final DeviceAdminInfo mInfo; + private final CharSequence mName; + private final Drawable mIcon; + private final DevicePolicyManager mDPM; + private CharSequence mDescription; + + public DeviceAdminListItem(Context context, DeviceAdminInfo info) { + mInfo = info; + mKey = mInfo.getComponent().flattenToString(); + mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); + final PackageManager pm = context.getPackageManager(); + mName = mInfo.loadLabel(pm); + try { + mDescription = mInfo.loadDescription(pm); + } catch (Resources.NotFoundException exception) { + Log.w(TAG, "Setting description to null because can't find resource: " + mKey); + } + mIcon = pm.getUserBadgedIcon(mInfo.loadIcon(pm), + new UserHandle(DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo))); + } + + @Override + public int compareTo(DeviceAdminListItem other) { + return this.mName.toString().compareTo(other.mName.toString()); + } + + public String getKey() { + return mKey; + } + + public CharSequence getName() { + return mName; + } + + public CharSequence getDescription() { + return mDescription; + } + + public boolean isActive() { + return mDPM.isAdminActiveAsUser(mInfo.getComponent(), + DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo)); + } + + public Drawable getIcon() { + return mIcon; + } + + public boolean isEnabled() { + return !mDPM.isRemovingAdmin(mInfo.getComponent(), + DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo)); + } + + public UserHandle getUser() { + return new UserHandle(DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo)); + } + + public Intent getLaunchIntent(Context context) { + return new Intent(context, DeviceAdminAdd.class) + .putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mInfo.getComponent()); + } +} diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java new file mode 100644 index 0000000000..52d186b762 --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2018 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.specialaccess.deviceadmin; + +import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; + +import android.app.AppGlobals; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DeviceAdminReceiver; +import android.app.admin.DevicePolicyManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Log; +import android.util.SparseArray; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.FooterPreferenceMixin; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +public class DeviceAdminListPreferenceController extends BasePreferenceController + implements LifecycleObserver, OnStart, OnStop { + + private static final IntentFilter FILTER = new IntentFilter(); + private static final String TAG = "DeviceAdminListPrefCtrl"; + + private final DevicePolicyManager mDPM; + private final UserManager mUm; + private final PackageManager mPackageManager; + private final IPackageManager mIPackageManager; + /** + * Internal collection of device admin info objects for all profiles associated with the current + * user. + */ + private final ArrayList mAdmins = new ArrayList<>(); + private final SparseArray mProfileOwnerComponents = new SparseArray<>(); + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // Refresh the list, if state change has been received. It could be that checkboxes + // need to be updated + if (TextUtils.equals(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED, intent.getAction())) { + updateList(); + } + } + }; + + private PreferenceGroup mPreferenceGroup; + private FooterPreferenceMixin mFooterPreferenceMixin; + + static { + FILTER.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); + } + + public DeviceAdminListPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); + mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); + mPackageManager = mContext.getPackageManager(); + mIPackageManager = AppGlobals.getPackageManager(); + } + + public DeviceAdminListPreferenceController setFooterPreferenceMixin( + FooterPreferenceMixin mixin) { + mFooterPreferenceMixin = mixin; + return this; + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreferenceGroup = (PreferenceGroup) screen.findPreference(getPreferenceKey()); + } + + @Override + public void onStart() { + mContext.registerReceiverAsUser( + mBroadcastReceiver, UserHandle.ALL, FILTER, + null /* broadcastPermission */, null /* scheduler */); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + mProfileOwnerComponents.clear(); + final List profiles = mUm.getUserProfiles(); + final int profilesSize = profiles.size(); + for (int i = 0; i < profilesSize; ++i) { + final int profileId = profiles.get(i).getIdentifier(); + mProfileOwnerComponents.put(profileId, mDPM.getProfileOwnerAsUser(profileId)); + } + updateList(); + } + + @Override + public void onStop() { + mContext.unregisterReceiver(mBroadcastReceiver); + } + + @VisibleForTesting + void updateList() { + refreshData(); + refreshUI(); + } + + private void refreshData() { + mAdmins.clear(); + final List profiles = mUm.getUserProfiles(); + for (UserHandle profile : profiles) { + final int profileId = profile.getIdentifier(); + updateAvailableAdminsForProfile(profileId); + } + Collections.sort(mAdmins); + } + + private void refreshUI() { + if (mPreferenceGroup == null) { + return; + } + if (mFooterPreferenceMixin != null) { + final FooterPreference footer = mFooterPreferenceMixin.createFooterPreference(); + footer.setTitle(R.string.no_device_admins); + footer.setVisible(mAdmins.isEmpty()); + } + final Map preferenceCache = new ArrayMap<>(); + final Context prefContext = mPreferenceGroup.getContext(); + final int childrenCount = mPreferenceGroup.getPreferenceCount(); + for (int i = 0; i < childrenCount; i++) { + SwitchPreference pref = (SwitchPreference) mPreferenceGroup.getPreference(i); + preferenceCache.put(pref.getKey(), pref); + } + for (DeviceAdminListItem item : mAdmins) { + final String key = item.getKey(); + SwitchPreference pref = preferenceCache.remove(key); + if (pref == null) { + pref = new SwitchPreference(prefContext); + mPreferenceGroup.addPreference(pref); + } + bindPreference(item, pref); + } + for (SwitchPreference unusedCacheItem : preferenceCache.values()) { + mPreferenceGroup.removePreference(unusedCacheItem); + } + } + + private void bindPreference(DeviceAdminListItem item, SwitchPreference pref) { + pref.setKey(item.getKey()); + pref.setTitle(item.getName()); + pref.setIcon(item.getIcon()); + pref.setChecked(item.isActive()); + pref.setSummary(item.getDescription()); + pref.setEnabled(item.isEnabled()); + pref.setOnPreferenceClickListener(preference -> { + final UserHandle user = item.getUser(); + mContext.startActivityAsUser(item.getLaunchIntent(mContext), user); + return true; + }); + pref.setOnPreferenceChangeListener((preference, newValue) -> false); + } + + /** + * Add device admins to the internal collection that belong to a profile. + * + * @param profileId the profile identifier. + */ + private void updateAvailableAdminsForProfile(final int profileId) { + // We are adding the union of two sets 'A' and 'B' of device admins to mAvailableAdmins. + // - Set 'A' is the set of active admins for the profile + // - set 'B' is the set of listeners to DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED for + // the profile. + + // Add all of set 'A' to mAvailableAdmins. + final List activeAdminsForProfile = mDPM.getActiveAdminsAsUser(profileId); + addActiveAdminsForProfile(activeAdminsForProfile, profileId); + + // Collect set 'B' and add B-A to mAvailableAdmins. + addDeviceAdminBroadcastReceiversForProfile(activeAdminsForProfile, profileId); + } + + /** + * Add a {@link DeviceAdminInfo} object to the internal collection of available admins for all + * active admin components associated with a profile. + */ + private void addActiveAdminsForProfile(List activeAdmins, int profileId) { + if (activeAdmins == null) { + return; + } + + for (ComponentName activeAdmin : activeAdmins) { + final ActivityInfo ai; + try { + ai = mIPackageManager.getReceiverInfo(activeAdmin, + PackageManager.GET_META_DATA | + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | + PackageManager.MATCH_DIRECT_BOOT_UNAWARE | + PackageManager.MATCH_DIRECT_BOOT_AWARE, profileId); + } catch (RemoteException e) { + Log.w(TAG, "Unable to load component: " + activeAdmin); + continue; + } + final DeviceAdminInfo deviceAdminInfo = DeviceAdminUtils.createDeviceAdminInfo( + mContext, ai); + if (deviceAdminInfo == null) { + continue; + } + mAdmins.add(new DeviceAdminListItem(mContext, deviceAdminInfo)); + } + } + + /** + * Add a profile's device admins that are receivers of + * {@code DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED} to the internal collection if they + * haven't been added yet. + * + * @param alreadyAddedComponents the set of active admin component names. Receivers of + * {@code DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED} + * whose component is in this + * set are not added to the internal collection again. + * @param profileId the identifier of the profile + */ + private void addDeviceAdminBroadcastReceiversForProfile( + Collection alreadyAddedComponents, int profileId) { + final List enabledForProfile = mPackageManager.queryBroadcastReceiversAsUser( + new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), + PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, + profileId); + if (enabledForProfile == null) { + return; + } + for (ResolveInfo resolveInfo : enabledForProfile) { + final ComponentName riComponentName = + new ComponentName(resolveInfo.activityInfo.packageName, + resolveInfo.activityInfo.name); + if (alreadyAddedComponents != null + && alreadyAddedComponents.contains(riComponentName)) { + continue; + } + DeviceAdminInfo deviceAdminInfo = DeviceAdminUtils.createDeviceAdminInfo( + mContext, resolveInfo.activityInfo); + // add only visible ones (note: active admins are added regardless of visibility) + if (deviceAdminInfo != null && deviceAdminInfo.isVisible()) { + if (!deviceAdminInfo.getActivityInfo().applicationInfo.isInternal()) { + continue; + } + mAdmins.add(new DeviceAdminListItem(mContext, deviceAdminInfo)); + } + } + } +} diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminSettings.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminSettings.java index 6e0f60c9d6..4cd4c049f4 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminSettings.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminSettings.java @@ -16,448 +16,55 @@ package com.android.settings.applications.specialaccess.deviceadmin; -import android.app.Activity; -import android.app.AppGlobals; -import android.app.ListFragment; -import android.app.admin.DeviceAdminInfo; -import android.app.admin.DeviceAdminReceiver; -import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; -import android.util.SparseArray; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.Switch; -import android.widget.TextView; +import android.provider.SearchIndexableResource; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.search.SearchIndexable; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; -public class DeviceAdminSettings extends ListFragment implements Instrumentable { +@SearchIndexable +public class DeviceAdminSettings extends DashboardFragment { static final String TAG = "DeviceAdminSettings"; - private VisibilityLoggerMixin mVisibilityLoggerMixin; - private DevicePolicyManager mDPM; - private UserManager mUm; - - private static class DeviceAdminListItem implements Comparable { - public DeviceAdminInfo info; - - // These aren't updated so they keep a stable sort order if user activates / de-activates - // an admin. - public String name; - public boolean active; - - public int compareTo(DeviceAdminListItem other) { - // Sort active admins first, then by name. - if (this.active != other.active) { - return this.active ? -1 : 1; - } - return this.name.compareTo(other.name); - } - } - - /** - * Internal collection of device admin info objects for all profiles associated with the current - * user. - */ - private final ArrayList - mAdmins = new ArrayList(); - - private String mDeviceOwnerPkg; - private SparseArray mProfileOwnerComponents = new SparseArray(); - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // Refresh the list, if state change has been received. It could be that checkboxes - // need to be updated - if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals( - intent.getAction())) { - updateList(); - } - } - }; - - @Override public int getMetricsCategory() { return MetricsProto.MetricsEvent.DEVICE_ADMIN_SETTINGS; } @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(), - FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mDPM = (DevicePolicyManager) getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); - mUm = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); - return inflater.inflate(R.layout.device_admin_settings, container, false); + public void onAttach(Context context) { + super.onAttach(context); + use(DeviceAdminListPreferenceController.class).setFooterPreferenceMixin( + mFooterPreferenceMixin); } @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - setHasOptionsMenu(true); - Utils.forceCustomPadding(getListView(), true /* additive padding */); - getActivity().setTitle(R.string.manage_device_admin); + protected int getPreferenceScreenResId() { + return R.xml.device_admin_settings; } @Override - public void onResume() { - super.onResume(); - final Activity activity = getActivity(); - mVisibilityLoggerMixin.onResume(); - IntentFilter filter = new IntentFilter(); - filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); - activity.registerReceiverAsUser( - mBroadcastReceiver, UserHandle.ALL, filter, null, null); - - final ComponentName deviceOwnerComponent = mDPM.getDeviceOwnerComponentOnAnyUser(); - mDeviceOwnerPkg = - deviceOwnerComponent != null ? deviceOwnerComponent.getPackageName() : null; - mProfileOwnerComponents.clear(); - final List profiles = mUm.getUserProfiles(); - final int profilesSize = profiles.size(); - for (int i = 0; i < profilesSize; ++i) { - final int profileId = profiles.get(i).getIdentifier(); - mProfileOwnerComponents.put(profileId, mDPM.getProfileOwnerAsUser(profileId)); - } - updateList(); + protected String getLogTag() { + return TAG; } - @Override - public void onPause() { - final Activity activity = getActivity(); - activity.unregisterReceiver(mBroadcastReceiver); - mVisibilityLoggerMixin.onPause(); - super.onPause(); - } - - /** - * Update the internal collection of available admins for all profiles associated with the - * current user. - */ - void updateList() { - mAdmins.clear(); - - final List profiles = mUm.getUserProfiles(); - final int profilesSize = profiles.size(); - for (int i = 0; i < profilesSize; ++i) { - final int profileId = profiles.get(i).getIdentifier(); - updateAvailableAdminsForProfile(profileId); - } - Collections.sort(mAdmins); - - getListView().setAdapter(new PolicyListAdapter()); - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - Object o = l.getAdapter().getItem(position); - DeviceAdminInfo dpi = (DeviceAdminInfo) o; - final UserHandle user = new UserHandle(getUserId(dpi)); - final Activity activity = getActivity(); - Intent intent = new Intent(activity, DeviceAdminAdd.class); - intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, dpi.getComponent()); - activity.startActivityAsUser(intent, user); - } - - static class ViewHolder { - ImageView icon; - TextView name; - Switch checkbox; - TextView description; - } - - class PolicyListAdapter extends BaseAdapter { - final LayoutInflater mInflater; - - PolicyListAdapter() { - mInflater = (LayoutInflater) - getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - @Override - public boolean hasStableIds() { - return false; - } - - @Override - public int getCount() { - return mAdmins.size(); - } - - /** - * The item for the given position in the list. - * - * @return DeviceAdminInfo object for actual device admins. - */ - @Override - public Object getItem(int position) { - return ((DeviceAdminListItem) (mAdmins.get(position))).info; - } - - @Override - public long getItemId(int position) { - return position; - } + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); - @Override - public boolean areAllItemsEnabled() { - return false; - } - - /** - * See {@link #getItemViewType} for the view types. - */ - @Override - public int getViewTypeCount() { - return 1; - } - - /** - * Returns 0 for all types. - */ - @Override - public int getItemViewType(int position) { - return 0; - } - - @Override - public boolean isEnabled(int position) { - Object o = getItem(position); - return isEnabled(o); - } - - private boolean isEnabled(Object o) { - DeviceAdminInfo info = (DeviceAdminInfo) o; - // Disable item if admin is being removed - if (isRemovingAdmin(info)) { - return false; - } - return true; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Object o = getItem(position); - if (convertView == null) { - convertView = newDeviceAdminView(parent); - } - bindView(convertView, (DeviceAdminInfo) o); - return convertView; - } - - private View newDeviceAdminView(ViewGroup parent) { - View v = mInflater.inflate(R.layout.device_admin_item, parent, false); - ViewHolder h = new ViewHolder(); - h.icon = v.findViewById(R.id.icon); - h.name = v.findViewById(R.id.name); - h.checkbox = v.findViewById(R.id.checkbox); - h.description = v.findViewById(R.id.description); - v.setTag(h); - return v; - } - - private void bindView(View view, DeviceAdminInfo item) { - final Activity activity = getActivity(); - ViewHolder vh = (ViewHolder) view.getTag(); - Drawable activityIcon = item.loadIcon(activity.getPackageManager()); - Drawable badgedIcon = activity.getPackageManager().getUserBadgedIcon( - activityIcon, new UserHandle(getUserId(item))); - vh.icon.setImageDrawable(badgedIcon); - vh.name.setText(item.loadLabel(activity.getPackageManager())); - vh.checkbox.setChecked(isActiveAdmin(item)); - final boolean enabled = isEnabled(item); - try { - vh.description.setText(item.loadDescription(activity.getPackageManager())); - } catch (Resources.NotFoundException e) { - } - vh.checkbox.setEnabled(enabled); - vh.name.setEnabled(enabled); - vh.description.setEnabled(enabled); - vh.icon.setEnabled(enabled); - } - } - - private boolean isDeviceOwner(DeviceAdminInfo item) { - return getUserId(item) == UserHandle.myUserId() - && item.getPackageName().equals(mDeviceOwnerPkg); - } - - private boolean isProfileOwner(DeviceAdminInfo item) { - ComponentName profileOwner = mProfileOwnerComponents.get(getUserId(item)); - return item.getComponent().equals(profileOwner); - } - - private boolean isActiveAdmin(DeviceAdminInfo item) { - return mDPM.isAdminActiveAsUser(item.getComponent(), getUserId(item)); - } - - private boolean isRemovingAdmin(DeviceAdminInfo item) { - return mDPM.isRemovingAdmin(item.getComponent(), getUserId(item)); - } - - /** - * Add device admins to the internal collection that belong to a profile. - * - * @param profileId the profile identifier. - */ - private void updateAvailableAdminsForProfile(final int profileId) { - // We are adding the union of two sets 'A' and 'B' of device admins to mAvailableAdmins. - // Set 'A' is the set of active admins for the profile whereas set 'B' is the set of - // listeners to DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED for the profile. - - // Add all of set 'A' to mAvailableAdmins. - List activeAdminsListForProfile = mDPM.getActiveAdminsAsUser(profileId); - addActiveAdminsForProfile(activeAdminsListForProfile, profileId); - - // Collect set 'B' and add B-A to mAvailableAdmins. - addDeviceAdminBroadcastReceiversForProfile(activeAdminsListForProfile, profileId); - } - - /** - * Add a profile's device admins that are receivers of - * {@code DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED} to the internal collection if they - * haven't been added yet. - * - * @param alreadyAddedComponents the set of active admin component names. Receivers of - * {@code DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED} whose component is in this - * set are not added to the internal collection again. - * @param profileId the identifier of the profile - */ - private void addDeviceAdminBroadcastReceiversForProfile( - Collection alreadyAddedComponents, final int profileId) { - final PackageManager pm = getActivity().getPackageManager(); - List enabledForProfile = pm.queryBroadcastReceiversAsUser( - new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), - PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, - profileId); - if (enabledForProfile == null) { - enabledForProfile = Collections.emptyList(); - } - final int n = enabledForProfile.size(); - for (int i = 0; i < n; ++i) { - ResolveInfo resolveInfo = enabledForProfile.get(i); - ComponentName riComponentName = - new ComponentName(resolveInfo.activityInfo.packageName, - resolveInfo.activityInfo.name); - if (alreadyAddedComponents == null - || !alreadyAddedComponents.contains(riComponentName)) { - DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo(resolveInfo.activityInfo); - // add only visible ones (note: active admins are added regardless of visibility) - if (deviceAdminInfo != null && deviceAdminInfo.isVisible()) { - if (!deviceAdminInfo.getActivityInfo().applicationInfo.isInternal()) { - continue; - } - DeviceAdminListItem item = new DeviceAdminListItem(); - item.info = deviceAdminInfo; - item.name = deviceAdminInfo.loadLabel(pm).toString(); - // Active ones already added. - item.active = false; - mAdmins.add(item); + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.device_admin_settings; + result.add(sir); + return result; } - } - } - } - - /** - * Add a {@link DeviceAdminInfo} object to the internal collection of available admins for all - * active admin components associated with a profile. - * - * @param profileId a profile identifier. - */ - private void addActiveAdminsForProfile(final List activeAdmins, - final int profileId) { - if (activeAdmins != null) { - final PackageManager packageManager = getActivity().getPackageManager(); - final IPackageManager iPackageManager = AppGlobals.getPackageManager(); - final int n = activeAdmins.size(); - for (int i = 0; i < n; ++i) { - final ComponentName activeAdmin = activeAdmins.get(i); - final ActivityInfo ai; - try { - ai = iPackageManager.getReceiverInfo(activeAdmin, - PackageManager.GET_META_DATA | - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | - PackageManager.MATCH_DIRECT_BOOT_UNAWARE | - PackageManager.MATCH_DIRECT_BOOT_AWARE, profileId); - } catch (RemoteException e) { - Log.w(TAG, "Unable to load component: " + activeAdmin); - continue; - } - final DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo(ai); - if (deviceAdminInfo == null) { - continue; - } - // Don't do the applicationInfo.isInternal() check here; if an active - // admin is already on SD card, just show it. - final DeviceAdminListItem item = new DeviceAdminListItem(); - item.info = deviceAdminInfo; - item.name = deviceAdminInfo.loadLabel(packageManager).toString(); - item.active = true; - mAdmins.add(item); - } - } - } - - /** - * Creates a device admin info object for the resolved intent that points to the component of - * the device admin. - * - * @param ai ActivityInfo for the admin component. - * @return new {@link DeviceAdminInfo} object or null if there was an error. - */ - private DeviceAdminInfo createDeviceAdminInfo(ActivityInfo ai) { - try { - return new DeviceAdminInfo(getActivity(), ai); - } catch (XmlPullParserException|IOException e) { - Log.w(TAG, "Skipping " + ai, e); - } - return null; - } - - /** - * Extracts the user id from a device admin info object. - * @param adminInfo the device administrator info. - * @return identifier of the user associated with the device admin. - */ - private int getUserId(DeviceAdminInfo adminInfo) { - return UserHandle.getUserId(adminInfo.getActivityInfo().applicationInfo.uid); - } + }; } diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java new file mode 100644 index 0000000000..13d9d20bec --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 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.specialaccess.deviceadmin; + +import android.app.admin.DeviceAdminInfo; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.os.UserHandle; +import android.util.Log; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +public class DeviceAdminUtils { + + private static final String TAG = "DeviceAdminUtils"; + + /** + * Creates a device admin info object for the resolved intent that points to the component of + * the device admin. + * + * @param ai ActivityInfo for the admin component. + * @return new {@link DeviceAdminInfo} object or null if there was an error. + */ + public static DeviceAdminInfo createDeviceAdminInfo(Context context, ActivityInfo ai) { + try { + return new DeviceAdminInfo(context, ai); + } catch (XmlPullParserException | IOException e) { + Log.w(TAG, "Skipping " + ai, e); + } + return null; + } + + /** + * Extracts the user id from a device admin info object. + * + * @param adminInfo the device administrator info. + * @return identifier of the user associated with the device admin. + */ + public static int getUserIdFromDeviceAdminInfo(DeviceAdminInfo adminInfo) { + return UserHandle.getUserId(adminInfo.getActivityInfo().applicationInfo.uid); + } +} diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsController.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsController.java deleted file mode 100644 index 5b05b866ab..0000000000 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsController.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.specialaccess.deviceadmin; - -import android.content.Context; - -import com.android.settings.R; -import com.android.settings.core.BasePreferenceController; - -public class DeviceAdministratorsController extends BasePreferenceController { - - public DeviceAdministratorsController(Context context, String key) { - super(context, key); - } - - @AvailabilityStatus - public int getAvailabilityStatus() { - return mContext.getResources().getBoolean(R.bool.config_show_device_administrators) - ? AVAILABLE - : UNSUPPORTED_ON_DEVICE; - } -} \ No newline at end of file diff --git a/src/com/android/settings/datetime/DatePreferenceController.java b/src/com/android/settings/datetime/DatePreferenceController.java index 856722ca46..ceb65ca852 100644 --- a/src/com/android/settings/datetime/DatePreferenceController.java +++ b/src/com/android/settings/datetime/DatePreferenceController.java @@ -20,8 +20,6 @@ import android.app.Activity; import android.app.AlarmManager; import android.app.DatePickerDialog; import android.content.Context; -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; import android.text.TextUtils; import android.text.format.DateFormat; import android.widget.DatePicker; @@ -32,6 +30,9 @@ import com.android.settingslib.core.AbstractPreferenceController; import java.util.Calendar; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; + public class DatePreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, DatePickerDialog.OnDateSetListener { diff --git a/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceController.java b/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceController.java index e4f2e76f7d..bbb217b498 100644 --- a/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceController.java +++ b/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceController.java @@ -14,42 +14,38 @@ package com.android.settings.enterprise; import android.content.Context; -import androidx.preference.Preference; import com.android.settings.R; -import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.BasePreferenceController; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.AbstractPreferenceController; -public class ManageDeviceAdminPreferenceController extends AbstractPreferenceController implements - PreferenceControllerMixin { +import androidx.preference.Preference; + +public class ManageDeviceAdminPreferenceController extends BasePreferenceController { - private static final String KEY_MANAGE_DEVICE_ADMIN = "manage_device_admin"; private final EnterprisePrivacyFeatureProvider mFeatureProvider; - public ManageDeviceAdminPreferenceController(Context context) { - super(context); + public ManageDeviceAdminPreferenceController(Context context, String key) { + super(context, key); mFeatureProvider = FeatureFactory.getFactory(context) .getEnterprisePrivacyFeatureProvider(context); } @Override - public void updateState(Preference preference) { + public CharSequence getSummary() { final int activeAdmins = mFeatureProvider.getNumberOfActiveDeviceAdminsForCurrentUserAndManagedProfile(); - preference.setSummary(activeAdmins == 0 + return activeAdmins == 0 ? mContext.getResources().getString(R.string.number_of_device_admins_none) : mContext.getResources().getQuantityString(R.plurals.number_of_device_admins, - activeAdmins, activeAdmins)); + activeAdmins, activeAdmins); } @Override - public boolean isAvailable() { - return mContext.getResources().getBoolean(R.bool.config_show_manage_device_admin); + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_manage_device_admin) + ? AVAILABLE_UNSEARCHABLE + : UNSUPPORTED_ON_DEVICE; } - @Override - public String getPreferenceKey() { - return KEY_MANAGE_DEVICE_ADMIN; - } } diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index 7ce6560f41..b5906184d1 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -29,7 +29,6 @@ import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.enterprise.EnterprisePrivacyPreferenceController; -import com.android.settings.enterprise.ManageDeviceAdminPreferenceController; import com.android.settings.fingerprint.FingerprintProfileStatusPreferenceController; import com.android.settings.fingerprint.FingerprintStatusPreferenceController; import com.android.settings.location.LocationPreferenceController; @@ -114,7 +113,6 @@ public class SecuritySettings extends DashboardFragment { Lifecycle lifecycle, SecuritySettings host) { final List controllers = new ArrayList<>(); controllers.add(new LocationPreferenceController(context, lifecycle)); - controllers.add(new ManageDeviceAdminPreferenceController(context)); controllers.add(new EnterprisePrivacyPreferenceController(context)); controllers.add(new ManageTrustAgentsPreferenceController(context)); controllers.add(new ScreenPinningPreferenceController(context)); diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml index 72f5134025..2d95b65790 100644 --- a/tests/robotests/res/values-mcc999/config.xml +++ b/tests/robotests/res/values-mcc999/config.xml @@ -33,7 +33,6 @@ false false false - false false false false diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java new file mode 100644 index 0000000000..e19d9e6863 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 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.specialaccess.deviceadmin; + + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import android.app.admin.DeviceAdminInfo; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class DeviceAdminListItemTest { + + @Mock + private DeviceAdminInfo mDeviceAdminInfo; + private Context mContext; + + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + } + + @Test + public void newInstance_shouldLoadInfoFromDeviceAdminInfo() { + final String label = "testlabel"; + final String description = "testdesc"; + final ComponentName cn = new ComponentName(mContext.getPackageName(), "test"); + when(mDeviceAdminInfo.getActivityInfo()).thenReturn(new ActivityInfo()); + mDeviceAdminInfo.getActivityInfo().applicationInfo = new ApplicationInfo(); + when(mDeviceAdminInfo.loadLabel(any(PackageManager.class))).thenReturn(label); + when(mDeviceAdminInfo.loadDescription(any(PackageManager.class))).thenReturn(description); + when(mDeviceAdminInfo.loadIcon(any(PackageManager.class))) + .thenReturn(new ColorDrawable(Color.BLUE)); + when(mDeviceAdminInfo.getComponent()).thenReturn(cn); + + DeviceAdminListItem item = new DeviceAdminListItem(mContext, mDeviceAdminInfo); + + assertThat(item.getKey()).isEqualTo(cn.flattenToShortString()); + assertThat(item.getName()).isEqualTo(label); + assertThat(item.getDescription()).isEqualTo(description); + } + +} diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceControllerTest.java new file mode 100644 index 0000000000..c99df010b7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceControllerTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 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.specialaccess.deviceadmin; + +import static androidx.lifecycle.Lifecycle.Event.ON_START; +import static androidx.lifecycle.Lifecycle.Event.ON_STOP; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.IntentFilter; +import android.os.UserHandle; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.FooterPreferenceMixin; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import androidx.lifecycle.LifecycleOwner; + +@RunWith(SettingsRobolectricTestRunner.class) +public class DeviceAdminListPreferenceControllerTest { + + @Mock + private FooterPreferenceMixin mFooterPreferenceMixin; + private Context mContext; + private DeviceAdminListPreferenceController mController; + private LifecycleOwner mLifecycleOwner; + private Lifecycle mLifecycle; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); + + mController = spy(new DeviceAdminListPreferenceController(mContext, "test_key") + .setFooterPreferenceMixin(mFooterPreferenceMixin)); + mLifecycle.addObserver(mController); + } + + @Test + public void onStart_registerReceiver() { + mLifecycle.handleLifecycleEvent(ON_START); + + verify(mContext).registerReceiverAsUser(any(BroadcastReceiver.class), eq(UserHandle.ALL), + any(IntentFilter.class), isNull(), isNull()); + } + + @Test + public void onStop_unregisterReceiver() { + mLifecycle.handleLifecycleEvent(ON_START); + mLifecycle.handleLifecycleEvent(ON_STOP); + + verify(mContext).unregisterReceiver(any(BroadcastReceiver.class)); + } +} diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsControllerTest.java deleted file mode 100644 index 6e3ff2c857..0000000000 --- a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdministratorsControllerTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.specialaccess.deviceadmin; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.spy; - -import android.content.Context; - -import com.android.settings.testutils.SettingsRobolectricTestRunner; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -@RunWith(SettingsRobolectricTestRunner.class) -public class DeviceAdministratorsControllerTest { - - private Context mContext; - private DeviceAdministratorsController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application.getApplicationContext()); - mController = new DeviceAdministratorsController(mContext, "key"); - } - - @Test - public void testDeviceAdministrators_byDefault_shouldBeShown() { - assertThat(mController.isAvailable()).isTrue(); - } - - @Test - @Config(qualifiers = "mcc999") - public void testDeviceAdministrators_ifDisabled_shouldNotBeShown() { - assertThat(mController.isAvailable()).isFalse(); - } -} diff --git a/tests/robotests/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceControllerTest.java index 885e8901cf..e9066aa290 100644 --- a/tests/robotests/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/enterprise/ManageDeviceAdminPreferenceControllerTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; -import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.testutils.FakeFeatureFactory; @@ -36,6 +35,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import androidx.preference.Preference; + @RunWith(SettingsRobolectricTestRunner.class) public class ManageDeviceAdminPreferenceControllerTest { @@ -51,7 +52,7 @@ public class ManageDeviceAdminPreferenceControllerTest { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); mFeatureFactory = FakeFeatureFactory.setupForTest(); - mController = new ManageDeviceAdminPreferenceController(mContext); + mController = new ManageDeviceAdminPreferenceController(mContext, "testkey"); } @Test @@ -60,7 +61,7 @@ public class ManageDeviceAdminPreferenceControllerTest { when(mFeatureFactory.enterprisePrivacyFeatureProvider .getNumberOfActiveDeviceAdminsForCurrentUserAndManagedProfile()).thenReturn(0); - when (mContext.getResources()).thenReturn(mResources); + when(mContext.getResources()).thenReturn(mResources); when(mResources.getString(R.string.number_of_device_admins_none)) .thenReturn("no apps"); mController.updateState(preference); @@ -84,15 +85,4 @@ public class ManageDeviceAdminPreferenceControllerTest { public void isAvailable_whenNotVisible_isFalse() { assertThat(mController.isAvailable()).isFalse(); } - - @Test - public void testHandlePreferenceTreeClick() { - assertThat(mController.handlePreferenceTreeClick(new Preference(mContext, null, 0, 0))) - .isFalse(); - } - - @Test - public void testGetPreferenceKey() { - assertThat(mController.getPreferenceKey()).isEqualTo("manage_device_admin"); - } } -- 2.11.0