跳到主要内容

示例代码解析


本章节课程目录:

1、安卓7.0+点按和手势

2、本地存储:保存整数等简单数据

3、本地存储:保存数组和复杂对象

4、本地存储:随手记

5、传感器

6、调用javaAPI

7、定时器

8、对话框的简单案例

9、对话框:简单计算器

10、对话框:模拟更新下载对话框(一)

11、对话框:模拟更新下载对话框(二)

12、对话框:模拟更新下载对话框(三)

13、对话框:UI模式下使用对话框

14、多线程:变量可见性实验

15、多线程:多线程按键监听

16、多线程:启动与关闭

17、多线程:简单示例

18、界面控件:按钮控件

19、界面控件:表格控件(一)

20、界面控件:表格控件(二)

21、界面控件:表格控件(三)

22、界面控件:表格控件(四)

23、界面控件:复选框单选框控件

24、界面控件:进度条控件(一)

25、界面控件:进度条控件(二)

26、界面控件:卡片布局

27、界面控件:列表控件(一)

28、界面控件:列表控件(二)

29、界面控件:列表控件(三)

30、界面控件:时间日期选择控件

31、界面控件:输入框控件

32、界面控件:图片控件(一)

33、界面控件:文本控件

34、界面控件:下拉菜单

35、界面控件:自定义控件—布局模板

36、界面控件:自定义控件—带颜色按钮

37、界面控件:自定义控件—配置勾选框

38、界面控件:自定义控件—模块

39、脚本引擎:停止所有正在运行的脚本

40、脚本引擎:运行脚本文件

41、脚本引擎:运行录制文件

42、脚本引擎:运行新的脚本任务

43、控制台:保存日志

44、控制台:产生随机数

45、控制台:调整控制台大小位置

46、控制台:格式化输出

47、控制台:控制台示例

48、控制台:终端模拟器

49、设备与设备信息:调整设备亮度

50、设备与设备信息:调整设备音量

51、设备与设备信息:获取设备信息

52、事件与按键、触摸监听:按键监听

53、事件与按键、触摸监听:触摸监听

54、事件与按键、触摸监听:通知监听

55、事件与按键、触摸监听:音量键控制脚本

56、事件与按键、触摸监听:长按返回退出当前程序

57、事件与按键、触摸监听:Toast监听

58、图片与图色处理:获取网络图片并保存

59、图片与图色处理:截图并保存

60、图片与图色处理:精确找色

61、图片与图色处理:模糊找色

62、图片与图色处理:区域找色1

63、图片与图色处理:区域找色2

64、图片与图色处理:实时显示触摸点颜色

65、图片与图色处理:图片处理

66、图片与图色处理:颜色获取和检测

67、图片与图色处理:找到QQ红点位置

68、图片与图色处理:找图

69、文件读写:读取文本文件

70、文件读写:读写文本文件

71、文件读写:删除所有空文件夹

72、文件读写:文件编码转换

73、文件读写:文件编码转换(高级)

74、文件读写:写入文本文件

75、协程:协程HelloWorld

76、协程:ui中使用协程

77、悬浮窗:动态悬浮文字

78、悬浮窗:护眼模式

79、悬浮窗:悬浮窗输入框

80、悬浮窗:悬浮窗运行脚本按钮简单版

81、悬浮窗:悬浮文字

82、悬浮窗:悬浮运行脚本按钮

83、应用:打开应用

84、应用:发送意图-文本消息分享

85、应用:强制停止应用

86、应用:卸载应用

87、应用:应用工具

点击课程标题即可跳转至视频教程


1、安卓7.0+点按和手势

本课视频

  • 点击左上角

"auto";

setScreenMetrics(1080, 1920);

click(100, 150);
  • 拉出通知栏

"auto";

//表示从位置(500, 10)滑动到位置(500, 1000), 持续两秒
swipe(500, 10, 500, 1000, 2000);
  • 三指捏合
"auto";

setScreenMetrics(1080, 1920);

//如果你使用的是MIUI,此脚本运行后会出现桌面多屏幕编辑
home();
sleep(1500);
gestures([350, [800, 300], [500, 1000]],
[350, [300, 1500], [500, 1000]],
[350, [300, 300], [500, 1000]]);
  • 三指下滑
"auto";

/**
* 同时模拟三个手势:
* 从(300, 400)到(300, 1400)
* 从(600, 400)到(600, 1400)
* 从(900, 400)到(900, 1400)
* 每一个的时长都为350毫秒
*/

gestures([350, [300, 400], [300, 1400]],
[350, [600, 400], [600, 1400]],
[350, [900, 400], [900, 1400]]
);

  • 双指捏合
"auto";

setScreenMetrics(1080, 1920);

//如果你使用的是MIUI,此脚本运行后会出现桌面编辑
home();
sleep(1500);
gestures([500, [800, 300], [500, 1000]],
[500, [300, 1500], [500, 1000]]);
  • 心形手势
"auto";

toast("开启开发者选项-指针位置或者在画画软件才能查看效果");

setScreenMetrics(1080, 1920);

var points = [10000];
var interval = 0.1;
var x0 = 600;
var y0 = 1000;
var a = 120;

//表达式 A=+B 会进行 B转化为数字 赋值给A
//表达式 A+=B 会进行 A = A + B; 也就是js的加法运算

for(var t = 0; t < 2 * Math.PI; t += interval){

var x = x0 + a * (2 * Math.cos(t) - Math.cos(2 * t));
var y = y0 + a * (2 * Math.sin(t) - Math.sin(2 * t));

points.push([parseInt(x), parseInt(y)]);
}

gesture.apply(null, points);

2、本地存储:保存整数等简单数据

本课视频

var storage = storages.create("Auto.js例子:简单数据");

var a = 1234;
var b = true;
var str = "hello";

//保存
storage.put("a", a);
storage.put("b", b);
storage.put("str", str);

console.show();

//取出
log("a = " + storage.get("a"));
log("b = " + storage.get("b"));
log("str = " + storage.get("str"));

3、本地存储:保存数组和复杂对象

本课视频

var storage = storages.create("Auto.js例子:复杂数据");
var arr = [1, 4, 2, 5];
var obj = {
name: "Auto.js",
url: "www.autojs.org"
};
//保存
storage.put("arr", arr);
storage.put("obj", obj);

console.show();
//取出
log("arr = ", storage.get("arr"));
log("obj = ", storage.get("obj"));

4、本地存储:随手记

本课视频

"ui";
ui.layout(
<vertical padding="16">
<horizontal>
<text textColor="black" textSize="18sp" layout_weight="1">随手记</text>
<button id="save" text="保存" w="auto" style="Widget.AppCompat.Button.Borderless.Colored"/>
</horizontal>
<input id="content" h="*" gravity="top"/>
</vertical>
);
var storage = storages.create("Auto.js例子:随手记");
var content = storage.get("content");
if(content != null){
ui.content.setText(content);
}
ui.save.click(()=>{
storage.put("content", ui.content.text());
});

5、传感器

本课视频

"ui";

ui.layout(
<scroll>
<vertical>
<text id="accelerometer" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="orientation" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="gyroscope" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="magnetic_field" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="gravity" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="linear_acceleration" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="ambient_temperature" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="light" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="pressure" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="proximity" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="relative_humidity" margin="12dp" textSize="16sp" textColor="#000000"/>
</vertical>
</scroll>
);

//忽略不支持的传感器,即使有传感器不支持也不抛出异常
sensors.ignoresUnsupportedSensor = true;

sensors.on("unsupported_sensor", function(sensorName, sensorType){
log(util.format("不支持的传感器: %s 类型: %d", sensorName, sensorType));
});

//加速度传感器
sensors.register("accelerometer", sensors.delay.ui).on("change", (event, ax, ay, az)=>{
ui.accelerometer.setText(util.format("x方向加速度: %d\ny方向加速度: %d\nz方向加速度: %d", ax, ay, az));
});
//方向传感器
sensors.register("orientation", sensors.delay.ui).on("change", (event, dx, dy, dz)=>{
ui.orientation.setText(util.format("绕x轴转过角度: %d\n绕y轴转过角度: %d\n绕z轴转过角度: %d", dx, dy, dz));
});
//陀螺仪传感器
sensors.register("gyroscope", sensors.delay.ui).on("change", (event, wx, wy, wz)=>{
ui.gyroscope.setText(util.format("绕x轴角速度: %d\n绕y轴角速度: %d\n绕z轴角速度: %d", wx, wy, wz));
});
//磁场传感器
sensors.register("magnetic_field", sensors.delay.ui).on("change", (event, bx, by, bz)=>{
ui.magnetic_field.setText(util.format("x方向磁场强度: %d\ny方向磁场强度: %d\nz方向磁场强度: %d", bx, by, bz));
});
//重力传感器
sensors.register("gravity", sensors.delay.ui).on("change", (event, gx, gy, gz)=>{
ui.gravity.setText(util.format("x方向重力: %d\ny方向重力: %d\nz方向重力: %d", gx, gy, gz));
});
//线性加速度传感器
sensors.register("linear_acceleration", sensors.delay.ui).on("change", (event, ax, ay, az)=>{
ui.linear_acceleration.setText(util.format("x方向线性加速度: %d\ny方向线性加速度: %d\nz方向线性加速度: %d", ax, ay, az));
});
//温度传感器
sensors.register("ambient_temperature", sensors.delay.ui).on("change", (event, t)=>{
ui.ambient_temperature.setText(util.format("当前温度: %d", t));
});
//光线传感器
sensors.register("light", sensors.delay.ui).on("change", (event, l)=>{
ui.light.setText(util.format("当前光的强度: %d", l));
});
//压力传感器
sensors.register("pressure", sensors.delay.ui).on("change", (event, p)=>{
ui.pressure.setText(util.format("当前压力: %d", p));
});
//距离传感器
sensors.register("proximity", sensors.delay.ui).on("change", (event, d)=>{
ui.proximity.setText(util.format("当前距离: %d", d));
});
//湿度传感器
sensors.register("relative_humidity", sensors.delay.ui).on("change", (event, rh)=>{
ui.relative_humidity.setText(util.format("当前相对湿度: %d", rh));
});

//30秒后退出程序
setTimeout(exit, 30 * 1000);

6、调用javaAPI

本课视频

/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
* liveConnect.js: a simple demonstration of JavaScript-to-Java connectivity
*/

// Create a new StringBuffer. Note that the class name must be fully qualified
// by its package. Packages other than "java" must start with "Packages", i.e.,
// "Packages.javax.servlet...".
var sb = new java.lang.StringBuffer();

// Now add some stuff to the buffer.
sb.append("hi, mom");
sb.append(3); // this will add "3.0" to the buffer since all JS numbers
// are doubles by default
sb.append(true);

// Now print it out. (The toString() method of sb is automatically called
// to convert the buffer to a string.)
// Should print "hi, mom3.0true".
print(sb);
openConsole();

7、定时器

本课视频

toast("静等20秒,你会看到想看的...");

var i = 0;

setTimeout(function(){
app.openUrl("http://music.163.com/#/song?id=109628&autoplay=true&market=baiduhd");
exit();
}, 20 * 1000);

setInterval(function(){
i++;
toast(i * 5 + "秒");
}, 5000);
var i = 0;

setInterval(function(){
i++;
toast(i * 4 + "秒");
if(i == 5){
exit();
}
}, 4000);

8、对话框的简单案例

本课视频

//菜单

while(true){
var i = dialogs.select("哲学的基本问题是", "社会和自然的关系问题", "思维与存在的关系问题", "政治和经济的关系问题", "实践和理论的关系问题");
if(i == -1){
toast("猜一下呗");
continue;
}
if(i == 1){
toast("答对辣");
break;
}else{
toast("答错辣")
}
}

