IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 【Android】使用deviceowner 配置手机设置 (Monkey自动化测试删去状态栏、设定输入法、静音、APP自动权限授予、Kiosk模式打开) -> 正文阅读

[开发测试]【Android】使用deviceowner 配置手机设置 (Monkey自动化测试删去状态栏、设定输入法、静音、APP自动权限授予、Kiosk模式打开)

背景:

需要使用Monkey进行自动化测试,但是测试时Monkey经常会下拉状态栏导致网络丢失等一系列问题,当前直接在百度上搜到的方法都是使用adb让屏幕全屏,但是我的测试机并不支持这个行为,所以需要找其它的方法。

初步方法汇总

在谷歌上搜索,找到了三种解决办法:

1. 屏幕固定功能ScreenPinning

这个功能可以在手机设置中开启,开启后可以固定手机只使用这个应用且屏蔽导航栏,开启需要使用虚拟按键。

所谓虚拟按键指的是屏幕下方出现返回、主页面、多任务 这些按钮,与之相对的是手势,也就是一般手机上推屏幕会出现多任务管理这个功能。

使用流程是:开启功能后,打开多任务管理,长按app,会出现锁定按钮,点击即可锁定。关闭是同时长按主页面和返回。

我的情况不太支持使用这个功能,首先我是对一些列app进行连续monkey测试,每次切换app锁定很困难,可能需要使用Appium之类的配合,其次,我需要app的截图,开启这个功能需要使用虚拟按键,app的截图会多出来虚拟按键的部分

2. 使用BroadcastReceiver打开和关闭WIFI

这个是我结合下面两个文章想到的
Android判断wifi状态 监听wifi连接
Android中使用BroadcastReceiver打开和关闭WIFI
完全可以试着写一个app监听wifi状态,在wifi关闭的时候自己设置打开wifi。
但是我没有实现这个想法。

3. 调用DeviceOwner中API,关闭状态栏。

最后一个方法就是使用DeviceOwner的API,
依旧是写个APP,调用Android中设备管理相关类的API

DevicePolicyManager下面的setStatusDisabled 函数
在这里插入图片描述

DeviceOwner设置和使用

概念

下面介绍几个概念:
device-owner:特殊的device-admin
设备管理者 device-admin
https://developer.android.com/guide/topics/admin/device-admin

app结构

常规的就是写一个最简单的app + 可以调用deviceOwner的一些设置
要完成调用deviceOwner首先,需要激活device-admin,此时可以使用一些deviceadmin相关的API设置,比如关闭相机等等,激活完device-admin再激活deviceOwner,之后就可以使用deviceOwner相关的API了

我自己这里是参照大佬的设计http://floatingmuseum.github.io/2016/07/device-admin-practice
也写成了设置界面的样式

但是核心设置其实就几点:https://github.com/XYScience/DeviceOwner
上面这个大佬的readme写的很清晰,我的app也基本参照两位大佬的代码

代码分析

下面对大佬的代码进行一下讲解
首先是device-admin编写:

1. 在res/xml目录下新建device_admin.xml文件;

<?xml version="1.0" encoding="utf-8"?>
<device-admin
    xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-policies>
    </uses-policies>
</device-admin>

2. 注册一个广播继承DeviceAdminReceiver;

public class MyDeviceAdminReceiver extends DeviceAdminReceiver{

    @Override
    public void onProfileProvisioningComplete(Context context, Intent intent) {
        super.onProfileProvisioningComplete(context, intent);
    }

    @Override
    public void onEnabled(Context context, Intent intent) {
        super.onEnabled(context, intent);
    }

    @Override
    public CharSequence onDisableRequested(Context context, Intent intent) {
        return super.onDisableRequested(context, intent);
    }

    @Override
    public void onDisabled(Context context, Intent intent) {
        super.onDisabled(context, intent);
    }

    @Override
    public void onPasswordChanged(Context context, Intent intent) {
        super.onPasswordChanged(context, intent);
        Logger.d("onPasswordChanged");
    }

