Disable Android Application Uninstallation using Device Administration
Android platform offers system-level device management capabilities through the Device Administration APIs. If an application package component is registered as system administrator, it can provide device administration features at the system level. An active system admin package can not be uninstalled until removed as system administrator. We will make benefits of this property to disable android application uninstallation by registering and activating system admin component.
In AndroidManifest.xml
,
- We need to declare a receiver which will subclass DeviceAdminReceiver.
- Permission attribute should be declared with value
android.permission.BIND_DEVICE_ADMIN
- meta-data tag defining device admin policies usage.
intent-filter
for admin enable, admin disable and admin disable request.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<receiver android:name=".SampleDeviceAdminReceiver" android:permission="android.permission.BIND_DEVICE_ADMIN" > <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin" /> <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" /> </intent-filter> </receiver> |
Create file /res/xml/device_admin.xml
, this file will define system label capabilities granted on activation. I have not defined any policies as out motto is to just register and activate a system admin to make our application not uninstallable. Just to brief I have mentioned type of policy management you can be granted.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="utf-8"?> <device-admin xmlns:android="http://schemas.android.com/apk/res/android" > <uses-policies> <!-- <limit-password /> <watch-login /> <reset-password /> <force-lock /> <wipe-data /> <expire-password /> <encrypted-storage /> <disable-camera /> --> </uses-policies> </device-admin> |
Create receiver class SampleDeviceAdminReceiver.java and it will extend DeviceAdminReceiver. We will override few functions to get admin enable and disable status.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com.androidsrc.sampledeviceadmin; import android.app.admin.DeviceAdminReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class SampleDeviceAdminReceiver extends DeviceAdminReceiver { @Override public void onDisabled(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "disabled dpm", Toast.LENGTH_SHORT).show(); super.onDisabled(context, intent); } @Override public void onEnabled(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "enabled dpm", Toast.LENGTH_SHORT).show(); super.onEnabled(context, intent); } @Override public CharSequence onDisableRequested(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "disable dpm request", Toast.LENGTH_SHORT).show(); return super.onDisableRequested(context, intent); } } |
Create a class PolicyManager.java, we will define api to check admin active status and removing admin component.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package com.androidsrc.sampledeviceadmin; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; public class PolicyManager { public static final int DPM_ACTIVATION_REQUEST_CODE = 100; private Context mContext; private DevicePolicyManager mDPM; private ComponentName adminComponent; public PolicyManager(Context context) { // TODO Auto-generated constructor stub this.mContext = context; mDPM = (DevicePolicyManager) mContext .getSystemService(Context.DEVICE_POLICY_SERVICE); adminComponent = new ComponentName(mContext.getPackageName(), mContext.getPackageName() + ".SampleDeviceAdminReceiver"); } public boolean isAdminActive() { return mDPM.isAdminActive(adminComponent); } public ComponentName getAdminComponent() { return adminComponent; } public void disableAdmin() { mDPM.removeActiveAdmin(adminComponent); } } |
In our main layout /res/layout/activity_main.xml
, we will add two buttons to activate and deactivate admin.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<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" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.androidsrc.sampledeviceadmin.MainActivity" > <Button android:id="@+id/activate_admin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:onClick="onClick" android:text="Activate Admin" android:textSize="22dp" android:textStyle="bold" /> <Button android:id="@+id/deactivate_admin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/activate_admin" android:layout_centerHorizontal="true" android:layout_marginTop="11dp" android:onClick="onClick" android:text="Deactivate Admin" android:textSize="22dp" android:textStyle="bold" /> </RelativeLayout> |
In application’s launcher activity MainActivity.java in sample app, we will implement View.OnCLickListener
to handle onclick events of buttons. For activation of admin, we need to start activity with intent action as DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN
. And to specify admin component we will add extars with Key as DevicePolicyManager.EXTRA_DEVICE_ADMIN
. You can attach admin activation explanation as well so that user know your intention to do it.
Once you enable admin component from your package, your application can not be uninstalled until it is deactivated. It can be verified by uninstalling it or in application info. No other application can remove your active component from there source, it can be removed only if call is from package which is owner of this admin component.
Once you disable this admin, your application can be uninstalled.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
package com.androidsrc.sampledeviceadmin; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; public class MainActivity extends Activity implements OnClickListener { private PolicyManager policyManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); policyManager = new PolicyManager(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.activate_admin: if (!policyManager.isAdminActive()) { Intent activateDeviceAdmin = new Intent( DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); activateDeviceAdmin.putExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN, policyManager.getAdminComponent()); activateDeviceAdmin .putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "After activating admin, you will be able to block application uninstallation."); startActivityForResult(activateDeviceAdmin, PolicyManager.DPM_ACTIVATION_REQUEST_CODE); } break; case R.id.deactivate_admin: if (policyManager.isAdminActive()) policyManager.disableAdmin(); break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // TODO Auto-generated method stub if (resultCode == Activity.RESULT_OK && requestCode == PolicyManager.DPM_ACTIVATION_REQUEST_CODE) { // handle code for successfull enable of admin } else { super.onActivityResult(requestCode, resultCode, data); } } } |
Many applications featuring enterprise management or application lock apps use this feature. Option is provided to user to enable this feature. Though a sophisticated android user can always activate/deactivate your active system admin from Settings->Security->Device Administrators
.