//单选框

var sex = dialogs.singleChoice("请选择性别", ["男", "女", "基佬", "女装", "其他"], 2);
toast("选择了第" + (sex + 1) + "个选项");

//多选框

var i = dialogs.multiChoice("下列作品出自李贽的是", ["《焚书》", "《西湖寻梦》", "《高太史全集》", "《续焚烧书》", "《藏书》"]);
toast("选择了: " + i);
if(i.length == 2 && i.toString() == [0, 4].toString()){
toast("答对辣");
}else{
toast("答错辣");
}

//确认框

var handsome = confirm("你帅吗?");
if(handsome){
toast("真不要脸!");
toast("真不要脸!");
toast("真不要脸!");
alert("真不要脸!");
}else{
toast("嗯");
}

//输入框

var name = rawInput("请输入名字");
alert("(•́へ•́╬)", "你好~ " + name);
var expr = dialogs.input("请输入简单的算式", "1+1");
alert("计算结果为 " + expr);

9、对话框:简单计算器

本课视频

var num1 = dialogs.input("请输入第一个数字");
var op = dialogs.singleChoice("请选择运算", ["加", "减", "乘", "除", "幂"]);
var num2 = dialogs.input("请输入第二个数字");
var result = 0;
switch(op){
case 0:
result = num1 + num2;
break;
case 1:
result = num1 - num2;
break;
case 2:
result = num1 * num2;
break;
case 3:
result = num1 / num2;
break;
case 4:
result = Math.pow(num1, num2);
break;
}
alert("运算结果", result);

10、对话框:模拟更新下载对话框(一)

本课视频

11、对话框:模拟更新下载对话框(二)

本课视频

12、对话框:模拟更新下载对话框(三)

本课视频

var releaseNotes = "版本 v7.7.7\n"
+ "更新日志:\n"
+ "* 新增 若干Bug\n";

dialogs.build({
title: "发现新版本",
content: releaseNotes,
positive: "立即下载",
negative: "取消",
neutral: "到浏览器下载"
}).on("positive", download)
.on("neutral", () => {
app.openUrl("https://www.autojs.org");
}).show();

var downloadDialog = null;
var downloadId = -1;

function download(){
downloadDialog = dialogs.build({
title: "下载中...",
positive: "暂停",
negative: "取消",
progress: {
max: 100,
showMinMax: true
},
autoDismiss: false
})
.on("positive", ()=>{
if(downloadDialog.getActionButton("positive") == "暂停"){
stopDownload();
downloadDialog.setActionButton("positive", "继续");
}else{
startDownload();
downloadDialog.setActionButton("positive", "暂停");
}
})
.on("negative", ()=>{
stopDownload();
downloadDialog.dismiss();
downloadDialog = null;
})
.show();
startDownload();
}

function startDownload(){
downloadId = setInterval(()=>{
var p = downloadDialog.getProgress();
if(p >= 100){
stopDownload();
downloadDialog.dismiss();
downloadDialog = null;
toast("下载完成");
}else{
downloadDialog.setProgress(p + 1);
}
}, 100);
}

function stopDownload(){
clearInterval(downloadId);
}

13、对话框:UI模式下使用对话框

本课视频

"ui";

ui.layout(
<vertical>
<button id="callback" align="center">回调形式</button>
<button id="promise" align="center">Promise形式</button>
<button id="calc" align="center">简单计算器</button>
</vertical>
);

ui.callback.click(()=>{
dialogs.confirm("要弹出输入框吗?", "", function(b){
if(b){
dialogs.rawInput("输入", "", function(str){
alert("您输入的是:" + str);
});
}else{
ui.finish();
}
});
});

ui.promise.click(()=>{
dialogs.confirm("要弹出输入框吗")
.then(function(b){
if(b){
return dialogs.rawInput("输入");
}else{
ui.finish();
}
}).then(function(str){
alert("您输入的是:" + str);
});
});


ui.calc.click(()=>{
let num1, num2, op;
dialogs.input("请输入第一个数字")
.then(n => {
num1 = n;
return dialogs.singleChoice("请选择运算", ["加", "减", "乘", "除", "幂"]);
})
.then(o => {
op = o;
return dialogs.input("请输入第二个数字");
})
.then(n => {
num2 = n;
var result;
switch(op){
case 0:
result = num1 + num2;
break;
case 1:
result = num1 - num2;
break;
case 2:
result = num1 * num2;
break;
case 3:
result = num1 / num2;
break;
case 4:
result = Math.pow(num1, num2);
break;
}
alert("运算结果", result);
});
});

14、多线程:变量可见性实验

本课视频

var running = true;

threads.start(function(){
while(running){
log("running = true");
}
});

sleep(2000);
running = false;
console.info("running = false");

15、多线程:多线程按键监听

本课视频

auto();

threads.start(function(){
//在子线程中调用observeKey()从而使按键事件处理在子线程执行
events.observeKey();
events.on("key_down", function(keyCode, events){
//音量键关闭脚本
if(keyCode == keys.volume_up){
exit();
}
});
});

toast("音量上键关闭脚本");

events.on("exit", function(){
toast("脚本已结束");
});

while(true){
log("脚本运行中...");
sleep(2000);
}

16、多线程:启动与关闭

本课视频

//启动一个无限循环的线程
var thread = threads.start(function(){
while(true){
log("子线程运行中...");
sleep(1000);
}
});


//5秒后关闭线程
sleep(5000);
thread.interrupt();

17、多线程:简单示例

本课视频

//启动一个线程
threads.start(function(){
//在线程中每隔1秒打印"线程1"
while(true){
log("线程1");
sleep(1000);
}
});

//启动另一个线程
threads.start(function(){
//在线程中每隔2秒打印"线程1"
while(true){
log("线程2");
sleep(2000);
}
});

//在主线程中每隔3秒打印"主线程"
for(var i = 0; i < 10; i++){
log("主线程");
sleep(3000);
}
//打印10次后退出所有线程
threads.shutDownAll();

18、界面控件:按钮控件

本课视频

"ui";

ui.layout(
<vertical padding="16">
<button text="普通按钮" w="auto"/>
<button text="带颜色按钮" style="Widget.AppCompat.Button.Colored" w="auto"/>
<button text="无边框按钮" style="Widget.AppCompat.Button.Borderless" w="auto"/>
<button text="无边框有颜色按钮" style="Widget.AppCompat.Button.Borderless.Colored" w="auto"/>
<button text="长长的按钮" w="*"/>
<button id="click_me" text="点我" w="auto"/>
</vertical>
);

ui.click_me.on("click", ()=>{
toast("我被点啦");
});

ui.click_me.on("long_click", ()=>{
toast("我被长按啦");
});

19、界面控件:表格控件(一)

本课视频)

20、界面控件:表格控件(二)

本课视频

21、界面控件:表格控件(三)

本课视频

22、界面控件:表格控件(四)

本课视频

"ui";

ui.layout(
<vertical>
<linear>
<input id="input" layout_weight="1" textColor="black" textSize="16sp" marginLeft="16"/>
<button id="search" text="搜索" style="Widget.AppCompat.Button.Borderless.Colored"/>
<button id="reset" text="重置" style="Widget.AppCompat.Button.Borderless.Colored"/>
</linear>
<grid id="icons" spanCount="4" h="*">
<img src="@drawable/{{this}}" h="80" margin="12" bg="?selectableItemBackgroundBorderless"/>
</grid>
</vertical>
);

