androiddevice-admindevice-ownerandroid-device-owner

Device Owner Admin / DevicePolicyManager, Possible to turn on Mobile Data & Data Roaming automatically on Android?


So I am developing an app which works as device owner on the specific Android device. This app is not available on the play store, but gets transferred with a provisioning app from a different device via NFC. Since those devices will be very specific to certain tasks (scanning NFC tags), I want to enable and disable a few things from the very beginning.

I want to disable sound:

devicePolicyManager.setMasterVolumeMuted(adminComponentName, true);

But this doesn't seem to work at all, but no exception either.

But what I really want to do is enabling mobile Data and Roaming, the SIM cards which we are using support that.

devicePolicyManager.setSecureSetting(adminComponentName, Settings.Global.DATA_ROAMING, String.valueOf(1));
devicePolicyManager.setSecureSetting(adminComponentName,"mobile_data",String.valueOf(1));

But sadly, those two lines of code throw a security exception:

java.lang.SecurityException: Permission denial: Device owners cannot update mobile_data

Interestingly, inserting APNs work (later in the code) Any chance to be able to turn on mobile data and data roaming as a device admin/owner? I mean, thats the whole purpose of being a device admin, right?

Here is the full code for reference: (the parts which make the app crash are commented out)

public static void enableRestrictedAppsAndSettings(Activity activity) {

        ComponentName adminComponentName = DeviceAdminReceiver.getComponentName(activity);
        DevicePolicyManager devicePolicyManager = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // disable keyguard and sound
            devicePolicyManager.setKeyguardDisabled(adminComponentName, true);
            devicePolicyManager.setMasterVolumeMuted(adminComponentName, true);

            devicePolicyManager.setSecureSetting(adminComponentName, Settings.Secure.LOCATION_MODE, String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY));

            //devicePolicyManager.setSecureSetting(adminComponentName, Settings.Global.DATA_ROAMING, String.valueOf(1));
            //devicePolicyManager.setSecureSetting(adminComponentName,"mobile_data",String.valueOf(1));

        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            if (devicePolicyManager.isDeviceOwnerApp(activity.getApplicationContext().getPackageName())) {
                devicePolicyManager.enableSystemApp(adminComponentName,"com.sec.android.app.camera");

                devicePolicyManager.clearUserRestriction(adminComponentName, UserManager.DISALLOW_DATA_ROAMING);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    L.debug("KIOSK", "APN");
                    ApnSetting apn;

                    TelephonyManager manager = (TelephonyManager)activity.getSystemService(Context.TELEPHONY_SERVICE);
                    if (manager.getSimState() == TelephonyManager.SIM_STATE_READY) {

                        String mcc = manager.getSimOperator().substring(0, 3);
                        String mnc = manager.getSimOperator().substring(3);

                        L.debug("KIOSK " + mcc + " "+mnc);

                        apn = new ApnSetting.Builder()
                                .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
                                .setApnName("em")
                                .setEntryName("em")
                                .setOperatorNumeric(mcc + mnc) // this is a must its consists from Telephony.Carriers.MCC + Telephony.Carriers.MNC, In my case, I had to pad the MNC with a leading zero
                                .setProtocol(ApnSetting.PROTOCOL_IPV4V6) // this is a must
                                .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) // this is a must
                                .setCarrierEnabled(true)
                                .build();

                        devicePolicyManager.removeOverrideApn(adminComponentName,0);
                        devicePolicyManager.addOverrideApn(adminComponentName, apn);

                        devicePolicyManager.setOverrideApnsEnabled(adminComponentName, true);
                    }
                }

            }
        }

Solution

  • Unfortunately the device owner has no access to mobile data status (you're right, weird restriction for the device owner app!).

    However, you can still get the mobile data status and force the user to turn it on or off if the status is wrong. Here're the code samples (thanks to Test if background data and packet data is enabled or not).

    public static boolean isMobileDataEnabled(Context context) {
        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
        try {
            Class clazz = Class.forName(cm.getClass().getName());
            Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
            method.setAccessible(true); // Make the method callable
            // get the setting for "mobile data"
            return (Boolean) method.invoke(cm);
        } catch (Exception e) {
            // Let it will be true by default
            return true;
        }
    }
    

    This code works on Android 5-9 (not tested on Android 10 yet).

    So you run a background service which performs this check once per some seconds and requires the user to turn on/off the mobile data in the status bar.

    You can see how it is done by cloning this open source Android MDM (this is my project). The method is here: Utils.isMobileDataEnabled(Context context).