Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Can I disable the Uninstall button of an app in settings android

I am implementing a Parent's And Child's App where

  1. parents can track their child
  2. the child can not uninstall the app.

I am using the Device Administration Feature to implement this.

When Enabled the Administrator, I want to disable the uninstall button in the child's app

image

Here is my code..

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.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.ACTION_SET_NEW_PASSWORD,"abcdefgh");
                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 == this.RESULT_OK && requestCode == PolicyManager.DPM_ACTIVATION_REQUEST_CODE) {
        // handle code for successfull enable of admin
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}
}

MyReceiver.java

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);
}



}

PolicyManager.java

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);
}
}
like image 882
Arpit116 Avatar asked Nov 17 '22 12:11

Arpit116


1 Answers

I also wanted to implement the same feature on my application.

I've successfully managed to enable the permission.

The catch is that you have to ask this permission from the user firing a specific intent called "DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN".

I have implemented the same feature in a demo application.

Adding the functionality step by step to make it code applicable.

My Application is developed in Kotlin, if you want to convert this code into java, than you can use the following links
1 Convert from Android Studio
2 Online Converter

STEP 1

  • Create a XML file in your res/xml folder
  • File name - my_admin.xml(You can modify the name as per your requirements)

my_admin.xml

<device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
    <uses-policies>
        <limit-password />
        <watch-login />
        <reset-password />
        <force-lock />
        <wipe-data />
    </uses-policies>
</device-admin>
  • Make sure you only add those permissions which are needed, adding unnecessary permissions will lead the user to not activate the admin rights.

Step 2

  • You will have to create a class which extends to DeviceAdminReceiver

  • In my case I've named the file as DeviceAdminDemo

DeviceAdminDemo.kt

 class DeviceAdminDemo : DeviceAdminReceiver() {

 override fun onReceive(context: Context, intent: Intent) {
    super.onReceive(context, intent)
 }

 override fun onEnabled(context: Context, intent: Intent) {
    super.onEnabled(context, intent)
 }

 override fun onDisabled(context: Context, intent: Intent) {
    super.onDisabled(context, intent)
 }
}
  • This class will receive user's feedback

Step 3

  • Edit your Manifest file likewise

AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
   <manifest 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.DeviceAdminDemo"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>

        <receiver
            android:name=".DeviceAdminDemo"
            android:description="@string/device_description"
            android:exported="true"
            android:label="@string/device_admin_label"
            android:permission="android.permission.BIND_DEVICE_ADMIN" >
            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/my_admin" />

            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

Step 4

  • Now this is my MainActivity's code, where I have fired the Intent

MainActivity.kt

class MainActivity : AppCompatActivity() {

lateinit var mDPM: DevicePolicyManager
lateinit var mAdminName: ComponentName

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val resultLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == Activity.RESULT_OK) {
                val data: Intent? = result.data
            }
        }

    try {
        mDPM = getSystemService(DEVICE_POLICY_SERVICE) as DevicePolicyManager
        mAdminName = ComponentName(this, DeviceAdminDemo::class.java)
        if (!mDPM.isAdminActive(mAdminName)) {

            val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
            intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName)
            intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application.")
            resultLauncher.launch(intent)

        } else {
            mDPM.lockNow()
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}
}
  • The minimum targeted API level is 21 & the maximum targeted API level is 32.

General Information

This application will redirect the user to a permission grantor screen, if the user grants the permission for admin rights then the user won't be able to force stop or uninstall the application, unless it decides to rollback the permission. The user would not be able to uninstall application from the app drawer.

Ones when the user has granted the permission than it can only uninstall the application either by going to the Application's Info Screen and finish the process as shown in the screenshots or has to go to the Settings>>Application Management>>App Info and finish the process as shown in the screenshots.

  • Also attaching screenshots for better understanding of the application

  • Permission Page

Permission Page

  • This is what it looks like after the user accepts the permission

Permission Granted

  • After clicking the uninstall button

Uninstall page

Note

The actual screens might differ from the screenshots due to different API levels and different OS Versions.

If you got the output you excepted please do drop an upvote to make me encourage solving more and more problems

Also share your thoughts and suggestions on this by using the comments sections.

ADIOS

like image 91
Vishal Shah Avatar answered May 16 '23 06:05

Vishal Shah