//所有内置图标名称
var icons = ['ic_3d_rotation_black_48dp', 'ic_accessibility_black_48dp', 'ic_accessible_black_48dp', 'ic_account_balance_black_48dp', 'ic_account_balance_wallet_black_48dp', 'ic_account_box_black_48dp', 'ic_account_circle_black_48dp', 'ic_add_shopping_cart_black_48dp', 'ic_alarm_add_black_48dp', 'ic_alarm_black_48dp', 'ic_alarm_off_black_48dp', 'ic_alarm_on_black_48dp', 'ic_all_out_black_48dp', 'ic_android_black_48dp', 'ic_announcement_black_48dp', 'ic_aspect_ratio_black_48dp', 'ic_assessment_black_48dp', 'ic_assignment_black_48dp', 'ic_assignment_ind_black_48dp', 'ic_assignment_late_black_48dp', 'ic_assignment_returned_black_48dp', 'ic_assignment_return_black_48dp', 'ic_assignment_turned_in_black_48dp', 'ic_autorenew_black_48dp', 'ic_backup_black_48dp', 'ic_bookmark_black_48dp', 'ic_bookmark_border_black_48dp', 'ic_book_black_48dp', 'ic_bug_report_black_48dp', 'ic_build_black_48dp', 'ic_cached_black_48dp', 'ic_camera_enhance_black_48dp', 'ic_card_giftcard_black_48dp', 'ic_card_membership_black_48dp', 'ic_card_travel_black_48dp', 'ic_change_history_black_48dp', 'ic_check_circle_black_48dp', 'ic_chrome_reader_mode_black_48dp', 'ic_class_black_48dp', 'ic_code_black_48dp', 'ic_compare_arrows_black_48dp', 'ic_copyright_black_48dp', 'ic_credit_card_black_48dp', 'ic_dashboard_black_48dp', 'ic_date_range_black_48dp', 'ic_delete_black_48dp', 'ic_delete_forever_black_48dp', 'ic_description_black_48dp', 'ic_dns_black_48dp', 'ic_done_all_black_48dp', 'ic_done_black_48dp', 'ic_donut_large_black_48dp', 'ic_donut_small_black_48dp', 'ic_eject_black_48dp', 'ic_euro_symbol_black_48dp', 'ic_event_black_48dp', 'ic_event_seat_black_48dp', 'ic_exit_to_app_black_48dp', 'ic_explore_black_48dp', 'ic_extension_black_48dp', 'ic_face_black_48dp', 'ic_favorite_black_48dp', 'ic_favorite_border_black_48dp', 'ic_feedback_black_48dp', 'ic_find_in_page_black_48dp', 'ic_find_replace_black_48dp', 'ic_fingerprint_black_48dp', 'ic_flight_land_black_48dp', 'ic_flight_takeoff_black_48dp', 'ic_flip_to_back_black_48dp', 'ic_flip_to_front_black_48dp', 'ic_gavel_black_48dp', 'ic_get_app_black_48dp', 'ic_gif_black_48dp', 'ic_grade_black_48dp', 'ic_group_work_black_48dp', 'ic_g_translate_black_48dp', 'ic_help_black_48dp', 'ic_help_outline_black_48dp', 'ic_highlight_off_black_48dp', 'ic_history_black_48dp', 'ic_home_black_48dp', 'ic_hourglass_empty_black_48dp', 'ic_hourglass_full_black_48dp', 'ic_https_black_48dp', 'ic_http_black_48dp', 'ic_important_devices_black_48dp', 'ic_info_black_48dp', 'ic_info_outline_black_48dp', 'ic_input_black_48dp', 'ic_invert_colors_black_48dp', 'ic_label_black_48dp', 'ic_label_outline_black_48dp', 'ic_language_black_48dp', 'ic_launch_black_48dp', 'ic_lightbulb_outline_black_48dp', 'ic_line_style_black_48dp', 'ic_line_weight_black_48dp', 'ic_list_black_48dp', 'ic_lock_black_48dp', 'ic_lock_open_black_48dp', 'ic_lock_outline_black_48dp', 'ic_loyalty_black_48dp', 'ic_markunread_mailbox_black_48dp', 'ic_motorcycle_black_48dp', 'ic_note_add_black_48dp', 'ic_offline_pin_black_48dp', 'ic_opacity_black_48dp', 'ic_open_in_browser_black_48dp', 'ic_open_in_new_black_48dp', 'ic_open_with_black_48dp', 'ic_pageview_black_48dp', 'ic_pan_tool_black_48dp', 'ic_payment_black_48dp', 'ic_perm_camera_mic_black_48dp', 'ic_perm_contact_calendar_black_48dp', 'ic_perm_data_setting_black_48dp', 'ic_perm_device_information_black_48dp', 'ic_perm_identity_black_48dp', 'ic_perm_media_black_48dp', 'ic_perm_phone_msg_black_48dp', 'ic_perm_scan_wifi_black_48dp', 'ic_pets_black_48dp', 'ic_picture_in_picture_alt_black_48dp', 'ic_picture_in_picture_black_48dp', 'ic_play_for_work_black_48dp', 'ic_polymer_black_48dp', 'ic_power_settings_new_black_48dp', 'ic_pregnant_woman_black_48dp', 'ic_print_black_48dp', 'ic_query_builder_black_48dp', 'ic_question_answer_black_48dp', 'ic_receipt_black_48dp', 'ic_record_voice_over_black_48dp', 'ic_redeem_black_48dp', 'ic_remove_shopping_cart_black_48dp', 'ic_reorder_black_48dp', 'ic_report_problem_black_48dp', 'ic_restore_black_48dp', 'ic_restore_page_black_48dp', 'ic_room_black_48dp', 'ic_rounded_corner_black_48dp', 'ic_rowing_black_48dp', 'ic_schedule_black_48dp', 'ic_search_black_48dp', 'ic_settings_applications_black_48dp', 'ic_settings_backup_restore_black_48dp', 'ic_settings_black_48dp', 'ic_settings_bluetooth_black_48dp', 'ic_settings_brightness_black_48dp', 'ic_settings_cell_black_48dp', 'ic_settings_ethernet_black_48dp', 'ic_settings_input_antenna_black_48dp', 'ic_settings_input_component_black_48dp', 'ic_settings_input_composite_black_48dp', 'ic_settings_input_hdmi_black_48dp', 'ic_settings_input_svideo_black_48dp', 'ic_settings_overscan_black_48dp', 'ic_settings_phone_black_48dp', 'ic_settings_power_black_48dp', 'ic_settings_remote_black_48dp', 'ic_settings_voice_black_48dp', 'ic_shopping_basket_black_48dp', 'ic_shopping_cart_black_48dp', 'ic_shop_black_48dp', 'ic_shop_two_black_48dp', 'ic_speaker_notes_black_48dp', 'ic_speaker_notes_off_black_48dp', 'ic_spellcheck_black_48dp', 'ic_stars_black_48dp', 'ic_store_black_48dp', 'ic_subject_black_48dp', 'ic_supervisor_account_black_48dp', 'ic_swap_horiz_black_48dp', 'ic_swap_vertical_circle_black_48dp', 'ic_swap_vert_black_48dp', 'ic_system_update_alt_black_48dp', 'ic_tab_black_48dp', 'ic_tab_unselected_black_48dp', 'ic_theaters_black_48dp', 'ic_thumbs_up_down_black_48dp', 'ic_thumb_down_black_48dp', 'ic_thumb_up_black_48dp', 'ic_timeline_black_48dp', 'ic_toc_black_48dp', 'ic_today_black_48dp', 'ic_toll_black_48dp', 'ic_touch_app_black_48dp', 'ic_track_changes_black_48dp', 'ic_translate_black_48dp', 'ic_trending_down_black_48dp', 'ic_trending_flat_black_48dp', 'ic_trending_up_black_48dp', 'ic_turned_in_black_48dp', 'ic_turned_in_not_black_48dp', 'ic_update_black_48dp', 'ic_verified_user_black_48dp', 'ic_view_agenda_black_48dp', 'ic_view_array_black_48dp', 'ic_view_carousel_black_48dp', 'ic_view_column_black_48dp', 'ic_view_day_black_48dp', 'ic_view_headline_black_48dp', 'ic_view_list_black_48dp', 'ic_view_module_black_48dp', 'ic_view_quilt_black_48dp', 'ic_view_stream_black_48dp', 'ic_view_week_black_48dp', 'ic_visibility_black_48dp', 'ic_visibility_off_black_48dp', 'ic_watch_later_black_48dp', 'ic_work_black_48dp', 'ic_youtube_searched_for_black_48dp', 'ic_zoom_in_black_48dp', 'ic_zoom_out_black_48dp', 'ic_add_alert_black_48dp', 'ic_error_black_48dp', 'ic_error_outline_black_48dp', 'ic_warning_black_48dp', 'ic_add_to_queue_black_48dp', 'ic_airplay_black_48dp', 'ic_album_black_48dp', 'ic_art_track_black_48dp', 'ic_av_timer_black_48dp', 'ic_branding_watermark_black_48dp', 'ic_call_to_action_black_48dp', 'ic_closed_caption_black_48dp', 'ic_equalizer_black_48dp', 'ic_explicit_black_48dp', 'ic_fast_forward_black_48dp', 'ic_fast_rewind_black_48dp', 'ic_featured_play_list_black_48dp', 'ic_featured_video_black_48dp', 'ic_fiber_dvr_black_48dp', 'ic_fiber_manual_record_black_48dp', 'ic_fiber_new_black_48dp', 'ic_fiber_pin_black_48dp', 'ic_fiber_smart_record_black_48dp', 'ic_forward_10_black_48dp', 'ic_forward_30_black_48dp', 'ic_forward_5_black_48dp', 'ic_games_black_48dp', 'ic_hd_black_48dp', 'ic_hearing_black_48dp', 'ic_high_quality_black_48dp', 'ic_library_add_black_48dp', 'ic_library_books_black_48dp', 'ic_library_music_black_48dp', 'ic_loop_black_48dp', 'ic_mic_black_48dp', 'ic_mic_none_black_48dp', 'ic_mic_off_black_48dp', 'ic_movie_black_48dp', 'ic_music_video_black_48dp', 'ic_new_releases_black_48dp', 'ic_note_black_48dp', 'ic_not_interested_black_48dp', 'ic_pause_black_48dp', 'ic_pause_circle_filled_black_48dp', 'ic_pause_circle_outline_black_48dp', 'ic_playlist_add_black_48dp', 'ic_playlist_add_check_black_48dp', 'ic_playlist_play_black_48dp', 'ic_play_arrow_black_48dp', 'ic_play_circle_filled_black_48dp', 'ic_play_circle_filled_white_black_48dp', 'ic_play_circle_outline_black_48dp', 'ic_queue_black_48dp', 'ic_queue_music_black_48dp', 'ic_queue_play_next_black_48dp', 'ic_radio_black_48dp', 'ic_recent_actors_black_48dp', 'ic_remove_from_queue_black_48dp', 'ic_repeat_black_48dp', 'ic_repeat_one_black_48dp', 'ic_replay_10_black_48dp', 'ic_replay_30_black_48dp', 'ic_replay_5_black_48dp', 'ic_replay_black_48dp', 'ic_shuffle_black_48dp', 'ic_skip_next_black_48dp', 'ic_skip_previous_black_48dp', 'ic_slow_motion_video_black_48dp', 'ic_snooze_black_48dp', 'ic_sort_by_alpha_black_48dp', 'ic_stop_black_48dp', 'ic_subscriptions_black_48dp', 'ic_subtitles_black_48dp', 'ic_surround_sound_black_48dp', 'ic_videocam_black_48dp', 'ic_videocam_off_black_48dp', 'ic_video_call_black_48dp', 'ic_video_label_black_48dp', 'ic_video_library_black_48dp', 'ic_volume_down_black_48dp', 'ic_volume_mute_black_48dp', 'ic_volume_off_black_48dp', 'ic_volume_up_black_48dp', 'ic_web_asset_black_48dp', 'ic_web_black_48dp', 'ic_business_black_48dp', 'ic_call_black_48dp', 'ic_call_end_black_48dp', 'ic_call_made_black_48dp', 'ic_call_merge_black_48dp', 'ic_call_missed_black_48dp', 'ic_call_missed_outgoing_black_48dp', 'ic_call_received_black_48dp', 'ic_call_split_black_48dp', 'ic_chat_black_48dp', 'ic_chat_bubble_black_48dp', 'ic_chat_bubble_outline_black_48dp', 'ic_clear_all_black_48dp', 'ic_comment_black_48dp', 'ic_contacts_black_48dp', 'ic_contact_mail_black_48dp', 'ic_contact_phone_black_48dp', 'ic_dialer_sip_black_48dp', 'ic_dialpad_black_48dp', 'ic_email_black_48dp', 'ic_forum_black_48dp', 'ic_import_contacts_black_48dp', 'ic_import_export_black_48dp', 'ic_invert_colors_off_black_48dp', 'ic_live_help_black_48dp', 'ic_location_off_black_48dp', 'ic_location_on_black_48dp', 'ic_mail_outline_black_48dp', 'ic_message_black_48dp', 'ic_no_sim_black_48dp', 'ic_phonelink_erase_black_48dp', 'ic_phonelink_lock_black_48dp', 'ic_phonelink_ring_black_48dp', 'ic_phonelink_setup_black_48dp', 'ic_phone_black_48dp', 'ic_portable_wifi_off_black_48dp', 'ic_present_to_all_black_48dp', 'ic_ring_volume_black_48dp', 'ic_rss_feed_black_48dp', 'ic_screen_share_black_48dp', 'ic_speaker_phone_black_48dp', 'ic_stay_current_landscape_black_48dp', 'ic_stay_current_portrait_black_48dp', 'ic_stay_primary_landscape_black_48dp', 'ic_stay_primary_portrait_black_48dp', 'ic_stop_screen_share_black_48dp', 'ic_swap_calls_black_48dp', 'ic_textsms_black_48dp', 'ic_voicemail_black_48dp', 'ic_vpn_key_black_48dp', 'ic_add_black_48dp', 'ic_add_box_black_48dp', 'ic_add_circle_black_48dp', 'ic_add_circle_outline_black_48dp', 'ic_archive_black_48dp', 'ic_backspace_black_48dp', 'ic_block_black_48dp', 'ic_clear_black_48dp', 'ic_content_copy_black_48dp', 'ic_content_cut_black_48dp', 'ic_content_paste_black_48dp', 'ic_create_black_48dp', 'ic_delete_sweep_black_48dp', 'ic_drafts_black_48dp', 'ic_filter_list_black_48dp', 'ic_flag_black_48dp', 'ic_font_download_black_48dp', 'ic_forward_black_48dp', 'ic_gesture_black_48dp', 'ic_inbox_black_48dp', 'ic_link_black_48dp', 'ic_low_priority_black_48dp', 'ic_mail_black_48dp', 'ic_markunread_black_48dp', 'ic_move_to_inbox_black_48dp', 'ic_next_week_black_48dp', 'ic_redo_black_48dp', 'ic_remove_black_48dp', 'ic_remove_circle_black_48dp', 'ic_remove_circle_outline_black_48dp', 'ic_reply_all_black_48dp', 'ic_reply_black_48dp', 'ic_report_black_48dp', 'ic_save_black_48dp', 'ic_select_all_black_48dp', 'ic_send_black_48dp', 'ic_sort_black_48dp', 'ic_text_format_black_48dp', 'ic_unarchive_black_48dp', 'ic_undo_black_48dp', 'ic_weekend_black_48dp', 'ic_access_alarms_black_48dp', 'ic_access_alarm_black_48dp', 'ic_access_time_black_48dp', 'ic_add_alarm_black_48dp', 'ic_airplanemode_active_black_48dp', 'ic_airplanemode_inactive_black_48dp', 'ic_battery_20_black_48dp', 'ic_battery_30_black_48dp', 'ic_battery_50_black_48dp', 'ic_battery_60_black_48dp', 'ic_battery_80_black_48dp', 'ic_battery_90_black_48dp', 'ic_battery_alert_black_48dp', 'ic_battery_charging_20_black_48dp', 'ic_battery_charging_30_black_48dp', 'ic_battery_charging_50_black_48dp', 'ic_battery_charging_60_black_48dp', 'ic_battery_charging_80_black_48dp', 'ic_battery_charging_90_black_48dp', 'ic_battery_charging_full_black_48dp', 'ic_battery_full_black_48dp', 'ic_battery_std_black_48dp', 'ic_battery_unknown_black_48dp', 'ic_bluetooth_black_48dp', 'ic_bluetooth_connected_black_48dp', 'ic_bluetooth_disabled_black_48dp', 'ic_bluetooth_searching_black_48dp', 'ic_brightness_auto_black_48dp', 'ic_brightness_high_black_48dp', 'ic_brightness_low_black_48dp', 'ic_brightness_medium_black_48dp', 'ic_data_usage_black_48dp', 'ic_developer_mode_black_48dp', 'ic_devices_black_48dp', 'ic_dvr_black_48dp', 'ic_gps_fixed_black_48dp', 'ic_gps_not_fixed_black_48dp', 'ic_gps_off_black_48dp', 'ic_graphic_eq_black_48dp', 'ic_location_disabled_black_48dp', 'ic_location_searching_black_48dp', 'ic_network_cell_black_48dp', 'ic_network_wifi_black_48dp', 'ic_nfc_black_48dp', 'ic_screen_lock_landscape_black_48dp', 'ic_screen_lock_portrait_black_48dp', 'ic_screen_lock_rotation_black_48dp', 'ic_screen_rotation_black_48dp', 'ic_sd_storage_black_48dp', 'ic_settings_system_daydream_black_48dp', 'ic_signal_cellular_0_bar_black_48dp', 'ic_signal_cellular_1_bar_black_48dp', 'ic_signal_cellular_2_bar_black_48dp', 'ic_signal_cellular_3_bar_black_48dp', 'ic_signal_cellular_4_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_0_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_1_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_2_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_3_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_4_bar_black_48dp', 'ic_signal_cellular_no_sim_black_48dp', 'ic_signal_cellular_null_black_48dp', 'ic_signal_cellular_off_black_48dp', 'ic_signal_wifi_0_bar_black_48dp', 'ic_signal_wifi_1_bar_black_48dp', 'ic_signal_wifi_1_bar_lock_black_48dp', 'ic_signal_wifi_2_bar_black_48dp', 'ic_signal_wifi_2_bar_lock_black_48dp', 'ic_signal_wifi_3_bar_black_48dp', 'ic_signal_wifi_3_bar_lock_black_48dp', 'ic_signal_wifi_4_bar_black_48dp', 'ic_signal_wifi_4_bar_lock_black_48dp', 'ic_signal_wifi_off_black_48dp', 'ic_storage_black_48dp', 'ic_usb_black_48dp', 'ic_wallpaper_black_48dp', 'ic_widgets_black_48dp', 'ic_wifi_lock_black_48dp', 'ic_wifi_tethering_black_48dp', 'ic_attach_file_black_48dp', 'ic_attach_money_black_48dp', 'ic_border_all_black_48dp', 'ic_border_bottom_black_48dp', 'ic_border_clear_black_48dp', 'ic_border_color_black_48dp', 'ic_border_horizontal_black_48dp', 'ic_border_inner_black_48dp', 'ic_border_left_black_48dp', 'ic_border_outer_black_48dp', 'ic_border_right_black_48dp', 'ic_border_style_black_48dp', 'ic_border_top_black_48dp', 'ic_border_vertical_black_48dp', 'ic_bubble_chart_black_48dp', 'ic_drag_handle_black_48dp', 'ic_format_align_center_black_48dp', 'ic_format_align_justify_black_48dp', 'ic_format_align_left_black_48dp', 'ic_format_align_right_black_48dp', 'ic_format_bold_black_48dp', 'ic_format_clear_black_48dp', 'ic_format_color_fill_black_48dp', 'ic_format_color_reset_black_48dp', 'ic_format_color_text_black_48dp', 'ic_format_indent_decrease_black_48dp', 'ic_format_indent_increase_black_48dp', 'ic_format_italic_black_48dp', 'ic_format_line_spacing_black_48dp', 'ic_format_list_bulleted_black_48dp', 'ic_format_list_numbered_black_48dp', 'ic_format_paint_black_48dp', 'ic_format_quote_black_48dp', 'ic_format_shapes_black_48dp', 'ic_format_size_black_48dp', 'ic_format_strikethrough_black_48dp', 'ic_format_textdirection_l_to_r_black_48dp', 'ic_format_textdirection_r_to_l_black_48dp', 'ic_format_underlined_black_48dp', 'ic_functions_black_48dp', 'ic_highlight_black_48dp', 'ic_insert_chart_black_48dp', 'ic_insert_comment_black_48dp', 'ic_insert_drive_file_black_48dp', 'ic_insert_emoticon_black_48dp', 'ic_insert_invitation_black_48dp', 'ic_insert_link_black_48dp', 'ic_insert_photo_black_48dp', 'ic_linear_scale_black_48dp', 'ic_merge_type_black_48dp', 'ic_mode_comment_black_48dp', 'ic_mode_edit_black_48dp', 'ic_monetization_on_black_48dp', 'ic_money_off_black_48dp', 'ic_multiline_chart_black_48dp', 'ic_pie_chart_black_48dp', 'ic_pie_chart_outlined_black_48dp', 'ic_publish_black_48dp', 'ic_short_text_black_48dp', 'ic_show_chart_black_48dp', 'ic_space_bar_black_48dp', 'ic_strikethrough_s_black_48dp', 'ic_text_fields_black_48dp', 'ic_title_black_48dp', 'ic_vertical_align_bottom_black_48dp', 'ic_vertical_align_center_black_48dp', 'ic_vertical_align_top_black_48dp', 'ic_wrap_text_black_48dp', 'ic_attachment_black_48dp', 'ic_cloud_black_48dp', 'ic_cloud_circle_black_48dp', 'ic_cloud_done_black_48dp', 'ic_cloud_download_black_48dp', 'ic_cloud_off_black_48dp', 'ic_cloud_queue_black_48dp', 'ic_cloud_upload_black_48dp', 'ic_create_new_folder_black_48dp', 'ic_file_download_black_48dp', 'ic_file_upload_black_48dp', 'ic_folder_black_48dp', 'ic_folder_open_black_48dp', 'ic_folder_shared_black_48dp', 'ic_cast_black_48dp', 'ic_cast_connected_black_48dp', 'ic_computer_black_48dp', 'ic_desktop_mac_black_48dp', 'ic_desktop_windows_black_48dp', 'ic_developer_board_black_48dp', 'ic_devices_other_black_48dp', 'ic_device_hub_black_48dp', 'ic_dock_black_48dp', 'ic_gamepad_black_48dp', 'ic_headset_black_48dp', 'ic_headset_mic_black_48dp', 'ic_keyboard_arrow_down_black_48dp', 'ic_keyboard_arrow_left_black_48dp', 'ic_keyboard_arrow_right_black_48dp', 'ic_keyboard_arrow_up_black_48dp', 'ic_keyboard_backspace_black_48dp', 'ic_keyboard_black_48dp', 'ic_keyboard_capslock_black_48dp', 'ic_keyboard_hide_black_48dp', 'ic_keyboard_return_black_48dp', 'ic_keyboard_tab_black_48dp', 'ic_keyboard_voice_black_48dp', 'ic_laptop_black_48dp', 'ic_laptop_chromebook_black_48dp', 'ic_laptop_mac_black_48dp', 'ic_laptop_windows_black_48dp', 'ic_memory_black_48dp', 'ic_mouse_black_48dp', 'ic_phonelink_black_48dp', 'ic_phonelink_off_black_48dp', 'ic_phone_android_black_48dp', 'ic_phone_iphone_black_48dp', 'ic_power_input_black_48dp', 'ic_router_black_48dp', 'ic_scanner_black_48dp', 'ic_security_black_48dp', 'ic_sim_card_black_48dp', 'ic_smartphone_black_48dp', 'ic_speaker_black_48dp', 'ic_speaker_group_black_48dp', 'ic_tablet_android_black_48dp', 'ic_tablet_black_48dp', 'ic_tablet_mac_black_48dp', 'ic_toys_black_48dp', 'ic_tv_black_48dp', 'ic_videogame_asset_black_48dp', 'ic_watch_black_48dp', 'ic_add_a_photo_black_48dp', 'ic_add_to_photos_black_48dp', 'ic_adjust_black_48dp', 'ic_assistant_black_48dp', 'ic_assistant_photo_black_48dp', 'ic_audiotrack_black_48dp', 'ic_blur_circular_black_48dp', 'ic_blur_linear_black_48dp', 'ic_blur_off_black_48dp', 'ic_blur_on_black_48dp', 'ic_brightness_1_black_48dp', 'ic_brightness_2_black_48dp', 'ic_brightness_3_black_48dp', 'ic_brightness_4_black_48dp', 'ic_brightness_5_black_48dp', 'ic_brightness_6_black_48dp', 'ic_brightness_7_black_48dp', 'ic_broken_image_black_48dp', 'ic_brush_black_48dp', 'ic_burst_mode_black_48dp', 'ic_camera_alt_black_48dp', 'ic_camera_black_48dp', 'ic_camera_front_black_48dp', 'ic_camera_rear_black_48dp', 'ic_camera_roll_black_48dp', 'ic_center_focus_strong_black_48dp', 'ic_center_focus_weak_black_48dp', 'ic_collections_black_48dp', 'ic_collections_bookmark_black_48dp', 'ic_colorize_black_48dp', 'ic_color_lens_black_48dp', 'ic_compare_black_48dp', 'ic_control_point_black_48dp', 'ic_control_point_duplicate_black_48dp', 'ic_crop_16_9_black_48dp', 'ic_crop_3_2_black_48dp', 'ic_crop_5_4_black_48dp', 'ic_crop_7_5_black_48dp', 'ic_crop_black_48dp', 'ic_crop_din_black_48dp', 'ic_crop_free_black_48dp', 'ic_crop_landscape_black_48dp', 'ic_crop_original_black_48dp', 'ic_crop_portrait_black_48dp', 'ic_crop_rotate_black_48dp', 'ic_crop_square_black_48dp', 'ic_dehaze_black_48dp', 'ic_details_black_48dp', 'ic_edit_black_48dp', 'ic_exposure_black_48dp', 'ic_exposure_neg_1_black_48dp', 'ic_exposure_neg_2_black_48dp', 'ic_exposure_plus_1_black_48dp', 'ic_exposure_plus_2_black_48dp', 'ic_exposure_zero_black_48dp', 'ic_filter_1_black_48dp', 'ic_filter_2_black_48dp', 'ic_filter_3_black_48dp', 'ic_filter_4_black_48dp', 'ic_filter_5_black_48dp', 'ic_filter_6_black_48dp', 'ic_filter_7_black_48dp', 'ic_filter_8_black_48dp', 'ic_filter_9_black_48dp', 'ic_filter_9_plus_black_48dp', 'ic_filter_black_48dp', 'ic_filter_b_and_w_black_48dp', 'ic_filter_center_focus_black_48dp', 'ic_filter_drama_black_48dp', 'ic_filter_frames_black_48dp', 'ic_filter_hdr_black_48dp', 'ic_filter_none_black_48dp', 'ic_filter_tilt_shift_black_48dp', 'ic_filter_vintage_black_48dp', 'ic_flare_black_48dp', 'ic_flash_auto_black_48dp', 'ic_flash_off_black_48dp', 'ic_flash_on_black_48dp', 'ic_flip_black_48dp', 'ic_gradient_black_48dp', 'ic_grain_black_48dp', 'ic_grid_off_black_48dp', 'ic_grid_on_black_48dp', 'ic_hdr_off_black_48dp', 'ic_hdr_on_black_48dp', 'ic_hdr_strong_black_48dp', 'ic_hdr_weak_black_48dp', 'ic_healing_black_48dp', 'ic_image_aspect_ratio_black_48dp', 'ic_image_black_48dp', 'ic_iso_black_48dp', 'ic_landscape_black_48dp', 'ic_leak_add_black_48dp', 'ic_leak_remove_black_48dp', 'ic_lens_black_48dp', 'ic_linked_camera_black_48dp', 'ic_looks_3_black_48dp', 'ic_looks_4_black_48dp', 'ic_looks_5_black_48dp', 'ic_looks_6_black_48dp', 'ic_looks_black_48dp', 'ic_looks_one_black_48dp', 'ic_looks_two_black_48dp', 'ic_loupe_black_48dp', 'ic_monochrome_photos_black_48dp', 'ic_movie_creation_black_48dp', 'ic_movie_filter_black_48dp', 'ic_music_note_black_48dp', 'ic_nature_black_48dp', 'ic_nature_people_black_48dp', 'ic_navigate_before_black_48dp', 'ic_navigate_next_black_48dp', 'ic_palette_black_48dp', 'ic_panorama_black_48dp', 'ic_panorama_fish_eye_black_48dp', 'ic_panorama_horizontal_black_48dp', 'ic_panorama_vertical_black_48dp', 'ic_panorama_wide_angle_black_48dp', 'ic_photo_album_black_48dp', 'ic_photo_black_48dp', 'ic_photo_camera_black_48dp', 'ic_photo_filter_black_48dp', 'ic_photo_library_black_48dp', 'ic_photo_size_select_actual_black_48dp', 'ic_photo_size_select_large_black_48dp', 'ic_photo_size_select_small_black_48dp', 'ic_picture_as_pdf_black_48dp', 'ic_portrait_black_48dp', 'ic_remove_red_eye_black_48dp', 'ic_rotate_90_degrees_ccw_black_48dp', 'ic_rotate_left_black_48dp', 'ic_rotate_right_black_48dp', 'ic_slideshow_black_48dp', 'ic_straighten_black_48dp', 'ic_style_black_48dp', 'ic_switch_camera_black_48dp', 'ic_switch_video_black_48dp', 'ic_tag_faces_black_48dp', 'ic_texture_black_48dp', 'ic_timelapse_black_48dp', 'ic_timer_10_black_48dp', 'ic_timer_3_black_48dp'];

