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     * @see DevicePolicyManager#isLockTaskPermitted(String)
174     *
175     * <p>The calling device admin must be the device owner or profile
176     * owner to receive this broadcast.
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     * @see DevicePolicyManager#isLockTaskPermitted(String)
187     *
188     * <p>The calling device admin must be the device owner or profile
189     * owner to receive this broadcast.
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 boolean describing whether the device is currently entering or exiting
197     * lock task mode.
198     *
199     * @see #ACTION_LOCK_TASK_CHANGED
200     */
201    public static final String EXTRA_LOCK_TASK_PACKAGE =
202            "android.app.extra.LOCK_TASK_PACKAGE";
203
204    /**
205     * Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
206     * or managed device has completed successfully.
207     *
208     * <p>The broadcast is limited to the profile that will be managed by the application that
209     * requested provisioning. In the device owner case the profile is the primary user.
210     * The broadcast will also be limited to the {@link DeviceAdminReceiver} component
211     * specified in the original intent or NFC bump that started the provisioning process
212     * (@see DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE).
213     *
214     * <p>A device admin application which listens to this intent can find out if the device was
215     * provisioned for the device owner or profile owner case by calling respectively
216     * {@link android.app.admin.DevicePolicyManager#isDeviceOwnerApp} and
217     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}.
218     *
219     * <p>Input: Nothing.</p>
220     * <p>Output: Nothing</p>
221     */
222    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
223    public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
224            "android.app.action.PROFILE_PROVISIONING_COMPLETE";
225
226    /**
227     * Name under which a DevicePolicy component publishes information
228     * about itself.  This meta-data must reference an XML resource containing
229     * a device-admin tag.  XXX TO DO: describe syntax.
230     */
231    public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
232
233    private DevicePolicyManager mManager;
234    private ComponentName mWho;
235
236    /**
237     * Retrieve the DevicePolicyManager interface for this administrator to work
238     * with the system.
239     */
240    public DevicePolicyManager getManager(Context context) {
241        if (mManager != null) {
242            return mManager;
243        }
244        mManager = (DevicePolicyManager)context.getSystemService(
245                Context.DEVICE_POLICY_SERVICE);
246        return mManager;
247    }
248
249    /**
250     * Retrieve the ComponentName describing who this device administrator is, for
251     * use in {@link DevicePolicyManager} APIs that require the administrator to
252     * identify itself.
253     */
254    public ComponentName getWho(Context context) {
255        if (mWho != null) {
256            return mWho;
257        }
258        mWho = new ComponentName(context, getClass());
259        return mWho;
260    }
261
262    /**
263     * Called after the administrator is first enabled, as a result of
264     * receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}.  At this point you
265     * can use {@link DevicePolicyManager} to set your desired policies.
266     *
267     * <p> If the admin is activated by a device owner, then the intent
268     * may contain private extras that are relevant to user setup.
269     * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
270     *      ComponentName, Intent)}
271     *
272     * @param context The running context as per {@link #onReceive}.
273     * @param intent The received intent as per {@link #onReceive}.
274     */
275    public void onEnabled(Context context, Intent intent) {
276    }
277
278    /**
279     * Called when the user has asked to disable the administrator, as a result of
280     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED}, giving you
281     * a chance to present a warning message to them.  The message is returned
282     * as the result; if null is returned (the default implementation), no
283     * message will be displayed.
284     * @param context The running context as per {@link #onReceive}.
285     * @param intent The received intent as per {@link #onReceive}.
286     * @return Return the warning message to display to the user before
287     * being disabled; if null is returned, no message is displayed.
288     */
289    public CharSequence onDisableRequested(Context context, Intent intent) {
290        return null;
291    }
292
293    /**
294     * Called prior to the administrator being disabled, as a result of
295     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLED}.  Upon return, you
296     * can no longer use the protected parts of the {@link DevicePolicyManager}
297     * API.
298     * @param context The running context as per {@link #onReceive}.
299     * @param intent The received intent as per {@link #onReceive}.
300     */
301    public void onDisabled(Context context, Intent intent) {
302    }
303
304    /**
305     * Called after the user has changed their password, as a result of
306     * receiving {@link #ACTION_PASSWORD_CHANGED}.  At this point you
307     * can use {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
308     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}
309     * to retrieve the active password characteristics.
310     * @param context The running context as per {@link #onReceive}.
311     * @param intent The received intent as per {@link #onReceive}.
312     */
313    public void onPasswordChanged(Context context, Intent intent) {
314    }
315
316    /**
317     * Called after the user has failed at entering their current password, as a result of
318     * receiving {@link #ACTION_PASSWORD_FAILED}.  At this point you
319     * can use {@link DevicePolicyManager} to retrieve the number of failed
320     * password attempts.
321     * @param context The running context as per {@link #onReceive}.
322     * @param intent The received intent as per {@link #onReceive}.
323     */
324    public void onPasswordFailed(Context context, Intent intent) {
325    }
326
327    /**
328     * Called after the user has succeeded at entering their current password,
329     * as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}.  This will
330     * only be received the first time they succeed after having previously
331     * failed.
332     * @param context The running context as per {@link #onReceive}.
333     * @param intent The received intent as per {@link #onReceive}.
334     */
335    public void onPasswordSucceeded(Context context, Intent intent) {
336    }
337
338    /**
339     * Called periodically when the password is about to expire or has expired.  It will typically
340     * be called at these times: on device boot, once per day before the password expires,
341     * and at the time when the password expires.
342     *
343     * <p>If the password is not updated by the user, this method will continue to be called
344     * once per day until the password is changed or the device admin disables password expiration.
345     *
346     * <p>The admin will typically post a notification requesting the user to change their password
347     * in response to this call. The actual password expiration time can be obtained by calling
348     * {@link DevicePolicyManager#getPasswordExpiration(ComponentName) }
349     *
350     * <p>The admin should be sure to take down any notifications it posted in response to this call
351     * when it receives {@link DeviceAdminReceiver#onPasswordChanged(Context, Intent) }.
352     *
353     * @param context The running context as per {@link #onReceive}.
354     * @param intent The received intent as per {@link #onReceive}.
355     */
356    public void onPasswordExpiring(Context context, Intent intent) {
357    }
358
359    /**
360     * Called when provisioning of a managed profile or managed device has completed successfully.
361     *
362     * <p> As a prerequisit for the execution of this callback the (@link DeviceAdminReceiver} has
363     * to declare an intent filter for {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
364     * Its component must also be specified in the {@link DevicePolicyManager#EXTRA_DEVICE_ADMIN}
365     * of the {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} intent that started the
366     * managed provisioning.
367     *
368     * <p>When provisioning is complete, the managed profile is hidden until the profile owner
369     * calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}. Typically a profile
370     * owner will enable the profile when it has finished any additional setup such as adding an
371     * account by using the {@link AccountManager} and calling apis to bring the profile into the
372     * desired state.
373     *
374     * <p> Note that provisioning completes without waiting for any server interactions, so the
375     * profile owner needs to wait for data to be available if required (e.g android device ids or
376     * other data that is set as a result of server interactions).
377     *
378     * @param context The running context as per {@link #onReceive}.
379     * @param intent The received intent as per {@link #onReceive}.
380     */
381    public void onProfileProvisioningComplete(Context context, Intent intent) {
382    }
383
384    /**
385     * Called when a device is entering lock task mode by a package authorized
386     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
387     *
388     * @param context The running context as per {@link #onReceive}.
389     * @param intent The received intent as per {@link #onReceive}.
390     * @param pkg If entering, the authorized package using lock task mode, otherwise null.
391     */
392    public void onLockTaskModeEntering(Context context, Intent intent, String pkg) {
393    }
394
395    /**
396     * Called when a device is exiting lock task mode by a package authorized
397     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
398     *
399     * @param context The running context as per {@link #onReceive}.
400     * @param intent The received intent as per {@link #onReceive}.
401     */
402    public void onLockTaskModeExiting(Context context, Intent intent) {
403    }
404
405    /**
406     * Intercept standard device administrator broadcasts.  Implementations
407     * should not override this method; it is better to implement the
408     * convenience callbacks for each action.
409     */
410    @Override
411    public void onReceive(Context context, Intent intent) {
412        String action = intent.getAction();
413
414        if (ACTION_PASSWORD_CHANGED.equals(action)) {
415            onPasswordChanged(context, intent);
416        } else if (ACTION_PASSWORD_FAILED.equals(action)) {
417            onPasswordFailed(context, intent);
418        } else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
419            onPasswordSucceeded(context, intent);
420        } else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
421            onEnabled(context, intent);
422        } else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
423            CharSequence res = onDisableRequested(context, intent);
424            if (res != null) {
425                Bundle extras = getResultExtras(true);
426                extras.putCharSequence(EXTRA_DISABLE_WARNING, res);
427            }
428        } else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
429            onDisabled(context, intent);
430        } else if (ACTION_PASSWORD_EXPIRING.equals(action)) {
431            onPasswordExpiring(context, intent);
432        } else if (ACTION_PROFILE_PROVISIONING_COMPLETE.equals(action)) {
433            onProfileProvisioningComplete(context, intent);
434        } else if (ACTION_LOCK_TASK_ENTERING.equals(action)) {
435            String pkg = intent.getStringExtra(EXTRA_LOCK_TASK_PACKAGE);
436            onLockTaskModeEntering(context, intent, pkg);
437        } else if (ACTION_LOCK_TASK_EXITING.equals(action)) {
438            onLockTaskModeExiting(context, intent);
439        }
440    }
441}
442