Android Studio, Kiosk mode, Single-Purpose Devices, Lock Task mode

XcodeNOOB picture XcodeNOOB · Dec 4, 2016 · Viewed 13.4k times · Source

I'm trying to create a single purpose app. So I have create an BaseActivity that all my activities inherit from it.

it's look like

public class LockDeviceActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }

    private void startLock() {


        if(mDevicePolicyManager.isLockTaskPermitted(getPackageName())) {
            /**
             * If lock task is permitted, we can lock the task. We can use an external DPM like
             * TestDPC provided by Google to manage lock task list.
             *
             * If the lock is obtained using TestDPC, features like status bar, home button, recent
             * apps, etc is disabled.
             *
             * To unlock we can programatically call stopLockTask() when users taps a button. But
             * in practice this should be done using a separate admin console or Confirm Credential.
             *
             * For API 23+ you can check if the lock is active by checking if
             * activityManager.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_NONE
             */
            Log.d(TAG, "startLock() called");
            this.startLockTask();
        } else {
            /**
             * The device is not whitelisted.
             */
            Toast.makeText(this, "The app is not whitelisted for lock", Toast.LENGTH_SHORT).show();
        //    Timber.d("The app is not whitelisted for lock task");


            /**
             * We can still pin the app but it will not be locked.
             *
             * We can simply unlock by pressing recent and back button together.
             *
             * Unlocking by calling stopLockTask() on button click can be achieved as well.
             */
         //   Timber.d("just pinning the app");
            this.startLockTask();
        }

    }

so when I first Enter the app, I can see some Pinned message and it's okay by me. The problem is, when I'm doing an Intent from one activity to other Activity which contain Fragment, I'm getting the following image :

Annyoing Message

plus i'm getting a some system toast message : " the app is not whitelisted for lock "

how can I avoid this kind of behavior ? thank you all .

Answer

hadifikri picture hadifikri · Apr 23, 2017

1) Reset device to factory default 2) Skip Account registration 3) Install the app then close it 4) Run adb shell dpm set-device-owner <app-package-name>/.<AppAdminReceiver> 5) Make sure you get a successful result. 6) Re-launch the app.

The following must be satisfied:

AndroidManifest.xml inside application tag

<activity
            android:name=".AppActivity"
            android:label="Locked Activity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.HOME"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
</activity>


<receiver
            android:name=".AppAdminReceiver"
            android:description="@string/app_name"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/device_admin_receiver" />
            <intent-filter>
                <action android:name="android.intent.action.DEVICE_ADMIN_ENABLED"/>
                <action android:name="android.intent.action.PROFILE_PROVISIONING_COMPLETE"/>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
</receiver>

Create a new Java Class named AppAdminReceiver.java (it's fine to leave it blank)

public class AppAdminReceiver extends android.app.admin.DeviceAdminReceiver {
    
}

Add device_admin_receiver.xml in /res/xml directory

<?xml version="1.0" encoding="utf-8"?>
<device-admin>
    <uses-policies>
        <disable-keyguard-features/>
    </uses-policies>
</device-admin>

In AppActivity.java calling startLockTask() and stopLockTask()

private ComponentName mAdminComponentName;
private DevicePolicyManager mDevicePolicyManager;
...

... onCreate(){

// Retrieve Device Policy Manager so that we can check whether we can
// lock to screen later
  mAdminComponentName = new ComponentName(this,AppAdminReceiver.class);
  mDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
  if(mDevicePolicyManager.isDeviceOwnerApp(getPackageName())){
            // App is whitelisted
            setDefaultCosuPolicies(true);
  }
  else {
           // did you provision the app using <adb shell dpm set-device-owner ...> ?
  }
}

... onStart(){
// Consider locking your app here or by some other mechanism
// Active Manager is supported on Android M
  if(mDevicePolicyManager.isLockTaskPermitted(this.getPackageName())){
            ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            if (am.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_NONE) {
                setDefaultCosuPolicies(true);
                startLockTask();
            }
    }
}


... unlockApp(){
  ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

  if (am.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED) {
    stopLockTask();
  }
  setDefaultCosuPolicies(false);

}

private void setDefaultCosuPolicies(boolean active){

        // Set user restrictions
        setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, active);
        setUserRestriction(UserManager.DISALLOW_FACTORY_RESET, active);
        setUserRestriction(UserManager.DISALLOW_ADD_USER, active);
        setUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, active);
        setUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME, active);

        // Disable keyguard and status bar
        mDevicePolicyManager.setKeyguardDisabled(mAdminComponentName, active);
        mDevicePolicyManager.setStatusBarDisabled(mAdminComponentName, active);

        // Enable STAY_ON_WHILE_PLUGGED_IN
        enableStayOnWhilePluggedIn(active);

        // Set system update policy
        if (active){
            mDevicePolicyManager.setSystemUpdatePolicy(mAdminComponentName,SystemUpdatePolicy.createWindowedInstallPolicy(60, 120));
        } else {
            mDevicePolicyManager.setSystemUpdatePolicy(mAdminComponentName,null);
        }

        // set this Activity as a lock task package
        mDevicePolicyManager.setLockTaskPackages(mAdminComponentName,active ? new String[]{getPackageName()} : new String[]{});

        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MAIN);
        intentFilter.addCategory(Intent.CATEGORY_HOME);
        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);

        if (active) {
            // set Cosu activity as home intent receiver so that it is started
            // on reboot
            mDevicePolicyManager.addPersistentPreferredActivity(mAdminComponentName, intentFilter, new ComponentName(getPackageName(), AppActivity.class.getName()));
        } else {
            mDevicePolicyManager.clearPackagePersistentPreferredActivities(mAdminComponentName, getPackageName());
        }
    }

    private void setUserRestriction(String restriction, boolean disallow){
        if (disallow) {
            mDevicePolicyManager.addUserRestriction(mAdminComponentName,restriction);
        } else {
            mDevicePolicyManager.clearUserRestriction(mAdminComponentName,restriction);
        }
    }

    private void enableStayOnWhilePluggedIn(boolean enabled){
        if (enabled) {
            mDevicePolicyManager.setGlobalSetting(mAdminComponentName,Settings.Global.STAY_ON_WHILE_PLUGGED_IN,Integer.toString(BatteryManager.BATTERY_PLUGGED_AC| BatteryManager.BATTERY_PLUGGED_USB| BatteryManager.BATTERY_PLUGGED_WIRELESS));
        } else {
            mDevicePolicyManager.setGlobalSetting(mAdminComponentName,Settings.Global.STAY_ON_WHILE_PLUGGED_IN,"0");
        }
    }
}

Similar tutorial on setting up kiosk mode