ui.icons.setDataSource(icons);

ui.icons.on("item_click", function(icon){
var d = "@drawable/" + icon;
setClip(d);
toast(d + "已复制到剪贴板");
});

ui.search.on("click", function(){
var text = ui.input.text();
if(text.length == 0){
return;
}
search(text);
});

ui.reset.on("click", function(){
ui.icons.setDataSource(icons);
});

function search(keywords){
var result = [];
for(var i = 0; i < icons.length; i++){
var icon = icons[i];
if(icon.indexOf(keywords) >= 0){
result.push(icon);
}
}
ui.icons.setDataSource(result);
}

23、界面控件:复选框单选框控件

本课视频

"ui";

ui.layout(
<vertical padding="16">
<checkbox id="cb1" text="复选框"/>
<checkbox id="cb2" checked="true" text="勾选的复选框"/>
<radiogroup>
<radio text="单选框1"/>
<radio text="单选框2"/>
<radio text="单选框3"/>
</radiogroup>
<radiogroup mariginTop="16">
<radio text="单选框1"/>
<radio text="单选框2"/>
<radio text="勾选的单选框3" checked="true"/>
</radiogroup>
</vertical>
);

ui.cb1.on("check", (checked)=>{
if(checked){
toast("第一个框被勾选了");
}else{
toast("第一个框被取消勾选了");
}
});

