Android DevicePolicyManager Example - Truiton
Skip to content

Android DevicePolicyManager Example

Android DevicePolicyManager

Its always good to learn new things in the area of your interest. Recently while mucking around Android I came across the Android DevicePolicyManager class. After making a few searches here and there I found out its a very powerful concept of android and could make a device really secure. One should never underestimate Android, its full of numerous useful features. This Android DevicePolicyManager class could be a very useful concept for enterprise level applications.

I always used to toy with the idea of enterprise level apps for android, but the thing which always stopped me was enterprise level security. But with these device administration APIs its very simple for an app to implement some device level security policies which can be a savior incase of security breach, and in worst case a device wipe. Now since this Android DevicePolicyManager is a class which works in conjunction with two more classes DeviceAdminReceiver, and ComponentName, this is going to be a long tutorial hence I’ll be splitting it into two parts:

  1. Android DevicePolicyManager Example
  2. Android Device Administrator Example

Here in the first part Android DevicePolicyManager Example I would explain how to implement the DevicePolicyManager and in the second part I would make a separate app where we could detect these policies. The way I picture it: enterprise level apps would come in a bunch, one app would implement all the device management policies and all other apps would only run if those polices are accepted by user.

Now since this is a sort of security implementation, hence most of the code in this app would be at back-end, resulting a simple UI, where a check box would be used to activate the Android DevicePolicyManager. Please have a look at the screen shot and its layout file:

Android DevicePolicyManager
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DevicePolicyAdmin" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:scaleType="centerCrop"
        android:src="@drawable/logo" />

    <View
        android:id="@+id/line"
        android:layout_width="fill_parent"
        android:layout_height="1dp"
        android:layout_below="@+id/imageView1"
        android:background="#000000" />

    <CheckBox
        android:id="@+id/checkBox1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/line"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="15dp"
        android:text="Truiton Device Admin Enabled"
        android:textStyle="bold" />

</RelativeLayout>

1. Device Management Policies

To start off, the first thing that should be discussed is the device management polices. In this Android DevicePolicyManager Example I am going to implement these six policies:

<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-policies>
    <limit-password />
    <watch-login />
    <force-lock />
    <wipe-data />
    <expire-password />
    <disable-camera />
  </uses-policies>
</device-admin>

The above stated file is an xml file stating your app’s device administration policies. This file should be saved in your res/xml folder by the name of your choice, I named it device_policies.xml. Now since the names for device admin policies are self
explanatory I would give a detailed explanation to these policies in a later step. For now lets move on to next step i.e. defining Manifest, and declaring Android DeviceAdminReceiver.

2. Android DeviceAdminReceiver

Before declaring Android DeviceAdminReceiver we need to define it in our manifest file, please have a look:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.truiton.devicepolicymanager"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.truiton.devicepolicymanager.DevicePolicyAdmin"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name="com.truiton.devicepolicymanager.DevicePolicyAdmin$MyDevicePolicyReceiver"
            android:description="@string/device_admin_description"
            android:label="@string/device_admin"
            android:permission="android.permission.BIND_DEVICE_ADMIN" >
            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/device_policies" />

            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
                <action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
                <action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
                <action android:name="android.app.action.ACTION_PASSWORD_CHANGED" />
                <action android:name="android.app.action.ACTION_PASSWORD_EXPIRING" />
                <action android:name="android.app.action.ACTION_PASSWORD_FAILED" />
                <action android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

Here in this manifest file the main things to notice are:

  1. The android.permission.BIND_DEVICE_ADMIN permission, as through this permission your receiver can listen to system broadcasts.
  2. The meta-data block where your XML file stating your policies is referenced, in my case device_policies.xml.
  3. The intent-filter block as this is the block which defines the intents which would be listened by our device DeviceAdminReciever.

