First pass at new device policy and administration APIs.
This adds new DevicAdmin, DevicePolicyManager, and DeviceAdminInfo classes.
See the java docs for each on documentation on them. Basically: a DeviceAdmin
is what you derive from to administer a device; DevicePolicyManager is what you
use to apply and check your policy requirements and perform other administration
tasks.
diff --git a/Android.mk b/Android.mk
index ded8173..7c7bb62 100644
--- a/Android.mk
+++ b/Android.mk
@@ -75,6 +75,7 @@
core/java/android/app/IActivityWatcher.aidl \
core/java/android/app/IAlarmManager.aidl \
core/java/android/app/IBackupAgent.aidl \
+ core/java/android/app/IDevicePolicyManager.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
core/java/android/app/ISearchManager.aidl \
diff --git a/api/current.xml b/api/current.xml
index b690e42..ee7d330 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -177,6 +177,17 @@
visibility="public"
>
</field>
+<field name="BIND_DEVICE_ADMIN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.BIND_DEVICE_ADMIN""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BIND_INPUT_METHOD"
type="java.lang.String"
transient="false"
@@ -188,6 +199,17 @@
visibility="public"
>
</field>
+<field name="BIND_WALLPAPER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.BIND_WALLPAPER""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BLUETOOTH"
type="java.lang.String"
transient="false"
@@ -19831,6 +19853,600 @@
</parameter>
</method>
</interface>
+<class name="DeviceAdmin"
+ extends="android.content.BroadcastReceiver"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeviceAdmin"
+ type="android.app.DeviceAdmin"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getManager"
+ return="android.app.DevicePolicyManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="getWho"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="onDisabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordFailed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordSucceeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onReceive"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<field name="ACTION_DEVICE_ADMIN_DISABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.action.DEVICE_ADMIN_DISABLED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DEVICE_ADMIN_ENABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.action.DEVICE_ADMIN_ENABLED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.action.ACTION_PASSWORD_CHANGED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_FAILED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.action.ACTION_PASSWORD_FAILED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_SUCCEEDED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.action.ACTION_PASSWORD_SUCCEEDED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DEVICE_ADMIN_META_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.device_admin""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DeviceAdminInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="DeviceAdminInfo"
+ type="android.app.DeviceAdminInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="receiver" type="android.content.pm.ResolveInfo">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="XmlPullParserException" type="org.xmlpull.v1.XmlPullParserException">
+</exception>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="dump"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pw" type="android.util.Printer">
+</parameter>
+<parameter name="prefix" type="java.lang.String">
+</parameter>
+</method>
+<method name="getActivityInfo"
+ return="android.content.pm.ActivityInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getComponent"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPackageName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getReceiverName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="loadIcon"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pm" type="android.content.pm.PackageManager">
+</parameter>
+</method>
+<method name="loadLabel"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pm" type="android.content.pm.PackageManager">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DevicePolicyManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getActiveMinimumPasswordLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getActivePasswordMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCurrentFailedPasswordAttempts"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaximumTimeToLock"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMinimumPasswordLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPasswordMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isAdminActive"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="who" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="removeActiveAdmin"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="who" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="setMaximumTimeToLock"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="timeMs" type="long">
+</parameter>
+</method>
+<method name="setMinimumPasswordLength"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setPasswordMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<method name="wipeData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="ACTION_ADD_DEVICE_ADMIN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.action.ADD_DEVICE_ADMIN""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_SET_NEW_PASSWORD"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.action.SET_NEW_PASSWORD""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DEVICE_ADMIN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.app.extra.DEVICE_ADMIN""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_MODE_ALPHANUMERIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_MODE_NUMERIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_MODE_UNSPECIFIED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WIPE_EXTERNAL_STORAGE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WIPE_LOW_LEVEL_FORMAT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="Dialog"
extends="java.lang.Object"
abstract="false"
@@ -32576,6 +33192,17 @@
visibility="public"
>
</field>
+<field name="DEVICE_POLICY_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""device_policy""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="DROPBOX_SERVICE"
type="java.lang.String"
transient="false"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index d89b877..fe05393 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -186,6 +186,7 @@
private boolean mRestricted;
private AccountManager mAccountManager; // protected by mSync
private DropBoxManager mDropBoxManager = null;
+ private DevicePolicyManager mDevicePolicyManager = null;
private final Object mSync = new Object();
@@ -895,6 +896,8 @@
return getWallpaperManager();
} else if (DROPBOX_SERVICE.equals(name)) {
return getDropBoxManager();
+ } else if (DEVICE_POLICY_SERVICE.equals(name)) {
+ return getDevicePolicyManager();
}
return null;
@@ -1064,6 +1067,16 @@
return mDropBoxManager;
}
+ private DevicePolicyManager getDevicePolicyManager() {
+ synchronized (mSync) {
+ if (mDevicePolicyManager == null) {
+ mDevicePolicyManager = new DevicePolicyManager(this,
+ mMainThread.getHandler());
+ }
+ }
+ return mDevicePolicyManager;
+ }
+
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
diff --git a/core/java/android/app/DeviceAdmin.java b/core/java/android/app/DeviceAdmin.java
new file mode 100644
index 0000000..4da3fee
--- /dev/null
+++ b/core/java/android/app/DeviceAdmin.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010 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 android.app;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Base class for implementing a device administration component. This
+ * class provides a convenience for interpreting the raw intent actions
+ * that are sent by the system.
+ *
+ * <p>When publishing your DeviceAdmin subclass as a receiver, it must
+ * handle {@link #ACTION_DEVICE_ADMIN_ENABLED} and require the
+ * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission. A typical
+ * manifest entry would look like:</p>
+ *
+ * <pre>{@include development/samples/ApiDemos/AndroidManifest.xml
+ * device_admin_declaration}</pre>
+ *
+ * <p>The meta-data referenced here provides addition information specific
+ * to the device administrator, as parsed by the {@link DeviceAdminInfo} class.
+ * A typical file would be:</p>
+ *
+ * <pre>{@include development/samples/ApiDemos/res/xml/sample_device_admin.xml
+ * meta_data}</pre>
+ */
+public class DeviceAdmin extends BroadcastReceiver {
+ private static String TAG = "DevicePolicy";
+ private static boolean DEBUG = false;
+ private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
+
+ /**
+ * This is the primary action that a device administrator must implement to be
+ * allowed to manage a device. This will be set to the receiver
+ * when the user enables it for administration. You will generally
+ * handle this in {@link DeviceAdmin#onEnabled(Context, Intent)}. To be
+ * supported, the receiver must also require the
+ * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission so
+ * that other applications can not abuse it.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEVICE_ADMIN_ENABLED
+ = "android.app.action.DEVICE_ADMIN_ENABLED";
+
+ /**
+ * Action sent to a device administrator when the user has disabled
+ * it. Upon return, the application no longer has access to the
+ * protected device policy manager APIs. You will generally
+ * handle this in {@link DeviceAdmin#onDisabled(Context, Intent)}. Note
+ * that this action will be
+ * sent the receiver regardless of whether it is explicitly listed in
+ * its intent filter.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEVICE_ADMIN_DISABLED
+ = "android.app.action.DEVICE_ADMIN_DISABLED";
+
+ /**
+ * Action sent to a device administrator when the user has changed the
+ * password of their device. You can at this point check the characteristics
+ * of the new password with {@link DevicePolicyManager#getActivePasswordMode()
+ * DevicePolicyManager.getActivePasswordMode()} and
+ * {@link DevicePolicyManager#getActiveMinimumPasswordLength()
+ * DevicePolicyManager.getActiveMinimumPasswordLength()}. You will generally
+ * handle this in {@link DeviceAdmin#onPasswordChanged(Context, Intent)}.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PASSWORD_CHANGED
+ = "android.app.action.ACTION_PASSWORD_CHANGED";
+
+ /**
+ * Action sent to a device administrator when the user has failed at
+ * attempted to enter the password. You can at this point check the
+ * number of failed password attempts there have been with
+ * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
+ * DevicePolicyManager.getCurrentFailedPasswordAttempts()}. You will generally
+ * handle this in {@link DeviceAdmin#onPasswordFailed(Context, Intent)}.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PASSWORD_FAILED
+ = "android.app.action.ACTION_PASSWORD_FAILED";
+
+ /**
+ * Action sent to a device administrator when the user has successfully
+ * entered their password, after failing one or more times.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PASSWORD_SUCCEEDED
+ = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
+
+ /**
+ * Name under which an DevicePolicy component publishes information
+ * about itself. This meta-data must reference an XML resource containing
+ * a device-admin tag. XXX TO DO: describe syntax.
+ */
+ public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
+
+ private DevicePolicyManager mManager;
+ private ComponentName mWho;
+
+ /**
+ * Retrieve the DevicePolicyManager interface for this administrator to work
+ * with the system.
+ */
+ public DevicePolicyManager getManager(Context context) {
+ if (mManager != null) {
+ return mManager;
+ }
+ mManager = (DevicePolicyManager)context.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ return mManager;
+ }
+
+ /**
+ * Retrieve the ComponentName describing who this device administrator is, for
+ * use in {@link DevicePolicyManager} APIs that require the administrator to
+ * identify itself.
+ */
+ public ComponentName getWho(Context context) {
+ if (mWho != null) {
+ return mWho;
+ }
+ mWho = new ComponentName(context, getClass());
+ return mWho;
+ }
+
+ /**
+ * Called after the administrator is first enabled, as a result of
+ * receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}. At this point you
+ * can use {@link DevicePolicyManager} to set your desired policies.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ */
+ public void onEnabled(Context context, Intent intent) {
+ }
+
+ /**
+ * Called prior to the administrator being disabled, as a result of
+ * receiving {@link #ACTION_DEVICE_ADMIN_DISABLED}. Upon return, you
+ * can no longer use the protected parts of the {@link DevicePolicyManager}
+ * API.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ */
+ public void onDisabled(Context context, Intent intent) {
+ }
+
+ /**
+ * Called after the user has changed their password, as a result of
+ * receiving {@link #ACTION_PASSWORD_CHANGED}. At this point you
+ * can use {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
+ * DevicePolicyManager.getCurrentFailedPasswordAttempts()}
+ * to retrieve the active password characteristics.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ */
+ public void onPasswordChanged(Context context, Intent intent) {
+ }
+
+ /**
+ * Called after the user has failed at entering their current password, as a result of
+ * receiving {@link #ACTION_PASSWORD_FAILED}. At this point you
+ * can use {@link DevicePolicyManager} to retrieve the number of failed
+ * password attempts.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ */
+ public void onPasswordFailed(Context context, Intent intent) {
+ }
+
+ /**
+ * Called after the user has succeeded at entering their current password,
+ * as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}. This will
+ * only be received the first time they succeed after having previously
+ * failed.
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ */
+ public void onPasswordSucceeded(Context context, Intent intent) {
+ }
+
+ /**
+ * Intercept standard device administrator broadcasts. Implementations
+ * should not override this method; it is better to implement the
+ * convenience callbacks for each action.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ACTION_PASSWORD_CHANGED.equals(action)) {
+ onPasswordChanged(context, intent);
+ } else if (ACTION_PASSWORD_FAILED.equals(action)) {
+ onPasswordFailed(context, intent);
+ } else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
+ onPasswordSucceeded(context, intent);
+ } else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
+ onEnabled(context, intent);
+ } else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
+ onDisabled(context, intent);
+ }
+ }
+}
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
new file mode 100644
index 0000000..eac6e46
--- /dev/null
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2010 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 android.app;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Printer;
+import android.util.Xml;
+
+import java.io.IOException;
+
+/**
+ * This class is used to specify meta information of a device administrator
+ * component.
+ */
+public final class DeviceAdminInfo implements Parcelable {
+ static final String TAG = "DeviceAdminInfo";
+
+ /**
+ * The BroadcastReceiver that implements this device admin component.
+ */
+ final ResolveInfo mReceiver;
+
+ /**
+ * Constructor.
+ *
+ * @param context The Context in which we are parsing the device admin.
+ * @param receiver The ResolveInfo returned from the package manager about
+ * this device admin's component.
+ */
+ public DeviceAdminInfo(Context context, ResolveInfo receiver)
+ throws XmlPullParserException, IOException {
+ mReceiver = receiver;
+ ActivityInfo ai = receiver.activityInfo;
+
+ PackageManager pm = context.getPackageManager();
+
+ XmlResourceParser parser = null;
+ try {
+ parser = ai.loadXmlMetaData(pm, DeviceAdmin.DEVICE_ADMIN_META_DATA);
+ if (parser == null) {
+ throw new XmlPullParserException("No "
+ + DeviceAdmin.DEVICE_ADMIN_META_DATA + " meta-data");
+ }
+
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!"device-admin".equals(nodeName)) {
+ throw new XmlPullParserException(
+ "Meta-data does not start with device-admin tag");
+ }
+
+ TypedArray sa = context.getResources().obtainAttributes(attrs,
+ com.android.internal.R.styleable.Wallpaper);
+
+ sa.recycle();
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ DeviceAdminInfo(Parcel source) {
+ mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
+ }
+
+ /**
+ * Return the .apk package that implements this device admin.
+ */
+ public String getPackageName() {
+ return mReceiver.activityInfo.packageName;
+ }
+
+ /**
+ * Return the class name of the receiver component that implements
+ * this device admin.
+ */
+ public String getReceiverName() {
+ return mReceiver.activityInfo.name;
+ }
+
+ /**
+ * Return the raw information about the receiver implementing this
+ * device admin. Do not modify the returned object.
+ */
+ public ActivityInfo getActivityInfo() {
+ return mReceiver.activityInfo;
+ }
+
+ /**
+ * Return the component of the receiver that implements this device admin.
+ */
+ public ComponentName getComponent() {
+ return new ComponentName(mReceiver.activityInfo.packageName,
+ mReceiver.activityInfo.name);
+ }
+
+ /**
+ * Load the user-displayed label for this device admin.
+ *
+ * @param pm Supply a PackageManager used to load the device admin's
+ * resources.
+ */
+ public CharSequence loadLabel(PackageManager pm) {
+ return mReceiver.loadLabel(pm);
+ }
+
+ /**
+ * Load the user-displayed icon for this device admin.
+ *
+ * @param pm Supply a PackageManager used to load the device admin's
+ * resources.
+ */
+ public Drawable loadIcon(PackageManager pm) {
+ return mReceiver.loadIcon(pm);
+ }
+
+ public void dump(Printer pw, String prefix) {
+ pw.println(prefix + "Receiver:");
+ mReceiver.dump(pw, prefix + " ");
+ }
+
+ @Override
+ public String toString() {
+ return "DeviceAdminInfo{" + mReceiver.activityInfo.name + "}";
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ mReceiver.writeToParcel(dest, flags);
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<DeviceAdminInfo> CREATOR =
+ new Parcelable.Creator<DeviceAdminInfo>() {
+ public DeviceAdminInfo createFromParcel(Parcel source) {
+ return new DeviceAdminInfo(source);
+ }
+
+ public DeviceAdminInfo[] newArray(int size) {
+ return new DeviceAdminInfo[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
new file mode 100644
index 0000000..4fdfe0a
--- /dev/null
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2010 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 android.app;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Public interface for managing policies enforced on a device. Most clients
+ * of this class must have published a {@link DeviceAdmin} that the user
+ * has currently enabled.
+ */
+public class DevicePolicyManager {
+ private static String TAG = "DevicePolicyManager";
+ private static boolean DEBUG = false;
+ private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final IDevicePolicyManager mService;
+
+ /*package*/ DevicePolicyManager(Context context, Handler handler) {
+ mContext = context;
+ mHandler = handler;
+ mService = IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ }
+
+ /**
+ * Activity action: ask the user to add a new device administrator to the system.
+ * The desired policy is the ComponentName of the policy in the
+ * {@link #EXTRA_DEVICE_ADMIN} extra field. This will invoke a UI to
+ * bring the user through adding the device administrator to the system (or
+ * allowing them to reject it).
+ *
+ * <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
+ = "android.app.action.ADD_DEVICE_ADMIN";
+
+ /**
+ * The ComponentName of the administrator component.
+ *
+ * @see #ACTION_ADD_DEVICE_ADMIN
+ */
+ public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
+
+ /**
+ * Activity action: have the user enter a new password. This activity
+ * should be launched after using {@link #setPasswordMode(ComponentName, int)}
+ * or {@link #setMinimumPasswordLength(ComponentName, int)} to have the
+ * user enter a new password that meets the current requirements. If the
+ * current password is sufficient, the activity will exit immediately without
+ * being displayed to the user. Upon receiving a result from this activity,
+ * you can check the new password characteristics to see if they are
+ * sufficient.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SET_NEW_PASSWORD
+ = "android.app.action.SET_NEW_PASSWORD";
+
+ /**
+ * Return true if the given administrator component is currently
+ * active (enabled) in the system.
+ */
+ public boolean isAdminActive(ComponentName who) {
+ if (mService != null) {
+ try {
+ return who.equals(mService.getActiveAdmin());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Remove a current administration component. This can only be called
+ * by the application that owns the administration component; if you
+ * try to remove someone else's component, a security exception will be
+ * thrown.
+ */
+ public void removeActiveAdmin(ComponentName who) {
+ if (mService != null) {
+ try {
+ mService.removeActiveAdmin(who);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Constant for {@link #setPasswordMode}: the policy has no requirements
+ * for the password.
+ */
+ public static final int PASSWORD_MODE_UNSPECIFIED = 0;
+
+ /**
+ * Constant for {@link #setPasswordMode}: the user must have at least a
+ * numeric password.
+ */
+ public static final int PASSWORD_MODE_NUMERIC = 1000;
+
+ /**
+ * Constant for {@link #setPasswordMode}: the user must have at least an
+ * alphanumeric password.
+ */
+ public static final int PASSWORD_MODE_ALPHANUMERIC = 2000;
+
+ /**
+ * Called by an application that is administering the device to set the
+ * password restrictions it is imposing. After setting this, the user
+ * will not be able to enter a new password that is not at least as
+ * restrictive as what has been set. Note that the current password
+ * will remain until the user has set a new one, so the change does not
+ * take place immediately. To prompt the user for a new password, use
+ * {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
+ *
+ * @param admin Which {@link DeviceAdmin} this request is associated with.
+ * @param mode The new desired mode. One of
+ * {@link #PASSWORD_MODE_UNSPECIFIED}, {@link #PASSWORD_MODE_NUMERIC},
+ * or {@link #PASSWORD_MODE_ALPHANUMERIC}.
+ */
+ public void setPasswordMode(ComponentName admin, int mode) {
+ if (mService != null) {
+ try {
+ mService.setPasswordMode(admin, mode);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current password mode that is in effect due to all
+ * device admins.
+ */
+ public int getPasswordMode() {
+ if (mService != null) {
+ try {
+ return mService.getPasswordMode();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return PASSWORD_MODE_UNSPECIFIED;
+ }
+
+ /**
+ * Retrieve the password mode associated with the last password the
+ * user selected.
+ */
+ public int getActivePasswordMode() {
+ if (mService != null) {
+ try {
+ return mService.getActivePasswordMode();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return PASSWORD_MODE_UNSPECIFIED;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the
+ * minimum allowed password length. After setting this, the user
+ * will not be able to enter a new password that is not at least as
+ * restrictive as what has been set. Note that the current password
+ * will remain until the user has set a new one, so the change does not
+ * take place immediately. To prompt the user for a new password, use
+ * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * constraint is only imposed if the administrator has also requested either
+ * {@link #PASSWORD_MODE_NUMERIC} or {@link #PASSWORD_MODE_ALPHANUMERIC}
+ * with {@link #setPasswordMode}.
+ *
+ * @param admin Which {@link DeviceAdmin} this request is associated with.
+ * @param length The new desired minimum password length. A value of 0
+ * means there is no restriction.
+ */
+ public void setMinimumPasswordLength(ComponentName admin, int length) {
+ if (mService != null) {
+ try {
+ mService.setMinimumPasswordLength(admin, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current minimum password length that is in effect due to all
+ * device admins.
+ */
+ public int getMinimumPasswordLength() {
+ if (mService != null) {
+ try {
+ return mService.getMinimumPasswordLength();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Retrieve the password length associated with the last password the
+ * user selected.
+ */
+ public int getActiveMinimumPasswordLength() {
+ if (mService != null) {
+ try {
+ return mService.getActiveMinimumPasswordLength();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Retrieve the number of times the user has failed at entering a
+ * password since that last successful password entry.
+ */
+ public int getCurrentFailedPasswordAttempts() {
+ if (mService != null) {
+ try {
+ return mService.getCurrentFailedPasswordAttempts();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Called by an application that is administering the device to set the
+ * maximum time for user activity until the device will lock. This limits
+ * the length that the user can set. It takes effect immediately.
+ *
+ * @param admin Which {@link DeviceAdmin} this request is associated with.
+ * @param timeMs The new desired maximum time to lock in milliseconds.
+ * A value of 0 means there is no restriction.
+ */
+ public void setMaximumTimeToLock(ComponentName admin, long timeMs) {
+ if (mService != null) {
+ try {
+ mService.setMaximumTimeToLock(admin, timeMs);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the current maximum time to lock that is in effect due to all
+ * device admins. Returns 0 if no maximum is set.
+ */
+ public long getMaximumTimeToLock() {
+ if (mService != null) {
+ try {
+ return mService.getMaximumTimeToLock();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Constant for {@link #wipeData}: perform a low-level format of data
+ * storage.
+ */
+ public static final int WIPE_LOW_LEVEL_FORMAT = 0x0001;
+
+ /**
+ * Constant for {@link #wipeData}: also wipe any external storage.
+ */
+ public static final int WIPE_EXTERNAL_STORAGE = 0x0002;
+
+ /**
+ * Ask the user date be wiped. This will cause the device to reboot,
+ * erasing all user data while next booting up.
+ *
+ * @param flags Bit mask of additional options: currently
+ * {@link #WIPE_LOW_LEVEL_FORMAT} and {@link #WIPE_EXTERNAL_STORAGE}.
+ */
+ public void wipeData(int flags) {
+ if (mService != null) {
+ try {
+ mService.wipeData(flags);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setActiveAdmin(ComponentName policyReceiver) {
+ if (mService != null) {
+ try {
+ mService.setActiveAdmin(policyReceiver);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * @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;
+ }
+
+ ActivityInfo ai;
+ try {
+ ai = mContext.getPackageManager().getReceiverInfo(cn,
+ PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+ return null;
+ }
+
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+
+ try {
+ return new DeviceAdminInfo(mContext, ri);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Unable to parse device policy " + cn, e);
+ return null;
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to parse device policy " + cn, e);
+ return null;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setActivePasswordState(int mode, int length) {
+ if (mService != null) {
+ try {
+ mService.setActivePasswordState(mode, length);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void reportFailedPasswordAttempt() {
+ if (mService != null) {
+ try {
+ mService.reportFailedPasswordAttempt();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void reportSuccessfulPasswordAttempt() {
+ if (mService != null) {
+ try {
+ mService.reportSuccessfulPasswordAttempt();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/IDevicePolicyManager.aidl b/core/java/android/app/IDevicePolicyManager.aidl
new file mode 100644
index 0000000..f62647f
--- /dev/null
+++ b/core/java/android/app/IDevicePolicyManager.aidl
@@ -0,0 +1,49 @@
+/*
+**
+** Copyright 2010, 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 android.app;
+
+import android.content.ComponentName;
+
+/**
+ * Internal IPC interface to the device policy service.
+ * {@hide}
+ */
+interface IDevicePolicyManager {
+ void setPasswordMode(in ComponentName who, int mode);
+ int getPasswordMode();
+ int getActivePasswordMode();
+
+ void setMinimumPasswordLength(in ComponentName who, int length);
+ int getMinimumPasswordLength();
+ int getActiveMinimumPasswordLength();
+
+ int getCurrentFailedPasswordAttempts();
+
+ void setMaximumTimeToLock(in ComponentName who, long timeMs);
+ long getMaximumTimeToLock();
+
+ void wipeData(int flags);
+
+ void setActiveAdmin(in ComponentName policyReceiver);
+ ComponentName getActiveAdmin();
+ void removeActiveAdmin(in ComponentName policyReceiver);
+
+ void setActivePasswordState(int mode, int length);
+ void reportFailedPasswordAttempt();
+ void reportSuccessfulPasswordAttempt();
+}
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 1034fab..1612ac9 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 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 android.app;
import org.xmlpull.v1.XmlPullParser;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0fafe5d..0b83f03 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1132,6 +1132,7 @@
* you're running long tasks.
*/
public static final String POWER_SERVICE = "power";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.view.WindowManager} for accessing the system's window
@@ -1141,6 +1142,7 @@
* @see android.view.WindowManager
*/
public static final String WINDOW_SERVICE = "window";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.view.LayoutInflater} for inflating layout resources in this
@@ -1150,6 +1152,7 @@
* @see android.view.LayoutInflater
*/
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.accounts.AccountManager} for receiving intents at a
@@ -1159,6 +1162,7 @@
* @see android.accounts.AccountManager
*/
public static final String ACCOUNT_SERVICE = "account";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.app.ActivityManager} for interacting with the global
@@ -1168,6 +1172,7 @@
* @see android.app.ActivityManager
*/
public static final String ACTIVITY_SERVICE = "activity";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.app.AlarmManager} for receiving intents at a
@@ -1177,6 +1182,7 @@
* @see android.app.AlarmManager
*/
public static final String ALARM_SERVICE = "alarm";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.app.NotificationManager} for informing the user of
@@ -1186,6 +1192,7 @@
* @see android.app.NotificationManager
*/
public static final String NOTIFICATION_SERVICE = "notification";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.view.accessibility.AccessibilityManager} for giving the user
@@ -1195,6 +1202,7 @@
* @see android.view.accessibility.AccessibilityManager
*/
public static final String ACCESSIBILITY_SERVICE = "accessibility";
+
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.app.NotificationManager} for controlling keyguard.
@@ -1203,6 +1211,7 @@
* @see android.app.KeyguardManager
*/
public static final String KEYGUARD_SERVICE = "keyguard";
+
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.location.LocationManager} for controlling location
@@ -1212,6 +1221,7 @@
* @see android.location.LocationManager
*/
public static final String LOCATION_SERVICE = "location";
+
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.app.SearchManager} for handling searches.
@@ -1220,6 +1230,7 @@
* @see android.app.SearchManager
*/
public static final String SEARCH_SERVICE = "search";
+
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.hardware.SensorManager} for accessing sensors.
@@ -1228,6 +1239,7 @@
* @see android.hardware.SensorManager
*/
public static final String SENSOR_SERVICE = "sensor";
+
/**
* Use with {@link #getSystemService} to retrieve a
* com.android.server.WallpaperService for accessing wallpapers.
@@ -1235,6 +1247,7 @@
* @see #getSystemService
*/
public static final String WALLPAPER_SERVICE = "wallpaper";
+
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.os.Vibrator} for interacting with the vibration hardware.
@@ -1243,6 +1256,7 @@
* @see android.os.Vibrator
*/
public static final String VIBRATOR_SERVICE = "vibrator";
+
/**
* Use with {@link #getSystemService} to retrieve a {@link
* android.app.StatusBarManager} for interacting with the status bar.
@@ -1340,6 +1354,15 @@
public static final String DROPBOX_SERVICE = "dropbox";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.app.DevicePolicyManager} for working with global
+ * device policy management.
+ *
+ * @see #getSystemService
+ */
+ public static final String DEVICE_POLICY_SERVICE = "device_policy";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index fe3b149..eb48a0c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -20,6 +20,8 @@
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseSurfaceHolder;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
@@ -58,9 +60,13 @@
public abstract class WallpaperService extends Service {
/**
* The {@link Intent} that must be declared as handled by the service.
+ * To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_WALLPAPER} permission so
+ * that other applications can not abuse it.
*/
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE =
- "android.service.wallpaper.WallpaperService";
+ "android.service.wallpaper.WallpaperService";
/**
* Name under which a WallpaperService component publishes information
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index a5e0e94..2ddf5f8 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -16,6 +16,8 @@
package android.view.inputmethod;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.ResultReceiver;
@@ -54,9 +56,12 @@
/**
* This is the interface name that a service implementing an input
* method should say that it supports -- that is, this is the action it
- * uses for its intent filter. (Note: this name is used because this
- * interface should be moved to the view package.)
+ * uses for its intent filter.
+ * To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission so
+ * that other applications can not abuse it.
*/
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE = "android.view.InputMethod";
/**
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 37372c5..0ce70fa 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -50,6 +50,7 @@
* Whether the children of this layout are baseline aligned. Only applicable
* if {@link #mOrientation} is horizontal.
*/
+ @ViewDebug.ExportedProperty
private boolean mBaselineAligned = true;
/**
@@ -59,6 +60,7 @@
* Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
* with whether the children of this layout are baseline aligned.
*/
+ @ViewDebug.ExportedProperty
private int mBaselineAlignedChildIndex = -1;
/**
@@ -66,12 +68,30 @@
* We'll calculate the baseline of this layout as we measure vertically; for
* horizontal linear layouts, the offset of 0 is appropriate.
*/
+ @ViewDebug.ExportedProperty
private int mBaselineChildTop = 0;
+ @ViewDebug.ExportedProperty
private int mOrientation;
+ @ViewDebug.ExportedProperty(mapping = {
+ @ViewDebug.IntToString(from = -1, to = "NONE"),
+ @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
+ @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
+ @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
+ @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
+ @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
+ @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
+ @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
+ @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+ @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
+ @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
+ @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
+ })
private int mGravity = Gravity.LEFT | Gravity.TOP;
+ @ViewDebug.ExportedProperty
private int mTotalLength;
+ @ViewDebug.ExportedProperty
private float mWeightSum;
private int[] mMaxAscent;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c49a86a..d81476a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -927,21 +927,27 @@
android:description="@string/permdesc_readInputState"
android:protectionLevel="signature" />
- <!-- Must be required by input method services, to ensure that only the
- system can bind to them. -->
+ <!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
+ to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_INPUT_METHOD"
android:label="@string/permlab_bindInputMethod"
android:description="@string/permdesc_bindInputMethod"
android:protectionLevel="signature" />
- <!-- Must be required by wallpaper services, to ensure that only the
- system can bind to them.
- @hide Live Wallpaper -->
+ <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
+ to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_WALLPAPER"
android:label="@string/permlab_bindWallpaper"
android:description="@string/permdesc_bindWallpaper"
android:protectionLevel="signatureOrSystem" />
+ <!-- Must be required by device administration receiver, to ensure that only the
+ system can interact with it. -->
+ <permission android:name="android.permission.BIND_DEVICE_ADMIN"
+ android:label="@string/permlab_bindDeviceAdmin"
+ android:description="@string/permdesc_bindDeviceAdmin"
+ android:protectionLevel="signature" />
+
<!-- Allows low-level access to setting the orientation (actually
rotation) of the screen. Not for use by normal applications. -->
<permission android:name="android.permission.SET_ORIENTATION"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 539db83..265dacd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -617,6 +617,12 @@
interface of a wallpaper. Should never be needed for normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindDeviceAdmin">interact with a device admin</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
+ a device administrator. Should never be needed for normal applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_setOrientation">change screen orientation</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_setOrientation">Allows an application to change
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
new file mode 100644
index 0000000..e13ddc8
--- /dev/null
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2010 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.server;
+
+import com.android.common.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.app.DeviceAdmin;
+import android.app.DeviceAdminInfo;
+import android.app.DevicePolicyManager;
+import android.app.IDevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.util.Log;
+import android.util.Xml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Implementation of the device policy APIs.
+ */
+public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ private static final String TAG = "DevicePolicyManagerService";
+
+ private final Context mContext;
+
+ int mActivePasswordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+ int mActivePasswordLength = 0;
+ int mFailedPasswordAttempts = 0;
+
+ ActiveAdmin mActiveAdmin;
+
+ static class ActiveAdmin {
+ ActiveAdmin(DeviceAdminInfo _info) {
+ info = _info;
+ }
+
+ final DeviceAdminInfo info;
+ int getUid() { return info.getActivityInfo().applicationInfo.uid; }
+
+ int passwordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+ int minimumPasswordLength = 0;
+ long maximumTimeToUnlock = 0;
+ }
+
+ /**
+ * Instantiates the service.
+ */
+ public DevicePolicyManagerService(Context context) {
+ mContext = context;
+ }
+
+ ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException {
+ if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingPid()) {
+ if (who != null) {
+ if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName)
+ || !who.getClassName().equals(mActiveAdmin.info.getActivityInfo().name)) {
+ throw new SecurityException("Current admin is not " + who);
+ }
+ }
+ return mActiveAdmin;
+ }
+ throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid());
+ }
+
+
+ void sendAdminCommandLocked(ActiveAdmin policy, String action) {
+ Intent intent = new Intent(action);
+ intent.setComponent(policy.info.getComponent());
+ mContext.sendBroadcast(intent);
+ }
+
+ 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,
+ DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLED);
+ // XXX need to wait for it to complete.
+ mActiveAdmin = null;
+ }
+ }
+
+ public DeviceAdminInfo findAdmin(ComponentName adminName) {
+ Intent resolveIntent = new Intent();
+ resolveIntent.setComponent(adminName);
+ List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
+ resolveIntent, PackageManager.GET_META_DATA);
+ if (infos == null || infos.size() <= 0) {
+ throw new IllegalArgumentException("Unknown admin: " + adminName);
+ }
+
+ try {
+ return new DeviceAdminInfo(mContext, infos.get(0));
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Bad device admin requested: " + adminName, e);
+ return null;
+ } catch (IOException e) {
+ Log.w(TAG, "Bad device admin requested: " + adminName, e);
+ return null;
+ }
+ }
+
+ private static JournaledFile makeJournaledFile() {
+ final String base = "/data/system/device_policies.xml";
+ return new JournaledFile(new File(base), new File(base + ".tmp"));
+ }
+
+ private void saveSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileOutputStream stream = null;
+ try {
+ stream = new FileOutputStream(journal.chooseForWrite(), false);
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+
+ out.startTag(null, "policies");
+
+ ActiveAdmin ap = mActiveAdmin;
+ if (ap != null) {
+ out.startTag(null, "admin");
+ out.attribute(null, "name", ap.info.getComponent().flattenToString());
+ if (ap.passwordMode != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
+ out.startTag(null, "password-mode");
+ out.attribute(null, "value", Integer.toString(ap.passwordMode));
+ out.endTag(null, "password-mode");
+ if (ap.minimumPasswordLength > 0) {
+ out.startTag(null, "min-password-length");
+ out.attribute(null, "value", Integer.toString(ap.minimumPasswordLength));
+ out.endTag(null, "mn-password-length");
+ }
+ }
+ if (ap.maximumTimeToUnlock != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
+ out.startTag(null, "max-time-to-unlock");
+ out.attribute(null, "value", Long.toString(ap.maximumTimeToUnlock));
+ out.endTag(null, "max-time-to-unlock");
+ }
+ out.endTag(null, "admin");
+ }
+ out.endTag(null, "policies");
+
+ out.endDocument();
+ stream.close();
+ journal.commit();
+ } catch (IOException e) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException ex) {
+ // Ignore
+ }
+ journal.rollback();
+ }
+ }
+
+ private void loadSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileInputStream stream = null;
+ File file = journal.chooseForRead();
+ boolean success = false;
+ try {
+ stream = new FileInputStream(file);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ int type = parser.next();
+ while (type != XmlPullParser.START_TAG) {
+ type = parser.next();
+ }
+ String tag = parser.getName();
+ if ("policies".equals(tag)) {
+ ActiveAdmin ap = null;
+ do {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG) {
+ tag = parser.getName();
+ if (ap == null) {
+ if ("admin".equals(tag)) {
+ DeviceAdminInfo dai = findAdmin(
+ ComponentName.unflattenFromString(
+ parser.getAttributeValue(null, "name")));
+ if (dai != null) {
+ ap = new ActiveAdmin(dai);
+ }
+ }
+ } else if ("password-mode".equals(tag)) {
+ ap.passwordMode = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-length".equals(tag)) {
+ ap.minimumPasswordLength = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("max-time-to-unlock".equals(tag)) {
+ ap.maximumTimeToUnlock = Long.parseLong(
+ parser.getAttributeValue(null, "value"));
+ }
+ } else if (type == XmlPullParser.END_TAG) {
+ tag = parser.getName();
+ if (ap != null && "admin".equals(tag)) {
+ mActiveAdmin = ap;
+ ap = null;
+ }
+ }
+ } while (type != XmlPullParser.END_DOCUMENT);
+ success = true;
+ }
+ } catch (NullPointerException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IOException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ }
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ if (!success) {
+ Log.w(TAG, "No valid start tag found in policies file");
+ }
+ }
+
+ public void systemReady() {
+ synchronized (this) {
+ loadSettingsLocked();
+ }
+ }
+
+ public void setActiveAdmin(ComponentName adminReceiver) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ DeviceAdminInfo info = findAdmin(adminReceiver);
+ if (info == null) {
+ throw new IllegalArgumentException("Bad admin: " + adminReceiver);
+ }
+ 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 (cur != null) {
+ removeActiveAdminLocked(adminReceiver);
+ }
+ mActiveAdmin = new ActiveAdmin(info);
+ saveSettingsLocked();
+ sendAdminCommandLocked(mActiveAdmin,
+ DeviceAdmin.ACTION_DEVICE_ADMIN_ENABLED);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public ComponentName getActiveAdmin() {
+ synchronized (this) {
+ return getActiveAdminLocked();
+ }
+ }
+
+ public void removeActiveAdmin(ComponentName adminReceiver) {
+ synchronized (this) {
+ if (mActiveAdmin == null || mActiveAdmin.getUid() != Binder.getCallingUid()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ removeActiveAdminLocked(adminReceiver);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void setPasswordMode(ComponentName who, int mode) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+ if (ap.passwordMode != mode) {
+ ap.passwordMode = mode;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMode() {
+ synchronized (this) {
+ return mActiveAdmin != null ? mActiveAdmin.passwordMode
+ : DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
+ }
+ }
+
+ public int getActivePasswordMode() {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null);
+ return mActivePasswordMode;
+ }
+ }
+
+ public void setMinimumPasswordLength(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+ if (ap.minimumPasswordLength != length) {
+ ap.minimumPasswordLength = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getMinimumPasswordLength() {
+ synchronized (this) {
+ return mActiveAdmin != null ? mActiveAdmin.minimumPasswordLength : 0;
+ }
+ }
+
+ public int getActiveMinimumPasswordLength() {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null);
+ return mActivePasswordLength;
+ }
+ }
+
+ public int getCurrentFailedPasswordAttempts() {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null);
+ return mFailedPasswordAttempts;
+ }
+ }
+
+ public void setMaximumTimeToLock(ComponentName who, long timeMs) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who);
+ if (ap.maximumTimeToUnlock != timeMs) {
+ ap.maximumTimeToUnlock = timeMs;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public long getMaximumTimeToLock() {
+ synchronized (this) {
+ return mActiveAdmin != null ? mActiveAdmin.maximumTimeToUnlock : 0;
+ }
+ }
+
+ public void wipeData(int flags) {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Log.w(TAG, "*************** WIPE DATA HERE");
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void setActivePasswordState(int mode, int length) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ synchronized (this) {
+ if (mActivePasswordMode != mode || mActivePasswordLength != length
+ || mFailedPasswordAttempts != 0) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mActivePasswordMode = mode;
+ mActivePasswordLength = length;
+ mFailedPasswordAttempts = 0;
+ sendAdminCommandLocked(mActiveAdmin,
+ DeviceAdmin.ACTION_PASSWORD_CHANGED);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+ }
+
+ public void reportFailedPasswordAttempt() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mFailedPasswordAttempts++;
+ sendAdminCommandLocked(mActiveAdmin,
+ DeviceAdmin.ACTION_PASSWORD_FAILED);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void reportSuccessfulPasswordAttempt() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ synchronized (this) {
+ if (mFailedPasswordAttempts != 0) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mFailedPasswordAttempts = 0;
+ sendAdminCommandLocked(mActiveAdmin,
+ DeviceAdmin.ACTION_PASSWORD_SUCCEEDED);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 674ade9..6b3f433 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -201,6 +201,7 @@
Log.e("System", "Failure starting core service", e);
}
+ DevicePolicyManagerService devicePolicy = null;
StatusBarService statusBar = null;
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
@@ -209,16 +210,25 @@
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
+ Log.i(TAG, "Device Policy");
+ devicePolicy = new DevicePolicyManagerService(context);
+ ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting DevicePolicyService", e);
+ }
+
+ try {
Log.i(TAG, "Status Bar");
statusBar = new StatusBarService(context);
- ServiceManager.addService("statusbar", statusBar);
+ ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
Log.e(TAG, "Failure starting StatusBarService", e);
}
try {
Log.i(TAG, "Clipboard Service");
- ServiceManager.addService("clipboard", new ClipboardService(context));
+ ServiceManager.addService(Context.CLIPBOARD_SERVICE,
+ new ClipboardService(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Clipboard Service", e);
}
@@ -280,14 +290,16 @@
try {
Log.i(TAG, "Location Manager");
- ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context));
+ ServiceManager.addService(Context.LOCATION_SERVICE,
+ new LocationManagerService(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Location Manager", e);
}
try {
Log.i(TAG, "Search Service");
- ServiceManager.addService( Context.SEARCH_SERVICE, new SearchManagerService(context) );
+ ServiceManager.addService(Context.SEARCH_SERVICE,
+ new SearchManagerService(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Search Service", e);
}
@@ -351,7 +363,8 @@
try {
Log.i(TAG, "Backup Service");
- ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
+ ServiceManager.addService(Context.BACKUP_SERVICE,
+ new BackupManagerService(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Backup Service", e);
}
@@ -391,6 +404,10 @@
// It is now time to start up the app processes...
+ if (devicePolicy != null) {
+ devicePolicy.systemReady();
+ }
+
if (notification != null) {
notification.systemReady();
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 40d194c..843058c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8381,7 +8381,7 @@
ActivityInfo ai = ris.get(i).activityInfo;
intent.setComponent(new ComponentName(ai.packageName, ai.name));
IIntentReceiver finisher = null;
- if (i == 0) {
+ if (i == ris.size()-1) {
finisher = new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
@@ -8397,7 +8397,7 @@
Log.i(TAG, "Sending system update to: " + intent.getComponent());
broadcastIntentLocked(null, null, intent, null, finisher,
0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
- if (i == 0) {
+ if (finisher != null) {
mWaitingUpdate = true;
}
}