24、界面控件:进度条控件(一)

本课视频

25、界面控件:进度条控件(二)

本课视频

"ui";

ui.layout(
<vertical padding="16">
<text text="处理中..." textColor="black" textSize="16sp"/>
<progressbar />

<text text="直线无限进度条" textColor="black" textSize="16sp" marginTop="24"/>
<progressbar indeterminate="true" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>

<text text="直线进度条" textColor="black" textSize="16sp" marginTop="24"/>
<progressbar progress="30" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>

<text text="可调节进度条" textColor="black" textSize="16sp" marginTop="24"/>
<seekbar progress="20"/>

<horizontal gravity="center" marginTop="24">
<text id="progress_value" textColor="black" textSize="16sp" margin="8" text="0"/>
<progressbar id="progress" w="*" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
</horizontal>
<button id="download">开始下载</button>
</vertical>
);

var downloadId = null;

ui.download.click(()=>{
if(downloadId != null){
stopDownload();
}else{
startDownload();
}
});

function stopDownload(){
ui.download.text("开始下载");
clearInterval(downloadId);
downloadId = null;
}

function startDownload(){
if(ui.progress.getProgress() == 100){
ui.progress.setProgress(0);
}
ui.download.text("停止下载");
downloadId = setInterval(()=>{
var p = ui.progress.getProgress();
p++;
if(p > 100){
stopDownload();
return;
}
ui.progress.setProgress(p);
ui.progress_value.setText(p.toString());
}, 200);
}

26、界面控件:卡片布局

本课视频

"ui";

ui.layout(
<vertical>
<appbar>
<toolbar id="toolbar" title="卡片布局"/>
</appbar>

<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">
<vertical padding="18 8" h="auto">
<text text="写操作系统作业" textColor="#222222" textSize="16sp"/>
<text text="明天第1~2节" textColor="#999999" textSize="14sp"/>
</vertical>
<View bg="#f44336" h="*" w="10"/>
</card>

<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">
<vertical padding="18 8" h="auto">
<text text="修复ui模式的Bug" textColor="#222222" textSize="16sp"/>
<text text="无限期" textColor="#999999" textSize="14sp"/>
</vertical>
<View bg="#ff5722" h="*" w="10"/>
</card>

<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">
<vertical padding="18 8" h="auto">
<text text="发布Auto.js 5.0.0正式版" textColor="#222222" textSize="16sp"/>
<text text="2019年1月" textColor="#999999" textSize="14sp"/>
</vertical>
<View bg="#4caf50" h="*" w="10"/>
</card>

<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">

<vertical padding="18 8" h="auto">
<text text="完成毕业设计和论文" textColor="#222222" textSize="16sp"/>
<text text="2019年4月" textColor="#999999" textSize="14sp"/>
</vertical>

<View bg="#2196f3" h="*" w="10"/>

</card>

</vertical>
);

27、界面控件:列表控件(一)

本课视频

28、界面控件:列表控件(二)

本课视频

29、界面控件:列表控件(三)

本课视频

"ui";

ui.layout(
<frame>
<list id="list">
<vertical>
<text id="name" textSize="16sp" textColor="#000000" text="姓名: {{name}}"/>
<text id="age" textSize="16sp" textColor="#000000" text="年龄: {{age}}岁"/>
<button id="deleteItem" text="删除"/>
</vertical>
</list>
</frame>
);

var items = [
{name: "小明", age: 18}, {name: "小红", age: 30},
{name: "小东", age: 19}, {name: "小强", age: 31},
{name: "小满", age: 20}, {name: "小一", age: 32},
{name: "小和", age: 21}, {name: "小二", age: 1},
{name: "小贤", age: 22}, {name: "小三", age: 2},
{name: "小伟", age: 23}, {name: "小四", age: 3},
{name: "小黄", age: 24}, {name: "小五", age: 4},
{name: "小健", age: 25}, {name: "小六", age: 5},
{name: "小啦", age: 26}, {name: "小七", age: 6},
{name: "小哈", age: 27}, {name: "小八", age: 7},
{name: "小啊", age: 28}, {name: "小九", age: 8},
{name: "小啪", age: 29}, {name: "小十", age: 9}
];

ui.list.setDataSource(items);

ui.list.on("item_click", function(item, i, itemView, listView){
toast("被点击的人名字为: " + item.name + ",年龄为: " + item.age);
});

ui.list.on("item_bind", function(itemView, itemHolder){
itemView.deleteItem.on("click", function(){
let item = itemHolder.item;
toast("被删除的人名字为: " + item.name + ",年龄为: " + item.age);
items.splice(itemHolder.position, 1);
});
})

30、界面控件:时间日期选择控件

本课视频

"ui";

ui.layout(
<scroll>
<vertical padding="16">
<text text="日历样式日期选择" textColor="black" textSize="16sp" marginTop="16"/>
<datepicker />

<text text="滑动日期选择" textColor="black" textSize="16sp" marginTop="16"/>
<datepicker datePickerMode="spinner"/>

<text text="时钟样式时间选择" textColor="black" textSize="16sp" marginTop="16"/>
<timepicker />

<text text="滑动时间选择" textColor="black" textSize="16sp" marginTop="16"/>
<timepicker timePickerMode="spinner"/>

</vertical>
</scroll>
)

31、界面控件:输入框控件

本课视频

"ui";

ui.layout(
<vertical padding="16">
<text text="输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input />

<!-- hint属性用来设置输入框的提示-->
<text text="带提示的输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input hint="请输入一些内容"/>

<!-- inputType属性用来设置输入类型,包括number, email, phone等-->
<text text="数字输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input inputType="number" text="123"/>

<!-- password属性用来设置输入框是否是密码输入框 -->
<text text="密码输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input password="true"/>

<!-- lines属性用来设置输入框的行数 -->
<text text="多行输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input lines="3"/>

<text text="设置输入框错误信息" textColor="black" textSize="16sp" marginTop="16"/>
<input id="qq" inputType="number" hint="请输入您的QQ号码"/>
<button id="ok" text="确定" w="auto" style="Widget.AppCompat.Button.Colored"/>
</vertical>
);

ui.ok.click(()=>{
var text = ui.qq.text();
if(text.length == 0){
ui.qq.setError("输入不能为空");
return;
}
var qq = parseInt(text);
if(qq < 10000){
ui.qq.setError("QQ号码格式错误");
return;
}
ui.qq.setError(null);
});

32、界面控件:图片控件(一)

本课视频

"ui";

ui.layout(
<scroll>
<vertical bg="#707070" padding="16">
<text text="网络图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png"
w="100" h="100"/>

<text text="带边框的图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" borderWidth="2dp" borderColor="#202020"/>

<text text="圆形图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" circle="true"/>

<text text="带边框的圆形图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" circle="true" borderWidth="2dp" borderColor="#202020"/>

<text text="圆角图片" textColor="black" textSize="16sp" marginTop="16"/>
<img id="rounded_img" src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" radius="20dp" scaleType="fitXY"/>
<button id="change_img" text="更改图片"/>
</vertical>
</scroll>
);

