summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/DeviceAdminSettings.java
diff options
context:
space:
mode:
authorZoltan Szatmary-Ban <szatmz@google.com>2014-07-02 16:48:00 +0100
committerZoltan Szatmary-Ban <szatmz@google.com>2014-08-01 09:29:33 +0000
commitf3d72098b0008a9a8e137985d7fbc0e0470adc9c (patch)
tree8e01b73d08102dad1f8f6f9ff2245aae76e1cb47 /src/com/android/settings/DeviceAdminSettings.java
parent5cd9063df2cb5e578326d7bc94c0487b884ece31 (diff)
downloadpackages_apps_Settings-f3d72098b0008a9a8e137985d7fbc0e0470adc9c.zip
packages_apps_Settings-f3d72098b0008a9a8e137985d7fbc0e0470adc9c.tar.gz
packages_apps_Settings-f3d72098b0008a9a8e137985d7fbc0e0470adc9c.tar.bz2
Update Device Admins Settings screen
The MDM is a Device Admin for the managed profile. The users should be able to see that it exists and it is controlling the device, but they should not be able to change it. Bug: 15558397 Change-Id: Ief372b606f1085f73c98ace97f2c1d9ac5fe3257
Diffstat (limited to 'src/com/android/settings/DeviceAdminSettings.java')
-rw-r--r--src/com/android/settings/DeviceAdminSettings.java394
1 files changed, 304 insertions, 90 deletions
diff --git a/src/com/android/settings/DeviceAdminSettings.java b/src/com/android/settings/DeviceAdminSettings.java
index f597b9a..1ea9859 100644
--- a/src/com/android/settings/DeviceAdminSettings.java
+++ b/src/com/android/settings/DeviceAdminSettings.java
@@ -20,6 +20,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
+import android.app.Dialog;
+import android.app.AlertDialog;
import android.app.ListFragment;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
@@ -30,8 +32,13 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
+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;
@@ -44,20 +51,25 @@ import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+import java.util.Collection;
public class DeviceAdminSettings extends ListFragment {
static final String TAG = "DeviceAdminSettings";
static final int DIALOG_WARNING = 1;
+ private DevicePolicyManager mDPM;
+ private UserManager mUm;
- DevicePolicyManager mDPM;
- final HashSet<ComponentName> mActiveAdmins = new HashSet<ComponentName>();
- final ArrayList<DeviceAdminInfo> mAvailableAdmins = new ArrayList<DeviceAdminInfo>();
- String mDeviceOwnerPkg;
- ComponentName mProfileOwnerComponent;
+ /**
+ * Internal collection of device admin info objects for all profiles associated with the current
+ * user.
+ */
+ private final SparseArray<ArrayList<DeviceAdminInfo>>
+ mAdminsByProfile = new SparseArray<ArrayList<DeviceAdminInfo>>();
+
+ private String mDeviceOwnerPkg;
+ private SparseArray<ComponentName> mProfileOwnerComponents = new SparseArray<ComponentName>();
@Override
public void onCreate(Bundle icicle) {
@@ -68,6 +80,7 @@ public class DeviceAdminSettings extends ListFragment {
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);
}
@@ -85,61 +98,28 @@ public class DeviceAdminSettings extends ListFragment {
if (mDeviceOwnerPkg != null && !mDPM.isDeviceOwner(mDeviceOwnerPkg)) {
mDeviceOwnerPkg = null;
}
- mProfileOwnerComponent = mDPM.getProfileOwner();
+ mProfileOwnerComponents.clear();
+ final List<UserHandle> 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();
}
+ /**
+ * Update the internal collection of available admins for all profiles associated with the
+ * current user.
+ */
void updateList() {
- mActiveAdmins.clear();
- List<ComponentName> cur = mDPM.getActiveAdmins();
- if (cur != null) {
- for (int i=0; i<cur.size(); i++) {
- mActiveAdmins.add(cur.get(i));
- }
- }
-
- mAvailableAdmins.clear();
- List<ResolveInfo> avail = getActivity().getPackageManager().queryBroadcastReceivers(
- new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
- PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
- if (avail == null) {
- avail = Collections.emptyList();
- }
-
- // Some admins listed in mActiveAdmins may not have been found by the above query.
- // We thus add them separately.
- Set<ComponentName> activeAdminsNotInAvail = new HashSet<ComponentName>(mActiveAdmins);
- for (ResolveInfo ri : avail) {
- ComponentName riComponentName =
- new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
- activeAdminsNotInAvail.remove(riComponentName);
- }
- if (!activeAdminsNotInAvail.isEmpty()) {
- avail = new ArrayList<ResolveInfo>(avail);
- PackageManager packageManager = getActivity().getPackageManager();
- for (ComponentName unlistedActiveAdmin : activeAdminsNotInAvail) {
- List<ResolveInfo> resolved = packageManager.queryBroadcastReceivers(
- new Intent().setComponent(unlistedActiveAdmin),
- PackageManager.GET_META_DATA
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
- if (resolved != null) {
- avail.addAll(resolved);
- }
- }
- }
+ mAdminsByProfile.clear();
- for (int i = 0, count = avail.size(); i < count; i++) {
- ResolveInfo ri = avail.get(i);
- try {
- DeviceAdminInfo dpi = new DeviceAdminInfo(getActivity(), ri);
- if (dpi.isVisible() || mActiveAdmins.contains(dpi.getComponent())) {
- mAvailableAdmins.add(dpi);
- }
- } catch (XmlPullParserException e) {
- Log.w(TAG, "Skipping " + ri.activityInfo, e);
- } catch (IOException e) {
- Log.w(TAG, "Skipping " + ri.activityInfo, e);
- }
+ final List<UserHandle> profiles = mUm.getUserProfiles();
+ final int profilesSize = profiles.size();
+ for (int i = 0; i < profilesSize; ++i) {
+ final int profileId = profiles.get(i).getIdentifier();
+ updateAvailableAdminsForProfile(profileId);
}
getListView().setAdapter(new PolicyListAdapter());
@@ -147,11 +127,21 @@ public class DeviceAdminSettings extends ListFragment {
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
- DeviceAdminInfo dpi = (DeviceAdminInfo)l.getAdapter().getItem(position);
- Intent intent = new Intent();
- intent.setClass(getActivity(), DeviceAdminAdd.class);
- intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, dpi.getComponent());
- startActivity(intent);
+ DeviceAdminInfo dpi = (DeviceAdminInfo) l.getAdapter().getItem(position);
+ final Activity activity = getActivity();
+ final int userId = getUserId(dpi);
+ if (userId == UserHandle.myUserId() || !isProfileOwner(dpi)) {
+ Intent intent = new Intent();
+ intent.setClass(activity, DeviceAdminAdd.class);
+ intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, dpi.getComponent());
+ activity.startActivityAsUser(intent, new UserHandle(userId));
+ } else {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setMessage(getString(R.string.managed_profile_device_admin_info,
+ dpi.loadLabel(activity.getPackageManager())));
+ builder.setPositiveButton(android.R.string.ok, null);
+ builder.create().show();
+ }
}
static class ViewHolder {
@@ -169,51 +159,129 @@ public class DeviceAdminSettings extends ListFragment {
getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
+ @Override
public boolean hasStableIds() {
- return true;
+ return false;
}
+ @Override
public int getCount() {
- return mAvailableAdmins.size();
+ int adminCount = 0;
+ final int profileCount = mAdminsByProfile.size();
+ for (int i = 0; i < profileCount; ++i) {
+ adminCount += mAdminsByProfile.valueAt(i).size();
+ }
+ // Add 'profileCount' for title items.
+ return adminCount + profileCount;
}
+ /**
+ * The item for the given position in the list.
+ *
+ * @return a String object for title items and a DeviceAdminInfo object for actual device
+ * admins.
+ */
+ @Override
public Object getItem(int position) {
- return mAvailableAdmins.get(position);
+ if (position < 0) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ // The position of the item in the list of admins.
+ // We start from the given position and discount the length of the upper lists until we
+ // get the one for the right profile
+ int adminPosition = position;
+ final int n = mAdminsByProfile.size();
+ int i = 0;
+ for (; i < n; ++i) {
+ // The elements in that section including the title item (that's why adding one).
+ final int listSize = mAdminsByProfile.valueAt(i).size() + 1;
+ if (adminPosition < listSize) {
+ break;
+ }
+ adminPosition -= listSize;
+ }
+ if (i == n) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ // If countdown == 0 that means the title item
+ if (adminPosition == 0) {
+ Resources res = getActivity().getResources();
+ if (mAdminsByProfile.keyAt(i) == UserHandle.myUserId()) {
+ return res.getString(R.string.personal_device_admin_title);
+ } else {
+ return res.getString(R.string.managed_device_admin_title);
+ }
+ } else {
+ // Subtracting one for the title.
+ return mAdminsByProfile.valueAt(i).get(adminPosition - 1);
+ }
}
+ @Override
public long getItemId(int position) {
return position;
}
+ @Override
public boolean areAllItemsEnabled() {
return false;
}
+ /**
+ * See {@link #getItemViewType} for the view types.
+ */
+ @Override
+ public int getViewTypeCount() {
+ return 2;
+ }
+
+ /**
+ * Returns 1 for title items and 0 for anything else.
+ */
+ @Override
+ public int getItemViewType(int position) {
+ Object o = getItem(position);
+ return (o instanceof String) ? 1 : 0;
+ }
+
+ @Override
public boolean isEnabled(int position) {
- DeviceAdminInfo info = mAvailableAdmins.get(position);
- String packageName = info.getPackageName();
- ComponentName component = info.getComponent();
- if (mActiveAdmins.contains(component)
- && (packageName.equals(mDeviceOwnerPkg)
- || component.equals(mProfileOwnerComponent))) {
+ Object o = getItem(position);
+ return isEnabled(o);
+ }
+
+ private boolean isEnabled(Object o) {
+ if (!(o instanceof DeviceAdminInfo)) {
+ // Title item
+ return false;
+ }
+ DeviceAdminInfo info = (DeviceAdminInfo) o;
+ if (isActiveAdmin(info) && getUserId(info) == UserHandle.myUserId()
+ && (isDeviceOwner(info) || isProfileOwner(info))) {
return false;
- } else {
- return true;
}
+ return true;
}
+ @Override
public View getView(int position, View convertView, ViewGroup parent) {
- View v;
- if (convertView == null) {
- v = newView(parent);
+ Object o = getItem(position);
+ if (o instanceof DeviceAdminInfo) {
+ if (convertView == null) {
+ convertView = newDeviceAdminView(parent);
+ }
+ bindView(convertView, (DeviceAdminInfo) o);
} else {
- v = convertView;
+ if (convertView == null) {
+ convertView = newTitleView(parent);
+ }
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ title.setText((String)o);
}
- bindView(v, position);
- return v;
+ return convertView;
}
- public View newView(ViewGroup parent) {
+ private View newDeviceAdminView(ViewGroup parent) {
View v = mInflater.inflate(R.layout.device_admin_item, parent, false);
ViewHolder h = new ViewHolder();
h.icon = (ImageView)v.findViewById(R.id.icon);
@@ -224,23 +292,169 @@ public class DeviceAdminSettings extends ListFragment {
return v;
}
- public void bindView(View view, int position) {
+ private View newTitleView(ViewGroup parent) {
+ final TypedArray a = mInflater.getContext().obtainStyledAttributes(null,
+ com.android.internal.R.styleable.Preference,
+ com.android.internal.R.attr.preferenceCategoryStyle, 0);
+ final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
+ 0);
+ return mInflater.inflate(resId, parent, false);
+ }
+
+ private void bindView(View view, DeviceAdminInfo item) {
final Activity activity = getActivity();
ViewHolder vh = (ViewHolder) view.getTag();
- DeviceAdminInfo item = mAvailableAdmins.get(position);
- vh.icon.setImageDrawable(item.loadIcon(activity.getPackageManager()));
+ Drawable activityIcon = item.loadIcon(activity.getPackageManager());
+ Drawable badgedIcon = mUm.getBadgedDrawableForUser(activityIcon,
+ new UserHandle(getUserId(item)));
+ vh.icon.setImageDrawable(badgedIcon);
vh.name.setText(item.loadLabel(activity.getPackageManager()));
- vh.checkbox.setChecked(mActiveAdmins.contains(item.getComponent()));
- final boolean activeOwner = vh.checkbox.isChecked()
- && item.getPackageName().equals(mDeviceOwnerPkg);
+ 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(!activeOwner);
- vh.name.setEnabled(!activeOwner);
- vh.description.setEnabled(!activeOwner);
- vh.icon.setEnabled(!activeOwner);
+ 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));
+ }
+
+ /**
+ * 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<ComponentName> 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<ComponentName> alreadyAddedComponents, final int profileId) {
+ final PackageManager pm = getActivity().getPackageManager();
+ List<ResolveInfo> enabledForProfile = pm.queryBroadcastReceivers(
+ 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();
+ ArrayList<DeviceAdminInfo> deviceAdmins = mAdminsByProfile.get(profileId);
+ if (deviceAdmins == null) {
+ deviceAdmins = new ArrayList<DeviceAdminInfo>(n);
+ }
+ 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);
+ // add only visible ones (note: active admins are added regardless of visibility)
+ if (deviceAdminInfo != null && deviceAdminInfo.isVisible()) {
+ deviceAdmins.add(deviceAdminInfo);
+ }
+ }
}
+ if (!deviceAdmins.isEmpty()) {
+ mAdminsByProfile.put(profileId, deviceAdmins);
+ }
+ }
+
+ /**
+ * 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<ComponentName> activeAdmins,
+ final int profileId) {
+ if (activeAdmins != null) {
+ final PackageManager packageManager = getActivity().getPackageManager();
+ final int n = activeAdmins.size();
+ ArrayList<DeviceAdminInfo> deviceAdmins = new ArrayList<DeviceAdminInfo>(n);
+ for (int i = 0; i < n; ++i) {
+ ComponentName activeAdmin = activeAdmins.get(i);
+ List<ResolveInfo> resolved = packageManager.queryBroadcastReceivers(
+ new Intent().setComponent(activeAdmin), PackageManager.GET_META_DATA
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, profileId);
+ if (resolved != null) {
+ final int resolvedMax = resolved.size();
+ for (int j = 0; j < resolvedMax; ++j) {
+ DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo(resolved.get(j));
+ if (deviceAdminInfo != null) {
+ deviceAdmins.add(deviceAdminInfo);
+ }
+ }
+ }
+ }
+ if (!deviceAdmins.isEmpty()) {
+ mAdminsByProfile.put(profileId, deviceAdmins);
+ }
+ }
+ }
+
+ /**
+ * Creates a device admin info object for the resolved intent that points to the component of
+ * the device admin.
+ *
+ * @param resolved resolved intent.
+ * @return new {@link DeviceAdminInfo} object or null if there was an error.
+ */
+ private DeviceAdminInfo createDeviceAdminInfo(ResolveInfo resolved) {
+ try {
+ return new DeviceAdminInfo(getActivity(), resolved);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Skipping " + resolved.activityInfo, e);
+ } catch (IOException e) {
+ Log.w(TAG, "Skipping " + resolved.activityInfo, 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);
}
}