    @Override
    public void onPasswordFailed(Context context, Intent intent) {
        super.onPasswordFailed(context, intent);
        Logger.d("onPasswordFailed");
    }

    @Override
    public void onPasswordSucceeded(Context context, Intent intent) {
        super.onPasswordSucceeded(context, intent);
        Logger.d("onPasswordSucceeded");
    }

    @Override
    public void onPasswordExpiring(Context context, Intent intent) {
        super.onPasswordExpiring(context, intent);
        Logger.d("onPasswordExpiring");
    }

    /**
     * 获取ComponentName,DevicePolicyManager的大多数方法都会用到
     */
    public static ComponentName getComponentName(Context context) {
        return new ComponentName(context.getApplicationContext(), MyDeviceAdminReceiver.class);
    }
}

3. 在清单文件里注册广播;

<receiver
   android:name=".MyDeviceAdminReceiver"
   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>

这样就完成了一个device-admin广播,之后就是激活和使用

4. 在其它类中激活设备管理器

激活的核心代码:

if (!devicePolicyManager.isAdminActive(comName)) {
    val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, comName)
    intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "激活此设备管理员后可免root停用应用")
    startActivityForResult(intent, 1)
} else {
    Toast.makeText(this, "此App已激活设备管理器", Toast.LENGTH_SHORT).show()
}

这段代码可以放在合适的地方使用,下面的代码,

dpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);

获取dpm在Fragment的onCreate中,
大佬app设置使用了PreferenceFragment(已过时,类似setting结构的fragment),点击对应preference后触发getAdmin()函数,激活deviceadmin,具体代码可以去看第一位大佬的github分析


 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref_deviceadmin);
        initListener();
        activity = DeviceAdminFragment.this.getActivity();
        if (dpm == null) {
            dpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
        }

        if (pm == null) {
            pm = activity.getPackageManager();
        }
        mComponentName = MyDeviceAdminReceiver.getComponentName(activity);
        if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP){
            Logger.d("isProfileOwnerApp:"+dpm.isProfileOwnerApp(activity.getPackageName()));
        }
    }

    private boolean checkDeviceAdminEnabled() {
        return dpm.isAdminActive(mComponentName);
    }

    private void getDeviceAdmin() {
        if (checkDeviceAdminEnabled()) {
            ToastUtil.show("已激活");
            return;
        }
        Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
        intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
                mComponentName);
        intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
                getString(R.string.device_admin_description));
        startActivity(intent);
    }

5. 设置device-admin权限

在使用device-admin的API时,有些设置需要特殊的权限
权限常量
对应在xml中设置政策:

<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-keyguard-features/>
        <!-- 禁用摄像头 -->
        <disable-camera />
    </uses-policies>
</device-admin>
<!--和<application>同级 --> 

6. 之后就是激活deviceOwner

现在一般有三种方式:我自己使用的是第二种adb的方式
利用ADB命令

$adb shell dpm set-device-owner com.example.deviceowner/.MyDeviceAdminReceiver

java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device

设置-账号中退出所有账户,然后重新尝试ADB设置

激活DeviceOwner时遇到的问题
1. 最初我直接在PC命令行输入 adb dpm set-…… 这一大串命令的时候,报错 Error: Bad admin: ComponentInfo{com.example.deviceowner/com.example.deviceowner.MyDeviceAdminReceiver}

如下图情况:会有一大堆使用说明最后有一点错误信息