ui.change_img.on("click", ()=>{
ui.rounded_img.setSource("http://www.autojs.org/assets/uploads/profile/1-profilecover.jpeg");
});

33、界面控件:文本控件

本课视频

"ui";

ui.layout(
<vertical padding="16">
<text textSize="40sp">大字</text>
<text textSize="12sp">小字</text>
<text textStyle="bold" textColor="black">加粗</text>
<text textStyle="italic">斜体</text>
<text textColor="#00ff00">原谅色</text>
<text margin="8">Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。Android操作系统最初由Andy Rubin开发,主要支持手机。20058月由Google收购注资。200711月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。</text>
<text maxLines="1" ellipsize="end" margin="8">Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。Android操作系统最初由Andy Rubin开发,主要支持手机。20058月由Google收购注资。200711月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。</text>
<text maxLines="2" ellipsize="end" margin="8">Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。Android操作系统最初由Andy Rubin开发,主要支持手机。20058月由Google收购注资。200711月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。</text>
<text w="*" gravity="center" textSize="20sp">居中</text>
<text autoLink="all">自动超链接网址www.baidu.com, 邮箱 123@qq.com等</text>
</vertical>
);

34、界面控件:下拉菜单

本课视频

"ui";

ui.layout(
<vertical padding="16">
<horizontal>
<text textSize="16sp">下拉菜单</text>
<spinner id="sp1" entries="选项1|选项2|选项3"/>
</horizontal>
<horizontal>
<text textSize="16sp">对话框菜单</text>
<spinner id="sp2" entries="选项4|选项5|选项6" spinnerMode="dialog"/>
</horizontal>
<button id="ok">确定</button>
<button id="select3">选择选项3</button>
</vertical>
);

ui.ok.on("click", ()=>{
var i = ui.sp1.getSelectedItemPosition();
var j = ui.sp2.getSelectedItemPosition();
toast("您的选择是选项" + (i + 1) + "和选项" + (j + 4));
});

ui.select3.on("click", ()=>{
ui.sp1.setSelection(2);
});

35、界面控件:自定义控件—布局模板

本课视频

"ui";

var InputLayout = (function() {
//继承至ui.Widget
util.extend(InputLayout, ui.Widget);

function InputLayout() {
ui.Widget.call(this);
this.defineAttr("hint", (view, attr, value, defineSetter)=>{
view._hint.setText(value);
});
this.defineAttr("text", (view, attr, value, defineSetter)=>{
view._input.setText(value);
});
}
InputLayout.prototype.render = function() {
return (
<vertical>
<text id="_hint" textSize="16sp" margin="4" textColor="gray"/>
<input id="_input" margin="0 16"/>
</vertical>
);
}
InputLayout.prototype.getInput = function() {
return this.view._input.getText();
};
ui.registerWidget("input-layout", InputLayout);
return InputLayout;
})();

ui.layout(
<vertical>
<input-layout id="name" hint="请输入名字"/>
<input-layout id="age" hint="请输入年龄" text="18"/>
<button id="ok" text="确认"/>
</vertical>
);

ui.ok.on("click", function(){
toast("名字是:" + ui.name.widget.getInput() + ", 年龄是:" + ui.age.widget.getInput());
});

36、界面控件:自定义控件—带颜色按钮

本课视频

"ui";

var ColoredButton = (function() {
//继承ui.Widget
util.extend(ColoredButton, ui.Widget);

function ColoredButton() {
//调用父类构造函数
ui.Widget.call(this);
//自定义属性color,定义按钮颜色
this.defineAttr("color", (view, name, defaultGetter) => {
return this._color;
}, (view, name, value, defaultSetter) => {
this._color = value;
view.attr("backgroundTint", value);
});
//自定义属性onClick,定义被点击时执行的代码
this.defineAttr("onClick", (view, name, defaultGetter) => {
return this._onClick;
}, (view, name, value, defaultSetter) => {
this._onClick = value;
});
}
ColoredButton.prototype.render = function() {
return (
<button textSize="16sp" style="Widget.AppCompat.Button.Colored" w="auto"/>
);
}
ColoredButton.prototype.onViewCreated = function(view) {
view.on("click", () => {
if (this._onClick) {
eval(this._onClick);
}
});
}
ui.registerWidget("colored-button", ColoredButton);
return ColoredButton;
})();

ui.layout(
<vertical>
<colored-button text="第一个按钮" color="#ff5722"/>
<colored-button text="第二个按钮" onClick="hello()"/>
</vertical>
);

function hello() {
alert("Hello ~");

}

37、界面控件:自定义控件—配置勾选框

本课视频

"ui";

//这个自定义控件是一个勾选框checkbox,能够保存自己的勾选状态,在脚本重新启动时能恢复状态
var PrefCheckBox = (function() {
//继承至ui.Widget
util.extend(PrefCheckBox, ui.Widget);

function PrefCheckBox() {
//调用父类构造函数
ui.Widget.call(this);
//自定义属性key,定义在配置中保存时的key
this.defineAttr("key");
}
PrefCheckBox.prototype.render = function() {
return (
<checkbox />
);
}
PrefCheckBox.prototype.onFinishInflation = function(view) {
view.setChecked(PrefCheckBox.getPref().get(this.getKey(), false));
view.on("check", (checked) => {
PrefCheckBox.getPref().put(this.getKey(), checked);
});
}
PrefCheckBox.prototype.getKey = function() {
if(this.key){
return this.key;
}
let id = this.view.attr("id");
if(!id){
throw new Error("should set a id or key to the checkbox");
}
return id.replace("@+id/", "");
}
PrefCheckBox.setPref = function(pref) {
PrefCheckBox._pref = pref;
}
PrefCheckBox.getPref = function(){
if(!PrefCheckBox._pref){
PrefCheckBox._pref = storages.create("pref");
}
return PrefCheckBox._pref;
}
ui.registerWidget("pref-checkbox", PrefCheckBox);
return PrefCheckBox;
})();

ui.layout(
<vertical>
<pref-checkbox id="perf1" text="配置1"/>
<pref-checkbox id="perf2" text="配置2"/>
<button id="btn" text="获取配置"/>
</vertical>
);

ui.btn.on("click", function(){
toast("配置1为" + PrefCheckBox.getPref().get("perf1"));
toast("配置2为" + PrefCheckBox.getPref().get("perf2"));
});

38、界面控件:自定义控件—模块

本课视频

"ui";

var PrefCheckBox = require('./XXX.js');

ui.layout(
<vertical>
<pref-checkbox id="perf1" text="配置1"/>
<pref-checkbox id="perf2" text="配置2"/>
<button id="btn" text="获取配置"/>
</vertical>
);

ui.btn.on("click", function(){
toast("配置1为" + PrefCheckBox.getPref().get("perf1"));
toast("配置2为" + PrefCheckBox.getPref().get("perf2"));
});

39、脚本引擎:停止所有正在运行的脚本

本课视频

engines.stopAllAndToast();

40、脚本引擎:运行脚本文件

本课视频

var scriptsPath = "/sdcard/脚本/";
if(!files.exists(scriptsPath)){
scriptsPath = "/sdcard/Scripts/";
}
var scriptFiles = files.listDir(scriptsPath, function(name){
return name.endsWith(".js");
});
var i = dialogs.singleChoice("请选择要运行的脚本", scriptFiles);
if(i < 0){
exit();
}
var path = files.join(scriptsPath, scriptFiles[i]);
engines.execScriptFile(path);

41、脚本引擎:运行录制文件

本课视频

var scriptsPath = "/sdcard/脚本/";

if(!files.exists(scriptsPath)){
scriptsPath = "/sdcard/Scripts/";
}
var scriptFiles = files.listDir(scriptsPath, function(name){
return name.endsWith(".auto");
});
var i = dialogs.singleChoice("请选择要运行的脚本", scriptFiles);
if(i < 0){
exit();
}
var path = files.join(scriptsPath, scriptFiles[i]);

engines.execAutoFile(path);

42、脚本引擎:运行新的脚本任务

本课视频

var script = "toast('Hello, Auto.js');" +
"sleep(3000);" +
"toast('略略略');";
var execution = engines.execScript("Hello", script);
sleep(1000);
execution.getEngine().forceStop();

43、控制台:保存日志

本课视频

console.setGlobalLogConfig({
file: "/sdcard/log.txt"
});
console.log(1);
console.log(2);
console.error(3);
app.viewFile("/sdcard/log.txt");

44、控制台:产生随机数

本课视频

console.show();

log("将产生5个1到100的随机数");

for(let i = 0; i < 5; i++){
print(random(1, 100));
print(" ");
sleep(400);
}
print("\n");

log("将产生10个1到20的不重复随机数");

var exists = {};

for(let i = 0; i < 10; i++){
var r;
do{
r = random(1, 20);
}while(exists[r]);
exists[r] = true;
print(r + " ");
sleep(400);
}

45、控制台:调整控制台大小位置

本课视频

console.show();
console.log("调整大小...");
console.setSize(1000, 1000);
sleep(2000);
console.log("调整位置...");
console.setPosition(0, 500);
sleep(2000);
console.hide();

46、控制台:格式化输出

本课视频

console.show();

var i = {
name: "小明",
age: 18,
height: 1.72
};

console.log("大家好, 我叫%s, 今年%d岁, 身高%d米", i.name, i.age, i.height);
console.log("实际上我是一个对象啦,长这样子: %j", i);

d整型输出,%ld长整型输出,

o以八进制数形式输出整数,

x以十六进制数形式输出整数,

u以十进制数输出unsigned型数据(无符号数)。

c用来输出一个字符,

s用来输出一个字符串,

f用来输出实数,以小数形式输出,(备注:浮点数是不能定义如的精度的,所以“%6.2f”这种写法是“错误的”!!!)

e以指数形式输出实数,

g根据大小自动选f格式或e格式,且不输出无意义的零。

47、控制台:控制台示例

本课视频

//显示控制台
console.show();

console.verbose("这是灰色");
console.log("这是黑色");
console.info("这是红色");
console.warn("这是蓝色");
console.error("这是绿色=_=");
hey();

function hey() {
console.trace("打印日志行数");
}

48、控制台:终端模拟器

本课视频

var sh = new Shell();
sh.setCallback({
onOutput: function(str){
print(str);
}
})
console.show();
do {
var cmd = console.rawInput();
sh.exec(cmd);
}while(cmd != "exit");
sh.exit();

49、设备与设备信息:调整设备亮度

本课视频

"ui";

ui.layout(
<vertical padding="16">
<checkbox id="auto" text="自动亮度"/>
<text textColor="black" textSize="16sp" margin="8">亮度</text>
<seekbar id="brightness" max="100"/>
</vertical>
);

//getBrightnessMode()返回亮度模式,1为自动亮度
ui.auto.setChecked(device.getBrightnessMode() == 1);
ui.auto.setOnCheckedChangeListener(function(v, checked){
device.setBrightnessMode(checked ? 1: 0);
});

ui.brightness.setProgress(device.getBrightness());
ui.brightness.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setBrightness(p);
}
}
});

50、设备与设备信息:调整设备音量

本课视频

"ui";

ui.layout(
<vertical padding="16">
<text textColor="black" textSize="16sp">媒体音量</text>
<seekbar id="music"/>

<text textColor="black" textSize="16sp">通知音量</text>
<seekbar id="notification"/>

<text textColor="black" textSize="16sp">闹钟音量</text>
<seekbar id="alarm"/>
</vertical>
);

ui.music.setMax(device.getMusicMaxVolume());
ui.music.setProgress(device.getMusicVolume());
ui.music.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setMusicVolume(p);
}
}
});

