DeviceAdminReceiver.java revision 6b85768058b065cc682757a366abc828c9ca727a
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app.admin;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.app.Service;
22import android.content.BroadcastReceiver;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.os.Bundle;
27
28/**
29 * Base class for implementing a device administration component.  This
30 * class provides a convenience for interpreting the raw intent actions
31 * that are sent by the system.
32 *
33 * <p>The callback methods, like the base
34 * {@link BroadcastReceiver#onReceive(Context, Intent) BroadcastReceiver.onReceive()}
35 * method, happen on the main thread of the process.  Thus long running
36 * operations must be done on another thread.  Note that because a receiver
37 * is done once returning from its receive function, such long-running operations
38 * should probably be done in a {@link Service}.
39 *
40 * <p>When publishing your DeviceAdmin subclass as a receiver, it must
41 * handle {@link #ACTION_DEVICE_ADMIN_ENABLED} and require the
42 * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission.  A typical
43 * manifest entry would look like:</p>
44 *
45 * {@sample development/samples/ApiDemos/AndroidManifest.xml device_admin_declaration}
46 *
47 * <p>The meta-data referenced here provides addition information specific
48 * to the device administrator, as parsed by the {@link DeviceAdminInfo} class.
49 * A typical file would be:</p>
50 *
51 * {@sample development/samples/ApiDemos/res/xml/device_admin_sample.xml meta_data}
52 */
53public class DeviceAdminReceiver extends BroadcastReceiver {
54    private static String TAG = "DevicePolicy";
55    private static boolean DEBUG = false;
56    private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
57
58    /**
59     * This is the primary action that a device administrator must implement to be
60     * allowed to manage a device.  This will be set to the receiver
61     * when the user enables it for administration.  You will generally
62     * handle this in {@link DeviceAdminReceiver#onEnabled(Context, Intent)}.  To be
63     * supported, the receiver must also require the
64     * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission so
65     * that other applications can not abuse it.
66     */
67    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
68    public static final String ACTION_DEVICE_ADMIN_ENABLED
69            = "android.app.action.DEVICE_ADMIN_ENABLED";
70
71    /**
72     * Action sent to a device administrator when the user has requested to
73     * disable it, but before this has actually been done.  This gives you
74     * a chance to supply a message to the user about the impact of
75     * disabling your admin, by setting the extra field
76     * {@link #EXTRA_DISABLE_WARNING} in the result Intent.  If not set,
77     * no warning will be displayed.  If set, the given text will be shown
78     * to the user before they disable your admin.
79     */
80    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
81    public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
82            = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
83
84    /**
85     * A CharSequence that can be shown to the user informing them of the
86     * impact of disabling your admin.
87     *
88     * @see #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
89     */
90    public static final String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
91
92    /**
93     * Action sent to a device administrator when the user has disabled
94     * it.  Upon return, the application no longer has access to the
95     * protected device policy manager APIs.  You will generally
96     * handle this in {@link DeviceAdminReceiver#onDisabled(Context, Intent)}.  Note
97     * that this action will be
98     * sent the receiver regardless of whether it is explicitly listed in
99     * its intent filter.
100     */
101    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
102    public static final String ACTION_DEVICE_ADMIN_DISABLED
103            = "android.app.action.DEVICE_ADMIN_DISABLED";
104
105    /**
106     * Action sent to a device administrator when the user has changed the
107     * password of their device.  You can at this point check the characteristics
108     * of the new password with {@link DevicePolicyManager#isActivePasswordSufficient()
109     * DevicePolicyManager.isActivePasswordSufficient()}.
110     * You will generally
111     * handle this in {@link DeviceAdminReceiver#onPasswordChanged}.
112     *
113     * <p>The calling device admin must have requested
114     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to receive
115     * this broadcast.
116     */
117    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
118    public static final String ACTION_PASSWORD_CHANGED
119            = "android.app.action.ACTION_PASSWORD_CHANGED";
120
121    /**
122     * Action sent to a device administrator when the user has failed at
123     * attempted to enter the password.  You can at this point check the
124     * number of failed password attempts there have been with
125     * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts
126     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}.  You will generally
127     * handle this in {@link DeviceAdminReceiver#onPasswordFailed}.
128     *
129     * <p>The calling device admin must have requested
130     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
131     * this broadcast.
132     */
133    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
134    public static final String ACTION_PASSWORD_FAILED
135            = "android.app.action.ACTION_PASSWORD_FAILED";
136
137    /**
138     * Action sent to a device administrator when the user has successfully
139     * entered their password, after failing one or more times.
140     *
141     * <p>The calling device admin must have requested
142     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
143     * this broadcast.
144     */
145    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
146    public static final String ACTION_PASSWORD_SUCCEEDED
147            = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
148
149    /**
150     * Action periodically sent to a device administrator when the device password
151     * is expiring.
152     *
153     * <p>The calling device admin must have requested
154     * {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to receive
155     * this broadcast.
156     */
157    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
158    public static final String ACTION_PASSWORD_EXPIRING
159            = "android.app.action.ACTION_PASSWORD_EXPIRING";
160
161    /**
162     * Name under which an DevicePolicy component publishes information
163     * about itself.  This meta-data must reference an XML resource containing
164     * a device-admin tag.  XXX TO DO: describe syntax.
165     */
166    public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
167
168    private DevicePolicyManager mManager;
169    private ComponentName mWho;
170
171    /**
172     * Retrieve the DevicePolicyManager interface for this administrator to work
173     * with the system.
174     */
175    public DevicePolicyManager getManager(Context context) {
176        if (mManager != null) {
177            return mManager;
178        }
179        mManager = (DevicePolicyManager)context.getSystemService(
180                Context.DEVICE_POLICY_SERVICE);
181        return mManager;
182    }
183
184    /**
185     * Retrieve the ComponentName describing who this device administrator is, for
186     * use in {@link DevicePolicyManager} APIs that require the administrator to
187     * identify itself.
188     */
189    public ComponentName getWho(Context context) {
190        if (mWho != null) {
191            return mWho;
192        }
193        mWho = new ComponentName(context, getClass());
194        return mWho;
195    }
196
197    /**
198     * Called after the administrator is first enabled, as a result of
199     * receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}.  At this point you
200     * can use {@link DevicePolicyManager} to set your desired policies.
201     * @param context The running context as per {@link #onReceive}.
202     * @param intent The received intent as per {@link #onReceive}.
203     */
204    public void onEnabled(Context context, Intent intent) {
205    }
206
207    /**
208     * Called when the user has asked to disable the administrator, as a result of
209     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED}, giving you
210     * a chance to present a warning message to them.  The message is returned
211     * as the result; if null is returned (the default implementation), no
212     * message will be displayed.
213     * @param context The running context as per {@link #onReceive}.
214     * @param intent The received intent as per {@link #onReceive}.
215     * @return Return the warning message to display to the user before
216     * being disabled; if null is returned, no message is displayed.
217     */
218    public CharSequence onDisableRequested(Context context, Intent intent) {
219        return null;
220    }
221
222    /**
223     * Called prior to the administrator being disabled, as a result of
224     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLED}.  Upon return, you
225     * can no longer use the protected parts of the {@link DevicePolicyManager}
226     * API.
227     * @param context The running context as per {@link #onReceive}.
228     * @param intent The received intent as per {@link #onReceive}.
229     */
230    public void onDisabled(Context context, Intent intent) {
231    }
232
233    /**
234     * Called after the user has changed their password, as a result of
235     * receiving {@link #ACTION_PASSWORD_CHANGED}.  At this point you
236     * can use {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
237     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}
238     * to retrieve the active password characteristics.
239     * @param context The running context as per {@link #onReceive}.
240     * @param intent The received intent as per {@link #onReceive}.
241     */
242    public void onPasswordChanged(Context context, Intent intent) {
243    }
244
245    /**
246     * Called after the user has failed at entering their current password, as a result of
247     * receiving {@link #ACTION_PASSWORD_FAILED}.  At this point you
248     * can use {@link DevicePolicyManager} to retrieve the number of failed
249     * password attempts.
250     * @param context The running context as per {@link #onReceive}.
251     * @param intent The received intent as per {@link #onReceive}.
252     */
253    public void onPasswordFailed(Context context, Intent intent) {
254    }
255
256    /**
257     * Called after the user has succeeded at entering their current password,
258     * as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}.  This will
259     * only be received the first time they succeed after having previously
260     * failed.
261     * @param context The running context as per {@link #onReceive}.
262     * @param intent The received intent as per {@link #onReceive}.
263     */
264    public void onPasswordSucceeded(Context context, Intent intent) {
265    }
266
267    /**
268     * Called periodically when the password is about to expire or has expired.  It will typically
269     * be called at these times: on device boot, once per day before the password expires,
270     * and at the time when the password expires.
271     *
272     * <p>If the password is not updated by the user, this method will continue to be called
273     * once per day until the password is changed or the device admin disables password expiration.
274     *
275     * <p>The admin will typically post a notification requesting the user to change their password
276     * in response to this call. The actual password expiration time can be obtained by calling
277     * {@link DevicePolicyManager#getPasswordExpiration(ComponentName) }
278     *
279     * <p>The admin should be sure to take down any notifications it posted in response to this call
280     * when it receives {@link DeviceAdminReceiver#onPasswordChanged(Context, Intent) }.
281     *
282     * @param context The running context as per {@link #onReceive}.
283     * @param intent The received intent as per {@link #onReceive}.
284     */
285    public void onPasswordExpiring(Context context, Intent intent) {
286    }
287
288    /**
289     * Intercept standard device administrator broadcasts.  Implementations
290     * should not override this method; it is better to implement the
291     * convenience callbacks for each action.
292     */
293    @Override
294    public void onReceive(Context context, Intent intent) {
295        String action = intent.getAction();
296        if (ACTION_PASSWORD_CHANGED.equals(action)) {
297            onPasswordChanged(context, intent);
298        } else if (ACTION_PASSWORD_FAILED.equals(action)) {
299            onPasswordFailed(context, intent);
300        } else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
301            onPasswordSucceeded(context, intent);
302        } else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
303            onEnabled(context, intent);
304        } else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
305            CharSequence res = onDisableRequested(context, intent);
306            if (res != null) {
307                Bundle extras = getResultExtras(true);
308                extras.putCharSequence(EXTRA_DISABLE_WARNING, res);
309            }
310        } else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
311            onDisabled(context, intent);
312        } else if (ACTION_PASSWORD_EXPIRING.equals(action)) {
313            onPasswordExpiring(context, intent);
314        }
315    }
316}
317