设备所有者管理员/DevicePolicyManager,可以在 Android 上自动打开移动数据和数据漫游吗?
Device Owner Admin / DevicePolicyManager, Possible to turn on Mobile Data & Data Roaming automatically on Android?
所以我正在开发一个应用程序,它作为特定 Android 设备上的设备所有者。此应用程序在 Play 商店中不可用,但会通过 NFC 与来自不同设备的配置应用程序一起传输。由于这些设备将非常特定于某些任务(扫描 NFC 标签),我想从一开始就启用和禁用一些东西。
我想关闭声音:
devicePolicyManager.setMasterVolumeMuted(adminComponentName, true);
但这似乎根本行不通,但也不例外。
但我真正想做的是启用移动数据和漫游,我们使用的 SIM 卡支持。
devicePolicyManager.setSecureSetting(adminComponentName, Settings.Global.DATA_ROAMING, String.valueOf(1));
devicePolicyManager.setSecureSetting(adminComponentName,"mobile_data",String.valueOf(1));
但遗憾的是,这两行代码引发了安全异常:
java.lang.SecurityException: Permission denial: Device owners cannot update mobile_data
有趣的是,插入 APNs 是有效的(在代码的后面)任何机会能够作为设备打开移动数据和数据漫游 admin/owner?我的意思是,这就是成为设备管理员的全部目的,对吧?
完整代码供参考:(导致应用崩溃的部分已注释掉)
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);
}
}
}
}
不幸的是,设备所有者无法访问移动数据状态(你是对的,设备所有者应用的奇怪限制!)。
但是,您仍然可以获取移动数据状态,并在状态错误时强制用户打开或关闭它。这是代码示例(感谢 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;
}
}
此代码适用于 Android 5-9(尚未在 Android 10 上测试)。
所以你 运行 后台服务每几秒钟执行一次此检查并要求用户在状态栏中打开 on/off 移动数据。
您可以通过克隆此 open source Android MDM(这是我的项目)来查看它是如何完成的。方法在这里:Utils.isMobileDataEnabled(Context上下文).
所以我正在开发一个应用程序,它作为特定 Android 设备上的设备所有者。此应用程序在 Play 商店中不可用,但会通过 NFC 与来自不同设备的配置应用程序一起传输。由于这些设备将非常特定于某些任务(扫描 NFC 标签),我想从一开始就启用和禁用一些东西。
我想关闭声音:
devicePolicyManager.setMasterVolumeMuted(adminComponentName, true);
但这似乎根本行不通,但也不例外。
但我真正想做的是启用移动数据和漫游,我们使用的 SIM 卡支持。
devicePolicyManager.setSecureSetting(adminComponentName, Settings.Global.DATA_ROAMING, String.valueOf(1));
devicePolicyManager.setSecureSetting(adminComponentName,"mobile_data",String.valueOf(1));
但遗憾的是,这两行代码引发了安全异常:
java.lang.SecurityException: Permission denial: Device owners cannot update mobile_data
有趣的是,插入 APNs 是有效的(在代码的后面)任何机会能够作为设备打开移动数据和数据漫游 admin/owner?我的意思是,这就是成为设备管理员的全部目的,对吧?
完整代码供参考:(导致应用崩溃的部分已注释掉)
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);
}
}
}
}
不幸的是,设备所有者无法访问移动数据状态(你是对的,设备所有者应用的奇怪限制!)。
但是,您仍然可以获取移动数据状态,并在状态错误时强制用户打开或关闭它。这是代码示例(感谢 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;
}
}
此代码适用于 Android 5-9(尚未在 Android 10 上测试)。
所以你 运行 后台服务每几秒钟执行一次此检查并要求用户在状态栏中打开 on/off 移动数据。
您可以通过克隆此 open source Android MDM(这是我的项目)来查看它是如何完成的。方法在这里:Utils.isMobileDataEnabled(Context上下文).