ui.notification.setMax(device.getNotificationMaxVolume());
ui.notification.setProgress(device.getAlarmVolume());
ui.notification.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setNotificationVolume(p);
}
}
});

ui.alarm.setMax(device.getAlarmMaxVolume());
ui.alarm.setProgress(device.getAlarmVolume());
ui.alarm.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setAlarmVolume(p);
}
}
});

51、设备与设备信息:获取设备信息

本课视频

console.show();

var str = "";
str += "屏幕宽度:" + device.width;
str += "\n屏幕高度:" + device.height;
str += "\nbuildId:" + device.buildId;
str += "\n主板:" + device.board;
str += "\n制造商:" + device.brand;
str += "\n型号:" + device.model;
str += "\n产品名称:" + device.product;
str += "\nbootloader版本:" + device.bootloader;
str += "\n硬件名称:" + device.hardware;
str += "\n唯一标识码:" + device.fingerprint;
str += "\nIMEI: " + device.getIMEI();
str += "\nAndroidId: " + device.getAndroidId();
str += "\nMac: " + device.getMacAddress();
str += "\nAPI: " + device.sdkInt;
str += "\n电量: " + device.getBattery();

log(str);

52、事件与按键、触摸监听:按键监听

本课视频

"auto";

events.observeKey();

var keyNames = {
"KEYCODE_VOLUME_UP": "音量上键",
"KEYCODE_VOLUME_DOWN": "音量下键",
"KEYCODE_HOME": "Home键",
"KEYCODE_BACK": "返回键",
"KEYCODE_MENU": "菜单键",
"KEYCODE_POWER": "电源键",
};

events.on("key", function(code, event){
var keyName = getKeyName(code, event);
if(event.getAction() == event.ACTION_DOWN){
toast(keyName + "被按下");
}else if(event.getAction() == event.ACTION_UP){
toast(keyName + "弹起");
}
});

loop();



function getKeyName(code, event){
var keyCodeStr = event.keyCodeToString(code);
var keyName = keyNames[keyCodeStr];
if(!keyName){
return keyCodeStr;
}
return keyName;
}

53、事件与按键、触摸监听:触摸监听

本课视频

events.observeTouch();

events.setTouchEventTimeout(30);

toast("请在日志中查看触摸的点的坐标");

events.on("touch", function(point){
log(point);
});

loop();

54、事件与按键、触摸监听:通知监听

本课视频

auto();

events.observeNotification();

events.onNotification(function(notification){
printNotification(notification);
});

toast("监听中,请在日志中查看记录的通知及其内容");

function printNotification(notification){
log("应用包名: " + notification.getPackageName());
log("通知文本: " + notification.getText());
log("通知优先级: " + notification.priority);
log("通知目录: " + notification.category);
log("通知时间: " + new Date(notification.when));
log("通知数: " + notification.number);
log("通知摘要: " + notification.tickerText);
}

55、事件与按键、触摸监听:音量键控制脚本

本课视频

"auto";

events.observeKey();

var interval = 5000;
var task = task1;

events.onKeyDown("volume_up", function(event){
if(task == task1){
task = task2;
}else{
task = task1;
}
toast("任务已切换");
});

events.onKeyDown("volume_down", function(event){
toast("程序结束");
exit();
});

task();

loop();

function task1(){
toast("任务1运行中,音量下键结束,音量上键切换任务");
setTimeout(task, interval);
}

function task2(){
toast("任务2运行中,音量下键结束,音量上键切换任务");
setTimeout(task, interval);
}

56、事件与按键、触摸监听:长按返回退出当前程序

本课视频

"auto";

var 长按间隔 = 1500;

var curPackage = null;
var timeoutId = null;

events.observeKey();

events.onKeyDown("back", function(event){
curPackage = currentPackage();
timeoutId = setTimeout(function(){
backBackBackBack();
}, 长按间隔);
});

events.onKeyUp("back", function(event){
clearTimeout(timeoutId);
});

loop();

function backBackBackBack(){
while(curPackage == currentPackage()){
back();
sleep(200);
}
}

57、事件与按键、触摸监听:Toast监听

本课视频

auto();
events.observeToast();

events.onToast(function(toast){

var pkg = toast.getPackageName();
log("Toast内容: " + toast.getText() +
" 来自: " + getAppName(pkg) +
" 包名: " + pkg);

});
toast("监听中,请在日志中查看记录的Toast及其内容");

58、图片与图色处理:获取网络图片并保存

本课视频

//这个是Auto.js图标的地址
var url = "https://www.autojs.org/assets/uploads/profile/3-profileavatar.png";

var logo = images.load(url);

//保存到路径/sdcard/auto.js.png
images.save(logo, "/sdcard/auto.js.png");

/* 保存到系统相册 */
media.scanFile("/sdcard/1.jpg")

59、图片与图色处理:截图并保存

本课视频

if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
images.saveImage(img, "/sdcard/1.png");

60、图片与图色处理:精确找色

本课视频

if(!requestScreenCapture()){
toast("请求截图失败");
stop();
}
var img = captureScreen();
toastLog("开始找色");

//0x1d75b3为编辑器默认主题蓝色字体(if, var等关键字)的颜色
//找到颜色与0x1d75b3完全相等的颜色

var point = findColorEquals(img, 0x006699);

if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}

61、图片与图色处理:模糊找色

本课视频

if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
//0x9966ff为编辑器紫色字体的颜色
toastLog("开始找色");
var point = findColor(img, 0x9966ff);
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}

62、图片与图色处理:区域找色1

本课视频

if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
toastLog("开始找色");
//指定在位置(100, 220)宽高为400*400的区域找色。
//#75438a是编辑器默认主题的棕红色字体(数字)颜色,位置大约在第5行的"2000",坐标大约为(283, 465)

var point = findColorInRegion(img, "#75438a", 90, 220, 900, 1000);

if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}

63、图片与图色处理:区域找色2

本课视频

if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
//0xffffff为白色
toastLog("开始找色");
//指定在位置(90, 220)宽高为900*1000的区域找色。
//0xff00cc是编辑器的深粉红色字体(字符串)颜色
var point = findColor(img, "#ff00cc", {
region: [90, 220, 900, 1000],
threads: 8
});
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}

64、图片与图色处理:实时显示触摸点颜色

本课视频

requestScreenCapture();
console.show();
events.observeTouch();
events.setTouchEventTimeout(30);
events.on("touch", function(point){
var c = colors.toString(images.pixel(captureScreen(), point.x, point.y));
log("(" + point.x + ", " + point.y + "): " + c);
});

65、图片与图色处理:图片处理

本课视频

"ui";

var url = "https://www.autojs.org/assets/uploads/files/1540386817060-918021-20160416200702191-185324559.jpg";
var logo = null;
var currentImg = null;

events.on("exit", function(){
if(logo != null){
logo.recycle();
}
if(currentImg != null){
currentImg.recycle();
}
});

ui.layout(
<vertical>
<img id="img" w="250" h="250" url="{{url}}" />
<scroll>
<vertical>
<button id="rotate" text="旋转" />
<button id="concat" text="拼接" />
<button id="grayscale" text="灰度化" />
<button id="binary" text="二值化" />
<button id="adaptiveBinary" text="自适应二值化" />
<button id="hsv" text="RGB转HSV" />
<button id="blur" text="模糊" />
<button id="medianBlur" text="中值滤波" />
<button id="gaussianBlur" text="高斯模糊" />
</vertical>
</scroll>
</vertical>
);

//把一张图片设置到图片控件中
function setImage(img) {
ui.run(() => {
ui.img.setImageBitmap(img.bitmap);
var oldImg = currentImg;
//不能立即回收currentImg,因为此时img控件还在使用它,应该在下次消息循环再回收它
ui.post(()=>{
if(oldImg != null){
oldImg.recycle();
}
});
currentImg = img;
});
}

//启动一个处理图片的线程
var imgProcess = threads.start(function () {
setInterval(() => { }, 1000);
});

//处理图片的函数,把任务交给图片处理线程处理
function processImg(process) {
imgProcess.setTimeout(() => {
if (logo == null) {
logo = images.load(url);
}
//处理图片
var result = process(logo);
//把处理后的图片设置到图片控件中
setImage(result);
}, 0);
}

var degress = 0;

ui.rotate.on("click", () => {
processImg(img => {
degress += 90;
//旋转degress角度
return images.rotate(img, degress);
});
});

ui.concat.on("click", () => {
processImg(img => {
if(currentImg == null){
toast("请先点击其他按钮,再点击本按钮");
return img.clone();
}
//把currentImg拼接在img右边
return images.concat(img, currentImg, "right");
});
});

ui.grayscale.on("click", () => {
processImg(img => {
//灰度化
return images.grayscale(img);
});
});

ui.binary.on("click", () => {
processImg(img => {
var g = images.grayscale(img);
//二值化,取灰度为30到200之间的图片
var result = images.threshold(g, 100, 200);
g.recycle();
return result;
});
});

ui.adaptiveBinary.on("click", () => {
processImg(img => {
var g = images.grayscale(img);
//自适应二值化,最大值为200,块大小为25
var result = images.adaptiveThreshold(g, 200, "MEAN_C", "BINARY", 25, 10);
g.recycle();
return result;
});
});

ui.hsv.on("click", () => {
processImg(img => {
//RGB转HSV
return images.cvtColor(img, "BGR2HSV");
});
});

ui.blur.on("click", () => {
processImg(img => {
//模糊
return images.blur(img, [10, 10]);
});
});

ui.medianBlur.on("click", () => {
processImg(img => {
//中值滤波
return images.medianBlur(img, 5);
});
});

ui.gaussianBlur.on("click", () => {
processImg(img => {
//高斯模糊
return images.gaussianBlur(img, [5, 5]);
});
});

66、图片与图色处理:颜色获取和检测

本课视频

if(!requestScreenCapture()){
toast("请求截图失败");
exit
}
sleep(2000);
var x = 760;
var y = 180;
//获取在点(x, y)处的颜色
var c = images.pixel(captureScreen(), x, y);
//显示该颜色
var msg = "";
msg += "在位置(" + x + ", " + y + ")处的颜色为" + colors.toString(c);
msg += "\nR = " + colors.red(c) + ", G = " + colors.green(c) + ", B = " + colors.blue(c);
//检测在点(x, y)处是否有颜色#73bdb6 (模糊比较)
var isDetected = images.detectsColor(captureScreen(), "#73bdb6", x, y);
msg += "\n该位置是否匹配到颜色#73bdb6: " + isDetected;
alert(msg);

67、图片与图色处理:找到QQ红点位置

本课视频

if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
launchApp("QQ");
sleep(2000);
var img = captureScreen();
toastLog("开始找色");
var point = findColor(img, "#f64d30");
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}

68、图片与图色处理:找图

本课视频

  1. 找出马里奥
var superMario = images.read("./super_mario.jpg");
var mario = images.read("./mario.png");
var point = findImage(superMario, mario);
toastLog(point);

superMario.recycle();
mario.recycle();
  1. 找出问号
var superMario = images.read("./super_mario.jpg");
var block = images.read("./block.png");

var result = images.matchTemplate(superMario, block, {
threshold: 0.8
}).matches;
toastLog(result);

superMario.recycle();
block.recycle();

3、

var superMario = images.read("./super_mario.jpg");
var block = images.read("./block.png");
var points = images.matchTemplate(superMario, block, {
threshold: 0.8
}).points;

toastLog(points);

var canvas = new Canvas(superMario);
var paint = new Paint();
paint.setColor(colors.parseColor("#2196F3"));
points.forEach(point => {
canvas.drawRect(point.x, point.y, point.x + block.width, point.y + block.height, paint);
});
var image = canvas.toImage();
images.save(image, "/sdcard/tmp.png");

