Bite the bullet and add support for multiple device admins.
This commit is contained in:
@@ -20399,6 +20399,17 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<method name="getActiveAdmins"
|
||||
return="java.util.List<android.content.ComponentName>"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getCurrentFailedPasswordAttempts"
|
||||
return="int"
|
||||
abstract="false"
|
||||
|
||||
@@ -2518,7 +2518,7 @@ public class Activity extends ContextThemeWrapper
|
||||
* and restored for you. Note that if the dialog is already created,
|
||||
* {@link #onCreateDialog(int, Bundle)} will not be called with the new
|
||||
* arguments but {@link #onPrepareDialog(int, Dialog, Bundle)} will be.
|
||||
* If you need to rebuild the dialog, call {@link #removeDialog(int)}<EFBFBD>first.
|
||||
* If you need to rebuild the dialog, call {@link #removeDialog(int)} first.
|
||||
* @return Returns true if the Dialog was created; false is returned if
|
||||
* it is not created because {@link #onCreateDialog(int, Bundle)} returns false.
|
||||
*
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Public interface for managing policies enforced on a device. Most clients
|
||||
@@ -65,10 +66,6 @@ public class DevicePolicyManager {
|
||||
* <p>You can optionally include the {@link #EXTRA_ADD_EXPLANATION}
|
||||
* field to provide the user with additional explanation (in addition
|
||||
* to your component's description) about what is being added.
|
||||
*
|
||||
* <p>Note: the current platform can only have one device administrator
|
||||
* active at a time. If you make this request while there is already
|
||||
* an active administrator, this new request will be canceled automatically.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_ADD_DEVICE_ADMIN
|
||||
@@ -111,7 +108,7 @@ public class DevicePolicyManager {
|
||||
public boolean isAdminActive(ComponentName who) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return who.equals(mService.getActiveAdmin());
|
||||
return mService.isAdminActive(who);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed talking with device policy service", e);
|
||||
}
|
||||
@@ -119,6 +116,22 @@ public class DevicePolicyManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all currently active device administrator's component
|
||||
* names. Note that if there are no administrators than null may be
|
||||
* returned.
|
||||
*/
|
||||
public List<ComponentName> getActiveAdmins() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getActiveAdmins();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed talking with device policy service", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a current administration component. This can only be called
|
||||
* by the application that owns the administration component; if you
|
||||
@@ -442,26 +455,7 @@ public class DevicePolicyManager {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public ComponentName getActiveAdmin() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getActiveAdmin();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed talking with device policy service", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public DeviceAdminInfo getActiveAdminInfo() {
|
||||
ComponentName cn = getActiveAdmin();
|
||||
if (cn == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public DeviceAdminInfo getAdminInfo(ComponentName cn) {
|
||||
ActivityInfo ai;
|
||||
try {
|
||||
ai = mContext.getPackageManager().getReceiverInfo(cn,
|
||||
|
||||
@@ -45,7 +45,8 @@ interface IDevicePolicyManager {
|
||||
void wipeData(int flags);
|
||||
|
||||
void setActiveAdmin(in ComponentName policyReceiver);
|
||||
ComponentName getActiveAdmin();
|
||||
boolean isAdminActive(in ComponentName policyReceiver);
|
||||
List<ComponentName> getActiveAdmins();
|
||||
void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
|
||||
void removeActiveAdmin(in ComponentName policyReceiver);
|
||||
|
||||
|
||||
@@ -121,11 +121,6 @@ public class LockPatternUtils {
|
||||
|
||||
}
|
||||
|
||||
public boolean isDevicePolicyActive() {
|
||||
ComponentName admin = mDevicePolicyManager.getActiveAdmin();
|
||||
return admin != null ? mDevicePolicyManager.isAdminActive(admin) : false;
|
||||
}
|
||||
|
||||
public int getRequestedMinimumPasswordLength() {
|
||||
return mDevicePolicyManager.getMinimumPasswordLength();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IPowerManager;
|
||||
import android.os.RecoverySystem;
|
||||
@@ -49,6 +48,8 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -65,7 +66,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
int mActivePasswordLength = 0;
|
||||
int mFailedPasswordAttempts = 0;
|
||||
|
||||
ActiveAdmin mActiveAdmin;
|
||||
final HashMap<ComponentName, ActiveAdmin> mAdminMap
|
||||
= new HashMap<ComponentName, ActiveAdmin>();
|
||||
final ArrayList<ActiveAdmin> mAdminList
|
||||
= new ArrayList<ActiveAdmin>();
|
||||
|
||||
static class ActiveAdmin {
|
||||
final DeviceAdminInfo info;
|
||||
@@ -148,7 +152,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
|
||||
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
|
||||
ActiveAdmin admin = mActiveAdmin;
|
||||
ActiveAdmin admin = mAdminMap.get(who);
|
||||
if (admin != null
|
||||
&& who.getPackageName().equals(admin.info.getActivityInfo().packageName)
|
||||
&& who.getClassName().equals(admin.info.getActivityInfo().name)) {
|
||||
@@ -159,7 +163,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
|
||||
ActiveAdmin getActiveAdminForCallerLocked(ComponentName who)
|
||||
throws SecurityException {
|
||||
ActiveAdmin admin = mActiveAdmin;
|
||||
ActiveAdmin admin = mAdminMap.get(who);
|
||||
if (admin != null && admin.getUid() == Binder.getCallingUid()) {
|
||||
if (who != null) {
|
||||
if (!who.getPackageName().equals(admin.info.getActivityInfo().packageName)
|
||||
@@ -167,7 +171,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
throw new SecurityException("Current admin is not " + who);
|
||||
}
|
||||
}
|
||||
return mActiveAdmin;
|
||||
return admin;
|
||||
}
|
||||
throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid());
|
||||
}
|
||||
@@ -190,28 +194,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
|
||||
void sendAdminCommandLocked(String action, int reqPolicy) {
|
||||
if (mActiveAdmin != null) {
|
||||
if (mActiveAdmin.info.usesPolicy(reqPolicy)) {
|
||||
return;
|
||||
final int N = mAdminList.size();
|
||||
if (N > 0) {
|
||||
for (int i=0; i<N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (admin.info.usesPolicy(reqPolicy)) {
|
||||
sendAdminCommandLocked(admin, action);
|
||||
}
|
||||
}
|
||||
sendAdminCommandLocked(mActiveAdmin, action);
|
||||
}
|
||||
}
|
||||
|
||||
ComponentName getActiveAdminLocked() {
|
||||
if (mActiveAdmin != null) {
|
||||
return mActiveAdmin.info.getComponent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void removeActiveAdminLocked(ComponentName adminReceiver) {
|
||||
ComponentName cur = getActiveAdminLocked();
|
||||
if (cur != null && cur.equals(adminReceiver)) {
|
||||
sendAdminCommandLocked(mActiveAdmin,
|
||||
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
|
||||
if (admin != null) {
|
||||
sendAdminCommandLocked(admin,
|
||||
DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLED);
|
||||
// XXX need to wait for it to complete.
|
||||
mActiveAdmin = null;
|
||||
mAdminList.remove(admin);
|
||||
mAdminMap.remove(adminReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,13 +252,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
|
||||
out.startTag(null, "policies");
|
||||
|
||||
ActiveAdmin ap = mActiveAdmin;
|
||||
if (ap != null) {
|
||||
out.startTag(null, "admin");
|
||||
out.attribute(null, "name", ap.info.getComponent().flattenToString());
|
||||
ap.writeToXml(out);
|
||||
out.endTag(null, "admin");
|
||||
final int N = mAdminList.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
ActiveAdmin ap = mAdminList.get(i);
|
||||
if (ap != null) {
|
||||
out.startTag(null, "admin");
|
||||
out.attribute(null, "name", ap.info.getComponent().flattenToString());
|
||||
ap.writeToXml(out);
|
||||
out.endTag(null, "admin");
|
||||
}
|
||||
}
|
||||
|
||||
out.endTag(null, "policies");
|
||||
|
||||
if (mFailedPasswordAttempts != 0) {
|
||||
@@ -314,7 +319,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
if (dai != null) {
|
||||
ActiveAdmin ap = new ActiveAdmin(dai);
|
||||
ap.readFromXml(parser);
|
||||
mActiveAdmin = ap;
|
||||
mAdminMap.put(ap.info.getComponent(), ap);
|
||||
mAdminList.add(ap);
|
||||
}
|
||||
} else if ("failed-password-attempts".equals(tag)) {
|
||||
mFailedPasswordAttempts = Integer.parseInt(
|
||||
@@ -369,16 +375,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
synchronized (this) {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
ComponentName cur = getActiveAdminLocked();
|
||||
if (cur != null && cur.equals(adminReceiver)) {
|
||||
throw new IllegalStateException("An admin is already set");
|
||||
if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
|
||||
throw new IllegalArgumentException("Admin is already added");
|
||||
}
|
||||
if (cur != null) {
|
||||
removeActiveAdminLocked(adminReceiver);
|
||||
}
|
||||
mActiveAdmin = new ActiveAdmin(info);
|
||||
ActiveAdmin admin = new ActiveAdmin(info);
|
||||
mAdminMap.put(adminReceiver, admin);
|
||||
mAdminList.add(admin);
|
||||
saveSettingsLocked();
|
||||
sendAdminCommandLocked(mActiveAdmin,
|
||||
sendAdminCommandLocked(admin,
|
||||
DeviceAdmin.ACTION_DEVICE_ADMIN_ENABLED);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
@@ -386,15 +390,33 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public ComponentName getActiveAdmin() {
|
||||
public boolean isAdminActive(ComponentName adminReceiver) {
|
||||
synchronized (this) {
|
||||
return getActiveAdminLocked();
|
||||
return getActiveAdminUncheckedLocked(adminReceiver) != null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<ComponentName> getActiveAdmins() {
|
||||
synchronized (this) {
|
||||
final int N = mAdminList.size();
|
||||
if (N <= 0) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
|
||||
for (int i=0; i<N; i++) {
|
||||
res.add(mAdminList.get(i).info.getComponent());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeActiveAdmin(ComponentName adminReceiver) {
|
||||
synchronized (this) {
|
||||
if (mActiveAdmin == null || mActiveAdmin.getUid() != Binder.getCallingUid()) {
|
||||
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
|
||||
if (admin == null) {
|
||||
return;
|
||||
}
|
||||
if (admin.getUid() != Binder.getCallingUid()) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
|
||||
}
|
||||
@@ -423,8 +445,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
|
||||
public int getPasswordMode() {
|
||||
synchronized (this) {
|
||||
return mActiveAdmin != null ? mActiveAdmin.passwordMode
|
||||
: DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
|
||||
final int N = mAdminList.size();
|
||||
int mode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
|
||||
for (int i=0; i<N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (mode < admin.passwordMode) {
|
||||
mode = admin.passwordMode;
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,7 +473,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
|
||||
public int getMinimumPasswordLength() {
|
||||
synchronized (this) {
|
||||
return mActiveAdmin != null ? mActiveAdmin.minimumPasswordLength : 0;
|
||||
final int N = mAdminList.size();
|
||||
int length = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (length < admin.minimumPasswordLength) {
|
||||
length = admin.minimumPasswordLength;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +523,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
|
||||
public int getMaximumFailedPasswordsForWipe() {
|
||||
synchronized (this) {
|
||||
return mActiveAdmin != null ? mActiveAdmin.maximumFailedPasswordsForWipe : 0;
|
||||
final int N = mAdminList.size();
|
||||
int count = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (count == 0) {
|
||||
count = admin.maximumFailedPasswordsForWipe;
|
||||
} else if (admin.maximumFailedPasswordsForWipe != 0
|
||||
&& count > admin.maximumFailedPasswordsForWipe) {
|
||||
count = admin.maximumFailedPasswordsForWipe;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +594,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
|
||||
public long getMaximumTimeToLock() {
|
||||
synchronized (this) {
|
||||
return mActiveAdmin != null ? mActiveAdmin.maximumTimeToUnlock : 0;
|
||||
final int N = mAdminList.size();
|
||||
long time = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (time == 0) {
|
||||
time = admin.maximumTimeToUnlock;
|
||||
} else if (admin.maximumTimeToUnlock != 0
|
||||
&& time > admin.maximumTimeToUnlock) {
|
||||
time = admin.maximumTimeToUnlock;
|
||||
}
|
||||
}
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user