Also have a look at the strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Device Policy Manager</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="device_admin">Truiton Device Admin</string>
    <string name="device_admin_description">Truiton\'s device admin implementation which shows the usage of DevicePolicyManager class.  This implementation provides you a way to control a device\'s security.</string>
    <string name="admin_explanation">Truiton Device Admin helps the user to get special privileges, for eg. to access the Truiton network data. These privileges can only be acquired by accepting these policies.</string>
</resources>

Now that we are ready with the manifest and strings lets have a look at the Android DeviceAdminReceiver:

	public static class MyDevicePolicyReceiver extends DeviceAdminReceiver {

		@Override
		public void onDisabled(Context context, Intent intent) {
			Toast.makeText(context, "Truiton's Device Admin Disabled",
					Toast.LENGTH_SHORT).show();
		}

		@Override
		public void onEnabled(Context context, Intent intent) {
			Toast.makeText(context, "Truiton's Device Admin is now enabled",
					Toast.LENGTH_SHORT).show();
		}

		@Override
		public CharSequence onDisableRequested(Context context, Intent intent) {
			CharSequence disableRequestedSeq = "Requesting to disable Device Admin";
			return disableRequestedSeq;
		}

		@TargetApi(Build.VERSION_CODES.HONEYCOMB)
		@Override
		public void onPasswordChanged(Context context, Intent intent) {
			Toast.makeText(context, "Device password is now changed",
					Toast.LENGTH_SHORT).show();
			DevicePolicyManager localDPM = (DevicePolicyManager) context
					.getSystemService(Context.DEVICE_POLICY_SERVICE);
			ComponentName localComponent = new ComponentName(context,
					MyDevicePolicyReceiver.class);
			localDPM.setPasswordExpirationTimeout(localComponent, 0L);
		}

		@TargetApi(Build.VERSION_CODES.HONEYCOMB)
		@Override
		public void onPasswordExpiring(Context context, Intent intent) {
			// This would require API 11 an above
			Toast.makeText(
					context,
					"Truiton's Device password is going to expire, please change to a new password",
					Toast.LENGTH_LONG).show();

			DevicePolicyManager localDPM = (DevicePolicyManager) context
					.getSystemService(Context.DEVICE_POLICY_SERVICE);
			ComponentName localComponent = new ComponentName(context,
					MyDevicePolicyReceiver.class);
			long expr = localDPM.getPasswordExpiration(localComponent);
			long delta = expr - System.currentTimeMillis();
			boolean expired = delta < 0L;
			if (expired) {
				localDPM.setPasswordExpirationTimeout(localComponent, 10000L);
				Intent passwordChangeIntent = new Intent(
						DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
				passwordChangeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				context.startActivity(passwordChangeIntent);
			}
		}

		@Override
		public void onPasswordFailed(Context context, Intent intent) {
			Toast.makeText(context, "Password failed", Toast.LENGTH_SHORT)
					.show();
		}

		@Override
		public void onPasswordSucceeded(Context context, Intent intent) {
			Toast.makeText(context, "Access Granted", Toast.LENGTH_SHORT)
					.show();
		}

		@Override
		public void onReceive(Context context, Intent intent) {
			Log.i(LOG_TAG,
					"MyDevicePolicyReciever Received: " + intent.getAction());
			super.onReceive(context, intent);
		}
	}

Have a look at the DeviceAdminReceiver.onPasswordExpiring method, here I have implemented a logic by the help of Android DevicePolicyManager class to increase the expiring password by ten seconds and prompt the user to change it immediately. Now untill the password is set it would keep on prompting to set the password.  Once the password is set then the PasswordExpirationTimeout is set to zero, which implies that this password wont expire.

3. Android DevicePolicyManager

Android DevicePolicyManager is a unique class through which an app can implement some special policies on the device it is installed. These polices could be anything, like device should have a password. You can also set rules for that password like number of digits in it, number of special characters etc. Number of retries for failed password attempts. Another great device admin policy that you can implement is to wipe out user data in-case of failed password attempts. As I said Android DevicePolicyManager is a powerful class, therefore it also gives you the ability to disable device’s camera. To make all this happen, all you need to do; is make the user accept and activate these policies. lets have a look at the complete DevicePolicyAdmin class:

package com.truiton.devicepolicymanager;

import android.os.Build;
import android.os.Bundle;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Toast;

public class DevicePolicyAdmin extends Activity {
	private final static String LOG_TAG = "DevicePolicyAdmin";
	DevicePolicyManager truitonDevicePolicyManager;
	ComponentName truitonDevicePolicyAdmin;
	private CheckBox truitonAdminEnabledCheckbox;
	protected static final int REQUEST_ENABLE = 1;
	protected static final int SET_PASSWORD = 2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_device_policy_admin);
		truitonDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
		truitonDevicePolicyAdmin = new ComponentName(this,
				MyDevicePolicyReceiver.class);

		truitonAdminEnabledCheckbox = (CheckBox) findViewById(R.id.checkBox1);
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (isMyDevicePolicyReceiverActive()) {
			truitonAdminEnabledCheckbox.setChecked(true);
		} else {
			truitonAdminEnabledCheckbox.setChecked(false);
		}
		truitonAdminEnabledCheckbox
		.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

			@Override
			public void onCheckedChanged(CompoundButton buttonView,
					boolean isChecked) {
				if (isChecked) {
					Intent intent = new Intent(
							DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
					intent.putExtra(
							DevicePolicyManager.EXTRA_DEVICE_ADMIN,
							truitonDevicePolicyAdmin);
					intent.putExtra(
							DevicePolicyManager.EXTRA_ADD_EXPLANATION,
							getString(R.string.admin_explanation));
					startActivityForResult(intent, REQUEST_ENABLE);
				} else {
					truitonDevicePolicyManager
							.removeActiveAdmin(truitonDevicePolicyAdmin);
				}
			}
		});
	}

	@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK) {
			switch (requestCode) {
			case REQUEST_ENABLE:
				Log.v(LOG_TAG, "Enabling Policies Now");
				truitonDevicePolicyManager.setMaximumTimeToLock(
						truitonDevicePolicyAdmin, 30000L);
				truitonDevicePolicyManager.setMaximumFailedPasswordsForWipe(
						truitonDevicePolicyAdmin, 5);
				truitonDevicePolicyManager.setPasswordQuality(
						truitonDevicePolicyAdmin,
						DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
				truitonDevicePolicyManager.setCameraDisabled(
						truitonDevicePolicyAdmin, true);
				boolean isSufficient = truitonDevicePolicyManager
						.isActivePasswordSufficient();
				if (isSufficient) {
					truitonDevicePolicyManager.lockNow();
				} else {
					Intent setPasswordIntent = new Intent(
							DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
					startActivityForResult(setPasswordIntent, SET_PASSWORD);
					truitonDevicePolicyManager.setPasswordExpirationTimeout(
							truitonDevicePolicyAdmin, 10000L);
				}
				break;
			}
		}
	}

	private boolean isMyDevicePolicyReceiverActive() {
		return truitonDevicePolicyManager
				.isAdminActive(truitonDevicePolicyAdmin);
	}

	public static class MyDevicePolicyReceiver extends DeviceAdminReceiver {

		@Override
		public void onDisabled(Context context, Intent intent) {
			Toast.makeText(context, "Truiton's Device Admin Disabled",
					Toast.LENGTH_SHORT).show();
		}

		@Override
		public void onEnabled(Context context, Intent intent) {
			Toast.makeText(context, "Truiton's Device Admin is now enabled",
					Toast.LENGTH_SHORT).show();
		}

		@Override
		public CharSequence onDisableRequested(Context context, Intent intent) {
			CharSequence disableRequestedSeq = "Requesting to disable Device Admin";
			return disableRequestedSeq;
		}

		@TargetApi(Build.VERSION_CODES.HONEYCOMB)
		@Override
		public void onPasswordChanged(Context context, Intent intent) {
			Toast.makeText(context, "Device password is now changed",
					Toast.LENGTH_SHORT).show();
			DevicePolicyManager localDPM = (DevicePolicyManager) context
					.getSystemService(Context.DEVICE_POLICY_SERVICE);
			ComponentName localComponent = new ComponentName(context,
					MyDevicePolicyReceiver.class);
			localDPM.setPasswordExpirationTimeout(localComponent, 0L);
		}

		@TargetApi(Build.VERSION_CODES.HONEYCOMB)
		@Override
		public void onPasswordExpiring(Context context, Intent intent) {
			// This would require API 11 an above
			Toast.makeText(
					context,
					"Truiton's Device password is going to expire, please change to a new password",
					Toast.LENGTH_LONG).show();

			DevicePolicyManager localDPM = (DevicePolicyManager) context
					.getSystemService(Context.DEVICE_POLICY_SERVICE);
			ComponentName localComponent = new ComponentName(context,
					MyDevicePolicyReceiver.class);
			long expr = localDPM.getPasswordExpiration(localComponent);
			long delta = expr - System.currentTimeMillis();
			boolean expired = delta < 0L;
			if (expired) {
				localDPM.setPasswordExpirationTimeout(localComponent, 10000L);
				Intent passwordChangeIntent = new Intent(
						DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
				passwordChangeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				context.startActivity(passwordChangeIntent);
			}
		}

		@Override
		public void onPasswordFailed(Context context, Intent intent) {
			Toast.makeText(context, "Password failed", Toast.LENGTH_SHORT)
					.show();
		}

		@Override
		public void onPasswordSucceeded(Context context, Intent intent) {
			Toast.makeText(context, "Access Granted", Toast.LENGTH_SHORT)
					.show();
		}

		@Override
		public void onReceive(Context context, Intent intent) {
			Log.i(LOG_TAG,
					"MyDevicePolicyReciever Received: " + intent.getAction());
			super.onReceive(context, intent);
		}
	}
}

Here in this class I have implemented Android DevicePolicyManager by a check box, on tap of check-box user is prompted to accept the device policies:

After user accepts the policies it is verified that is the active password sufficient by DevicePolicyManager.isActivePasswordSufficient() method, if it is then screen is locked by DevicePolicyManager.lockNow() method. Else user is taken to screen where he could set the password according to the device policy manager. Another great feature of Android DevicePolicyManager is that we can also set the maximum time in which device screen should lock by DevicePolicyManager.setMaximumTimeToLock() method. And if the amount of failed attempts cross the limit the device can also be wiped out:

To uninstall any android device admin you need to first deactivate it, which would result in a callback to DeviceAdminReceiver.onDisabled() method where you can write the code to do something like erase some secure data or a complete wipe-out. With this I would like to conclude this tutorial by saying that there may be a case where your device would be having more than one active device policy managers, in that case the more strict DevicePolicyManager would be enforced. If you would like to know which Android DevicePolicyManager is active please read my next tutorial on active device administrators. If you like this tutorial please share it with your friends on Google+, Facebook and also like our Facebook page, to get our updates.

5 thoughts on “Android DevicePolicyManager Example”

  1. Hello Mohit,

    It was really a great article about device admin policy and to developers who are really interested in developing apps for enterprises. I am working on enterprise application and one of the feature I am looking for my application is to prevent users (Employees of organization) to uninstall the app from the settings. I know this is possible via Android Device API, but I am not having any idea about it and I am searching all over the internet and learning it. While searching I got very good articles of yours and I thought if you can share some idea/tips for the same with me then I would be very much thankful to you.

    Thanks,
    Keyur

  2. Hello Mohit,

    It was really a great article about device admin policy, I want open camera on shake when device is locked.. Can u help me in this.
    It will be really great if i get something like this.

    Thanks,
    Aakash

Leave a Reply

Your email address will not be published. Required fields are marked *