DeviceAdminReceiver.java revision c70d0e71c09da0292958d748cedaa5fbacbec74a
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.accounts.AccountManager;
20import android.annotation.SdkConstant;
21import android.annotation.SdkConstant.SdkConstantType;
22import android.app.Service;
23import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.Intent;
27import android.os.Bundle;
28
29/**
30 * Base class for implementing a device administration component.  This
31 * class provides a convenience for interpreting the raw intent actions
32 * that are sent by the system.
33 *
34 * <p>The callback methods, like the base
35 * {@link BroadcastReceiver#onReceive(Context, Intent) BroadcastReceiver.onReceive()}
36 * method, happen on the main thread of the process.  Thus long running
37 * operations must be done on another thread.  Note that because a receiver
38 * is done once returning from its receive function, such long-running operations
39 * should probably be done in a {@link Service}.
40 *
41 * <p>When publishing your DeviceAdmin subclass as a receiver, it must
42 * handle {@link #ACTION_DEVICE_ADMIN_ENABLED} and require the
43 * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission.  A typical
44 * manifest entry would look like:</p>
45 *
46 * {@sample development/samples/ApiDemos/AndroidManifest.xml device_admin_declaration}
47 *
48 * <p>The meta-data referenced here provides addition information specific
49 * to the device administrator, as parsed by the {@link DeviceAdminInfo} class.
50 * A typical file would be:</p>
51 *
52 * {@sample development/samples/ApiDemos/res/xml/device_admin_sample.xml meta_data}
53 *
54 * <div class="special reference">
55 * <h3>Developer Guides</h3>
56 * <p>For more information about device administration, read the
57 * <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
58 * developer guide.</p>
59 * </div>
60 */
61public class DeviceAdminReceiver extends BroadcastReceiver {
62    private static String TAG = "DevicePolicy";
63    private static boolean localLOGV = false;
64
65    /**
66     * This is the primary action that a device administrator must implement to be
67     * allowed to manage a device.  This will be set to the receiver
68     * when the user enables it for administration.  You will generally
69     * handle this in {@link DeviceAdminReceiver#onEnabled(Context, Intent)}.  To be
70     * supported, the receiver must also require the
71     * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission so
72     * that other applications can not abuse it.
73     */
74    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
75    public static final String ACTION_DEVICE_ADMIN_ENABLED
76            = "android.app.action.DEVICE_ADMIN_ENABLED";
77
78    /**
79     * Action sent to a device administrator when the user has requested to
80     * disable it, but before this has actually been done.  This gives you
81     * a chance to supply a message to the user about the impact of
82     * disabling your admin, by setting the extra field
83     * {@link #EXTRA_DISABLE_WARNING} in the result Intent.  If not set,
84     * no warning will be displayed.  If set, the given text will be shown
85     * to the user before they disable your admin.
86     */
87    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
88    public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
89            = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
90
91    /**
92     * A CharSequence that can be shown to the user informing them of the
93     * impact of disabling your admin.
94     *
95     * @see #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
96     */
97    public static final String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
98
99    /**
100     * Action sent to a device administrator when the user has disabled
101     * it.  Upon return, the application no longer has access to the
102     * protected device policy manager APIs.  You will generally
103     * handle this in {@link DeviceAdminReceiver#onDisabled(Context, Intent)}.  Note
104     * that this action will be
105     * sent the receiver regardless of whether it is explicitly listed in
106     * its intent filter.
107     */
108    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
109    public static final String ACTION_DEVICE_ADMIN_DISABLED
110            = "android.app.action.DEVICE_ADMIN_DISABLED";
111
112    /**
113     * Action sent to a device administrator when the user has changed the
114     * password of their device.  You can at this point check the characteristics
115     * of the new password with {@link DevicePolicyManager#isActivePasswordSufficient()
116     * DevicePolicyManager.isActivePasswordSufficient()}.
117     * You will generally
118     * handle this in {@link DeviceAdminReceiver#onPasswordChanged}.
119     *
120     * <p>The calling device admin must have requested
121     * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to receive
122     * this broadcast.
123     */
124    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
125    public static final String ACTION_PASSWORD_CHANGED
126            = "android.app.action.ACTION_PASSWORD_CHANGED";
127
128    /**
129     * Action sent to a device administrator when the user has failed at
130     * attempted to enter the password.  You can at this point check the
131     * number of failed password attempts there have been with
132     * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts
133     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}.  You will generally
134     * handle this in {@link DeviceAdminReceiver#onPasswordFailed}.
135     *
136     * <p>The calling device admin must have requested
137     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
138     * this broadcast.
139     */
140    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
141    public static final String ACTION_PASSWORD_FAILED
142            = "android.app.action.ACTION_PASSWORD_FAILED";
143
144    /**
145     * Action sent to a device administrator when the user has successfully
146     * entered their password, after failing one or more times.
147     *
148     * <p>The calling device admin must have requested
149     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
150     * this broadcast.
151     */
152    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
153    public static final String ACTION_PASSWORD_SUCCEEDED
154            = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
155
156    /**
157     * Action periodically sent to a device administrator when the device password
158     * is expiring.
159     *
160     * <p>The calling device admin must have requested
161     * {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to receive
162     * this broadcast.
163     */
164    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
165    public static final String ACTION_PASSWORD_EXPIRING
166            = "android.app.action.ACTION_PASSWORD_EXPIRING";
167
168    /**
169     * Action sent to a device administrator to notify that the device is entering
170     * lock task mode from an authorized package.  The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
171     * will describe the authorized package using lock task mode.
172     *
173     * <p>The calling device admin must be the device owner or profile
174     * owner to receive this broadcast.
175     *
176     * @see DevicePolicyManager#isLockTaskPermitted(String)
177     */
178    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
179    public static final String ACTION_LOCK_TASK_ENTERING
180            = "android.app.action.LOCK_TASK_ENTERING";
181
182    /**
183     * Action sent to a device administrator to notify that the device is exiting
184     * lock task mode from an authorized package.
185     *
186     * <p>The calling device admin must be the device owner or profile
187     * owner to receive this broadcast.
188     *
189     * @see DevicePolicyManager#isLockTaskPermitted(String)
190     */
191    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
192    public static final String ACTION_LOCK_TASK_EXITING
193            = "android.app.action.LOCK_TASK_EXITING";
194
195    /**
196     * A string containing the name of the package entering lock task mode.
197     *
198     * @see #ACTION_LOCK_TASK_ENTERING
199     */
200    public static final String EXTRA_LOCK_TASK_PACKAGE =
201            "android.app.extra.LOCK_TASK_PACKAGE";
202
203    /**
204     * Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
205     * or managed device has completed successfully.
206     *
207     * <p>The broadcast is limited to the profile that will be managed by the application that
208     * requested provisioning. In the device owner case the profile is the primary user.
209     * The broadcast will also be limited to the {@link DeviceAdminReceiver} component
210     * specified in the original intent or NFC bump that started the provisioning process
211     * (@see DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE).
212     *
213     * <p>A device admin application which listens to this intent can find out if the device was
214     * provisioned for the device owner or profile owner case by calling respectively
215     * {@link android.app.admin.DevicePolicyManager#isDeviceOwnerApp} and
216     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}.
217     *
218     * <p>Input: Nothing.</p>
219     * <p>Output: Nothing</p>
220     */
221    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
222    public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
223            "android.app.action.PROFILE_PROVISIONING_COMPLETE";
224
225    /**
226     * Name under which a DevicePolicy component publishes information
227     * about itself.  This meta-data must reference an XML resource containing
228     * a device-admin tag.  XXX TO DO: describe syntax.
229     */
230    public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
231
232    private DevicePolicyManager mManager;
233    private ComponentName mWho;
234
235    /**
236     * Retrieve the DevicePolicyManager interface for this administrator to work
237     * with the system.
238     */
239    public DevicePolicyManager getManager(Context context) {
240        if (mManager != null) {
241            return mManager;
242        }
243        mManager = (DevicePolicyManager)context.getSystemService(
244                Context.DEVICE_POLICY_SERVICE);
245        return mManager;
246    }
247
248    /**
249     * Retrieve the ComponentName describing who this device administrator is, for
250     * use in {@link DevicePolicyManager} APIs that require the administrator to
251     * identify itself.
252     */
253    public ComponentName getWho(Context context) {
254        if (mWho != null) {
255            return mWho;
256        }
257        mWho = new ComponentName(context, getClass());
258        return mWho;
259    }
260
261    /**
262     * Called after the administrator is first enabled, as a result of
263     * receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}.  At this point you
264     * can use {@link DevicePolicyManager} to set your desired policies.
265     *
266     * <p> If the admin is activated by a device owner, then the intent
267     * may contain private extras that are relevant to user setup.
268     * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
269     *      ComponentName, Intent)}
270     *
271     * @param context The running context as per {@link #onReceive}.
272     * @param intent The received intent as per {@link #onReceive}.
273     */
274    public void onEnabled(Context context, Intent intent) {
275    }
276
277    /**
278     * Called when the user has asked to disable the administrator, as a result of
279     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED}, giving you
280     * a chance to present a warning message to them.  The message is returned
281     * as the result; if null is returned (the default implementation), no
282     * message will be displayed.
283     * @param context The running context as per {@link #onReceive}.
284     * @param intent The received intent as per {@link #onReceive}.
285     * @return Return the warning message to display to the user before
286     * being disabled; if null is returned, no message is displayed.
287     */
288    public CharSequence onDisableRequested(Context context, Intent intent) {
289        return null;
290    }
291
292    /**
293     * Called prior to the administrator being disabled, as a result of
294     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLED}.  Upon return, you
295     * can no longer use the protected parts of the {@link DevicePolicyManager}
296     * API.
297     * @param context The running context as per {@link #onReceive}.
298     * @param intent The received intent as per {@link #onReceive}.
299     */
300    public void onDisabled(Context context, Intent intent) {
301    }
302
303    /**
304     * Called after the user has changed their password, as a result of
305     * receiving {@link #ACTION_PASSWORD_CHANGED}.  At this point you
306     * can use {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
307     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}
308     * to retrieve the active password characteristics.
309     * @param context The running context as per {@link #onReceive}.
310     * @param intent The received intent as per {@link #onReceive}.
311     */
312    public void onPasswordChanged(Context context, Intent intent) {
313    }
314
315    /**
316     * Called after the user has failed at entering their current password, as a result of
317     * receiving {@link #ACTION_PASSWORD_FAILED}.  At this point you
318     * can use {@link DevicePolicyManager} to retrieve the number of failed
319     * password attempts.
320     * @param context The running context as per {@link #onReceive}.
321     * @param intent The received intent as per {@link #onReceive}.
322     */
323    public void onPasswordFailed(Context context, Intent intent) {
324    }
325
326    /**
327     * Called after the user has succeeded at entering their current password,
328     * as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}.  This will
329     * only be received the first time they succeed after having previously
330     * failed.
331     * @param context The running context as per {@link #onReceive}.
332     * @param intent The received intent as per {@link #onReceive}.
333     */
334    public void onPasswordSucceeded(Context context, Intent intent) {
335    }
336
337    /**
338     * Called periodically when the password is about to expire or has expired.  It will typically
339     * be called at these times: on device boot, once per day before the password expires,
340     * and at the time when the password expires.
341     *
342     * <p>If the password is not updated by the user, this method will continue to be called
343     * once per day until the password is changed or the device admin disables password expiration.
344     *
345     * <p>The admin will typically post a notification requesting the user to change their password
346     * in response to this call. The actual password expiration time can be obtained by calling
347     * {@link DevicePolicyManager#getPasswordExpiration(ComponentName) }
348     *
349     * <p>The admin should be sure to take down any notifications it posted in response to this call
350     * when it receives {@link DeviceAdminReceiver#onPasswordChanged(Context, Intent) }.
351     *
352     * @param context The running context as per {@link #onReceive}.
353     * @param intent The received intent as per {@link #onReceive}.
354     */
355    public void onPasswordExpiring(Context context, Intent intent) {
356    }
357
358    /**
359     * Called when provisioning of a managed profile or managed device has completed successfully.
360     *
361     * <p> As a prerequisit for the execution of this callback the (@link DeviceAdminReceiver} has
362     * to declare an intent filter for {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
363     * Its component must also be specified in the {@link DevicePolicyManager#EXTRA_DEVICE_ADMIN}
364     * of the {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} intent that started the
365     * managed provisioning.
366     *
367     * <p>When provisioning is complete, the managed profile is hidden until the profile owner
368     * calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}. Typically a profile
369     * owner will enable the profile when it has finished any additional setup such as adding an
370     * account by using the {@link AccountManager} and calling apis to bring the profile into the
371     * desired state.
372     *
373     * <p> Note that provisioning completes without waiting for any server interactions, so the
374     * profile owner needs to wait for data to be available if required (e.g android device ids or
375     * other data that is set as a result of server interactions).
376     *
377     * @param context The running context as per {@link #onReceive}.
378     * @param intent The received intent as per {@link #onReceive}.
379     */
380    public void onProfileProvisioningComplete(Context context, Intent intent) {
381    }
382
383    /**
384     * Called when a device is entering lock task mode by a package authorized
385     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
386     *
387     * @param context The running context as per {@link #onReceive}.
388     * @param intent The received intent as per {@link #onReceive}.
389     * @param pkg If entering, the authorized package using lock task mode, otherwise null.
390     */
391    public void onLockTaskModeEntering(Context context, Intent intent, String pkg) {
392    }
393
394    /**
395     * Called when a device is exiting lock task mode by a package authorized
396     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
397     *
398     * @param context The running context as per {@link #onReceive}.
399     * @param intent The received intent as per {@link #onReceive}.
400     */
401    public void onLockTaskModeExiting(Context context, Intent intent) {
402    }
403
404    /**
405     * Intercept standard device administrator broadcasts.  Implementations
406     * should not override this method; it is better to implement the
407     * convenience callbacks for each action.
408     */
409    @Override
410    public void onReceive(Context context, Intent intent) {
411        String action = intent.getAction();
412
413        if (ACTION_PASSWORD_CHANGED.equals(action)) {
414            onPasswordChanged(context, intent);
415        } else if (ACTION_PASSWORD_FAILED.equals(action)) {
416            onPasswordFailed(context, intent);
417        } else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
418            onPasswordSucceeded(context, intent);
419        } else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
420            onEnabled(context, intent);
421        } else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
422            CharSequence res = onDisableRequested(context, intent);
423            if (res != null) {
424                Bundle extras = getResultExtras(true);
425                extras.putCharSequence(EXTRA_DISABLE_WARNING, res);
426            }
427        } else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
428            onDisabled(context, intent);
429        } else if (ACTION_PASSWORD_EXPIRING.equals(action)) {
430            onPasswordExpiring(context, intent);
431        } else if (ACTION_PROFILE_PROVISIONING_COMPLETE.equals(action)) {
432            onProfileProvisioningComplete(context, intent);
433        } else if (ACTION_LOCK_TASK_ENTERING.equals(action)) {
434            String pkg = intent.getStringExtra(EXTRA_LOCK_TASK_PACKAGE);
435            onLockTaskModeEntering(context, intent, pkg);
436        } else if (ACTION_LOCK_TASK_EXITING.equals(action)) {
437            onLockTaskModeExiting(context, intent);
438        }
439    }
440}
441