D:\UIDump-master>adb shell dpm set-device-owner com.example.deviceowner/.MyDeviceAdminReceiver
usage: dpm [subcommand] [options]
usage: dpm set-active-admin [ --user <USER_ID> | current ]
usage: dpm set-device-owner [ --user <USER_ID> | current EXPERIMENTAL ] [ --name ]
usage: dpm set-profile-owner [ --user <USER_ID> | current ] [ --name ]
usage: dpm remove-active-admin [ --user <USER_ID> | current ] [ --name ]
dpm set-active-admin: Sets the given component as active admin for an existing user.
dpm set-device-owner: Sets the given component as active admin, and its package as device owner.
dpm set-profile-owner: Sets the given component as active admin and profile owner for an existing user.
dpm remove-active-admin: Disables an active admin, the admin must have declared android:testOnly in the application in its
manifest. This will also remove device and profile owners.
dpm clear-freeze-period-record: clears framework-maintained record of past freeze periods that the device went through. For use during feature development to prevent triggering restriction on setting freeze periods.
dpm force-network-logs: makes all network logs available to the DPC and triggers DeviceAdminReceiver.onNetworkLogsAvailable() if needed.
dpm force-security-logs: makes all security logs available to the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed.
usage: dpm mark-profile-owner-on-organization-owned-device: [ --user <USER_ID> | current ]
Error: Bad admin: ComponentInfo{com.example.deviceowner/com.example.deviceowner.MyDeviceAdminReceiver}
在这里插入图片描述

当我先使用adb shell进入手机命令行,再使用dpm命令时就不会了

2. 经典错误 java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device

java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device
at android.os.Parcel.createExceptionOrNull(Parcel.java:2381)
at android.os.Parcel.createException(Parcel.java:2357)
at android.os.Parcel.readException(Parcel.java:2340)
at android.os.Parcel.readException(Parcel.java:2282)
at android.app.admin.IDevicePolicyManager S t u b Stub StubProxy.setDeviceOwner(IDevicePolicyManager.java:8665)
at com.android.commands.dpm.Dpm.runSetDeviceOwner(Dpm.java:203)
at com.android.commands.dpm.Dpm.onRun(Dpm.java:115)
at com.android.internal.os.BaseCommand.run(BaseCommand.java:60)
at com.android.commands.dpm.Dpm.main(Dpm.java:41)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:438)
在这里插入图片描述

这个错误很常见,简单说就是这个DeviceOwner本来就只是希望在新的测试设备上使用,所有不能有其他账户和他绑定。

具体解释可以看 Not allowed to set the device owner because there are already several users on the device

“设备所有者只能在未配置的设备上设置,除非它是由“adb”启动的,在这种情况下,如果没有与设备关联的帐户,我们会允许它”。因此,在使用 dpm 命令之前,请确保您没有与当前用户集关联的任何帐户(例如 Gmail) “

关于账号处理问题,我有看到别人比较详细的处理方法总结:
adb設置DeviceOwner發生問題

下面记录一下我自己采用的方法,就是简单直接全部删除了,本来我想备份一下来着,但是没成果。

I. 删掉多的userInfo
adb shell pm list users

Notallowedtosetthedevice owner because there are already some accounts on thedevice
在这里插入图片描述
删掉除了0以外的账户

adb shell pm remove-user 999
II. 删掉account
adb shell dunmpsys account

可以看到所有的账号
在这里插入图片描述
直接打开手机设置->里面有accounts,然后删掉就行,有些删除不了的账户可以直接卸载应用
最后再执行dpm就可以了
在这里插入图片描述

7. 调用deviceOwner的API

激活deviceOwner后即可调用需要的API,
我自己是使用了三种,状态栏不可用,静音、APP自动权限授予
具体有哪些函数可以去看安卓文档,功能还是很强大的
https://developer.android.com/reference/android/app/admin/DevicePolicyManager

这里给一个设置静音和状态栏不可用的样例,就是调用相应API

   dpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);

dpm也是放在了onCreate中获取

  private void setVolumeMuted() {
        boolean muted = SPUtil.getBoolean(activity, "muted", false);
        Logger.d("静音:" + muted);
        dpm.setMasterVolumeMuted(mComponentName, !muted);
        SPUtil.editBoolean(activity, "muted", !muted);
    }
    
  @TargetApi(Build.VERSION_CODES.M)
  private void disableStatusBar() {
        boolean result = dpm.setStatusBarDisabled(mComponentName,statusbar);
        statusbar = !statusbar;
        Logger.d("result:"+result+"...statusbar:"+statusbar);
    }

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 12:07:07  更:2022-04-26 12:07:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 5:21:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码