app.viewFile("/sdcard/tmp.png");

superMario.recycle();
block.recycle();
image.recycle();

69、文件读写:读取文本文件

本课视频

//文件路径
var path = "/sdcard/1.txt";
//打开文件
var file = open(path);
//读取文件的所有内容
var text = file.read();
//打印到控制台
print(text);
//关闭文件
file.close();
console.show();

70、文件读写:读写文本文件

本课视频

//以写入模式打开SD卡根目录文件1.txt
var file = open("/sdcard/1.txt", "w")
//写入aaaa
file.write("aaaa");
//写入bbbbb后换行
file.writeline("bbbbb");
//写入ccc与ddd两行
file.writelines(["ccc", "ddd"]);
//关闭文件
file.close();

//以附加模式打开文件
file = open("/sdcard/1.txt", "a");
//附加一行"啦啦啦啦"
file.writeline("啦啦啦啦");
//附加一行"哈哈哈哈"
file.writeline("哈哈哈哈");
//附加两行ccc, ddd
file.writelines(["ccc", "ddd"]);
//输出缓冲区
file.flush();
//关闭文件
file.close();


//以读取模式打开文件
file = open("/sdcard/1.txt", "r")
//读取一行并打印
var arr = file.readlines();


//读取剩余所有行并打印
arr.forEach(line => {
print(line)
})
file.close()

//显示控制台
console.show()

71、文件读写:删除所有空文件夹

本课视频

if(confirm("该操作会删除SD卡目录及其子目录下所有空文件夹,是否继续?")){
toast("请点击右上角打开日志");
deleteAllEmptyDirs(files.getSdcardPath());
toast("全部完成!");
}

function deleteAllEmptyDirs(dir){
var list = files.listDir(dir);
var len = list.length;
if(len == 0){
log("删除目录 " + dir + " " + (files.remove(dir) ? "成功" : "失败"));
return;
}
for(let i = 0; i < len; i++){
var child = files.join(dir, list[i]);
if(files.isDir(child)){
deleteAllEmptyDirs(child);
}
}
}

72、文件读写:文件编码转换

本课视频

//以UTF-8编码打开SD卡上的1.txt文件
var f = open("/sdcard/1.txt", "r", "utf-8");
//读取文件所有内容
var text = f.read();
//关闭文件
f.close();

//以gbk编码打开SD卡上的2.txt文件
var out = open("/sdcard/2.txt", "w", "gbk");
//写入内容
out.write(text);
//关闭文件
out.close();

73、文件读写:文件编码转换(高级)

本课视频

convert("/sdcard/1.txt", "utf-8", "/sdcard/2.txt", "gbk");

/**
* fromFile: 源文件路径
* fromEncoding: 源文件编码
* toFile: 输出文件路径
* toEncoding: 输出文件编码
*/
function convert(fromFile, fromEncoding, toFile, toEncoding){
fromFile = open(fromFile, "r", fromEncoding);
toFile = open(toFile, "w", toEncoding);
while(true){
var line = fromFile.readline();
if(!line)
break;
toFile.writeline(line);
}
fromFile.close()
toFile.close()
}

74、文件读写:写入文本文件

本课视频

//文件路径
var path = "/sdcard/1.txt";
//要写入的文件内容
var text = "Hello, AutoJs";
//以写入模式打开文件
var file = open(path, "w");
//写入文件
file.write(text);
//关闭文件
file.close();

75、协程:协程HelloWorld

本课视频

"useFeatures": ["continuation"]
// 注意,要使用协程这个特性,必须使用项目功能,并且在project.json配置好features属性


// delay不同于sleep,不会阻塞当前线程
function delay(millis) {
var cont = continuation.create();
setTimeout(()=>{
cont.resume();
}, millis);
cont.await();
}

// 异步IO例子,在另一个线程读取文件,读取完成后返回当前线程继续执行
function read(path) {
var cont = continuation.create();
threads.start(function(){
try {
cont.resume(files.read(path));
}catch(err){
cont.resumeError(err);
}
});
return cont.await();
}

// 使用Promise和协程的例子
function add(a, b) {
return new Promise(function(resolve, reject) {
var sum = a + b;
resolve(sum);
});
}

toastLog("Hello, Continuation!");

//3秒后发出提示
setTimeout(()=>{
toastLog("3秒后....");
}, 3000);

// 你可以尝试把delay更换成sleep,看会发生什么!
delay(6000);
toastLog("6秒后...");

try {
toastLog("读取文件hello.txt: " + read("./hello.txt"));
}catch(err){
console.error(err);
}

var sum = add(1, 2).await();
toastLog("1 + 2 = " + sum);

76、协程:ui中使用协程

本课视频

"ui";

ui.layout(
<frame bg="#4fc3f7">
<text textColor="white" textSize="18sp" layout_gravity="center">
UI中使用协程
</text>
</frame>
);

continuation.delay(5000);
if (!requestScreenCapture()) {
dialogs.alert("请授予软件截图权限").await();
}

// 退出应用对话框
ui.emitter.on("back_pressed", function (e) {
e.consumed = true;
let exit = dialogs.confirm("确定要退出程序").await();
if (exit) {
ui.finish();
}
});

77、悬浮窗:动态悬浮文字

本课视频

var window = floaty.window(
<frame gravity="center">
<text id="text" textSize="16sp" textColor="#f44336"/>
</frame>
);

window.exitOnClose();

window.text.click(()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
});

setInterval(()=>{
//对控件的操作需要在UI线程中执行
ui.run(function(){
window.text.setText(dynamicText());
});
}, 1000);

function dynamicText(){
var date = new Date();
var str = util.format("时间: %d:%d:%d\n", date.getHours(), date.getMinutes(), date.getSeconds());
str += util.format("内存使用量: %d%%\n", getMemoryUsage());
str += "当前活动: " + currentActivity() + "\n";
str += "当前包名: " + currentPackage();
return str;
}

//获取内存使用率
function getMemoryUsage(){
var usage = (100 * device.getAvailMem() / device.getTotalMem());
//保留一位小数
return Math.round(usage * 10) / 10;
}

78、悬浮窗:护眼模式

本课视频

var w = floaty.rawWindow(
<frame gravity="center" bg="#44ffcc00"/>
);

w.setSize(-1, -1);
w.setTouchable(false);

setTimeout(()=>{
w.close();
}, 60000);

79、悬浮窗:悬浮窗输入框

本课视频

var window = floaty.window(
<vertical>
<input id="input" text="请输入你的名字" textSize="16sp" focusable="true"/>
<button id="ok" text="确定"/>
</vertical>
);

window.exitOnClose();

toast("长按确定键可调整位置");

window.input.on("key", function(keyCode, event){
if(event.getAction() == event.ACTION_DOWN && keyCode == keys.back){
window.disableFocus();
event.consumed = true;
}
});

window.input.on("touch_down", ()=>{
window.requestFocus();
window.input.requestFocus();
});

window.ok.on("click", ()=>{
toast("傻瓜! " + window.input.text());
window.disableFocus();
});

window.ok.on("long_click", ()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
});

setInterval(()=>{}, 1000);

80、悬浮窗:悬浮窗运行脚本按钮简单版

本课视频

var path = "/sdcard/脚本/test.js";
if(!files.exists(path)){
toast("脚本文件不存在: " + path);
exit();
}
var window = floaty.window(
<frame>
<button id="action" text="开始运行" w="90" h="40" bg="#77ffffff"/>
</frame>
);

window.exitOnClose();

var execution = null;

window.action.click(()=>{
if(window.action.getText() == '开始运行'){
execution = engines.execScriptFile(path);
window.action.setText('停止运行');
}else{
if(execution){
execution.getEngine().forceStop();
}
window.action.setText('开始运行');
}
});

window.action.longClick(()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
return true;
});

setInterval(()=>{}, 1000);

81、悬浮窗:悬浮文字

本课视频

var window = floaty.window(
<frame gravity="center">
<text id="text" text="点击可调整位置" textSize="16sp"/>
</frame>
);

window.exitOnClose();

window.text.click(()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
});

setInterval(()=>{}, 1000);

82、悬浮窗:悬浮运行脚本按钮

本课视频

var path = "/sdcard/脚本/test.js";
if(!files.exists(path)){
toast("脚本文件不存在: " + path);
exit();
}
var window = floaty.window(
<frame>
<button id="action" text="开始运行" w="90" h="40" bg="#77ffffff"/>
</frame>
);

setInterval(()=>{}, 1000);

var execution = null;

//记录按键被按下时的触摸坐标
var x = 0, y = 0;
//记录按键被按下时的悬浮窗位置
var windowX, windowY;
//记录按键被按下的时间以便判断长按等动作
var downTime;

window.action.setOnTouchListener(function(view, event){
switch(event.getAction()){
case event.ACTION_DOWN:
x = event.getRawX();
y = event.getRawY();
windowX = window.getX();
windowY = window.getY();
downTime = new Date().getTime();
return true;
case event.ACTION_MOVE:
//移动手指时调整悬浮窗位置
window.setPosition(windowX + (event.getRawX() - x),
windowY + (event.getRawY() - y));
//如果按下的时间超过1.5秒判断为长按,退出脚本
if(new Date().getTime() - downTime > 1500){
exit();
}
return true;
case event.ACTION_UP:
//手指弹起时如果偏移很小则判断为点击
if(Math.abs(event.getRawY() - y) < 5 && Math.abs(event.getRawX() - x) < 5){
onClick();
}
return true;
}
return true;
});

function onClick(){
if(window.action.getText() == '开始运行'){
execution = engines.execScriptFile(path);
window.action.setText('停止运行');
}else{
if(execution){
execution.getEngine().forceStop();
}
window.action.setText('开始运行');
}
}

83、应用:打开应用

本课视频

var appName = rawInput("请输入应用名称");
launchApp(appName);

//启动微信
launch("com.tencent.mm");

84、应用:发送意图-文本消息分享

本课视频

var content = rawInput('请输入要分享的文本');
app.startActivity({
action: "android.intent.action.SEND",
type: "text/*",
extras: {
"android.intent.extra.TEXT": content
},
packageName: "com.tencent.mobileqq",
className: "com.tencent.mobileqq.activity.JumpActivity"
});

85、应用:强制停止应用

本课视频

"auto";

var appName = rawInput("请输入应用名称");
openAppSetting(getPackageName(appName));
while(!click("强制停止"));

86、应用:卸载应用

本课视频

//输入应用名称
var appName = rawInput('请输入要卸载的应用名称');
//获取应用包名
var packageName = getPackageName(appName);
if(!packageName){
toast("应用不存在!");
}else{
//卸载应用
app.uninstall(packageName);
}

87、应用:应用工具

本课视频

var i = dialogs.select("请选择工具", "获取应用包名", "打开应用详情页", "卸载应用");

if(i == -1){
alert("没有选择任何工具!");
}

switch(i){
case 0:
//获取应用包名
appName = rawInput("请输入应用名称", "QQ");
packageName = getPackageName(appName);
toast(packageName);
setClip(packageName);
toast("已复制到剪贴板");
break;
case 1:
//打开应用详情页
appName = rawInput("请输入应用名称", "微信");
openAppSetting(getPackageName(appName));
break;
case 2:
//卸载应用
appName = rawInput("请输入应用名称");
packageName = getPackageName(appName);
if(packageName == ""){
toast("应用不存在");
}else if(confirm("确定卸载应用" + packageName + "吗?")){
app.uninstall(packageName);
}
break;
}