diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..01096b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# Built application files +*.apk +*.ap_ +*.rar +*.zip + +# Files for the Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +obj/ + +# Eclipse Generate files +.classpath +.project +.settings/ + + +# Gradle files +*.iml +.gradle/ +build/ +/*/build/ +app/.externalNativeBuild/ +app/src/main/libs/ + +# Local configuration file (sdk path, etc) +local.properties +gradle.properties +*.keystore + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Make +build*/ + +# Android Studio +.idea/* diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..ebbb924 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,20 @@ +Androlua 1.0 Copyright (C) 2011 by Michal Kottman +Androlua+ 3.0 Copyright (C) 2015-2016 by Nirenr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4a977f --- /dev/null +++ b/README.md @@ -0,0 +1,1179 @@ +# AndLuaX+ +AndLuaX+是基于开源框架AndroLua+开发的第三方编辑器,内置LuaFileSysteam库 +基于AndroLua+5.0.8版本 +[AndroLua_pro](https://github.com/nirenr/AndroLua_pro) +比原版[AndroLua](https://github.com/mkottman/AndroLua)的运行速度快了不少 +# AndroLua- +lua 5.3.3 for android pro + +5.0.8 +bug修复。 + +5.0.7 +修复switch的bug。 + +5.0.6 +修复bug。 + +5.0.5 +修复http异步上传的bug。 + +5.0.4 +修复http异步编码bug。 + +5.0.3 +bug修复。 + +5.0.2 +优化编辑器。 + +5.0.1 +bug修复。 + +5.0.0 +解决65000对象引用问题 + +4.4.4 +支持变长参数。 +bug 修复。 + +4.4.3 +bug 修复。 + +4.4.2 +bug 修复。 + +4.4.1 +switch case 支持多个值。 + +4.4.0 +bug 修复。 + +4.3.6 +bug 修复。 + +4.3.5 +支持有参数构建函数的虚类。 + +4.3.4 +增加table.const(常量表)。 +增加数组a=[]。 + +4.3.3 +增加when(单行判断语句)。 + +4.3.2 +增加bsh(测试)。 + +4.3.1 +增加一些函数。 + +4.3.0 +增加lambda关键字。 +增加defer延时执行。 +增加toclose自关闭局部变量,变量名前加*。 + +4.2.6 +os.date支持64位时间。 + +4.2.5 +io增加部分函数。 + +4.2.4 +table增加部分函数。 + +4.2.3 +增加luajava.override。 +增加使用关键字作table的key。 + +4.2.2 +修复setSharedData bug。 + +4.2.1 +优化多维数组。 +增加luajava.astable(obk,true)深转换。 + +4.2.0 +支持虚类。 + +4.1.9 +优化Http返回值。 + +4.1.8 +优化HorizontalListView。 +布局表支持GIF背景图设置。 + +4.1.7 +优化HorizontalListView。 +优化日志查看。 + +4.1.6 +增加activity.stopService()方法。 +修复activity.startService()方法。 + +4.1.5 +增加activity.getLuaResources()方法。 +优化LuaResources。 + +4.1.4 +增加androlua://package name/path?key=value uri支持。 + +4.1.3 +修复FileProvider bug。 +修复LuaBitmapDrawable bug。 +最近任务可变标题与图标。 +第一次运行获得权限。 + +4.1.2 +setter支持多个参数。 + +4.1.1 +Http post增加一些方法。 +浮点数比较使用近似值。 + +4.1.0 +适配安卓P。 + +4.0.25 +增加LuaBitmapDrawable,支持jpg,png,gif,bmp等。 +支持设置网络图片缓存时间。 + +4.0.24 +优化强制类型处理。 +优化错误信息。 + +4.0.23 +优化HorizontalListView。 +可以省略所有仅使用Context的构建方法的参数。 + +4.0.22 +优化PageView,增加PageAdapter。 +增加HorizontalListView。 + +4.0.21 +优化task最多支持1024线程,128并行。 + +4.0.20 +一些更新。 + +4.0.19 +修复格式化bug。 +LuaEditor增加addPackage方法。 + +4.0.18 +省略Dialog的context参数。 + +4.0.17 +修复获取内部类缓存bug。 + +4.0.16 +修复高亮异常。 + +4.0.15 +修复setter参数为table时意外错误的bug。 + +4.0.14 +增加LuaPreferenceFragment。 + +4.0.13 +修复bug。 + +4.0.12 +编辑器增加块区间线。 + +4.0.11 +优化自动换行。 +优化高亮。 + +4.0.10 +优化自动换行。 +优化LuaAdapter。 + +4.0.9 +优化getter/setter效率。 +优化单参数无参数方法效率。 + +4.0.8 +优化布局助手。 +优化布局表对style支持。 + +4.0.7 +优化LuaDialog。 +增加多属性赋值语句。 + +4.0.6 +修复第一次初始化过慢bug。 + +4.0.5 +增加设置luaExtDir方法。 +修复部分bug。 + +4.0.4 +优化lua字符串U码使用。 +支持鼠标滚轮滚动。 +修复部分bug。 + +4.0.3 +兼容旧版main入口。 +增加luajava.getContext()函数。 +activity增加部分api。 +修复部分bug。 + +4.0.2 +修复部分bug。 + +4.0.1 +优化import对环境影响。 +修复部分bug。 + +4.0.0 +升级为lua 5.4随机数算法。 +修复lua部分bug。 + +4.0.0 rc4 +增加__type元方法。 +修复switch case bug。 + +4.0.0 rc3 +增加continue。 + +4.0.0 rc2 +一些优化。 + +4.0.0 alpha4 +使用增强的utf8模块。 +增加简化lambda表达式。 + +4.0.0 alpha3 +优化switch case。 + +4.0.0 alpha2 +可选择省略then do。 +增加switch case。 + +4.0.0 rc1 +修复activity缓存的bug。 + +4.0.0 beta4 +修复载入dex缓存的bug。 + +4.0.0 beta3 +模拟滑动支持指定path +bug修复。 + +4.0.0 beta2 +修复打包不能安装bug。 + +4.0.0 beta +修复安卓8不能打包bug。 + +4.0.0 alpha +优化辅助功能,支持监听按键,模拟点击,模拟触摸,截图等功能。 +增加ColorFinder类,用于颜色查找。 +修复loadbitmap分辨率异常的bug。 + +3.6.5 +修复参数转换bug。 + +3.6.4 +修复导入分析不能的bug。 +修复执行子目录文件的bug。 +支持画中画模式。 +修复适配器搜索的bug。 + +3.6.3 +修复参数转换bug。 + +3.6.2 +适配全面屏。 +支持分屏。 +增加getUriForPath/getUriForFile方法。 +增强超级辅助。 + +3.6.1 +优化辅助功能超级辅助。 + +3.6.0 +修复finish activity可能导致程序退出的bug。 +修复运行内嵌子工程引用目录混乱的bug。 +增强辅助功能超级辅助。\ + +3.5.9 +修复华为看不到log的bug。 +追加适配器过滤器。 +增加辅助功能超级辅助。 + +3.5.8 +修复bug。 + +3.5.7 +修复子目录导入bug。 + +3.5.6 +增加LuaContentObserver。 + +3.5.5 +增加LuaFileObserver。 + +3.5.4 +增加getActivity方法。 + +3.5.3 +增加LuaServer/LuaClient。 +bug修复。 + +3.5.2 +修复异步Http不能获取错误请求详细信息的bug。 +import增加一次导入多个包功能。 + +3.5 +增加代码加密。 + +3.4.5 +增加多窗口功能。 + +3.4.3 +增加与活动文件同名函数回调,方便处理传入参数。 +修复统计sdk读取app id一处bug。 + +3.4.2 +增加百度移动统计与错误反馈。 +bug修复。 + +3.4.1 +增加共享数据getSharedData/setSharedData方法。 +bug修复。 + +3.4.0 +增加LuaResources。 + +3.3.5 +增加辅助功能回调函数onAccessibilityEvent。 +修复bug。 +3.3.4 + +增加LuaMultiAdapter适配器。 +优化RippleLayout。 +回滚编辑器实现。 +支持修改工程版本号和SDK版本。 +支持设置关联文件。 +优化权限选择提示。 +修复bug。 + +3.3.3 +增加打包时编译自带模块。 +优化RippleLayout效果。 +优化编辑器高亮解析速度。 +优化PullingLayout效果。 +优化LuaDrawable和LuaAnimation实现。 +getter支持isxxx简写。 +LuaWebView支持打开第三方应用。 +LuaWebView支持处理SSL错误。 +bug修复。 + +3.3.2 +增加LuaDialog。 +修复RippleLayout连续点击效果异常的bug。 +修复部分工程不能导入布局的bug。 +增加方法调用时函数自动转为接口。 + +3.3.1 +增加RippleLayout圆形扩散效果。 +修复布局助手不能查看子视图的bug。 + +3.3 +优化setter效率提高800%。 +优化适配器数据格式,支持首字母小写。 +优化编辑器效率。 +更新帮助。 +bug修复。 + +3.2.6 +优化setter/getter,支持首字母小写。 +优化异步Http多线程。 +优化异步task多线程。 +优化LuaArrayAdapter图片显示效果。 +优化编辑器。 +修复LuaUtil.zip压缩文件错误的bug。 +优化bmob用户登录。 +bug修复。 + +3.2.5 +去除无用权限。 +优化编辑器。 +优化RippleLayout效果。 +优化错误信息。 +LuaContext增加getGlobalData()方法。 +修复LuaThread函数调用两次的bug。 +增强loadlayout容错。 +增加导入分析。 +修复安卓7.x打包bug。 +bug修复。 + +3.2.4 +修复悬浮窗焦点切换无效的bug。 + +3.2.3 +关联alp文件。 +增加简单test功能。 +修复bug。 + +3.2.2 +优化FloatWindow焦点切换。 +修复bug。 + +3.2.1 +增加RippleLayout。 +增加LuaExpandableListAdapter适配器。 +优化ToolBar显示效果。 +修复垃圾回收bug。 +修复jar资源加载异常的bug。 + +3.2 +更新Lua5.3.3。 +增加onVersionChanged回调函数。 +增加onResult回调函数。 +优化搜索选中效果。 +增加ide支持高亮与补全Java类。 +修复横竖屏切换bug。 +增加Http异步网络模块。 +修复在最左边删除,看不到待删除字符的问题。 +修复ToolBar不能设置空白标题的bug。 +优化PageLayouts与SlidingLayout. +增加PullingLayout布局。 +增加线程自动回收机制。 +增加PageView。 +增加LuaFragment。 +增加级联风格调用。 +修复未实现接口函数调用出错的bug。 +增加支持自动导入libs目录so模块。 +增加支持TextView跑马灯。 +修复加载dex异常的bug。 +增加设置壁纸权限。 +优化task用法,自动导入外部代码导入的包与类。 +优化启动闪图逻辑。 +增加启动图不全屏时,自动适应空白区域颜色。 +优化内核,性能提高40%。 +优化打开工程逻辑。 +打开工程支持搜索。 +增加比例尺寸。 +优化log显示效果。 +优化第一次启动闪图效果。 +增加ide最近打开功能。 +增加记录最近打开文件光标位置功能。 +更新帮助。 + +3.1 +增加可视布局设计器, +升级内核,速度提高20%, +http模块支持自定义UA与header +优化luajava错误提示, +增加工程导出/导入, +修复打开文件的bug, +增加后台服务, +优化错误提示, +修复类型转换bug, +增加Ticker主线程回调定时器, +编辑器自动夜间模式, +编辑器支持自定义配色, +增加导入dex函数, +loadbitmap加载网络图片支持本地缓存, +LuaArrayAdapter和LuaAdapter适配器支持异步加载图片与缓存, +增加Java方法浏览器, +增加导包提示, + +3.0.0 +支持打包apk的权限配置, +增加Map对象的简洁使用, +完善luajavaa.astable函数,全面支持array List Map, +增加在方法调用时Lua表自动转换为Java数组或接口, +增加LuaArrayAdapter和LuaAdapter适配器, +LuaWebView支WebClient,在js调用Lua函数, +timer支持设置时间间隔, +newActivity支持传递参数, +http增加download和upload, +日志支持清除, +Java方法支持table与array,map与interface自动转换, +增强取长度运算符,可以获取Java对象大小, +更换运行方式, +支持打包文件夹, +打包自动分析使用的c模块, +增加tointeger函数, +setContentView支持布局表参数, + +2.1.0 +去除广告,欢迎捐赠, +修复接口方法错误无法显示错误信息的问题, +修复import函数一处逻辑错误, +修复onKeyDown等回调方法不能返回值的bug, +优化luajava性能, +优化IDE编辑器性能, +修复IDE打开文件bug, +增加setXXXListener控件事件快速设置, +重写task与thread函数 +增加timer函数, +修复数字类型转换bug, +增加查看logcat输出功能, +布局表支持绝对布局, +布局表支持ListView预设项目, +布局表支持style属性, +布局表支持?android获取系统资源, +修复astable索引0的bug, +IDE增加函数导航, +IDE增加搜索与转到, + +2.0.4 +增加luajava.astable方法, +增加each与enum迭代器 +布局表支持相对布局, +布局表gravity属性支持或( | )操作, +优化IDE逻辑, + +2.0.3 +修复IDE布局bug + +2.0.2 +增加getter与setter快速调用,用于简化控件属性设置, +修复Java方法返回null没有返回值的bug, +更新布局表算法,支持布局间距, +优化Java方法缓存机制,效率提高一倍,布局表效率提高8倍, + +2.0.1 +布局表增加自绘制背景, +修复自动缩进算法错误, +增加百度广告,仅在打包时出现,不影响使用,希望大家支持, + +2.0 +更新Lua5.3.1, +更新luajava3.0, +增加打包apk功能, +增加布局表, +增加线程, +增加更多回调方法, +更新支持高亮,自动缩进,自动补全编辑器, + + +关于 +AndroLua是基于LuaJava开发的安卓平台轻量级脚本编程语言工具,既具有Lua简洁优雅的特质,又支持绝大部分安卓API,可以使你在手机上快速编写小型应用。 +官方QQ群:236938279 +http://jq.qq.com/?_wv=1027&k=dcofRr +百度贴吧: +http://c.tieba.baidu.com/mo/m?kw=androlua +项目地址: +http://sf.net/p/androlua +点击链接支持我的工作,一块也可以哦: +https://qr.alipay.com/apt7ujjb4jngmu3z9a + +本程序使用了以下开源项目部分代码 + +bson,crypt,md5 +https://github.com/cloudwu/skynet + +cjson +https://sourceforge.net/projects/cjson/ + +zlib +https://github.com/brimworks/lua-zlib + +xml +https://github.com/chukong/quick-cocos2d-x + +luv +https://github.com/luvit/luv +https://github.com/clibs/uv + +zip +https://github.com/brimworks/lua-zip +https://github.com/julienr/libzip-android + +luagl +http://luagl.sourceforge.net/ + +luasocket +https://github.com/diegonehab/luasocket + +sensor +https://github.com/ddlee/AndroidLuaActivity + +canvas +由落叶似秋开发 + +jni +由nirenr开发 + + +与标准Lua5.3.1的不同 +打开了部分兼容选项,module,unpack,bit32 +添加string.gfind函数,用于递归返回匹配位置 +增加tointeger函数,强制将数值转为整数 +修改tonumber支持转换Java对象 + +1,参考链接 +关于lua的语法和Android API请参考以下网页。 +Lua官网: +http://www.lua.org +Android 中文API: +http://android.toolib.net/reference/packages.html + +2,导入模块 +在每个脚本程序的开头应该写上 require "import" 以导入import模块,简化写代码的难度。目前程序内置bson,canvas,cjson,crypt,ftp,gl,http,import,md5,smtp,socket,sensor,xml,zip,zlib。 + +3,导入包或类 +可以导入包或者类 +import "android.widget.*" +import "android.widget.Button" +导入内部类 +import "android.view.View_*" +或 +import "android.view.View_OnClickListener" +或 +View.OnClickListene +包名和类名必须用引号包围。 + +4,创建布局与组件 +layout=LinearLayout(activity) +activity.setContentView(layout) +button=Button(activity) +layout.addView(button) +注.activity是当前窗口的Context对象,如果习惯写this只需要 +this=activity +button=Button(this) + +5,使用方法 +button.setText("按钮") + +getter/setter +Java的getxxx方法没有参数与setxxx方法只有一个参数时可以简写, +button.Text="按钮" +x=button.X + +6,使用事件 +创建事件处理函数 +function click(s) +print("点击") +end +把函数添加到事件接口 +listener=View.OnClickListener{onClick = click} +把接口注册到组件 +button.setOnClickListener(listener) + +也可以使用匿名函数 +button.setOnClickListener(View.OnClickListener {onClick = function(s) +print("点击") +end +}) + +onxxx事件可以简写 +button.onClick=function(v) +print(v) +end + +7,回调方法 +function onResume() +print("返回程序") +end +function onDestroy() +print("程序已退出") +end +function onCreateOptionsMenu(menu) +menu.add("菜单") +end +支持onCreate,onStart,onResume,onPause,onStop,onDestroy,onActivityResult,onCreateOptionsMenu,onCreateContextMenu,onMenuItemSelected + +8,按键与触控 +function onKeyDown(code,event) +print(code event) +end +function onTouchEvent(event) +print(event) +end +支持onKeyDown,onKeyUp,onKeyLongPress,onTouchEvent +函数必须返布尔值 + +9,使用数组 +array=float{1,2,3} +或者 +array=int[10] +a=array[0] +array[0]=4 + +10,使用线程 +需导入import模块,参看thread,timer与task函数说明 +任务 + +task(str,args,callback) + +str 为任务执行代码,args 为参数,callback 为回调函数,任务返回值将传递到回调方法 +线程 + +t=thread(str,args) + +str 为线程中执行的代码,args 为初始传入参数 +调用线程中方法 +call(t,fn,args) +t 为线程,fn 为方法名称,args 为参数 +设置线程变量 +set(t,fn,arg) +t 为线程,fn 为变量名称,arg 为变量值 +线程调用主线程中方法 +call(fn,args) +fn 为方法名称,args 为参数 +线程设置主线程变量 +set(fn,arg) +fn 为变量名称,arg 为变量值 + +注. 参数类型为 字符串,数值,Java对象,布尔值与nil +线程要使用quit结束线程。 + +t=timer(func,delay,period,args) + +func 为定时器执行的函数,delay 为定时器延时,period 为定时器间隔,args 为初始化参数 +t.Enable=false 暂停定时器 +t.Enable=true 启动定时器 +t.stop() 停止定时器 + +注意:定时器函数定义run函数时定时器重复执行run函数,否则重复执行构建时的func函数 + +11,使用布局表 +使用布局表须导入android.view与android.widget包。 +require "import" +import "android.widget.*" +import "android.view.*" +布局表格式 +layout={ +控件名称, +id=控件名称, +属性=值, +{ +子控件名称, +id=控件名称, +属性=值, +} +} + +布局表支持大全部安卓控件属性, +与安卓XML布局文件的不同点: +id表示在Lua中变量的名称,而不是安卓的可以findbyid的数字id。 +ImageView的src属性是当前目录图片名称或绝对文件路径图片或网络上的图片, +layout_width与layout_height的值支持fill与wrap简写, +onClick值为lua函数或java onClick接口或他们的全局变量名称, +背景background支持背景图片,背景色与LuaDrawable自绘制背景,背景图片参数为是当前目录图片名称或绝对文件路径图片或网络上的图片,颜色同backgroundColor,自绘制背景参数为绘制函数或绘制函数的全局变量名称, +绘制函数形式 +function draw(canvas,paint) +canvas.drawRect(1,1,100,100,paint) +end +控件背景色使用backgroundColor设置,值为"十六进制颜色值"。 +其他参考loadlayout与loadbitmap + +12,2D绘图 +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "android.graphics.*" +activity.setTitle('AndroLua') + +paint=Paint() +paint.setARGB(100,0,250,0) +paint.setStrokeWidth(20) +paint.setTextSize(28) + +sureface = SurfaceView(activity); +callback=SurfaceHolder_Callback{ +surfaceChanged=function(holder,format,width,height) +end, +surfaceCreated=function(holder) +ca=holder.lockCanvas() +if (ca~=nil) then +ca.drawRGB(0,79,90); +ca.drawRect(0,0,200,300,paint) +end +holder.unlockCanvasAndPost(ca) +end, +surfaceDestroyed=function(holder) +end +} +holder=sureface.getHolder() +holder.addCallback(callback) +activity.setContentView(sureface) + +13,Lua类型与Java类型 +在大多数情况下androlua可以很好的处理Lua与Java类型之间的自动转换,但是Java的数值类型有多种(double,float,long,int,short,byte),而Lua只有number,在必要的情况下可以使用类型的强制转换。 +i=int(10) +i就是一个Java的int类型数据 +d=double(10) +d是一个Java的double类型 +在调用Java方法时androlua可以自动将Lua的table转换成Java的array,Map或interface +Map类型可以像使用Lua表一样简便。 +map=HashMap{a=1,b=2} +print(map.a) +map.a=3 +取长度运算符#可以获取Java中array,List,Map,Set,String的长度。 + + +14,部分模块 +(1) canvas模块 +require "import" +import "canvas" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "android.graphics.*" +activity.setTitle('AndroLua') + +paint=Paint() +paint.setARGB(100,0,250,0) +paint.setStrokeWidth(20) +paint.setTextSize(28) + +sureface = SurfaceView(activity); +callback=SurfaceHolder_Callback{ +surfaceChanged=function(holder,format,width,height) +end, +surfaceCreated=function(holder) +ca=canvas.lockCanvas(holder) +if (ca~=nil) then +ca:drawRGB(0,79,90) +ca:drawRect(0,0,200,300,paint) +end +canvas.unlockCanvasAndPost(holder,ca) +end, +surfaceDestroyed=function(holder) +end +} +holder=sureface.getHolder() +holder.addCallback(callback) +activity.setContentView(sureface) + +(2) OpenGL模块 +require "import" +import "gl" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "android.opengl.*" +activity.setTitle('AndroLua') +--activity.setTheme( android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen) + +mTriangleData ={ +0.0, 0.6, 0.0, +-0.6, 0.0, 0.0, +0.6, 0.0, 0.0, +}; +mTriangleColor = { +1, 0, 0, 0, +0, 1, 0, 0, +0, 0, 1, 0, +}; + +sr=GLSurfaceView.Renderer{ +onSurfaceCreated=function(gl2, config) +gl.glDisable(gl.GL_DITHER); +gl.glHint(gl.GL_PERSPECTIVE_CORRECTION_HINT, gl.GL_FASTEST); +gl.glClearColor(0, 0, 0, 0); +gl.glShadeModel(gl.GL_SMOOTH); +gl.glClearDepth(1.0) +gl.glEnable(gl.GL_DEPTH_TEST); +gl.glDepthFunc(gl.GL_LEQUAL); +end, +onDrawFrame=function(gl2, config) +gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT); +gl.glMatrixMode(gl.GL_MODELVIEW); +gl.glLoadIdentity(); +gl.glRotate(0,1,1,1) +gl.glTranslate(0, 0,0); +gl.glEnableClientState(gl.GL_VERTEX_ARRAY); +gl.glEnableClientState(gl.GL_COLOR_ARRAY); +gl.glVertexPointer( mTriangleData,3); +gl.glColorPointer(mTriangleColor,4); +gl.glDrawArrays( gl.GL_TRIANGLE_STRIP , 0, 3); +gl.glFinish(); +gl.glDisableClientState(gl.GL_VERTEX_ARRAY); +gl.glDisableClientState(gl.GL_COLOR_ARRAY); +end, +onSurfaceChanged= function (gl2, w, h) +gl.glViewport(0, 0, w, h); +gl.glLoadIdentity(); +ratio = w / h; +gl.glFrustum(-rautio, ratio, -1, 1, 1, 10); +end +} + +glSurefaceView = GLSurfaceView(activity); +glSurefaceView.setRenderer(sr); +activity.setContentView(glSurefaceView); + + +(3) http模块 +body,cookie,code,headers=http.get(url [,cookie]) +body,cookie,code,headers=http.post(url ,postdata [,cookie]) +code,headers=http.download(url [,cookie]) +body,cookie,code,headers=http.upload(url ,datas ,files [,cookie]) + +require "import" +import "http" + +--get函数以get请求获取网页,参数为请求的网址与cookie +body,cookie,code,headers=http.get("http://www.androlua.com") + +--post函数以post请求获取网页,通常用于提交表单,参数为请求的网址,要发送的内容与cookie +body,cookie,code,headers=http.post("http://androlua.com/Login.Asp?Login=Login&Url=http://androlua.com/bbs/index.asp","name=用户名&pass=密码&ki=1") + +--download函数和get函数类似,用于下载文件,参数为请求的网址,保存文件的路径与cookie +http.download("http://androlua.com","/sdcard/a.txt") + +--upload用于上传文件,参数是请求的网址,请求内容字符串部分,格式为以key=value形式的表,请求文件部分,格式为key=文件路径的表,最后一个参数为cookie +http.upload("http://androlua.com",{title="标题",msg="内容"},{file1="/sdcard/1.txt",file2="/sdcard/2.txt"}) + +(4) import模块 + +require "import" +import "android.widget.*" +import "android.view.*" +layout={ +LinearLayout, +orientation="vertical", +{ +EditText, +id="edit", +layout_width="fill" +}, +{ +Button, +text="按钮", +layout_width="fill", +onClick="click" +} +} + +function click() +Toast.makeText(activity, edit.getText().toString(), Toast.LENGTH_SHORT ).show() +end +activity.setContentView(loadlayout(layout)) + + +关于打包 +新建工程或在脚本目录新建init.lua文件。 +写入以下内容,即可将文件夹下所有lua文件打包,main.lua为程序人口。 +appname="demo" +appver="1.0" +packagename="com.androlua.demo" +目录下icon.png替换图标,welcome.png替换启动图。 +没有int.lua文件打包当前文件。 +打包使用debug签名。 + +部分函数参考 + +[a]表示参数a可选,(...)表示不定参数。函数调用在只有一个参数且参数为字符串或表时可以省略括号。 +AndroLua库函数在import模块,为便于使用都是全局变量。 +s 表示string类型,i 表示整数类型,n 表示浮点数或整数类型,t 表示表类型,b 表示布尔类型,o 表示Java对象类型,f为Lua函数。 +--表示注释。 + +each(o) +参数:o 实现Iterable接口的Java对象 +返回:用于Lua迭代的闭包 +作用:Java集合迭代器 + + +enum(o) +参数:o 实现Enumeration接口的Java对象 +返回:用于Lua迭代的闭包 +作用:Java集合迭代器 + +import(s) +参数:s 要载入的包或类的名称 +返回:载入的类或模块 +作用:载入包或类或Lua模块 +import "http" --载入http模块 +import "android.widget.*" --载入android.widget包 +import "android.widget.Button" --载入android.widget.Button类 +import "android.view.View$OnClickListener" --载入android.view.View.OnClickListener内部类 + +loadlayout(t [,t2]) +参数:t 要载入的布局表,t2 保存view的表 +返回:布局最外层view +作用:载入布局表,生成view +layout={ +LinearLayout, +layout_width="fill", +{ +TextView, +text="Androlua", +id="tv" +} +} +main={} +activity.setContentView(loadlayout(layout,main)) +print(main.tv.getText()) + +loadbitmap(s) +参数:s 要载入图片的地址,支持相对地址,绝对地址与网址 +返回:bitmap对象 +作用:载入图片 +注意:载入网络图片需要在线程中进行 + +task(s [,...], f) +参数:s 任务中运行的代码或函数,... 任务传入参数,f 回调函数 +返回:无返回值 +作用:在异步线程运行Lua代码,执行完毕在主线程调用回调函数 +注意:参数类型包括 布尔,数值,字符串,Java对象,不允许Lua对象 +function func(a,b) +require "import" +print(a,b) +return a+b +end +task(func,1,2,print) + +thread(s[,...]) +参数:s 线程中运行的lua代码或脚本的相对路径(不加扩展名)或函数,... 线程初始化参数 +返回:返回线程对象 +作用:开启一个线程运行Lua代码 +注意:线程需要调用quit方法结束线程 +func=[[ +a,b=... +function add() +call("print",a+b) +end +]] +t=thread(func,1,2) +t.add() + +timer(s,i1,i2[,...]) +参数:s 定时器运行的代码或函数,i1 前延时,i2 定时器间隔,... 定时器初始化参数 +返回:定时器对象 +作用:创建定时器重复执行函数 +function f(a) +function run() +print(a) +a=a+1 +end +end + +t=timer(f,0,1000,1) +t.Enabled=false--暂停定时器 +t.Enabled=true--重新定时器 +t.stop()--停止定时器 + +new_env() +参数:无 +返回:一个继承了import模块函数的环境表 +作用:产生一个继承import模块函数的环境表 +function foo() +local _ENV=new_env() +import "android.widget.*" +b=Button(activity) +end + +luajava.bindClass(s) +参数:s class的完整名称,支持基本类型 +返回:Java class对象 +作用:载入Java class +Button=luajava.bindClass("android.widget.Button") +int=luajava.bindClass("int") + +luajava.createProxy(s,t) +参数:s 接口的完整名称,t 接口函数表 +返回:Java接口对象 +作用:创建Java接口 +onclick=luajava.createProxy("android.view.View$OnClickListener",{onClick=function(v)print(v)end}) + +luajava.createArray(s,t) +参数:s 类的完整名称,支持基本类型,t 要转化为Java数组的表 +返回:创建的Java数组对象 +作用:创建Java数组 +arr=luajava.createArray("int",{1,2,3,4}) + +luajava.newInstance(s [,...]) +参数:s 类的完整名称,... 构建方法的参数 +作用:创建Java类的实例 +b=luajava.newInstance("android.widget.Button",activity) + +luajava.new(o[,...]) +参数:o Java类对象,... 参数 +返回:类的实例或数组对象或接口对象 +作用:创建一个类实例或数组对象或接口对象 +注意:当只有一个参数且为表类型时,如果类对象为interface创建接口,为class创建数组,参数为其他情况创建实例 +b=luajava.new(Button,activity) +onclick=luajava.new(OnClickListener,{onClick=function(v)print(v)end}) +arr=luajava.new(int,{1,2,3}) +(示例中假设已载入相关类) + +luajava.coding(s [,s2 [, s3]]) +参数:s 要转换编码的Lua字符串,s2 字符串的原始编码,s3 字符串的目标编码 +返回:转码后的Lua字符串 +作用:转换字符串编码 +注意:默认进行GBK转UTF8 + +luajava.clear(o) +参数:o Java对象 +返回:无 +作用:销毁Java对象 +注意:尽量避免使用此函数,除非确认不在使用此对象,且该对象比较大 + +luajava.astable(o) +参数:o Java对象 +返回:Lua表 +作用:转换Java的Array List或Map为Lua表 + +luajava.tostring(o) +参数:o Java对象 +返回:Lua字符串 +作用:相当于 o.toString() + +activity部分API参考 +setContentView(layout, env) +设置布局表layout为当前activity的主视图,env是保存视图ID的表,默认是_G +getLuaDir() +返回脚本当前目录 +getLuaDir(name) +返回脚本当前目录的子目录 +getLuaExtDir() +返回Androlua在SD的工作目录 +getLuaExtDir(name) +返回Androlua在SD的工作目录的子目录 +getWidth() +返回屏幕宽度 +getHeight() +返回屏幕高度,不包括状态栏与导航栏 +loadDex(path) +加载当前目录dex或jar,返回DexClassLoader +loadLib(path) +加载当前目录c模块,返回载入后模块的返回值(通常是包含模块函数的包) +registerReceiver(filter) +注册一个广播接收者,当再次调用该方法时将移除上次注册的过滤器 +newActivity(req, path, arg) +打开一个新activity,运行路径为path的Lua文件,其他两个参数为可选,arg为表,接受脚本为变长参数 +newTask(func, update, callback) +新建一个Task异步任务,在线程中执行func函数,其他两个参数可选,执行结束回调callback,在任务调用update函数时在UI线程回调该函数 +新建的Task在调用execute{}时通过表传入参数,在func以unpack形式接收,执行func可以返回多个值, +newThread(func, arg) +新建一个线程,在线程中运行func函数,可以以表的形式传入arg,在func以unpack形式接收 +新建的线程调用start()方法运行,线程为含有loop线程,在当前activity结束后自动结束loop +newTimer(func, arg) +新建一个定时器,在线程中运行func函数,可以以表的形式传入arg,在func以unpack形式接收 +调用定时器的start(delay, period)开始定时器,stop()停止定时器,Enabled暂停恢复定时器,Period属性改变定时器间隔 + +LICENSE: +Androlua+ Copyright (C) 2015-2016 by Nirenr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..2c6b97d --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,41 @@ +apply plugin: 'com.android.application' +android { + compileSdkVersion 28 + buildToolsVersion '28.0.3' + defaultConfig { + applicationId "com.androlua" + minSdkVersion 18 + targetSdkVersion 23 + ndk { + abiFilters 'armeabi-v7a' + } + } + packagingOptions { + exclude 'META-INF/proguard/androidx-annotations.pro' + exclude 'META-INF/NOTICE' + exclude 'META-INF/LICENSE' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + debug { + debuggable true + jniDebuggable true + } + } + externalNativeBuild { + ndkBuild { + path 'src/main/jni/android.mk' + } + } + productFlavors { + } +} + +dependencies { + implementation 'com.android.support:support-annotations:28.0.0' +} \ No newline at end of file diff --git a/app/gradlew b/app/gradlew new file mode 100644 index 0000000..9d82f78 --- /dev/null +++ b/app/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/app/gradlew.bat b/app/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/app/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt new file mode 100644 index 0000000..c1facea --- /dev/null +++ b/app/proguard-rules.txt @@ -0,0 +1,69 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontoptimize +-dontpreverify +-verbose +-printmapping mapping.txt +-optimizations !code/simplification/arithmetic,!field/,!class/merging/ +-keepattributes Annotation +-keep class com.baidu.mobstat.**{*;} + +-keep class android.app.**{ +public ; +public ; +} +-keep class android.content.**{*;} +-keep class com.android.cglib.proxy.**{ +public ; +public ; +} +-keep interface com.android.cglib.proxy.**{ +public ; +public ; +} + +-keep class android.widget.**{ +public ; +public ; +} + +-keep class com.androlua.**{ +public ; +public ; +} + +-keep class com.nirenr.**{ +public ; +public ; +} + +-keep interface com.androlua.**{ +public ; +public ; +} +-keep interface com.nirenr.**{ +public ; +public ; +} +-keep class com.luajava.**{ +public ; +public ; +} +-keepclasseswithmembernames class * { + native ; +} +-keep final class com.android.cglib.dx.* { +public ; +public ; +} +-keep enum com.android.cglib.dx.* {*;} +-keepattributes Signature +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.preference.Preference +-keep public class * extends android.preference.PreferenceActivity +-keep public class * extends android.accessibilityservice.AccessibilityService + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3b37adc --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/AndLua.lua b/app/src/main/assets/AndLua.lua new file mode 100644 index 0000000..4b4a42e --- /dev/null +++ b/app/src/main/assets/AndLua.lua @@ -0,0 +1,472 @@ +----------------------------------------------------------------------------- +-- Author: AndLua+ 陵阳 +----------------------------------------------------------------------------- + +import "android.graphics.PorterDuffColorFilter" +import "android.graphics.PorterDuff" +local open=io.open +function MD提示(str,color,color2,ele,rad) + if time then toasttime=Toast.LENGTH_SHORT else toasttime= Toast.LENGTH_SHORT end + toasts={ + CardView; + id="toastb", + CardElevation=ele; + radius=rad; + backgroundColor=color; + { + TextView; + layout_margin="7dp"; + textSize="13sp"; + TextColor=color2, + text=str; + layout_gravity="center"; + id="mess", + }; + }; + local toast=Toast.makeText(activity,nil,toasttime); + toast.setView(loadlayout(toasts)) + toast.show() +end + +function 窗口标题(text) + activity.setTitle(text) +end + +function 载入界面(id) + activity.setContentView(loadlayout(id)) +end + +function 隐藏标题栏() + activity.ActionBar.hide() +end + +function 设置主题(id) + activity.setTheme(id) +end + +function 打印(text) + print(text) +end + +function 窗口全屏() + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN) +end + +function 取消全屏() + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) +end + +function 返回桌面() + activity.moveTaskToBack(true) +end + +function 提示(text) + Toast.makeText(activity,text,Toast.LENGTH_SHORT).show() +end + +function 截取文本(str,str1,str2) + str1=str1:gsub("%p",function(s) return("%"..s) end) + return str:match(str1 .. "(.-)"..str2) +end + +function 替换文本(str,str1,str2) + str1=str1:gsub("%p",function(s) return("%"..s) end) + str2=str2:gsub("%%","%%%%") + return str:gsub(str1,str2) +end + +function 字符串长度(str) + return utf8.len(str) +end + +function 状态栏颜色(color) + if Build.VERSION.SDK_INT >= 21 then + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(color); + end +end + +function 沉浸状态栏() + if Build.VERSION.SDK_INT >= 19 then + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + end +end + +function 设置文本(id,text) + id.Text=text +end + +function 跳转页面(name) + activity.newActivity(name) +end + +function 跳转界面(name) + activity.newActivity(name) +end + +function 关闭页面() + activity.finish() +end + +function 关闭界面() + activity.finish() +end + +function 获取文本(id) + return id.Text +end + +function 结束程序() + activity.finish() +end + +function 重构页面() + activity.recreate() +end + +function 重构界面() + activity.recreate() +end + +function 控件圆角(view,InsideColor,radiu) + import "android.graphics.drawable.GradientDrawable" + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(InsideColor) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + view.setBackgroundDrawable(drawable) +end + +function 获取设备标识码() + import "android.provider.Settings$Secure" + return Secure.getString(activity.getContentResolver(), Secure.ANDROID_ID) +end + +function 获取IMEI() + import "android.content.Context" + return activity.getSystemService(Context.TELEPHONY_SERVICE).getDeviceId() +end + +function 控件背景渐变动画(view,color1,color2,color3,color4) + import "android.animation.ObjectAnimator" + import "android.animation.ArgbEvaluator" + import "android.animation.ValueAnimator" + import "android.graphics.Color" + colorAnim = ObjectAnimator.ofInt(view,"backgroundColor",{color1, color2, color3,color4}) + colorAnim.setDuration(3000) + colorAnim.setEvaluator(ArgbEvaluator()) + colorAnim.setRepeatCount(ValueAnimator.INFINITE) + colorAnim.setRepeatMode(ValueAnimator.REVERSE) + colorAnim.start() +end + +function 获取屏幕尺寸(ctx) + import "android.util.DisplayMetrics" + dm = DisplayMetrics(); + ctx.getWindowManager().getDefaultDisplay().getMetrics(dm); + diagonalPixels = Math.sqrt(Math.pow(dm.widthPixels, 2) + Math.pow(dm.heightPixels, 2)); + return diagonalPixels / (160 * dm.density); +end + +function 是否安装APP(packageName) + if pcall(function() activity.getPackageManager().getPackageInfo(packageName,0) end) then + return true + else + return false + end +end + +function 设置中划线(id) + import "android.graphics.Paint" + id.getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG) +end + +function 设置下划线(id) + import "android.graphics.Paint" + id.getPaint().setFlags(Paint. UNDERLINE_TEXT_FLAG) +end + +function 设置字体加粗(id) + import "android.graphics.Paint" + id.getPaint().setFakeBoldText(true) +end + +function 设置斜体(id) + import "android.graphics.Paint" + id.getPaint().setTextSkewX(0.2) +end + +function 分享内容(text) + intent=Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, "分享"); + intent.putExtra(Intent.EXTRA_TEXT, text); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(Intent.createChooser(intent,"分享到:")); +end + +function 加QQ群(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqapi://card/show_pslcard?src_type=internal&version=1&uin="..qq.."&card_type=group&source=qrcode"))) +end + +function 跳转QQ群(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqapi://card/show_pslcard?src_type=internal&version=1&uin="..qq.."&card_type=group&source=qrcode"))) +end + +function QQ聊天(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin="..qq))) +end + +function 跳转QQ聊天(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin="..qq))) +end + +function 发送短信(phone,text) + require "import" + import "android.telephony.*" + SmsManager.getDefault().sendTextMessage(tostring(phone), nil, tostring(text), nil, nil) +end + +function 获取剪切板() + import "android.content.Context" + return activity.getSystemService(Context.CLIPBOARD_SERVICE).getText() +end + +function 写入剪切板(text) + import "android.content.Context" + activity.getSystemService(Context.CLIPBOARD_SERVICE).setText(text) +end + +function 开启WIFI() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.setWifiEnabled(true) +end + +function 关闭WIFI() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.setWifiEnabled(false) +end + +function 断开网络() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.disconnect() +end + +function 创建文件(file) + import "java.io.File" + return File(file).createNewFile() +end + +function 创建文件夹(file) + import "java.io.File" + return File(file).mkdir() +end + +function 创建多级文件夹(file) + import "java.io.File" + return File(file).mkdirs() +end + +function 移动文件(file,file2) + import "java.io.File" + return File(file).renameTo(File(file2)) +end + +function 写入文件(file,text) + return open(file,"w"):write(text):close() +end + +function 设置按钮颜色(id,color) + id.getBackground().setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)) +end + +function 设置编辑框颜色(id,color) + id.getBackground().setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)); +end + +function 设置进度条颜色(id,color) + id.IndeterminateDrawable.setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)) +end + +function 设置控件颜色(id,color) + id.setBackgroundColor(color) +end + +function 获取手机存储路径() + return Environment.getExternalStorageDirectory().toString() +end + +function 获取屏幕宽() + return activity.getWidth() +end + +function 获取屏幕高() + return activity.getHeight() +end + +function 文件是否存在(file) + return File(file).exists() +end + +function 关闭左侧滑(id) + id.closeDrawer(3) +end + +function 打开左侧滑() + id.openDrawer(3) +end + +function 显示控件(id) + id.setVisibility(0) +end + +function 隐藏控件(id) + id.setVisibility(8) +end + +function 播放本地音乐(url) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(Intent.ACTION_VIEW) + uri = Uri.parse("file://"..url) + intent.setDataAndType(uri, "audio/mp3") + this.startActivity(intent) +end + +function 在线播放音乐(url) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(Intent.ACTION_VIEW) + uri = Uri.parse(url) + intent.setDataAndType(uri, "audio/mp3") + this.startActivity(intent) +end + +function 播放本地视频(url) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(Intent.ACTION_VIEW) + uri = Uri.parse("file://"..url) + intent.setDataAndType(uri, "video/mp4") + activity.startActivity(intent) +end + +function 在线播放视频(url) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(Intent.ACTION_VIEW) + uri = Uri.parse(url) + intent.setDataAndType(uri, "video/mp4") + activity.startActivity(intent) +end + +function 打开APP(packageName) + import "android.content.Intent" + import "android.content.pm.PackageManager" + manager = activity.getPackageManager() + open = manager.getLaunchIntentForPackage(packageName) + this.startActivity(open) +end + +function 卸载APP(file) + import "android.net.Uri" + import "android.content.Intent" + uri = Uri.parse("package:"..file) + intent = Intent(Intent.ACTION_DELETE,uri) + activity.startActivity(intent) +end + +function 安装APP(file) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(Intent.ACTION_VIEW) + intent.setDataAndType(Uri.parse("file://"..file), "application/vnd.android.package-archive") + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + activity.startActivity(intent) +end + +function 系统下载文件(url,directory,name) + import "android.content.Context" + import "android.net.Uri" + downloadManager=activity.getSystemService(Context.DOWNLOAD_SERVICE); + url=Uri.parse(url); + request=DownloadManager.Request(url); + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE|DownloadManager.Request.NETWORK_WIFI); + request.setDestinationInExternalPublicDir(directory,name); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + downloadManager.enqueue(request); +end + +function 调用系统下载文件(url,directory,name) + import "android.content.Context" + import "android.net.Uri" + downloadManager=activity.getSystemService(Context.DOWNLOAD_SERVICE); + url=Uri.parse(url); + request=DownloadManager.Request(url); + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE|DownloadManager.Request.NETWORK_WIFI); + request.setDestinationInExternalPublicDir(directory,name); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + downloadManager.enqueue(request); +end + +function 弹窗1(title,content,text,fun) + dialog=AlertDialog.Builder(this) + .setTitle(title) + .setMessage(content) + .setPositiveButton(text,{onClick=fun}) + .show() + dialog.create() +end + +function 确定弹窗(title,content,text,fun) + dialog=AlertDialog.Builder(this) + .setTitle(title) + .setMessage(content) + .setPositiveButton(text,{onClick=fun}) + .show() + dialog.create() +end + +function 波纹(id,color) + import "android.content.res.ColorStateList" + local attrsArray = {android.R.attr.selectableItemBackgroundBorderless} + local typedArray =activity.obtainStyledAttributes(attrsArray) + ripple=typedArray.getResourceId(0,0) + aoos=activity.Resources.getDrawable(ripple) + aoos.setColor(ColorStateList(int[0].class{int{}},int{color})) + id.setBackground(aoos.setColor(ColorStateList(int[0].class{int{}},int{color}))) +end + +function 添加波纹效果(id,color) + import "android.content.res.ColorStateList" + local attrsArray = {android.R.attr.selectableItemBackgroundBorderless} + local typedArray =activity.obtainStyledAttributes(attrsArray) + ripple=typedArray.getResourceId(0,0) + aoos=activity.Resources.getDrawable(ripple) + aoos.setColor(ColorStateList(int[0].class{int{}},int{color})) + id.setBackground(aoos.setColor(ColorStateList(int[0].class{int{}},int{color}))) +end + +function 随机数(min,max) + return math.random(min,max) +end + +function 删除控件(id,id2) + return (id).removeView(id2) +end + +function 状态栏亮色() + if Build.VERSION.SDK_INT >= 23 then + activity.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + end +end \ No newline at end of file diff --git a/app/src/main/assets/Community.aly b/app/src/main/assets/Community.aly new file mode 100644 index 0000000..58b433b --- /dev/null +++ b/app/src/main/assets/Community.aly @@ -0,0 +1,19 @@ +{ + RelativeLayout; + layout_width="fill"; + layout_height="fill"; + { + PageView; + layout_height="100%h"; + layout_width="fill"; + id="page"; + touchEnabled=false; + overScrollMode=2; + pages={ + -- layout1, + layout2, + + layout4, + }; + }; +}; \ No newline at end of file diff --git a/app/src/main/assets/Dialog.lua b/app/src/main/assets/Dialog.lua new file mode 100644 index 0000000..3b2d8bf --- /dev/null +++ b/app/src/main/assets/Dialog.lua @@ -0,0 +1,238 @@ +import"android.view.animation.*" +import"android.view.animation.Animation$AnimationListener" +import"android.graphics.drawable.GradientDrawable" +import "android.widget.LinearLayout" +import "android.view.View" +import "android.view.animation.TranslateAnimation" +import "android.widget.CardView" +import "android.view.WindowManager" +import "android.graphics.drawable.GradientDrawable" +import "android.view.Gravity" +import "android.widget.PageView" +import "android.view.animation.Animation$AnimationListener" +import "android.app.AlertDialog" +import "android.widget.PageLayout$OnPageChangeListener" +import "android.widget.PageView$OnPageChangeListener" +import "android.R$id" +import "android.graphics.drawable.ColorDrawable" +import "com.androlua.R$drawable" +import "android.R$drawable" +import "android.view.animation.Animation$AnimationListener" +import "android.view.animation.AlphaAnimation" +import "android.widget.AbsoluteLayout" +MyDialog={} +MyDialog.设置布局=function(v) MyDialog.layout=v or MyDialog.layout return MyDialog end + +MyDialog.弹窗高度="fill" +MyDialog.弹窗圆角="5dp" +MyDialog.弹窗外部颜色="#00000000" +MyDialog.弹窗阴影="0dp" +MyDialog.弹窗背景="#FFFFFFFF" +MyDialog.弹窗宽度="100%w" +MyDialog.弹窗上边距="0dp" +MyDialog.弹窗下边距="0dp" +MyDialog.设置弹窗下边距=function(v) MyDialog.弹窗下边距=v or MyDialog.弹窗下边距 return MyDialog end +MyDialog.设置弹窗外部点击事件=function(v) MyDialog.弹窗外部点击事件=v or MyDialog.弹窗外部点击事件 return MyDialog end +MyDialog.设置弹窗上边距=function(v) MyDialog.弹窗上边距=v or MyDialog.弹窗上边距 return MyDialog end +MyDialog.设置弹窗宽度=function(v) MyDialog.弹窗宽度= v or MyDialog.弹窗宽度 return MyDialog end +MyDialog.设置弹窗背景=function(v) MyDialog.弹窗背景=v or MyDialog.弹窗背景 return MyDialog end +MyDialog.设置弹窗阴影=function(v) MyDialog.弹窗阴影=v or MyDialog.弹窗阴影 return MyDialog end +MyDialog.设置弹窗外部颜色=function(v) MyDialog.弹窗外部颜色=v or MyDialog.弹窗外部颜色 return MyDialog end +MyDialog.设置弹窗圆角=function(v) MyDialog.弹窗圆角=v or MyDialog.弹窗圆角 return MyDialog end +MyDialog.设置弹窗高度=function(v) MyDialog.弹窗高度=v or MyDialog.弹窗高度 return MyDialog end + + + +MyDialog.弹窗获取高宽 = function(A0_100) + A0_100.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)) + MyDialog.弹窗高= A0_100.getMeasuredHeight() + MyDialog.弹窗宽= A0_100.getMeasuredWidth() + return MyDialog.弹窗高, MyDialog.弹窗宽 +end + +MyDialog.layout={} +MyDialog.弹窗高=50 +MyDialog.弹窗外部点击事件=function()MyDialog.弹窗关闭()end +MyDialog.弹窗快速消失动画 = AlphaAnimation(1, 0.2).setDuration(0).setFillAfter(true) +MyDialog.弹窗消失动画= AlphaAnimation(1, 0).setDuration(250).setFillAfter(true) +MyDialog.弹窗显示动画= AlphaAnimation(0, 1).setDuration(250).setFillAfter(true) +MyDialog.弹窗快速消失动画 = AlphaAnimation(1, 0).setDuration(0).setFillAfter(true) +MyDialog.弹窗上移动画 = TranslateAnimation(0, 0, 2000, 0).setDuration(300).setFillAfter(true) +MyDialog.弹窗下移动画 = TranslateAnimation(0, 0, 0, 2000).setDuration(300).setFillAfter(true) +MyDialog.弹窗设置圆角 = function(控件,颜色,上圆角, 下圆角) + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(颜色) + drawable.setCornerRadii({ + 上圆角, + 上圆角, + 上圆角, + 上圆角, + 下圆角, + 下圆角, + 下圆角, + 下圆角 + }) + 控件.setBackgroundDrawable(rawable) + return MyDialog +end + +MyDialog.弹窗状态改变事件=function()end +MyDialog.弹窗位置改变事件 = function(A0_115) + if A0_115 == 1 then + MyDialog.弹窗关闭() + end +end + +MyDialog.弹窗滑动事件=function()end +MyDialog.弹窗关闭=function() + _弹窗区域.startAnimation(MyDialog.弹窗下移动画) + _弹窗阴影区域.startAnimation(MyDialog.弹窗消失动画) + MyDialog.弹窗下移动画.setAnimationListener(AnimationListener({ + onAnimationEnd = function() + _弹窗主布局.startAnimation(MyDialog.弹窗快速消失动画) + _弹窗主布局.setVisibility(View.GONE) + MyDialog.dialog.dismiss() + end + })) +end +MyDialog.显示=function() + import "android.graphics.Typeface" + import "android.graphics.drawable.ColorDrawable" + local aly2= { + AbsoluteLayout, + id = "_弹窗主布局", + layout_height = "100%h", + layout_width = "100%w", + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + { + LinearLayout, + id = "_弹窗圆角布局", + layout_width = "0dp", + background = MyDialog.弹窗背景, + { + LinearLayout, + layout_height = MyDialog.弹窗圆角, + } + }, + + { + LinearLayout, + id = "_弹窗阴影区域", + background = MyDialog.弹窗外部颜色, + layout_height = "100%h", + layout_width = "100%w", + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + layout_gravity = "bottom", + + { + LinearLayout, + rotation = "270", + layout_width = "100%h", + layout_height = "fill_parent", + gravity = "bottom", + layout_gravity = "bottom", + + { + PageView, + background = "#00000000", + id = "_弹窗页面布局", + + OnPageChangeListener=(PageView.OnPageChangeListener({ + onPageSelected = function(A0_105) + MyDialog.弹窗位置改变事件(A0_105) + end, + onPageScrolled = function(A0_106, A1_107, A2_108) + end, + onPageScrollStateChanged = function(A0_109) + MyDialog.弹窗状态改变事件(A0_109) + end + })), + pages = { + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + + rotation = "90", + background = "#00000000", + { + LinearLayout, + id = "_弹窗父布局", + layout_height = "100%h", + layout_width = "100%w", + gravity = "bottom|center", + onClick=function()MyDialog.弹窗外部点击事件()end, + { + CardView, + id = "_弹窗区域", + elevation = MyDialog.弹窗阴影, + layout_gravity = "bottom|center", + layout_marginTop = MyDialog.弹窗上边距, + layout_marginBottom = MyDialog.弹窗下边距, + layout_width = MyDialog.弹窗宽度, + Radius=MyDialog.弹窗圆角, + onClick=function()end, + { + LinearLayout, + id = "_弹窗区域布局", + layout_width = MyDialog.弹窗宽度, + layout_height = MyDialog.弹窗高度, + gravity = "top|center", + onClick=function()end, + MyDialog.layout, + } + } + } + }, + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + + } + } + } + } + } + } + } + } + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + MyDialog.dialog=dialog1 + dialog1.getWindow().setContentView(loadlayout(aly2)); + + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + + local dialogWindow = dialog1.getWindow(); + + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.setCanceledOnTouchOutside(false); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + + + + _弹窗页面布局.addOnPageChangeListener(PageView.OnPageChangeListener({ + onPageSelected = function(A0_105) + MyDialog.弹窗位置改变事件(A0_105) + end, + onPageScrolled = function(A0_106, A1_107, A2_108) + end, + onPageScrollStateChanged = function(A0_109) + MyDialog.弹窗状态改变事件(A0_109) + end + })) + _弹窗主布局.setVisibility(0) + return MyDialog +end + + +function MyBottomSheetDialog() return MyDialog end diff --git a/app/src/main/assets/My.aly b/app/src/main/assets/My.aly new file mode 100644 index 0000000..63e73f3 --- /dev/null +++ b/app/src/main/assets/My.aly @@ -0,0 +1,833 @@ +{ + LinearLayout; + orientation="vertical"; + layout_height="fill"; + layout_width="fill"; + backgroundColor=颜色2; + { + LinearLayout; + gravity="center"; + layout_height="25%h"; + layout_width="match_parent"; + { + CardView; + radius="7dp"; + CardElevation="0dp"; + layout_height="20%h"; + layout_width="90%w"; + backgroundColor=颜色1; + { + LinearLayout; + orientation="vertical"; + layout_height="match_parent"; + layout_width="match_parent"; + { + LinearLayout; + orientation="horizontal"; + layout_height="10%h"; + layout_marginTop="1%h"; + layout_width="match_parent"; + { + CardView; + radius="5dp"; + CardElevation="0dp"; + layout_height="15%w"; + layout_width="15%w"; + layout_gravity="center"; + backgroundColor="0x0000000"; + layout_marginLeft="5%w"; + { + ImageView; + id="m4_tx"; + layout_gravity="center"; + src="img/a5.png"; + layout_height="-1"; + layout_width="-1"; + }; + }; + { + LinearLayout; + orientation="vertical"; + layout_height="match_parent"; + layout_width="match_parent"; + { + LinearLayout; + layout_width="match_parent"; + { + TextView; + text="加载中"; + id="m4_mc", + + + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/a.ttf")); + layout_marginTop="1%h"; + textColor=颜色3; + layout_marginLeft="2%h"; + textSize="16sp"; + }; + { + ImageView; + src="image/a0.png"; + id="m4_dj"; + layout_height="2.3%h"; + layout_marginTop="0.5%h"; + layout_marginLeft="1%h"; + layout_gravity="center"; + }; + { + CardView; + backgroundColor="0xffd3f7f7"; + CardElevation="0dp"; + layout_marginTop="0.5%h", + layout_height="2.5%h"; + layout_gravity="center", + layout_marginLeft="1.5%h", + id="m4_rz", + radius="3dp"; + Visibility=8; + { + TextView; + id="m4_rz1", + textSize="10sp"; + layout_marginLeft="1%h", + layout_marginRight="1%h", + textColor="0xff49dadb"; + text="用户认证"; + layout_gravity="center"; + }; + }; + }; + { + LinearLayout; + layout_marginLeft="2%h"; + orientation="horizontal"; + layout_height="match_parent"; + layout_width="match_parent"; + { + ImageView; + layout_gravity="center"; + src="img/b1.png"; + ColorFilter="0xff49dadb"; + layout_height="3.5%h"; + layout_width="4%h"; + }; + { + TextView; + text="加载中"; + id="m4_hy"; + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/b.ttf")); + layout_width="40%w"; + textColor=颜色3; + layout_marginLeft="1%h"; + layout_gravity="center"; + }; + { + CardView; + radius="15"; + CardElevation="0dp"; + layout_height="4%h"; + layout_width="12%w"; + id="m4_dn", + layout_gravity="center"; + backgroundColor="0xff49dadb"; + { + TextView; + layout_gravity="center"; + text="加载中"; + id="m4_zt"; + textSize="13sp"; + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/a.ttf")); + textColor="0xffffffff"; + }; + }; + }; + }; + }; + { + TextView; + layout_marginBottom="1%h"; + layout_width="80%w"; + layout_gravity="center"; + backgroundColor="0xffd1d1d1"; + layout_marginTop="1%h"; + layout_height="0.1%w"; + }; + { + LinearLayout; + orientation="horizontal"; + layout_height="match_parent"; + layout_width="match_parent"; + { + ImageView; + layout_height="4%h"; + layout_width="4%h"; + src="img/b2.png"; + layout_marginLeft="6%w"; + layout_gravity="center"; + }; + { + TextView; + text="自动检测更新"; + layout_width="60%w"; + + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/b.ttf")); + textColor="0xffadadad"; + layout_gravity="center"; + layout_marginLeft="4%w"; + textSize="14sp"; + }; + { + ImageView; + id="m4_jc"; + layout_gravity="center"; + src="img/check_on.png"; + layout_height="3%h"; + layout_width="3%h"; + }; + }; + }; + }; + }; +{ + LinearLayout; + layout_height="120dp"; + layout_width="match_parent"; + orientation="vertical"; + gravity="center"; + { + CardView; + backgroundColor=颜色1; + CardElevation=0; + radius=25; + layout_width="88.8%w"; + layout_height="12%h"; + { + HorizontalScrollView; + layout_width="fill"; + layout_height="fill"; + horizontalScrollBarEnabled=false; + { + LinearLayout; + layout_width="match_parent"; + --gravity="center"; + { + LinearLayout; + gravity="center"; + orientation="vertical"; + layout_height="12%h"; + id="m4_gz", + layout_width="25%w"; + { + ImageView; + src="img/c1.png"; + layout_height="10%w"; + layout_width="10%w"; + }; + { + TextView; + text="我的关注"; + textSize="13sp"; + textColor=颜色3, + }; + }; + { + LinearLayout; + layout_width="match_parent"; + { + LinearLayout; + gravity="center"; + orientation="vertical"; + id="m4_tz", + layout_height="12%h"; + layout_width="25%w"; + { + ImageView; + src="img/c2.png"; + layout_height="10%w"; + layout_width="10%w"; + }; + { + TextView; + text="我的帖子"; + textSize="13sp"; + textColor=颜色3, + }; + }; + { + LinearLayout; + layout_width="match_parent"; + { + LinearLayout; + gravity="center"; + orientation="vertical"; + layout_height="12%h"; + id="m4_sc", + layout_width="25%w"; + { + ImageView; + src="img/c3.png"; + layout_height="10%w"; + layout_width="10%w"; + }; + { + TextView; + text="我的收藏"; + textSize="13sp"; + textColor=颜色3, + }; + }; + { + LinearLayout; + layout_width="match_parent"; + { + LinearLayout; + gravity="center"; + orientation="vertical"; + layout_height="12%h"; + layout_width="25%w"; + id="m4_fs", + { + ImageView; + src="img/c4.png"; + layout_height="10%w"; + layout_width="10%w"; + }; + { + TextView; + text="我的粉丝"; + textSize="13sp"; + textColor=颜色3, + }; + }; + }; + }; + }; + }; + }; + }; + }; + + + + { + LinearLayout; + layout_height="32.1%h"; + layout_width="match_parent"; + gravity="center"; + backgroundColor=颜色2; + { + ScrollView; + --layout_width="fill"; + --layout_height="fill"; + verticalScrollBarEnabled=false; + { + CardView; + layout_marginBottom="5dp"; + CardElevation=0; + radius=25; + layout_width="88.8%w"; + layout_height="32.1%h"; + backgroundColor=颜色1; + + { + LinearLayout; + -- layout_height="34.1%h"; + layout_width="match_parent"; + orientation="vertical"; + + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + --id="重要公告"; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + id="m4_qd", + --gravity="center"; + -- text="重要公告", + + { + ImageView; + ColorFilter="0xFF03A9F4"; + -- layout_gravity="center"; + layout_marginLeft="15dp"; + src="picture/a2.png"; + layout_width="35dp"; + }; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center"; + -- text="重要公告", + + { + TextView; + textColor=颜色3, + text="每日签到"; + --layout_marginLeft="5.5%w"; + -- layout_gravity="center"; + }, + }, + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center|right"; + -- text="重要公告", + + { + ImageView; + layout_height="40dp"; + layout_width="40dp"; + + --layout_margin="15dp"; + + src="res/AndLuaXY10.png"; + }; + + }, + }, + + + }; + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + --id="重要公告"; + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + id="备份管理", + --gravity="center"; + -- text="重要公告", + + { + ImageView; + ColorFilter="0xFF03A9F4"; + -- layout_gravity="center"; + layout_marginLeft="15dp"; + src="imgs/AndLuaXY2.png"; + layout_width="35dp"; + }; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center"; + -- text="重要公告", + + { + TextView; + textColor=颜色3, + text="备份管理"; + --layout_marginLeft="5.5%w"; + -- layout_gravity="center"; + }, + }, + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center|right"; + -- text="重要公告", + + { + ImageView; + layout_height="40dp"; + layout_width="40dp"; + + --layout_margin="15dp"; + + src="res/AndLuaXY10.png"; + }; + + }, + }, + + + }; + + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + --id="重要公告"; + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + id="重要公告", + --gravity="center"; + -- text="重要公告", + + { + ImageView; + ColorFilter="0xFF03A9F4"; + -- layout_gravity="center"; + layout_marginLeft="15dp"; + src="imgs/AndLuaXY3.png"; + layout_width="35dp"; + }; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center"; + -- text="重要公告", + + { + TextView; + textColor=颜色3, + text="重要公告"; + --layout_marginLeft="5.5%w"; + -- layout_gravity="center"; + }, + }, + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center|right"; + -- text="重要公告", + + { + ImageView; + layout_height="40dp"; + layout_width="40dp"; + + --layout_margin="15dp"; + + src="res/AndLuaXY10.png"; + }; + + }, + }, + + + }; + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + --id="重要公告"; + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + id="打包管理", + --gravity="center"; + -- text="重要公告", + + { + ImageView; + ColorFilter="0xFF03A9F4"; + -- layout_gravity="center"; + layout_marginLeft="15dp"; + src="imgs/AndLuaXY4.png"; + layout_width="35dp"; + }; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center"; + -- text="重要公告", + + { + TextView; + textColor=颜色3, + text="打包管理"; + --layout_marginLeft="5.5%w"; + -- layout_gravity="center"; + }, + }, + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center|right"; + -- text="重要公告", + + { + ImageView; + layout_height="40dp"; + layout_width="40dp"; + + --layout_margin="15dp"; + + src="res/AndLuaXY10.png"; + }; + + }, + }, + + + }; + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + --id="重要公告"; + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + id="软件设置", + --gravity="center"; + -- text="重要公告", + + { + ImageView; + ColorFilter="0xFF03A9F4"; + -- layout_gravity="center"; + layout_marginLeft="15dp"; + src="imgs/Set.png"; + layout_width="35dp"; + }; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center"; + -- text="重要公告", + + { + TextView; + textColor=颜色3, + text="软件设置"; + --layout_marginLeft="5.5%w"; + -- layout_gravity="center"; + }, + }, + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center|right"; + -- text="重要公告", + + { + ImageView; + layout_height="40dp"; + layout_width="40dp"; + + --layout_margin="15dp"; + + src="res/AndLuaXY10.png"; + }; + + }, + }, + + + }; + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + --id="重要公告"; + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + id="m4_sz", + --gravity="center"; + -- text="重要公告", + + { + ImageView; + ColorFilter="0xFF03A9F4"; + -- layout_gravity="center"; + layout_marginLeft="15dp"; + src="imgs/Set.png"; + layout_width="35dp"; + }; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center"; + -- text="重要公告", + + { + TextView; + textColor=颜色3, + text="个人设置"; + --layout_marginLeft="5.5%w"; + -- layout_gravity="center"; + }, + }, + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center|right"; + -- text="重要公告", + + { + ImageView; + layout_height="40dp"; + layout_width="40dp"; + + --layout_margin="15dp"; + + src="res/AndLuaXY10.png"; + }; + + }, + }, + + + }; + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + id="教程手册"; + { + LinearLayout; + layout_height="match_parent"; + layout_width="75%w"; + { + ImageView; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_marginLeft="15dp"; + src="imgs/Teach.png"; + layout_width="35dp"; + }; + { + TextView; + textColor=颜色3, + text="教程手册"; + layout_marginLeft="5.5%w"; + layout_gravity="center"; + }; + }; + { + ImageView; + layout_height="35dp"; + layout_width="35dp"; + layout_gravity="center"; + src="res/AndLuaXY10.png"; + }; + }; + { + LinearLayout; + layout_height="50dp"; + layout_width="match_parent"; + orientation="horizontal"; + --id="重要公告"; + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + id="捐赠我们", + --gravity="center"; + -- text="重要公告", + + { + ImageView; + ColorFilter="0xFF03A9F4"; + -- layout_gravity="center"; + layout_marginLeft="15dp"; + src="imgs/Donate.png"; + layout_width="35dp"; + }; + + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center"; + -- text="重要公告", + + { + TextView; + textColor=颜色3, + text="爱心投食"; + --layout_marginLeft="5.5%w"; + -- layout_gravity="center"; + }, + }, + { + RippleView; + layout_height="50dp"; + layout_width="match_parent"; + -- orientation="horizontal"; + --id="重要公告", + gravity="center|right"; + -- text="重要公告", + + { + ImageView; + layout_height="40dp"; + layout_width="40dp"; + + --layout_margin="15dp"; + + src="res/AndLuaXY10.png"; + }; + }; + }, + }, + + + + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/app/src/main/assets/ThomeLua.lua b/app/src/main/assets/ThomeLua.lua new file mode 100644 index 0000000..31147c8 --- /dev/null +++ b/app/src/main/assets/ThomeLua.lua @@ -0,0 +1,544 @@ +--ThomeLua MostBlack +import "android.graphics.PorterDuffColorFilter" +import "android.graphics.PorterDuff" +local open=io.open +function 圆角提示(内容) + local tsbj={ + LinearLayout; + layout_width="fill"; + layout_height="fill"; + gravity="center"; + orientation="vertical"; + { + CardView; + radius=15, + CardElevation="0dp"; + backgroundColor="0xff6f6f6f"; + { + TextView; + layout_marginRight="35dp"; + text="提示"; + id="提示内容", + textColor="0xffffffff"; + layout_marginLeft="35dp"; + layout_marginTop="10dp"; + layout_gravity="center"; + layout_marginBottom="10dp"; + }; + }; + }; + local toast=Toast.makeText(activity,"内容",Toast.LENGTH_SHORT).setView(loadlayout(tsbj)) + toast.setGravity(Gravity.BOTTOM,0,100) + 提示内容.Text=tostring(内容) + toast.show() +end + +function MD提示(str,color,color2,ele,rad) + local toasts={ + CardView; + id="toastb", + CardElevation=ele; + radius=rad; + backgroundColor=color; + { + TextView; + layout_margin="7dp"; + textSize="13sp"; + TextColor=color2, + text=str; + layout_gravity="center"; + id="mess", + }; + }; + local toast=Toast.makeText(activity,nil,Toast.LENGTH_SHORT); + toast.setView(loadlayout(toasts)) + toast.show() +end + +function 窗口标题(text) + activity.setTitle(text) +end + +function 载入界面(id) + activity.setContentView(loadlayout(id)) +end + +function 隐藏标题栏() + activity.ActionBar.hide() +end + +function 设置主题(id) + activity.setTheme(id) +end + +function 打印(text) + print(text) +end + +function 窗口全屏() + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN) +end + +function 取消全屏() + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) +end + +function 返回桌面() + activity.moveTaskToBack(true) +end + +function 提示(text) + Toast.makeText(activity,text,Toast.LENGTH_SHORT).show() +end + +function 截取文本(str,str1,str2) + local strr=str1:gsub("%p",function(s) + return("%"..s) + end) + return str:match(strr.."(.-)"..str2) +end + +function 替换文本(str,str1,str2) + local str1=str1:gsub("%p",function(s) return("%"..s) end) + local str2=str2:gsub("%%","%%%%") + return str:gsub(str1,str2) +end + +function 字符串长度(str) + return utf8.len(str) +end + +function 状态栏颜色(color) + switch (true) + case (Build.VERSION.SDK_INT >= 21) + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(color); + end +end + +function 沉浸状态栏() + switch(true) + case (Build.VERSION.SDK_INT >= 19) + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + end +end + +function 设置文本(id,text) + id.Text=text +end + +function 跳转页面(name) + activity.newActivity(name) +end + +function 跳转界面(name) + activity.newActivity(name) +end + +function 关闭页面() + activity.finish() +end + +function 关闭界面() + activity.finish() +end + +function 获取文本(id) + return id.Text +end + +function 结束程序() + activity.finish() +end + +function 重构页面() + activity.recreate() +end + +function 重构界面() + activity.recreate() +end + +function 字符转ASCII码(str,num) +return string.byte(str,tonumber(num)) +end + +function ASCII码转字符(ascii) +return string.char(tonumber(ascii)) +end + +function ASCII码判断字符(str,num,ascii) +switch string.byte(str,num) +case ascii +return true +default +return false +end +end + +function 控件圆角(view,InsideColor,radiu) +import "android.graphics.drawable.GradientDrawable" +switch type(InsideColor) +case "number" +local drawable = GradientDrawable() +drawable.setShape(GradientDrawable.RECTANGLE) +drawable.setColor(InsideColor) +drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); +view.setBackgroundDrawable(drawable) +default +switch string.byte(InsideColor) +case 35 +local Hex=string.format("%#x",string.gsub(InsideColor,"#","0x")) +local drawable = GradientDrawable() +drawable.setShape(GradientDrawable.RECTANGLE) +drawable.setColor(tonumber(Hex)) +drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); +view.setBackgroundDrawable(drawable) +default +local Hex=string.format("%#x",InsideColor) +local drawable = GradientDrawable() +drawable.setShape(GradientDrawable.RECTANGLE) +drawable.setColor(tonumber(Hex)) +drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); +view.setBackgroundDrawable(drawable) +end +end +end + +function 获取设备标识码() + import "android.provider.Settings$Secure" + return Secure.getString(activity.getContentResolver(), Secure.ANDROID_ID) +end + +function 获取IMEI() + import "android.content.Context" + return activity.getSystemService(Context.TELEPHONY_SERVICE).getDeviceId() +end + +function 控件背景渐变动画(view,color1,color2,color3,color4) + import "android.animation.ObjectAnimator" + import "android.animation.ArgbEvaluator" + import "android.animation.ValueAnimator" + import "android.graphics.Color" + local colorAnim = ObjectAnimator.ofInt(view,"backgroundColor",{color1, color2, color3,color4}) + colorAnim.setDuration(3000) + colorAnim.setEvaluator(ArgbEvaluator()) + colorAnim.setRepeatCount(ValueAnimator.INFINITE) + colorAnim.setRepeatMode(ValueAnimator.REVERSE) + colorAnim.start() +end + +function 获取屏幕尺寸(ctx) + import "android.util.DisplayMetrics" + local dm = DisplayMetrics(); + ctx.getWindowManager().getDefaultDisplay().getMetrics(dm); + local diagonalPixels = Math.sqrt(Math.pow(dm.widthPixels, 2) + Math.pow(dm.heightPixels, 2)); + return diagonalPixels / (160 * dm.density); +end + +function 是否安装APP(packageName) + switch pcall(function() + activity.getPackageManager().getPackageInfo(packageName,0) + end) + case true + return true + default + return false + end +end + +function 设置中划线(id) + import "android.graphics.Paint" + id.getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG) +end + +function 设置下划线(id) + import "android.graphics.Paint" + id.getPaint().setFlags(Paint. UNDERLINE_TEXT_FLAG) +end + +function 设置字体加粗(id) + import "android.graphics.Paint" + id.getPaint().setFakeBoldText(true) +end + +function 设置斜体(id) + import "android.graphics.Paint" + id.getPaint().setTextSkewX(0.2) +end + +function 分享内容(text) + import "android.content.Intent" + local intent=Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, "分享"); + intent.putExtra(Intent.EXTRA_TEXT, text); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(Intent.createChooser(intent,"分享到:")); +end + +function 加QQ群(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqapi://card/show_pslcard?src_type=internal&version=1&uin="..qq.."&card_type=group&source=qrcode"))) +end + +function 跳转QQ群(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqapi://card/show_pslcard?src_type=internal&version=1&uin="..qq.."&card_type=group&source=qrcode"))) +end + +function QQ聊天(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin="..qq))) +end + +function 跳转QQ聊天(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin="..qq))) +end + +function 发送短信(phone,text) + import "android.telephony.*" + SmsManager.getDefault().sendTextMessage(tostring(phone), nil, tostring(text), nil, nil) +end + +function 获取剪切板() + import "android.content.Context" + return activity.getSystemService(Context.CLIPBOARD_SERVICE).getText() +end + +function 写入剪切板(text) + import "android.content.Context" + activity.getSystemService(Context.CLIPBOARD_SERVICE).setText(text) +end + +function 开启WIFI() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.setWifiEnabled(true) +end + +function 关闭WIFI() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.setWifiEnabled(false) +end + +function 断开网络() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.disconnect() +end + +function 创建文件(file) + import "java.io.File" + return File(file).createNewFile() +end + +function 创建文件夹(file) + import "java.io.File" + return File(file).mkdir() +end + +function 创建多级文件夹(file) + import "java.io.File" + return File(file).mkdirs() +end + +function 移动文件(file,file2) + import "java.io.File" + return File(file).renameTo(File(file2)) +end + +function 写入文件(file,text) + return open(file,"w"):write(text):close() +end + +function 设置按钮颜色(id,color) + id.getBackground().setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)) +end + +function 设置编辑框颜色(id,color) + id.getBackground().setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)); +end + +function 设置进度条颜色(id,color) + id.IndeterminateDrawable.setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)) +end + +function 设置控件颜色(id,color) + id.setBackgroundColor(color) +end + +function 获取手机存储路径() + return Environment.getExternalStorageDirectory().toString() +end + +function 获取屏幕宽() + return activity.getWidth() +end + +function 获取屏幕高() + return activity.getHeight() +end + +function 文件是否存在(file) + return File(file).exists() +end + +function 关闭左侧滑(id) + id.closeDrawer(3) +end + +function 打开左侧滑() + id.openDrawer(3) +end + +function 显示控件(id) + id.setVisibility(0) +end + +function 隐藏控件(id) + id.setVisibility(8) +end + +function 播放本地音乐(url) + import "android.content.Intent" + import "android.net.Uri" + local intent = Intent(Intent.ACTION_VIEW) + local uri = Uri.parse("file://"..url) + intent.setDataAndType(uri, "audio/mp3") + this.startActivity(intent) +end + +function 在线播放音乐(url) + import "android.content.Intent" + import "android.net.Uri" + local intent = Intent(Intent.ACTION_VIEW) + local uri = Uri.parse(url) + intent.setDataAndType(uri, "audio/mp3") + this.startActivity(intent) +end + +function 播放本地视频(url) + import "android.content.Intent" + import "android.net.Uri" + local intent = Intent(Intent.ACTION_VIEW) + local uri = Uri.parse("file://"..url) + intent.setDataAndType(uri, "video/mp4") + activity.startActivity(intent) +end + +function 在线播放视频(url) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(Intent.ACTION_VIEW) + local uri = Uri.parse(url) + intent.setDataAndType(uri, "video/mp4") + activity.startActivity(intent) +end + +function 打开APP(packageName) + import "android.content.Intent" + import "android.content.pm.PackageManager" + local manager = activity.getPackageManager() + local open = manager.getLaunchIntentForPackage(packageName) + this.startActivity(open) +end + +function 卸载APP(file) + import "android.net.Uri" + import "android.content.Intent" + local uri = Uri.parse("package:"..file) + local intent = Intent(Intent.ACTION_DELETE,uri) + activity.startActivity(intent) +end + +function 安装APP(file) + import "android.content.Intent" + import "android.net.Uri" + local intent = Intent(Intent.ACTION_VIEW) + intent.setDataAndType(Uri.parse("file://"..file), "application/vnd.android.package-archive") + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + activity.startActivity(intent) +end + +function 系统下载文件(url,directory,name) + import "android.content.Context" + import "android.net.Uri" + local downloadManager=activity.getSystemService(Context.DOWNLOAD_SERVICE); + local url=Uri.parse(url); + local request=DownloadManager.Request(url); + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE|DownloadManager.Request.NETWORK_WIFI); + request.setDestinationInExternalPublicDir(directory,name); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + downloadManager.enqueue(request); +end + +function 调用系统下载文件(url,directory,name) + import "android.content.Context" + import "android.net.Uri" + local downloadManager=activity.getSystemService(Context.DOWNLOAD_SERVICE); + local url=Uri.parse(url); + local request=DownloadManager.Request(url); + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE|DownloadManager.Request.NETWORK_WIFI); + request.setDestinationInExternalPublicDir(directory,name); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + downloadManager.enqueue(request); +end + +function 弹窗1(title,content,text,fun) + dialog=AlertDialog.Builder(this) + .setTitle(title) + .setMessage(content) + .setPositiveButton(text,{onClick=fun}) + .show() + dialog.create() +end + +function 确定弹窗(title,content,text,fun) + dialog=AlertDialog.Builder(this) + .setTitle(title) + .setMessage(content) + .setPositiveButton(text,{onClick=fun}) + .show() + dialog.create() +end + +function 波纹(id,color) + import "android.content.res.ColorStateList" + local attrsArray = {android.R.attr.selectableItemBackgroundBorderless} + local typedArray =activity.obtainStyledAttributes(attrsArray) + local ripple=typedArray.getResourceId(0,0) + local aoos=activity.Resources.getDrawable(ripple) + aoos.setColor(ColorStateList(int[0].class{int{}},int{color})) + id.setBackground(aoos.setColor(ColorStateList(int[0].class{int{}},int{color}))) +end + +function 添加波纹效果(id,color) + import "android.content.res.ColorStateList" + local attrsArray = {android.R.attr.selectableItemBackgroundBorderless} + local typedArray =activity.obtainStyledAttributes(attrsArray) + local ripple=typedArray.getResourceId(0,0) + local aoos=activity.Resources.getDrawable(ripple) + aoos.setColor(ColorStateList(int[0].class{int{}},int{color})) + id.setBackground(aoos.setColor(ColorStateList(int[0].class{int{}},int{color}))) +end + +function 随机数(min,max) + return math.random(min,max) +end + +function 删除控件(id,id2) + return (id).removeView(id2) +end + +function 状态栏亮色() + switch(true) + case (Build.VERSION.SDK_INT >= 23) + activity.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + end +end \ No newline at end of file diff --git a/app/src/main/assets/Verify/set1.XY b/app/src/main/assets/Verify/set1.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set10.XY b/app/src/main/assets/Verify/set10.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set11.XY b/app/src/main/assets/Verify/set11.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set12.XY b/app/src/main/assets/Verify/set12.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set13.XY b/app/src/main/assets/Verify/set13.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set2.XY b/app/src/main/assets/Verify/set2.XY new file mode 100644 index 0000000..606652f --- /dev/null +++ b/app/src/main/assets/Verify/set2.XY @@ -0,0 +1 @@ +Fun ( ) [ ] { } " = : . , ; ! _ + - * / \ | % # $ ? < > ~ ; @ ' @XY \ No newline at end of file diff --git a/app/src/main/assets/Verify/set3.XY b/app/src/main/assets/Verify/set3.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set4.XY b/app/src/main/assets/Verify/set4.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set5.XY b/app/src/main/assets/Verify/set5.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set6.XY b/app/src/main/assets/Verify/set6.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set7.XY b/app/src/main/assets/Verify/set7.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set8.XY b/app/src/main/assets/Verify/set8.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/set9.XY b/app/src/main/assets/Verify/set9.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/setb.XY b/app/src/main/assets/Verify/setb.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/Verify/setbb.XY b/app/src/main/assets/Verify/setbb.XY new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/android.lua b/app/src/main/assets/android.lua new file mode 100644 index 0000000..ce4673b --- /dev/null +++ b/app/src/main/assets/android.lua @@ -0,0 +1,3585 @@ +apinr=[[【com.androlua.Http】 +【com.androlua.Http$HttpTask】 +【com.androlua.LuaRunnable】 +【com.androlua.LuaThread】 +【com.androlua.LuaBitmap】 +【com.androlua.LuaBitmap】 +【com.androlua.LuaFileObserver】 +【com.androlua.LuaContentObserver】 +【com.androlua.LuaAdapter】 +【com.androlua.LuaMultiAdapter】 +【com.androlua.LuaExpandableListAdapter】 +【com.androlua.LuaService】 +【com.androlua.LuaApplication】 +【com.androlua.LuaTimerTask】 +【com.androlua.LuaWebView】 +【com.androlua.LuaAsyncTask】 +【com.androlua.LuaEditor】 +【com.androlua.LuaArrayAdapter】 +【com.androlua.LuaCameraView】 +【com.androlua.LuaClient】 +【com.androlua.LuaDialog】 +【com.androlua.LuaDrawable】 +【com.androlua.LuaServer】 +【com.androlua.LuaTimer】 +【com.androlua.LuaBroadcastReceiver】 +【com.androlua.LuaBroadcastReceiver$OnReceiveListerer】 +【com.androlua.LuaFragment】 +【com.androlua.Ticker】 +【com.androlua.util.RSASecurity】 +【com.androlua.LuaUtil】 +【com.androlua.ZipUtil】 +【android.app.FloatWindow】 +【android.widget.RoundRectDrawableWithShadow】 +【android.widget.ArrayListAdapter】 +【android.widget.ArrayExpandableListAdapter】 +【android.widget.CircleImageView】 +【android.widget.PageLayout】 +【android.widget.PageView】 +【android.widget.RippleLayout】 +【android.widget.PullingLayout】 +【android.widget.SlidingLayout】 +【android.widget.ToolBar】 +【android.widget.CardView】 +【android.widget.DrawerLayout】 +【android.widget.DrawerLayout$DrawerListener】 +【android.widget.FloatButton】 +【android.support.multidex.MultiDex】 + +【android.accessibilityservice.AccessibilityService】 +【android.accessibilityservice.AccessibilityServiceInfo】 +【android.accounts.AbstractAccountAuthenticator】 +【android.accounts.Account】 +【android.accounts.AccountAuthenticatorActivity】 +【android.accounts.AccountAuthenticatorResponse】 +【android.accounts.AccountManager】 +【android.accounts.AccountManagerCallback】 +【android.accounts.AccountManagerFuture】 +【android.accounts.AccountsException】 +【android.accounts.AuthenticatorDescription】 +【android.accounts.AuthenticatorException】 +【android.accounts.NetworkErrorException】 +【android.accounts.OnAccountsUpdateListener】 +【android.accounts.OperationCanceledException】 +【android.animation.Animator$AnimatorListener】 +【android.animation.Animator$AnimatorPauseListener】 +【android.animation.Animator】 +【android.animation.AnimatorInflater】 +【android.animation.AnimatorListenerAdapter】 +【android.animation.AnimatorSet$Builder】 +【android.animation.AnimatorSet】 +【android.animation.ArgbEvaluator】 +【android.animation.BidirectionalTypeConverter】 +【android.animation.FloatArrayEvaluator】 +【android.animation.FloatEvaluator】 +【android.animation.IntArrayEvaluator】 +【android.animation.IntEvaluator】 +【android.animation.Keyframe】 +【android.animation.LayoutTransition$TransitionListener】 +【android.animation.LayoutTransition】 +【android.animation.ObjectAnimator】 +【android.animation.PointFEvaluator】 +【android.animation.PropertyValuesHolder】 +【android.animation.RectEvaluator】 +【android.animation.StateListAnimator】 +【android.animation.TimeAnimator$TimeListener】 +【android.animation.TimeAnimator】 +【android.animation.TimeInterpolator】 +【android.animation.TypeConverter】 +【android.animation.TypeEvaluator】 +【android.animation.ValueAnimator$AnimatorUpdateListener】 +【android.animation.ValueAnimator】 +【android.annotation.SuppressLint】 +【android.annotation.TargetApi】 +【android.app.ActionBar$LayoutParams】 +【android.app.ActionBar$OnMenuVisibilityListener】 +【android.app.ActionBar$OnNavigationListener】 +【android.app.ActionBar$Tab】 +【android.app.ActionBar$TabListener】 +【android.app.ActionBar】 +【android.app.Activity】 +【android.app.ActivityGroup】 +【android.app.ActivityManager$AppTask】 +【android.app.ActivityManager$MemoryInfo】 +【android.app.ActivityManager$ProcessErrorStateInfo】 +【android.app.ActivityManager$RecentTaskInfo】 +【android.app.ActivityManager$RunningAppProcessInfo】 +【android.app.ActivityManager$RunningServiceInfo】 +【android.app.ActivityManager$RunningTaskInfo】 +【android.app.ActivityManager$TaskDescription】 +【android.app.ActivityManager】 +【android.app.ActivityOptions】 +【android.app.admin.DeviceAdminInfo】 +【android.app.admin.DeviceAdminReceiver】 +【android.app.admin.DevicePolicyManager】 +【android.app.AlarmManager$AlarmClockInfo】 +【android.app.AlarmManager】 +【android.app.AlertDialog$Builder】 +【android.app.AlertDialog】 +【android.app.AliasActivity】 +【android.app.Application$ActivityLifecycleCallbacks】 +【android.app.Application$OnProvideAssistDataListener】 +【android.app.Application】 +【android.app.ApplicationErrorReport$AnrInfo】 +【android.app.ApplicationErrorReport$BatteryInfo】 +【android.app.ApplicationErrorReport$CrashInfo】 +【android.app.ApplicationErrorReport$RunningServiceInfo】 +【android.app.ApplicationErrorReport】 +【android.app.AppOpsManager$OnOpChangedListener】 +【android.app.AppOpsManager】 +【android.app.backup.BackupAgent】 +【android.app.backup.BackupAgentHelper】 +【android.app.backup.BackupDataInput】 +【android.app.backup.BackupDataInputStream】 +【android.app.backup.BackupDataOutput】 +【android.app.backup.BackupHelper】 +【android.app.backup.BackupManager】 +【android.app.backup.FileBackupHelper】 +【android.app.backup.FileBackupHelperBase】 +【android.app.backup.FullBackupDataOutput】 +【android.app.backup.RestoreObserver】 +【android.app.backup.SharedPreferencesBackupHelper】 +【android.app.DatePickerDialog$OnDateSetListener】 +【android.app.DatePickerDialog】 +【android.app.Dialog】 +【android.app.DialogFragment】 +【android.app.DownloadManager$Query】 +【android.app.DownloadManager$Request】 +【android.app.DownloadManager】 +【android.app.ExpandableListActivity】 +【android.app.Fragment$InstantiationException】 +【android.app.Fragment$SavedState】 +【android.app.Fragment】 +【android.app.FragmentBreadCrumbs$OnBreadCrumbClickListener】 +【android.app.FragmentBreadCrumbs】 +【android.app.FragmentManager$BackStackEntry】 +【android.app.FragmentManager$OnBackStackChangedListener】 +【android.app.FragmentManager】 +【android.app.FragmentTransaction】 +【android.app.Instrumentation$ActivityMonitor】 +【android.app.Instrumentation$ActivityResult】 +【android.app.Instrumentation】 +【android.app.IntentService】 +【android.app.job.JobInfo$Builder】 +【android.app.job.JobInfo】 +【android.app.job.JobParameters】 +【android.app.job.JobScheduler】 +【android.app.job.JobService】 +【android.app.KeyguardManager$KeyguardLock】 +【android.app.KeyguardManager$OnKeyguardExitResult】 +【android.app.KeyguardManager】 +【android.app.LauncherActivity$IconResizer】 +【android.app.LauncherActivity$ListItem】 +【android.app.LauncherActivity】 +【android.app.ListActivity】 +【android.app.ListFragment】 +【android.app.LoaderManager$LoaderCallbacks】 +【android.app.LoaderManager】 +【android.app.LocalActivityManager】 +【android.app.MediaRouteActionProvider】 +【android.app.MediaRouteButton】 +【android.app.NativeActivity】 +【android.app.Notification$Action$Builder】 +【android.app.Notification$Action$Extender】 +【android.app.Notification$Action$WearableExtender】 +【android.app.Notification$Action】 +【android.app.Notification$BigPictureStyle】 +【android.app.Notification$BigTextStyle】 +【android.app.Notification$Builder】 +【android.app.Notification$Extender】 +【android.app.Notification$InboxStyle】 +【android.app.Notification$MediaStyle】 +【android.app.Notification$Style】 +【android.app.Notification$WearableExtender】 +【android.app.Notification】 +【android.app.NotificationManager】 +【android.app.PendingIntent$CanceledException】 +【android.app.PendingIntent$OnFinished】 +【android.app.PendingIntent】 +【android.app.Presentation】 +【android.app.ProgressDialog】 +【android.app.RemoteInput$Builder】 +【android.app.RemoteInput】 +【android.app.SearchableInfo】 +【android.app.SearchManager$OnCancelListener】 +【android.app.SearchManager$OnDismissListener】 +【android.app.SearchManager】 +【android.app.Service】 +【android.app.SharedElementCallback】 +【android.app.TabActivity】 +【android.app.TaskStackBuilder】 +【android.app.TimePickerDialog$OnTimeSetListener】 +【android.app.TimePickerDialog】 +【android.app.UiAutomation$AccessibilityEventFilter】 +【android.app.UiAutomation$OnAccessibilityEventListener】 +【android.app.UiAutomation】 +【android.app.UiModeManager】 +【android.app.usage.ConfigurationStats】 +【android.app.usage.UsageEvents$Event】 +【android.app.usage.UsageEvents】 +【android.app.usage.UsageStats】 +【android.app.usage.UsageStatsManager】 +【android.app.WallpaperInfo】 +【android.app.WallpaperManager】 +【android.appwidget.AppWidgetHost】 +【android.appwidget.AppWidgetHostView】 +【android.appwidget.AppWidgetManager】 +【android.appwidget.AppWidgetProvider】 +【android.appwidget.AppWidgetProviderInfo】 +【android.bluetooth.BluetoothA2dp】 +【android.bluetooth.BluetoothAdapter$LeScanCallback】 +【android.bluetooth.BluetoothAdapter】 +【android.bluetooth.BluetoothAssignedNumbers】 +【android.bluetooth.BluetoothClass$Device$Major】 +【android.bluetooth.BluetoothClass$Device】 +【android.bluetooth.BluetoothClass$Service】 +【android.bluetooth.BluetoothClass】 +【android.bluetooth.BluetoothDevice】 +【android.bluetooth.BluetoothGatt】 +【android.bluetooth.BluetoothGattCallback】 +【android.bluetooth.BluetoothGattCharacteristic】 +【android.bluetooth.BluetoothGattDescriptor】 +【android.bluetooth.BluetoothGattServer】 +【android.bluetooth.BluetoothGattServerCallback】 +【android.bluetooth.BluetoothGattService】 +【android.bluetooth.BluetoothHeadset】 +【android.bluetooth.BluetoothHealth】 +【android.bluetooth.BluetoothHealthAppConfiguration】 +【android.bluetooth.BluetoothHealthCallback】 +【android.bluetooth.BluetoothManager】 +【android.bluetooth.BluetoothProfile$ServiceListener】 +【android.bluetooth.BluetoothProfile】 +【android.bluetooth.BluetoothServerSocket】 +【android.bluetooth.BluetoothSocket】 +【android.bluetooth.le.AdvertiseCallback】 +【android.bluetooth.le.AdvertiseData$Builder】 +【android.bluetooth.le.AdvertiseData】 +【android.bluetooth.le.AdvertiseSettings$Builder】 +【android.bluetooth.le.AdvertiseSettings】 +【android.bluetooth.le.BluetoothLeAdvertiser】 +【android.bluetooth.le.BluetoothLeScanner】 +【android.bluetooth.le.ScanCallback】 +【android.bluetooth.le.ScanFilter$Builder】 +【android.bluetooth.le.ScanFilter】 +【android.bluetooth.le.ScanRecord】 +【android.bluetooth.le.ScanResult】 +【android.bluetooth.le.ScanSettings$Builder】 +【android.bluetooth.le.ScanSettings】 +【android.content.AbstractThreadedSyncAdapter】 +【android.content.ActivityNotFoundException】 +【android.content.AsyncQueryHandler$WorkerArgs】 +【android.content.AsyncQueryHandler$WorkerHandler】 +【android.content.AsyncQueryHandler】 +【android.content.AsyncTaskLoader】 +【android.content.BroadcastReceiver$PendingResult】 +【android.content.BroadcastReceiver】 +【android.content.ClipboardManager$OnPrimaryClipChangedListener】 +【android.content.ClipboardManager】 +【android.content.ClipData$Item】 +【android.content.ClipData】 +【android.content.ClipDescription】 +【android.content.ComponentCallbacks】 +【android.content.ComponentCallbacks2】 +【android.content.ComponentName】 +【android.content.ContentProvider$PipeDataWriter】 +【android.content.ContentProvider】 +【android.content.ContentProviderClient】 +【android.content.ContentProviderOperation$Builder】 +【android.content.ContentProviderOperation】 +【android.content.ContentProviderResult】 +【android.content.ContentQueryMap】 +【android.content.ContentResolver】 +【android.content.ContentUris】 +【android.content.ContentValues】 +【android.content.Context】 +【android.content.ContextWrapper】 +【android.content.CursorLoader】 +【android.content.DialogInterface$OnCancelListener】 +【android.content.DialogInterface$OnClickListener】 +【android.content.DialogInterface$OnDismissListener】 +【android.content.DialogInterface$OnKeyListener】 +【android.content.DialogInterface$OnMultiChoiceClickListener】 +【android.content.DialogInterface$OnShowListener】 +【android.content.DialogInterface】 +【android.content.Entity$NamedContentValues】 +【android.content.Entity】 +【android.content.EntityIterator】 +【android.content.Intent$FilterComparison】 +【android.content.Intent$ShortcutIconResource】 +【android.content.Intent】 +【android.content.IntentFilter$AuthorityEntry】 +【android.content.IntentFilter$MalformedMimeTypeException】 +【android.content.IntentFilter】 +【android.content.IntentSender$OnFinished】 +【android.content.IntentSender$SendIntentException】 +【android.content.IntentSender】 +【android.content.Loader$ForceLoadContentObserver】 +【android.content.Loader$OnLoadCanceledListener】 +【android.content.Loader$OnLoadCompleteListener】 +【android.content.Loader】 +【android.content.MutableContextWrapper】 +【android.content.OperationApplicationException】 +【android.content.PeriodicSync】 +【android.content.pm.ActivityInfo】 +【android.content.pm.ApplicationInfo$DisplayNameComparator】 +【android.content.pm.ApplicationInfo】 +【android.content.pm.ComponentInfo】 +【android.content.pm.ConfigurationInfo】 +【android.content.pm.FeatureGroupInfo】 +【android.content.pm.FeatureInfo】 +【android.content.pm.InstrumentationInfo】 +【android.content.pm.LabeledIntent】 +【android.content.pm.LauncherActivityInfo】 +【android.content.pm.LauncherApps$Callback】 +【android.content.pm.LauncherApps】 +【android.content.pm.PackageInfo】 +【android.content.pm.PackageInstaller$Session】 +【android.content.pm.PackageInstaller$SessionCallback】 +【android.content.pm.PackageInstaller$SessionInfo】 +【android.content.pm.PackageInstaller$SessionParams】 +【android.content.pm.PackageInstaller】 +【android.content.pm.PackageItemInfo$DisplayNameComparator】 +【android.content.pm.PackageItemInfo】 +【android.content.pm.PackageManager$NameNotFoundException】 +【android.content.pm.PackageManager】 +【android.content.pm.PackageStats】 +【android.content.pm.PathPermission】 +【android.content.pm.PermissionGroupInfo】 +【android.content.pm.PermissionInfo】 +【android.content.pm.ProviderInfo】 +【android.content.pm.ResolveInfo$DisplayNameComparator】 +【android.content.pm.ResolveInfo】 +【android.content.pm.ServiceInfo】 +【android.content.pm.Signature】 +【android.content.ReceiverCallNotAllowedException】 +【android.content.res.AssetFileDescriptor$AutoCloseInputStream】 +【android.content.res.AssetFileDescriptor$AutoCloseOutputStream】 +【android.content.res.AssetFileDescriptor】 +【android.content.res.AssetManager$AssetInputStream】 +【android.content.res.AssetManager】 +【android.content.res.ColorStateList】 +【android.content.res.Configuration】 +【android.content.res.ObbInfo】 +【android.content.res.ObbScanner】 +【android.content.res.Resources$NotFoundException】 +【android.content.res.Resources$Theme】 +【android.content.res.Resources】 +【android.content.res.TypedArray】 +【android.content.res.XmlResourceParser】 +【android.content.RestrictionEntry】 +【android.content.RestrictionsManager】 +【android.content.SearchRecentSuggestionsProvider】 +【android.content.ServiceConnection】 +【android.content.SharedPreferences$Editor】 +【android.content.SharedPreferences$OnSharedPreferenceChangeListener】 +【android.content.SharedPreferences】 +【android.content.SyncAdapterType】 +【android.content.SyncContext】 +【android.content.SyncInfo】 +【android.content.SyncRequest$Builder】 +【android.content.SyncRequest】 +【android.content.SyncResult】 +【android.content.SyncStats】 +【android.content.SyncStatusObserver】 +【android.content.UriMatcher】 +【android.content.UriPermission】 +【android.database.AbstractCursor$SelfContentObserver】 +【android.database.AbstractCursor】 +【android.database.AbstractWindowedCursor】 +【android.database.CharArrayBuffer】 +【android.database.ContentObservable】 +【android.database.ContentObserver】 +【android.database.CrossProcessCursor】 +【android.database.CrossProcessCursorWrapper】 +【android.database.Cursor】 +【android.database.CursorIndexOutOfBoundsException】 +【android.database.CursorJoiner$Result】 +【android.database.CursorJoiner】 +【android.database.CursorWindow】 +【android.database.CursorWrapper】 +【android.database.DatabaseErrorHandler】 +【android.database.DatabaseUtils$InsertHelper】 +【android.database.DatabaseUtils】 +【android.database.DataSetObservable】 +【android.database.DataSetObserver】 +【android.database.DefaultDatabaseErrorHandler】 +【android.database.MatrixCursor$RowBuilder】 +【android.database.MatrixCursor】 +【android.database.MergeCursor】 +【android.database.Observable】 +【android.database.SQLException】 +【android.database.sqlite.SQLiteAbortException】 +【android.database.sqlite.SQLiteAccessPermException】 +【android.database.sqlite.SQLiteBindOrColumnIndexOutOfRangeException】 +【android.database.sqlite.SQLiteBlobTooBigException】 +【android.database.sqlite.SQLiteCantOpenDatabaseException】 +【android.database.sqlite.SQLiteClosable】 +【android.database.sqlite.SQLiteConstraintException】 +【android.database.sqlite.SQLiteCursor】 +【android.database.sqlite.SQLiteCursorDriver】 +【android.database.sqlite.SQLiteDatabase$CursorFactory】 +【android.database.sqlite.SQLiteDatabase】 +【android.database.sqlite.SQLiteDatabaseCorruptException】 +【android.database.sqlite.SQLiteDatabaseLockedException】 +【android.database.sqlite.SQLiteDatatypeMismatchException】 +【android.database.sqlite.SQLiteDiskIOException】 +【android.database.sqlite.SQLiteDoneException】 +【android.database.sqlite.SQLiteException】 +【android.database.sqlite.SQLiteFullException】 +【android.database.sqlite.SQLiteMisuseException】 +【android.database.sqlite.SQLiteOpenHelper】 +【android.database.sqlite.SQLiteOutOfMemoryException】 +【android.database.sqlite.SQLiteProgram】 +【android.database.sqlite.SQLiteQuery】 +【android.database.sqlite.SQLiteQueryBuilder】 +【android.database.sqlite.SQLiteReadOnlyDatabaseException】 +【android.database.sqlite.SQLiteStatement】 +【android.database.sqlite.SQLiteTableLockedException】 +【android.database.sqlite.SQLiteTransactionListener】 +【android.database.StaleDataException】 +【android.drm.DrmConvertedStatus】 +【android.drm.DrmErrorEvent】 +【android.drm.DrmEvent】 +【android.drm.DrmInfo】 +【android.drm.DrmInfoEvent】 +【android.drm.DrmInfoRequest】 +【android.drm.DrmInfoStatus】 +【android.drm.DrmManagerClient$OnErrorListener】 +【android.drm.DrmManagerClient$OnEventListener】 +【android.drm.DrmManagerClient$OnInfoListener】 +【android.drm.DrmManagerClient】 +【android.drm.DrmRights】 +【android.drm.DrmStore$Action】 +【android.drm.DrmStore$ConstraintsColumns】 +【android.drm.DrmStore$DrmObjectType】 +【android.drm.DrmStore$Playback】 +【android.drm.DrmStore$RightsStatus】 +【android.drm.DrmStore】 +【android.drm.DrmSupportInfo】 +【android.drm.DrmUtils$ExtendedMetadataParser】 +【android.drm.DrmUtils】 +【android.drm.ProcessedData】 +【android.gesture.Gesture】 +【android.gesture.GestureLibraries】 +【android.gesture.GestureLibrary】 +【android.gesture.GestureOverlayView$OnGestureListener】 +【android.gesture.GestureOverlayView$OnGesturePerformedListener】 +【android.gesture.GestureOverlayView$OnGesturingListener】 +【android.gesture.GestureOverlayView】 +【android.gesture.GesturePoint】 +【android.gesture.GestureStore】 +【android.gesture.GestureStroke】 +【android.gesture.GestureUtils】 +【android.gesture.OrientedBoundingBox】 +【android.gesture.Prediction】 +【android.graphics.AvoidXfermode$Mode】 +【android.graphics.AvoidXfermode】 +【android.graphics.Bitmap$CompressFormat】 +【android.graphics.Bitmap$Config】 +【android.graphics.Bitmap】 +【android.graphics.BitmapFactory$Options】 +【android.graphics.BitmapFactory】 +【android.graphics.BitmapRegionDecoder】 +【android.graphics.BitmapShader】 +【android.graphics.BlurMaskFilter$Blur】 +【android.graphics.BlurMaskFilter】 +【android.graphics.Camera】 +【android.graphics.Canvas$EdgeType】 +【android.graphics.Canvas$VertexMode】 +【android.graphics.Canvas】 +【android.graphics.Color】 +【android.graphics.ColorFilter】 +【android.graphics.ColorMatrix】 +【android.graphics.ColorMatrixColorFilter】 +【android.graphics.ComposePathEffect】 +【android.graphics.ComposeShader】 +【android.graphics.CornerPathEffect】 +【android.graphics.DashPathEffect】 +【android.graphics.DiscretePathEffect】 +【android.graphics.drawable.Animatable】 +【android.graphics.drawable.AnimatedStateListDrawable】 +【android.graphics.drawable.AnimatedVectorDrawable】 +【android.graphics.drawable.AnimationDrawable】 +【android.graphics.drawable.BitmapDrawable】 +【android.graphics.drawable.ClipDrawable】 +【android.graphics.drawable.ColorDrawable】 +【android.graphics.drawable.Drawable$Callback】 +【android.graphics.drawable.Drawable$ConstantState】 +【android.graphics.drawable.Drawable】 +【android.graphics.drawable.DrawableContainer$DrawableContainerState】 +【android.graphics.drawable.DrawableContainer】 +【android.graphics.drawable.GradientDrawable$Orientation】 +【android.graphics.drawable.GradientDrawable】 +【android.graphics.drawable.InsetDrawable】 +【android.graphics.drawable.LayerDrawable】 +【android.graphics.drawable.LevelListDrawable】 +【android.graphics.drawable.NinePatchDrawable】 +【android.graphics.drawable.PaintDrawable】 +【android.graphics.drawable.PictureDrawable】 +【android.graphics.drawable.RippleDrawable】 +【android.graphics.drawable.RotateDrawable】 +【android.graphics.drawable.ScaleDrawable】 +【android.graphics.drawable.ShapeDrawable$ShaderFactory】 +【android.graphics.drawable.ShapeDrawable】 +【android.graphics.drawable.shapes.ArcShape】 +【android.graphics.drawable.shapes.OvalShape】 +【android.graphics.drawable.shapes.PathShape】 +【android.graphics.drawable.shapes.RectShape】 +【android.graphics.drawable.shapes.RoundRectShape】 +【android.graphics.drawable.shapes.Shape】 +【android.graphics.drawable.StateListDrawable】 +【android.graphics.drawable.TransitionDrawable】 +【android.graphics.drawable.VectorDrawable】 +【android.graphics.DrawFilter】 +【android.graphics.EmbossMaskFilter】 +【android.graphics.ImageFormat】 +【android.graphics.Interpolator$Result】 +【android.graphics.Interpolator】 +【android.graphics.LayerRasterizer】 +【android.graphics.LightingColorFilter】 +【android.graphics.LinearGradient】 +【android.graphics.MaskFilter】 +【android.graphics.Matrix$ScaleToFit】 +【android.graphics.Matrix】 +【android.graphics.Movie】 +【android.graphics.NinePatch】 +【android.graphics.Outline】 +【android.graphics.Paint$Align】 +【android.graphics.Paint$Cap】 +【android.graphics.Paint$FontMetrics】 +【android.graphics.Paint$FontMetricsInt】 +【android.graphics.Paint$Join】 +【android.graphics.Paint$Style】 +【android.graphics.Paint】 +【android.graphics.PaintFlagsDrawFilter】 +【android.graphics.Path$Direction】 +【android.graphics.Path$FillType】 +【android.graphics.Path$Op】 +【android.graphics.Path】 +【android.graphics.PathDashPathEffect$Style】 +【android.graphics.PathDashPathEffect】 +【android.graphics.PathEffect】 +【android.graphics.PathMeasure】 +【android.graphics.pdf.PdfDocument$Page】 +【android.graphics.pdf.PdfDocument$PageInfo$Builder】 +【android.graphics.pdf.PdfDocument$PageInfo】 +【android.graphics.pdf.PdfDocument】 +【android.graphics.pdf.PdfRenderer$Page】 +【android.graphics.pdf.PdfRenderer】 +【android.graphics.Picture】 +【android.graphics.PixelFormat】 +【android.graphics.PixelXorXfermode】 +【android.graphics.Point】 +【android.graphics.PointF】 +【android.graphics.PorterDuff$Mode】 +【android.graphics.PorterDuff】 +【android.graphics.PorterDuffColorFilter】 +【android.graphics.PorterDuffXfermode】 +【android.graphics.RadialGradient】 +【android.graphics.Rasterizer】 +【android.graphics.Rect】 +【android.graphics.RectF】 +【android.graphics.Region$Op】 +【android.graphics.Region】 +【android.graphics.RegionIterator】 +【android.graphics.Shader$TileMode】 +【android.graphics.Shader】 +【android.graphics.SumPathEffect】 +【android.graphics.SurfaceTexture$OnFrameAvailableListener】 +【android.graphics.SurfaceTexture$OutOfResourcesException】 +【android.graphics.SurfaceTexture】 +【android.graphics.SweepGradient】 +【android.graphics.Typeface】 +【android.graphics.Xfermode】 +【android.graphics.YuvImage】 +【android.hardware.Camera$Area】 +【android.hardware.Camera$AutoFocusCallback】 +【android.hardware.Camera$AutoFocusMoveCallback】 +【android.hardware.Camera$CameraInfo】 +【android.hardware.Camera$ErrorCallback】 +【android.hardware.Camera$Face】 +【android.hardware.Camera$FaceDetectionListener】 +【android.hardware.Camera$OnZoomChangeListener】 +【android.hardware.Camera$Parameters】 +【android.hardware.Camera$PictureCallback】 +【android.hardware.Camera$PreviewCallback】 +【android.hardware.Camera$ShutterCallback】 +【android.hardware.Camera$Size】 +【android.hardware.Camera】 +【android.hardware.camera2.CameraAccessException】 +【android.hardware.camera2.CameraCaptureSession$CaptureCallback】 +【android.hardware.camera2.CameraCaptureSession$StateCallback】 +【android.hardware.camera2.CameraCaptureSession】 +【android.hardware.camera2.CameraCharacteristics$Key】 +【android.hardware.camera2.CameraCharacteristics】 +【android.hardware.camera2.CameraDevice$StateCallback】 +【android.hardware.camera2.CameraDevice】 +【android.hardware.camera2.CameraManager$AvailabilityCallback】 +【android.hardware.camera2.CameraManager】 +【android.hardware.camera2.CameraMetadata】 +【android.hardware.camera2.CaptureFailure】 +【android.hardware.camera2.CaptureRequest$Builder】 +【android.hardware.camera2.CaptureRequest$Key】 +【android.hardware.camera2.CaptureRequest】 +【android.hardware.camera2.CaptureResult$Key】 +【android.hardware.camera2.CaptureResult】 +【android.hardware.camera2.DngCreator】 +【android.hardware.camera2.params.BlackLevelPattern】 +【android.hardware.camera2.params.ColorSpaceTransform】 +【android.hardware.camera2.params.Face】 +【android.hardware.camera2.params.LensShadingMap】 +【android.hardware.camera2.params.MeteringRectangle】 +【android.hardware.camera2.params.RggbChannelVector】 +【android.hardware.camera2.params.StreamConfigurationMap】 +【android.hardware.camera2.params.TonemapCurve】 +【android.hardware.camera2.TotalCaptureResult】 +【android.hardware.ConsumerIrManager$CarrierFrequencyRange】 +【android.hardware.ConsumerIrManager】 +【android.hardware.display.DisplayManager$DisplayListener】 +【android.hardware.display.DisplayManager】 +【android.hardware.display.VirtualDisplay$Callback】 +【android.hardware.display.VirtualDisplay】 +【android.hardware.GeomagneticField】 +【android.hardware.input.InputManager$InputDeviceListener】 +【android.hardware.input.InputManager】 +【android.hardware.Sensor】 +【android.hardware.SensorEvent】 +【android.hardware.SensorEventListener】 +【android.hardware.SensorEventListener2】 +【android.hardware.SensorListener】 +【android.hardware.SensorManager】 +【android.hardware.TriggerEvent】 +【android.hardware.TriggerEventListener】 +【android.hardware.usb.UsbAccessory】 +【android.hardware.usb.UsbConfiguration】 +【android.hardware.usb.UsbConstants】 +【android.hardware.usb.UsbDevice】 +【android.hardware.usb.UsbDeviceConnection】 +【android.hardware.usb.UsbEndpoint】 +【android.hardware.usb.UsbInterface】 +【android.hardware.usb.UsbManager】 +【android.hardware.usb.UsbRequest】 +【android.inputmethodservice.AbstractInputMethodService$AbstractInputMethodImpl】 +【android.inputmethodservice.AbstractInputMethodService$AbstractInputMethodSessionImpl】 +【android.inputmethodservice.AbstractInputMethodService】 +【android.inputmethodservice.ExtractEditText】 +【android.inputmethodservice.InputMethodService$InputMethodImpl】 +【android.inputmethodservice.InputMethodService$InputMethodSessionImpl】 +【android.inputmethodservice.InputMethodService$Insets】 +【android.inputmethodservice.InputMethodService】 +【android.inputmethodservice.Keyboard$Key】 +【android.inputmethodservice.Keyboard$Row】 +【android.inputmethodservice.Keyboard】 +【android.inputmethodservice.KeyboardView$OnKeyboardActionListener】 +【android.inputmethodservice.KeyboardView】 +【android.location.Address】 +【android.location.Criteria】 +【android.location.Geocoder】 +【android.location.GpsSatellite】 +【android.location.GpsStatus$Listener】 +【android.location.GpsStatus$NmeaListener】 +【android.location.GpsStatus】 +【android.location.Location】 +【android.location.LocationListener】 +【android.location.LocationManager】 +【android.location.LocationProvider】 +【android.location.SettingInjectorService】 +【android.Manifest$permission】 +【android.Manifest$permission_group】 +【android.Manifest】 +【android.media.AsyncPlayer】 +【android.media.AudioAttributes$Builder】 +【android.media.AudioAttributes】 +【android.media.AudioFormat$Builder】 +【android.media.AudioFormat】 +【android.media.audiofx.AcousticEchoCanceler】 +【android.media.audiofx.AudioEffect$Descriptor】 +【android.media.audiofx.AudioEffect$OnControlStatusChangeListener】 +【android.media.audiofx.AudioEffect$OnEnableStatusChangeListener】 +【android.media.audiofx.AudioEffect】 +【android.media.audiofx.AutomaticGainControl】 +【android.media.audiofx.BassBoost$OnParameterChangeListener】 +【android.media.audiofx.BassBoost$Settings】 +【android.media.audiofx.BassBoost】 +【android.media.audiofx.EnvironmentalReverb$OnParameterChangeListener】 +【android.media.audiofx.EnvironmentalReverb$Settings】 +【android.media.audiofx.EnvironmentalReverb】 +【android.media.audiofx.Equalizer$OnParameterChangeListener】 +【android.media.audiofx.Equalizer$Settings】 +【android.media.audiofx.Equalizer】 +【android.media.audiofx.LoudnessEnhancer】 +【android.media.audiofx.NoiseSuppressor】 +【android.media.audiofx.PresetReverb$OnParameterChangeListener】 +【android.media.audiofx.PresetReverb$Settings】 +【android.media.audiofx.PresetReverb】 +【android.media.audiofx.Virtualizer$OnParameterChangeListener】 +【android.media.audiofx.Virtualizer$Settings】 +【android.media.audiofx.Virtualizer】 +【android.media.audiofx.Visualizer$MeasurementPeakRms】 +【android.media.audiofx.Visualizer$OnDataCaptureListener】 +【android.media.audiofx.Visualizer】 +【android.media.AudioManager$OnAudioFocusChangeListener】 +【android.media.AudioManager】 +【android.media.AudioRecord$OnRecordPositionUpdateListener】 +【android.media.AudioRecord】 +【android.media.AudioTimestamp】 +【android.media.AudioTrack$OnPlaybackPositionUpdateListener】 +【android.media.AudioTrack】 +【android.media.browse.MediaBrowser$ConnectionCallback】 +【android.media.browse.MediaBrowser$MediaItem】 +【android.media.browse.MediaBrowser$SubscriptionCallback】 +【android.media.browse.MediaBrowser】 +【android.media.CamcorderProfile】 +【android.media.CameraProfile】 +【android.media.DeniedByServerException】 +【android.media.effect.Effect】 +【android.media.effect.EffectContext】 +【android.media.effect.EffectFactory】 +【android.media.effect.EffectUpdateListener】 +【android.media.ExifInterface】 +【android.media.FaceDetector$Face】 +【android.media.FaceDetector】 +【android.media.Image$Plane】 +【android.media.Image】 +【android.media.ImageReader$OnImageAvailableListener】 +【android.media.ImageReader】 +【android.media.JetPlayer$OnJetEventListener】 +【android.media.JetPlayer】 +【android.media.MediaActionSound】 +【android.media.MediaCodec$BufferInfo】 +【android.media.MediaCodec$Callback】 +【android.media.MediaCodec$CodecException】 +【android.media.MediaCodec$CryptoException】 +【android.media.MediaCodec$CryptoInfo】 +【android.media.MediaCodec】 +【android.media.MediaCodecInfo$AudioCapabilities】 +【android.media.MediaCodecInfo$CodecCapabilities】 +【android.media.MediaCodecInfo$CodecProfileLevel】 +【android.media.MediaCodecInfo$EncoderCapabilities】 +【android.media.MediaCodecInfo$VideoCapabilities】 +【android.media.MediaCodecInfo】 +【android.media.MediaCodecList】 +【android.media.MediaCrypto】 +【android.media.MediaCryptoException】 +【android.media.MediaDescription$Builder】 +【android.media.MediaDescription】 +【android.media.MediaDrm$CryptoSession】 +【android.media.MediaDrm$KeyRequest】 +【android.media.MediaDrm$MediaDrmStateException】 +【android.media.MediaDrm$OnEventListener】 +【android.media.MediaDrm$ProvisionRequest】 +【android.media.MediaDrm】 +【android.media.MediaDrmException】 +【android.media.MediaExtractor】 +【android.media.MediaFormat】 +【android.media.MediaMetadata$Builder】 +【android.media.MediaMetadata】 +【android.media.MediaMetadataEditor】 +【android.media.MediaMetadataRetriever】 +【android.media.MediaMuxer$OutputFormat】 +【android.media.MediaMuxer】 +【android.media.MediaPlayer$OnBufferingUpdateListener】 +【android.media.MediaPlayer$OnCompletionListener】 +【android.media.MediaPlayer$OnErrorListener】 +【android.media.MediaPlayer$OnInfoListener】 +【android.media.MediaPlayer$OnPreparedListener】 +【android.media.MediaPlayer$OnSeekCompleteListener】 +【android.media.MediaPlayer$OnTimedTextListener】 +【android.media.MediaPlayer$OnVideoSizeChangedListener】 +【android.media.MediaPlayer$TrackInfo】 +【android.media.MediaPlayer】 +【android.media.MediaRecorder$AudioEncoder】 +【android.media.MediaRecorder$AudioSource】 +【android.media.MediaRecorder$OnErrorListener】 +【android.media.MediaRecorder$OnInfoListener】 +【android.media.MediaRecorder$OutputFormat】 +【android.media.MediaRecorder$VideoEncoder】 +【android.media.MediaRecorder$VideoSource】 +【android.media.MediaRecorder】 +【android.media.MediaRouter$Callback】 +【android.media.MediaRouter$RouteCategory】 +【android.media.MediaRouter$RouteGroup】 +【android.media.MediaRouter$RouteInfo】 +【android.media.MediaRouter$SimpleCallback】 +【android.media.MediaRouter$UserRouteInfo】 +【android.media.MediaRouter$VolumeCallback】 +【android.media.MediaRouter】 +【android.media.MediaScannerConnection$MediaScannerConnectionClient】 +【android.media.MediaScannerConnection$OnScanCompletedListener】 +【android.media.MediaScannerConnection】 +【android.media.MediaSyncEvent】 +【android.media.NotProvisionedException】 +【android.media.projection.MediaProjection$Callback】 +【android.media.projection.MediaProjection】 +【android.media.projection.MediaProjectionManager】 +【android.media.Rating】 +【android.media.RemoteControlClient$MetadataEditor】 +【android.media.RemoteControlClient$OnGetPlaybackPositionListener】 +【android.media.RemoteControlClient$OnMetadataUpdateListener】 +【android.media.RemoteControlClient$OnPlaybackPositionUpdateListener】 +【android.media.RemoteControlClient】 +【android.media.RemoteController$MetadataEditor】 +【android.media.RemoteController$OnClientUpdateListener】 +【android.media.RemoteController】 +【android.media.ResourceBusyException】 +【android.media.Ringtone】 +【android.media.RingtoneManager】 +【android.media.session.MediaController$Callback】 +【android.media.session.MediaController$PlaybackInfo】 +【android.media.session.MediaController$TransportControls】 +【android.media.session.MediaController】 +【android.media.session.MediaSession$Callback】 +【android.media.session.MediaSession$QueueItem】 +【android.media.session.MediaSession$Token】 +【android.media.session.MediaSession】 +【android.media.session.MediaSessionManager$OnActiveSessionsChangedListener】 +【android.media.session.MediaSessionManager】 +【android.media.session.PlaybackState$Builder】 +【android.media.session.PlaybackState$CustomAction$Builder】 +【android.media.session.PlaybackState$CustomAction】 +【android.media.session.PlaybackState】 +【android.media.SoundPool$Builder】 +【android.media.SoundPool$OnLoadCompleteListener】 +【android.media.SoundPool】 +【android.media.ThumbnailUtils】 +【android.media.TimedText】 +【android.media.ToneGenerator】 +【android.media.tv.TvContentRating】 +【android.media.tv.TvContract$BaseTvColumns】 +【android.media.tv.TvContract$Channels$Logo】 +【android.media.tv.TvContract$Channels】 +【android.media.tv.TvContract$Programs$Genres】 +【android.media.tv.TvContract$Programs】 +【android.media.tv.TvContract】 +【android.media.tv.TvInputInfo】 +【android.media.tv.TvInputManager$TvInputCallback】 +【android.media.tv.TvInputManager】 +【android.media.tv.TvInputService$HardwareSession】 +【android.media.tv.TvInputService$Session】 +【android.media.tv.TvInputService】 +【android.media.tv.TvTrackInfo$Builder】 +【android.media.tv.TvTrackInfo】 +【android.media.tv.TvView$OnUnhandledInputEventListener】 +【android.media.tv.TvView$TvInputCallback】 +【android.media.tv.TvView】 +【android.media.UnsupportedSchemeException】 +【android.media.VolumeProvider】 +【android.mtp.MtpConstants】 +【android.mtp.MtpDevice】 +【android.mtp.MtpDeviceInfo】 +【android.mtp.MtpObjectInfo】 +【android.mtp.MtpStorageInfo】 +【android.net.ConnectivityManager$NetworkCallback】 +【android.net.ConnectivityManager$OnNetworkActiveListener】 +【android.net.ConnectivityManager】 +【android.net.Credentials】 +【android.net.DhcpInfo】 +【android.net.http.AndroidHttpClient】 +【android.net.http.HttpResponseCache】 +【android.net.http.SslCertificate$DName】 +【android.net.http.SslCertificate】 +【android.net.http.SslError】 +【android.net.http.X509TrustManagerExtensions】 +【android.net.IpPrefix】 +【android.net.LinkAddress】 +【android.net.LinkProperties】 +【android.net.LocalServerSocket】 +【android.net.LocalSocket】 +【android.net.LocalSocketAddress$Namespace】 +【android.net.LocalSocketAddress】 +【android.net.MailTo】 +【android.net.Network】 +【android.net.NetworkCapabilities】 +【android.net.NetworkInfo$DetailedState】 +【android.net.NetworkInfo$State】 +【android.net.NetworkInfo】 +【android.net.NetworkRequest$Builder】 +【android.net.NetworkRequest】 +【android.net.nsd.NsdManager$DiscoveryListener】 +【android.net.nsd.NsdManager$RegistrationListener】 +【android.net.nsd.NsdManager$ResolveListener】 +【android.net.nsd.NsdManager】 +【android.net.nsd.NsdServiceInfo】 +【android.net.ParseException】 +【android.net.Proxy】 +【android.net.ProxyInfo】 +【android.net.PskKeyManager】 +【android.net.RouteInfo】 +【android.net.rtp.AudioCodec】 +【android.net.rtp.AudioGroup】 +【android.net.rtp.AudioStream】 +【android.net.rtp.RtpStream】 +【android.net.sip.SipAudioCall$Listener】 +【android.net.sip.SipAudioCall】 +【android.net.sip.SipErrorCode】 +【android.net.sip.SipException】 +【android.net.sip.SipManager】 +【android.net.sip.SipProfile$Builder】 +【android.net.sip.SipProfile】 +【android.net.sip.SipRegistrationListener】 +【android.net.sip.SipSession$Listener】 +【android.net.sip.SipSession$State】 +【android.net.sip.SipSession】 +【android.net.SSLCertificateSocketFactory】 +【android.net.SSLSessionCache】 +【android.net.TrafficStats】 +【android.net.Uri$Builder】 +【android.net.Uri】 +【android.net.UrlQuerySanitizer$IllegalCharacterValueSanitizer】 +【android.net.UrlQuerySanitizer$ParameterValuePair】 +【android.net.UrlQuerySanitizer$ValueSanitizer】 +【android.net.UrlQuerySanitizer】 +【android.net.VpnService$Builder】 +【android.net.VpnService】 +【android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo】 +【android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest】 +【android.net.wifi.p2p.nsd.WifiP2pServiceInfo】 +【android.net.wifi.p2p.nsd.WifiP2pServiceRequest】 +【android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo】 +【android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest】 +【android.net.wifi.p2p.WifiP2pConfig】 +【android.net.wifi.p2p.WifiP2pDevice】 +【android.net.wifi.p2p.WifiP2pDeviceList】 +【android.net.wifi.p2p.WifiP2pGroup】 +【android.net.wifi.p2p.WifiP2pInfo】 +【android.net.wifi.p2p.WifiP2pManager$ActionListener】 +【android.net.wifi.p2p.WifiP2pManager$Channel】 +【android.net.wifi.p2p.WifiP2pManager$ChannelListener】 +【android.net.wifi.p2p.WifiP2pManager$ConnectionInfoListener】 +【android.net.wifi.p2p.WifiP2pManager$DnsSdServiceResponseListener】 +【android.net.wifi.p2p.WifiP2pManager$DnsSdTxtRecordListener】 +【android.net.wifi.p2p.WifiP2pManager$GroupInfoListener】 +【android.net.wifi.p2p.WifiP2pManager$PeerListListener】 +【android.net.wifi.p2p.WifiP2pManager$ServiceResponseListener】 +【android.net.wifi.p2p.WifiP2pManager$UpnpServiceResponseListener】 +【android.net.wifi.p2p.WifiP2pManager】 +【android.net.wifi.ScanResult】 +【android.net.wifi.SupplicantState】 +【android.net.wifi.WifiConfiguration$AuthAlgorithm】 +【android.net.wifi.WifiConfiguration$GroupCipher】 +【android.net.wifi.WifiConfiguration$KeyMgmt】 +【android.net.wifi.WifiConfiguration$PairwiseCipher】 +【android.net.wifi.WifiConfiguration$Protocol】 +【android.net.wifi.WifiConfiguration$Status】 +【android.net.wifi.WifiConfiguration】 +【android.net.wifi.WifiEnterpriseConfig$Eap】 +【android.net.wifi.WifiEnterpriseConfig$Phase2】 +【android.net.wifi.WifiEnterpriseConfig】 +【android.net.wifi.WifiInfo】 +【android.net.wifi.WifiManager$MulticastLock】 +【android.net.wifi.WifiManager$WifiLock】 +【android.net.wifi.WifiManager$WpsCallback】 +【android.net.wifi.WifiManager】 +【android.net.wifi.WpsInfo】 +【android.nfc.cardemulation.CardEmulation】 +【android.nfc.cardemulation.HostApduService】 +【android.nfc.cardemulation.OffHostApduService】 +【android.nfc.FormatException】 +【android.nfc.NdefMessage】 +【android.nfc.NdefRecord】 +【android.nfc.NfcAdapter$CreateBeamUrisCallback】 +【android.nfc.NfcAdapter$CreateNdefMessageCallback】 +【android.nfc.NfcAdapter$OnNdefPushCompleteCallback】 +【android.nfc.NfcAdapter$ReaderCallback】 +【android.nfc.NfcAdapter】 +【android.nfc.NfcEvent】 +【android.nfc.NfcManager】 +【android.nfc.Tag】 +【android.nfc.TagLostException】 +【android.nfc.tech.BasicTagTechnology】 +【android.nfc.tech.IsoDep】 +【android.nfc.tech.MifareClassic】 +【android.nfc.tech.MifareUltralight】 +【android.nfc.tech.Ndef】 +【android.nfc.tech.NdefFormatable】 +【android.nfc.tech.NfcA】 +【android.nfc.tech.NfcB】 +【android.nfc.tech.NfcBarcode】 +【android.nfc.tech.NfcF】 +【android.nfc.tech.NfcV】 +【android.nfc.tech.TagTechnology】 +【android.opengl.EGL14】 +【android.opengl.EGLConfig】 +【android.opengl.EGLContext】 +【android.opengl.EGLDisplay】 +【android.opengl.EGLExt】 +【android.opengl.EGLObjectHandle】 +【android.opengl.EGLSurface】 +【android.opengl.ETC1】 +【android.opengl.ETC1Util$ETC1Texture】 +【android.opengl.ETC1Util】 +【android.opengl.GLDebugHelper】 +【android.opengl.GLES10】 +【android.opengl.GLES10Ext】 +【android.opengl.GLES11】 +【android.opengl.GLES11Ext】 +【android.opengl.GLES20】 +【android.opengl.GLES30】 +【android.opengl.GLES31】 +【android.opengl.GLES31Ext$DebugProcKHR】 +【android.opengl.GLES31Ext】 +【android.opengl.GLException】 +【android.opengl.GLSurfaceView$EGLConfigChooser】 +【android.opengl.GLSurfaceView$EGLContextFactory】 +【android.opengl.GLSurfaceView$EGLWindowSurfaceFactory】 +【android.opengl.GLSurfaceView$GLWrapper】 +【android.opengl.GLSurfaceView$Renderer】 +【android.opengl.GLSurfaceView】 +【android.opengl.GLU】 +【android.opengl.GLUtils】 +【android.opengl.Matrix】 +【android.opengl.Visibility】 +【android.os.AsyncTask$Status】 +【android.os.AsyncTask】 +【android.os.BadParcelableException】 +【android.os.BaseBundle】 +【android.os.BatteryManager】 +【android.os.Binder】 +【android.os.Build$VERSION】 +【android.os.Build$VERSION_CODES】 +【android.os.Build】 +【android.os.Bundle】 +【android.os.CancellationSignal$OnCancelListener】 +【android.os.CancellationSignal】 +【android.os.ConditionVariable】 +【android.os.CountDownTimer】 +【android.os.DeadObjectException】 +【android.os.Debug$InstructionCount】 +【android.os.Debug$MemoryInfo】 +【android.os.Debug】 +【android.os.DropBoxManager$Entry】 +【android.os.DropBoxManager】 +【android.os.Environment】 +【android.os.FileObserver】 +【android.os.Handler$Callback】 +【android.os.Handler】 +【android.os.HandlerThread】 +【android.os.IBinder$DeathRecipient】 +【android.os.IBinder】 +【android.os.IInterface】 +【android.os.Looper】 +【android.os.MemoryFile】 +【android.os.Message】 +【android.os.MessageQueue$IdleHandler】 +【android.os.MessageQueue】 +【android.os.Messenger】 +【android.os.NetworkOnMainThreadException】 +【android.os.OperationCanceledException】 +【android.os.Parcel】 +【android.os.Parcelable$ClassLoaderCreator】 +【android.os.Parcelable$Creator】 +【android.os.Parcelable】 +【android.os.ParcelFileDescriptor$AutoCloseInputStream】 +【android.os.ParcelFileDescriptor$AutoCloseOutputStream】 +【android.os.ParcelFileDescriptor$FileDescriptorDetachedException】 +【android.os.ParcelFileDescriptor$OnCloseListener】 +【android.os.ParcelFileDescriptor】 +【android.os.ParcelFormatException】 +【android.os.ParcelUuid】 +【android.os.PatternMatcher】 +【android.os.PersistableBundle】 +【android.os.PowerManager$WakeLock】 +【android.os.PowerManager】 +【android.os.Process】 +【android.os.RecoverySystem$ProgressListener】 +【android.os.RecoverySystem】 +【android.os.RemoteCallbackList】 +【android.os.RemoteException】 +【android.os.ResultReceiver】 +【android.os.StatFs】 +【android.os.storage.OnObbStateChangeListener】 +【android.os.storage.StorageManager】 +【android.os.StrictMode$ThreadPolicy$Builder】 +【android.os.StrictMode$ThreadPolicy】 +【android.os.StrictMode$VmPolicy$Builder】 +【android.os.StrictMode$VmPolicy】 +【android.os.StrictMode】 +【android.os.SystemClock】 +【android.os.TokenWatcher】 +【android.os.Trace】 +【android.os.TransactionTooLargeException】 +【android.os.UserHandle】 +【android.os.UserManager】 +【android.os.Vibrator】 +【android.os.WorkSource】 +【android.preference.CheckBoxPreference】 +【android.preference.DialogPreference】 +【android.preference.EditTextPreference】 +【android.preference.ListPreference】 +【android.preference.MultiSelectListPreference】 +【android.preference.Preference$BaseSavedState】 +【android.preference.Preference$OnPreferenceChangeListener】 +【android.preference.Preference$OnPreferenceClickListener】 +【android.preference.Preference】 +【android.preference.PreferenceActivity$Header】 +【android.preference.PreferenceActivity】 +【android.preference.PreferenceCategory】 +【android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback】 +【android.preference.PreferenceFragment】 +【android.preference.PreferenceGroup】 +【android.preference.PreferenceManager$OnActivityDestroyListener】 +【android.preference.PreferenceManager$OnActivityResultListener】 +【android.preference.PreferenceManager$OnActivityStopListener】 +【android.preference.PreferenceManager】 +【android.preference.PreferenceScreen】 +【android.preference.RingtonePreference】 +【android.preference.SwitchPreference】 +【android.preference.TwoStatePreference】 +【android.print.PageRange】 +【android.print.pdf.PrintedPdfDocument】 +【android.print.PrintAttributes$Builder】 +【android.print.PrintAttributes$Margins】 +【android.print.PrintAttributes$MediaSize】 +【android.print.PrintAttributes$Resolution】 +【android.print.PrintAttributes】 +【android.print.PrintDocumentAdapter$LayoutResultCallback】 +【android.print.PrintDocumentAdapter$WriteResultCallback】 +【android.print.PrintDocumentAdapter】 +【android.print.PrintDocumentInfo$Builder】 +【android.print.PrintDocumentInfo】 +【android.print.PrinterCapabilitiesInfo$Builder】 +【android.print.PrinterCapabilitiesInfo】 +【android.print.PrinterId】 +【android.print.PrinterInfo$Builder】 +【android.print.PrinterInfo】 +【android.print.PrintJob】 +【android.print.PrintJobId】 +【android.print.PrintJobInfo$Builder】 +【android.print.PrintJobInfo】 +【android.print.PrintManager】 +【android.printservice.PrintDocument】 +【android.printservice.PrinterDiscoverySession】 +【android.printservice.PrintJob】 +【android.printservice.PrintService】 +【android.provider.AlarmClock】 +【android.provider.BaseColumns】 +【android.provider.Browser$BookmarkColumns】 +【android.provider.Browser$SearchColumns】 +【android.provider.Browser】 +【android.provider.CalendarContract$Attendees】 +【android.provider.CalendarContract$AttendeesColumns】 +【android.provider.CalendarContract$CalendarAlerts】 +【android.provider.CalendarContract$CalendarAlertsColumns】 +【android.provider.CalendarContract$CalendarCache】 +【android.provider.CalendarContract$CalendarCacheColumns】 +【android.provider.CalendarContract$CalendarColumns】 +【android.provider.CalendarContract$CalendarEntity】 +【android.provider.CalendarContract$Calendars】 +【android.provider.CalendarContract$CalendarSyncColumns】 +【android.provider.CalendarContract$Colors】 +【android.provider.CalendarContract$ColorsColumns】 +【android.provider.CalendarContract$EventDays】 +【android.provider.CalendarContract$EventDaysColumns】 +【android.provider.CalendarContract$Events】 +【android.provider.CalendarContract$EventsColumns】 +【android.provider.CalendarContract$EventsEntity】 +【android.provider.CalendarContract$ExtendedProperties】 +【android.provider.CalendarContract$ExtendedPropertiesColumns】 +【android.provider.CalendarContract$Instances】 +【android.provider.CalendarContract$Reminders】 +【android.provider.CalendarContract$RemindersColumns】 +【android.provider.CalendarContract$SyncColumns】 +【android.provider.CalendarContract$SyncState】 +【android.provider.CalendarContract】 +【android.provider.CallLog$Calls】 +【android.provider.CallLog】 +【android.provider.Contacts$ContactMethods】 +【android.provider.Contacts$ContactMethodsColumns】 +【android.provider.Contacts$Extensions】 +【android.provider.Contacts$ExtensionsColumns】 +【android.provider.Contacts$GroupMembership】 +【android.provider.Contacts$Groups】 +【android.provider.Contacts$GroupsColumns】 +【android.provider.Contacts$Intents$Insert】 +【android.provider.Contacts$Intents$UI】 +【android.provider.Contacts$Intents】 +【android.provider.Contacts$OrganizationColumns】 +【android.provider.Contacts$Organizations】 +【android.provider.Contacts$People$ContactMethods】 +【android.provider.Contacts$People$Extensions】 +【android.provider.Contacts$People$Phones】 +【android.provider.Contacts$People】 +【android.provider.Contacts$PeopleColumns】 +【android.provider.Contacts$Phones】 +【android.provider.Contacts$PhonesColumns】 +【android.provider.Contacts$Photos】 +【android.provider.Contacts$PhotosColumns】 +【android.provider.Contacts$PresenceColumns】 +【android.provider.Contacts$Settings】 +【android.provider.Contacts$SettingsColumns】 +【android.provider.Contacts】 +【android.provider.ContactsContract$AggregationExceptions】 +【android.provider.ContactsContract$BaseSyncColumns】 +【android.provider.ContactsContract$CommonDataKinds$BaseTypes】 +【android.provider.ContactsContract$CommonDataKinds$Callable】 +【android.provider.ContactsContract$CommonDataKinds$CommonColumns】 +【android.provider.ContactsContract$CommonDataKinds$Contactables】 +【android.provider.ContactsContract$CommonDataKinds$Email】 +【android.provider.ContactsContract$CommonDataKinds$Event】 +【android.provider.ContactsContract$CommonDataKinds$GroupMembership】 +【android.provider.ContactsContract$CommonDataKinds$Identity】 +【android.provider.ContactsContract$CommonDataKinds$Im】 +【android.provider.ContactsContract$CommonDataKinds$Nickname】 +【android.provider.ContactsContract$CommonDataKinds$Note】 +【android.provider.ContactsContract$CommonDataKinds$Organization】 +【android.provider.ContactsContract$CommonDataKinds$Phone】 +【android.provider.ContactsContract$CommonDataKinds$Photo】 +【android.provider.ContactsContract$CommonDataKinds$Relation】 +【android.provider.ContactsContract$CommonDataKinds$SipAddress】 +【android.provider.ContactsContract$CommonDataKinds$StructuredName】 +【android.provider.ContactsContract$CommonDataKinds$StructuredPostal】 +【android.provider.ContactsContract$CommonDataKinds$Website】 +【android.provider.ContactsContract$CommonDataKinds】 +【android.provider.ContactsContract$ContactNameColumns】 +【android.provider.ContactsContract$ContactOptionsColumns】 +【android.provider.ContactsContract$Contacts$AggregationSuggestions】 +【android.provider.ContactsContract$Contacts$Data】 +【android.provider.ContactsContract$Contacts$Entity】 +【android.provider.ContactsContract$Contacts$Photo】 +【android.provider.ContactsContract$Contacts$StreamItems】 +【android.provider.ContactsContract$Contacts】 +【android.provider.ContactsContract$ContactsColumns】 +【android.provider.ContactsContract$ContactStatusColumns】 +【android.provider.ContactsContract$Data】 +【android.provider.ContactsContract$DataColumns】 +【android.provider.ContactsContract$DataColumnsWithJoins】 +【android.provider.ContactsContract$DataUsageFeedback】 +【android.provider.ContactsContract$DataUsageStatColumns】 +【android.provider.ContactsContract$DeletedContacts】 +【android.provider.ContactsContract$DeletedContactsColumns】 +【android.provider.ContactsContract$Directory】 +【android.provider.ContactsContract$DisplayNameSources】 +【android.provider.ContactsContract$DisplayPhoto】 +【android.provider.ContactsContract$FullNameStyle】 +【android.provider.ContactsContract$Groups】 +【android.provider.ContactsContract$GroupsColumns】 +【android.provider.ContactsContract$Intents$Insert】 +【android.provider.ContactsContract$Intents】 +【android.provider.ContactsContract$PhoneLookup】 +【android.provider.ContactsContract$PhoneLookupColumns】 +【android.provider.ContactsContract$PhoneticNameStyle】 +【android.provider.ContactsContract$PinnedPositions】 +【android.provider.ContactsContract$Presence】 +【android.provider.ContactsContract$PresenceColumns】 +【android.provider.ContactsContract$Profile】 +【android.provider.ContactsContract$ProfileSyncState】 +【android.provider.ContactsContract$QuickContact】 +【android.provider.ContactsContract$RawContacts$Data】 +【android.provider.ContactsContract$RawContacts$DisplayPhoto】 +【android.provider.ContactsContract$RawContacts$Entity】 +【android.provider.ContactsContract$RawContacts$StreamItems】 +【android.provider.ContactsContract$RawContacts】 +【android.provider.ContactsContract$RawContactsColumns】 +【android.provider.ContactsContract$RawContactsEntity】 +【android.provider.ContactsContract$SearchSnippets】 +【android.provider.ContactsContract$Settings】 +【android.provider.ContactsContract$SettingsColumns】 +【android.provider.ContactsContract$StatusColumns】 +【android.provider.ContactsContract$StatusUpdates】 +【android.provider.ContactsContract$StreamItemPhotos】 +【android.provider.ContactsContract$StreamItemPhotosColumns】 +【android.provider.ContactsContract$StreamItems$StreamItemPhotos】 +【android.provider.ContactsContract$StreamItems】 +【android.provider.ContactsContract$StreamItemsColumns】 +【android.provider.ContactsContract$SyncColumns】 +【android.provider.ContactsContract$SyncState】 +【android.provider.ContactsContract】 +【android.provider.DocumentsContract$Document】 +【android.provider.DocumentsContract$Root】 +【android.provider.DocumentsContract】 +【android.provider.DocumentsProvider】 +【android.provider.LiveFolders】 +【android.provider.MediaStore$Audio$AlbumColumns】 +【android.provider.MediaStore$Audio$Albums】 +【android.provider.MediaStore$Audio$ArtistColumns】 +【android.provider.MediaStore$Audio$Artists$Albums】 +【android.provider.MediaStore$Audio$Artists】 +【android.provider.MediaStore$Audio$AudioColumns】 +【android.provider.MediaStore$Audio$Genres$Members】 +【android.provider.MediaStore$Audio$Genres】 +【android.provider.MediaStore$Audio$GenresColumns】 +【android.provider.MediaStore$Audio$Media】 +【android.provider.MediaStore$Audio$Playlists$Members】 +【android.provider.MediaStore$Audio$Playlists】 +【android.provider.MediaStore$Audio$PlaylistsColumns】 +【android.provider.MediaStore$Audio$Radio】 +【android.provider.MediaStore$Audio】 +【android.provider.MediaStore$Files$FileColumns】 +【android.provider.MediaStore$Files】 +【android.provider.MediaStore$Images$ImageColumns】 +【android.provider.MediaStore$Images$Media】 +【android.provider.MediaStore$Images$Thumbnails】 +【android.provider.MediaStore$Images】 +【android.provider.MediaStore$MediaColumns】 +【android.provider.MediaStore$Video$Media】 +【android.provider.MediaStore$Video$Thumbnails】 +【android.provider.MediaStore$Video$VideoColumns】 +【android.provider.MediaStore$Video】 +【android.provider.MediaStore】 +【android.provider.OpenableColumns】 +【android.provider.SearchRecentSuggestions】 +【android.provider.Settings$Global】 +【android.provider.Settings$NameValueTable】 +【android.provider.Settings$Secure】 +【android.provider.Settings$SettingNotFoundException】 +【android.provider.Settings$System】 +【android.provider.Settings】 +【android.provider.SyncStateContract$Columns】 +【android.provider.SyncStateContract$Constants】 +【android.provider.SyncStateContract$Helpers】 +【android.provider.SyncStateContract】 +【android.provider.Telephony$BaseMmsColumns】 +【android.provider.Telephony$CanonicalAddressesColumns】 +【android.provider.Telephony$Carriers】 +【android.provider.Telephony$Mms$Addr】 +【android.provider.Telephony$Mms$Draft】 +【android.provider.Telephony$Mms$Inbox】 +【android.provider.Telephony$Mms$Intents】 +【android.provider.Telephony$Mms$Outbox】 +【android.provider.Telephony$Mms$Part】 +【android.provider.Telephony$Mms$Rate】 +【android.provider.Telephony$Mms$Sent】 +【android.provider.Telephony$Mms】 +【android.provider.Telephony$MmsSms$PendingMessages】 +【android.provider.Telephony$MmsSms】 +【android.provider.Telephony$Sms$Conversations】 +【android.provider.Telephony$Sms$Draft】 +【android.provider.Telephony$Sms$Inbox】 +【android.provider.Telephony$Sms$Intents】 +【android.provider.Telephony$Sms$Outbox】 +【android.provider.Telephony$Sms$Sent】 +【android.provider.Telephony$Sms】 +【android.provider.Telephony$TextBasedSmsColumns】 +【android.provider.Telephony$Threads】 +【android.provider.Telephony$ThreadsColumns】 +【android.provider.Telephony】 +【android.provider.UserDictionary$Words】 +【android.provider.UserDictionary】 +【android.provider.VoicemailContract$Status】 +【android.provider.VoicemailContract$Voicemails】 +【android.provider.VoicemailContract】 +【android.R】 +【android.renderscript.Allocation$MipmapControl】 +【android.renderscript.Allocation$OnBufferAvailableListener】 +【android.renderscript.Allocation】 +【android.renderscript.AllocationAdapter】 +【android.renderscript.BaseObj】 +【android.renderscript.Byte2】 +【android.renderscript.Byte3】 +【android.renderscript.Byte4】 +【android.renderscript.Double2】 +【android.renderscript.Double3】 +【android.renderscript.Double4】 +【android.renderscript.Element$Builder】 +【android.renderscript.Element$DataKind】 +【android.renderscript.Element$DataType】 +【android.renderscript.Element】 +【android.renderscript.FieldPacker】 +【android.renderscript.Float2】 +【android.renderscript.Float3】 +【android.renderscript.Float4】 +【android.renderscript.Int2】 +【android.renderscript.Int3】 +【android.renderscript.Int4】 +【android.renderscript.Long2】 +【android.renderscript.Long3】 +【android.renderscript.Long4】 +【android.renderscript.Matrix2f】 +【android.renderscript.Matrix3f】 +【android.renderscript.Matrix4f】 +【android.renderscript.RenderScript$ContextType】 +【android.renderscript.RenderScript$Priority】 +【android.renderscript.RenderScript$RSErrorHandler】 +【android.renderscript.RenderScript$RSMessageHandler】 +【android.renderscript.RenderScript】 +【android.renderscript.RSDriverException】 +【android.renderscript.RSIllegalArgumentException】 +【android.renderscript.RSInvalidStateException】 +【android.renderscript.RSRuntimeException】 +【android.renderscript.Sampler$Builder】 +【android.renderscript.Sampler$Value】 +【android.renderscript.Sampler】 +【android.renderscript.Script$Builder】 +【android.renderscript.Script$FieldBase】 +【android.renderscript.Script$FieldID】 +【android.renderscript.Script$KernelID】 +【android.renderscript.Script$LaunchOptions】 +【android.renderscript.Script】 +【android.renderscript.ScriptC】 +【android.renderscript.ScriptGroup$Builder】 +【android.renderscript.ScriptGroup】 +【android.renderscript.ScriptIntrinsic】 +【android.renderscript.ScriptIntrinsic3DLUT】 +【android.renderscript.ScriptIntrinsicBlend】 +【android.renderscript.ScriptIntrinsicBlur】 +【android.renderscript.ScriptIntrinsicColorMatrix】 +【android.renderscript.ScriptIntrinsicConvolve3x3】 +【android.renderscript.ScriptIntrinsicConvolve5x5】 +【android.renderscript.ScriptIntrinsicHistogram】 +【android.renderscript.ScriptIntrinsicLUT】 +【android.renderscript.ScriptIntrinsicResize】 +【android.renderscript.ScriptIntrinsicYuvToRGB】 +【android.renderscript.Short2】 +【android.renderscript.Short3】 +【android.renderscript.Short4】 +【android.renderscript.Type$Builder】 +【android.renderscript.Type$CubemapFace】 +【android.renderscript.Type】 +【android.sax.Element】 +【android.sax.ElementListener】 +【android.sax.EndElementListener】 +【android.sax.EndTextElementListener】 +【android.sax.RootElement】 +【android.sax.StartElementListener】 +【android.sax.TextElementListener】 +【android.security.KeyChain】 +【android.security.KeyChainAliasCallback】 +【android.security.KeyChainException】 +【android.security.KeyPairGeneratorSpec$Builder】 +【android.security.KeyPairGeneratorSpec】 +【android.security.KeyStoreParameter$Builder】 +【android.security.KeyStoreParameter】 +【android.service.carrier.CarrierMessagingService$ResultCallback】 +【android.service.carrier.CarrierMessagingService$SendMmsResult】 +【android.service.carrier.CarrierMessagingService$SendMultipartSmsResult】 +【android.service.carrier.CarrierMessagingService$SendSmsResult】 +【android.service.carrier.CarrierMessagingService】 +【android.service.carrier.MessagePdu】 +【android.service.dreams.DreamService】 +【android.service.media.MediaBrowserService$BrowserRoot】 +【android.service.media.MediaBrowserService$Result】 +【android.service.media.MediaBrowserService】 +【android.service.notification.NotificationListenerService$Ranking】 +【android.service.notification.NotificationListenerService$RankingMap】 +【android.service.notification.NotificationListenerService】 +【android.service.notification.StatusBarNotification】 +【android.service.restrictions.RestrictionsReceiver】 +【android.service.textservice.SpellCheckerService$Session】 +【android.service.textservice.SpellCheckerService】 +【android.service.voice.AlwaysOnHotwordDetector$Callback】 +【android.service.voice.AlwaysOnHotwordDetector$EventPayload】 +【android.service.voice.AlwaysOnHotwordDetector】 +【android.service.voice.VoiceInteractionService】 +【android.service.voice.VoiceInteractionSession】 +【android.service.voice.VoiceInteractionSessionService】 +【android.service.wallpaper.WallpaperService$Engine】 +【android.service.wallpaper.WallpaperService】 +【android.speech.RecognitionListener】 +【android.speech.RecognitionService$Callback】 +【android.speech.RecognitionService】 +【android.speech.RecognizerIntent】 +【android.speech.RecognizerResultsIntent】 +【android.speech.SpeechRecognizer】 +【android.speech.tts.SynthesisCallback】 +【android.speech.tts.SynthesisRequest】 +【android.speech.tts.TextToSpeech$Engine】 +【android.speech.tts.TextToSpeech$EngineInfo】 +【android.speech.tts.TextToSpeech$OnInitListener】 +【android.speech.tts.TextToSpeech$OnUtteranceCompletedListener】 +【android.speech.tts.TextToSpeech】 +【android.speech.tts.TextToSpeechService】 +【android.speech.tts.UtteranceProgressListener】 +【android.speech.tts.Voice】 +【android.system.ErrnoException】 +【android.system.Os】 +【android.system.OsConstants】 +【android.system.StructPollfd】 +【android.system.StructStat】 +【android.system.StructStatVfs】 +【android.system.StructUtsname】 +【android.telecom.TelecomManager】 +【android.telephony.cdma.CdmaCellLocation】 +【android.telephony.CellIdentityCdma】 +【android.telephony.CellIdentityGsm】 +【android.telephony.CellIdentityLte】 +【android.telephony.CellIdentityWcdma】 +【android.telephony.CellInfo】 +【android.telephony.CellInfoCdma】 +【android.telephony.CellInfoGsm】 +【android.telephony.CellInfoLte】 +【android.telephony.CellInfoWcdma】 +【android.telephony.CellLocation】 +【android.telephony.CellSignalStrength】 +【android.telephony.CellSignalStrengthCdma】 +【android.telephony.CellSignalStrengthGsm】 +【android.telephony.CellSignalStrengthLte】 +【android.telephony.CellSignalStrengthWcdma】 +【android.telephony.gsm.GsmCellLocation】 +【android.telephony.gsm.SmsManager】 +【android.telephony.gsm.SmsMessage$MessageClass】 +【android.telephony.gsm.SmsMessage$SubmitPdu】 +【android.telephony.gsm.SmsMessage】 +【android.telephony.IccOpenLogicalChannelResponse】 +【android.telephony.NeighboringCellInfo】 +【android.telephony.PhoneNumberFormattingTextWatcher】 +【android.telephony.PhoneNumberUtils】 +【android.telephony.PhoneStateListener】 +【android.telephony.ServiceState】 +【android.telephony.SignalStrength】 +【android.telephony.SmsManager】 +【android.telephony.SmsMessage$MessageClass】 +【android.telephony.SmsMessage$SubmitPdu】 +【android.telephony.SmsMessage】 +【android.telephony.SubscriptionInfo】 +【android.telephony.SubscriptionManager$OnSubscriptionsChangedListener】 +【android.telephony.SubscriptionManager】 +【android.telephony.TelephonyManager】 +【android.test.ActivityInstrumentationTestCase】 +【android.test.ActivityInstrumentationTestCase2】 +【android.test.ActivityTestCase】 +【android.test.ActivityUnitTestCase】 +【android.test.AndroidTestCase】 +【android.test.AndroidTestRunner】 +【android.test.ApplicationTestCase】 +【android.test.AssertionFailedError】 +【android.test.ComparisonFailure】 +【android.test.FlakyTest】 +【android.test.InstrumentationTestCase】 +【android.test.InstrumentationTestRunner】 +【android.test.InstrumentationTestSuite】 +【android.test.IsolatedContext】 +【android.test.LoaderTestCase】 +【android.test.mock.MockApplication】 +【android.test.mock.MockContentProvider】 +【android.test.mock.MockContentResolver】 +【android.test.mock.MockContext】 +【android.test.mock.MockCursor】 +【android.test.mock.MockDialogInterface】 +【android.test.mock.MockPackageManager】 +【android.test.mock.MockResources】 +【android.test.MoreAsserts】 +【android.test.PerformanceTestCase$Intermediates】 +【android.test.PerformanceTestCase】 +【android.test.ProviderTestCase】 +【android.test.ProviderTestCase2】 +【android.test.RenamingDelegatingContext】 +【android.test.ServiceTestCase】 +【android.test.SingleLaunchActivityTestCase】 +【android.test.suitebuilder.annotation.LargeTest】 +【android.test.suitebuilder.annotation.MediumTest】 +【android.test.suitebuilder.annotation.SmallTest】 +【android.test.suitebuilder.annotation.Smoke】 +【android.test.suitebuilder.annotation.Suppress】 +【android.test.suitebuilder.TestMethod】 +【android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests】 +【android.test.suitebuilder.TestSuiteBuilder】 +【android.test.SyncBaseInstrumentation】 +【android.test.TestSuiteProvider】 +【android.test.TouchUtils】 +【android.test.UiThreadTest】 +【android.test.ViewAsserts】 +【android.text.AlteredCharSequence】 +【android.text.AndroidCharacter】 +【android.text.Annotation】 +【android.text.AutoText】 +【android.text.BidiFormatter$Builder】 +【android.text.BidiFormatter】 +【android.text.BoringLayout$Metrics】 +【android.text.BoringLayout】 +【android.text.ClipboardManager】 +【android.text.DynamicLayout】 +【android.text.Editable$Factory】 +【android.text.Editable】 +【android.text.format.DateFormat】 +【android.text.format.DateUtils】 +【android.text.format.Formatter】 +【android.text.format.Time】 +【android.text.GetChars】 +【android.text.Html$ImageGetter】 +【android.text.Html$TagHandler】 +【android.text.Html】 +【android.text.InputFilter$AllCaps】 +【android.text.InputFilter$LengthFilter】 +【android.text.InputFilter】 +【android.text.InputType】 +【android.text.Layout$Alignment】 +【android.text.Layout$Directions】 +【android.text.Layout】 +【android.text.LoginFilter$PasswordFilterGMail】 +【android.text.LoginFilter$UsernameFilterGeneric】 +【android.text.LoginFilter$UsernameFilterGMail】 +【android.text.LoginFilter】 +【android.text.method.ArrowKeyMovementMethod】 +【android.text.method.BaseKeyListener】 +【android.text.method.BaseMovementMethod】 +【android.text.method.CharacterPickerDialog】 +【android.text.method.DateKeyListener】 +【android.text.method.DateTimeKeyListener】 +【android.text.method.DialerKeyListener】 +【android.text.method.DigitsKeyListener】 +【android.text.method.HideReturnsTransformationMethod】 +【android.text.method.KeyListener】 +【android.text.method.LinkMovementMethod】 +【android.text.method.MetaKeyKeyListener】 +【android.text.method.MovementMethod】 +【android.text.method.MultiTapKeyListener】 +【android.text.method.NumberKeyListener】 +【android.text.method.PasswordTransformationMethod】 +【android.text.method.QwertyKeyListener】 +【android.text.method.ReplacementTransformationMethod】 +【android.text.method.ScrollingMovementMethod】 +【android.text.method.SingleLineTransformationMethod】 +【android.text.method.TextKeyListener$Capitalize】 +【android.text.method.TextKeyListener】 +【android.text.method.TimeKeyListener】 +【android.text.method.Touch】 +【android.text.method.TransformationMethod】 +【android.text.NoCopySpan$Concrete】 +【android.text.NoCopySpan】 +【android.text.ParcelableSpan】 +【android.text.Selection】 +【android.text.Spannable$Factory】 +【android.text.Spannable】 +【android.text.SpannableString】 +【android.text.SpannableStringBuilder】 +【android.text.SpannableStringInternal】 +【android.text.Spanned】 +【android.text.SpannedString】 +【android.text.SpanWatcher】 +【android.text.StaticLayout】 +【android.text.style.AbsoluteSizeSpan】 +【android.text.style.AlignmentSpan$Standard】 +【android.text.style.AlignmentSpan】 +【android.text.style.BackgroundColorSpan】 +【android.text.style.BulletSpan】 +【android.text.style.CharacterStyle】 +【android.text.style.ClickableSpan】 +【android.text.style.DrawableMarginSpan】 +【android.text.style.DynamicDrawableSpan】 +【android.text.style.EasyEditSpan】 +【android.text.style.ForegroundColorSpan】 +【android.text.style.IconMarginSpan】 +【android.text.style.ImageSpan】 +【android.text.style.LeadingMarginSpan$LeadingMarginSpan2】 +【android.text.style.LeadingMarginSpan$Standard】 +【android.text.style.LeadingMarginSpan】 +【android.text.style.LineBackgroundSpan】 +【android.text.style.LineHeightSpan$WithDensity】 +【android.text.style.LineHeightSpan】 +【android.text.style.LocaleSpan】 +【android.text.style.MaskFilterSpan】 +【android.text.style.MetricAffectingSpan】 +【android.text.style.ParagraphStyle】 +【android.text.style.QuoteSpan】 +【android.text.style.RasterizerSpan】 +【android.text.style.RelativeSizeSpan】 +【android.text.style.ReplacementSpan】 +【android.text.style.ScaleXSpan】 +【android.text.style.StrikethroughSpan】 +【android.text.style.StyleSpan】 +【android.text.style.SubscriptSpan】 +【android.text.style.SuggestionSpan】 +【android.text.style.SuperscriptSpan】 +【android.text.style.TabStopSpan$Standard】 +【android.text.style.TabStopSpan】 +【android.text.style.TextAppearanceSpan】 +【android.text.style.TtsSpan$Builder】 +【android.text.style.TtsSpan$CardinalBuilder】 +【android.text.style.TtsSpan$DateBuilder】 +【android.text.style.TtsSpan$DecimalBuilder】 +【android.text.style.TtsSpan$DigitsBuilder】 +【android.text.style.TtsSpan$ElectronicBuilder】 +【android.text.style.TtsSpan$FractionBuilder】 +【android.text.style.TtsSpan$MeasureBuilder】 +【android.text.style.TtsSpan$MoneyBuilder】 +【android.text.style.TtsSpan$OrdinalBuilder】 +【android.text.style.TtsSpan$SemioticClassBuilder】 +【android.text.style.TtsSpan$TelephoneBuilder】 +【android.text.style.TtsSpan$TextBuilder】 +【android.text.style.TtsSpan$TimeBuilder】 +【android.text.style.TtsSpan$VerbatimBuilder】 +【android.text.style.TtsSpan】 +【android.text.style.TypefaceSpan】 +【android.text.style.UnderlineSpan】 +【android.text.style.UpdateAppearance】 +【android.text.style.UpdateLayout】 +【android.text.style.URLSpan】 +【android.text.style.WrapTogetherSpan】 +【android.text.TextDirectionHeuristic】 +【android.text.TextDirectionHeuristics】 +【android.text.TextPaint】 +【android.text.TextUtils$EllipsizeCallback】 +【android.text.TextUtils$SimpleStringSplitter】 +【android.text.TextUtils$StringSplitter】 +【android.text.TextUtils$TruncateAt】 +【android.text.TextUtils】 +【android.text.TextWatcher】 +【android.text.util.Linkify$MatchFilter】 +【android.text.util.Linkify$TransformFilter】 +【android.text.util.Linkify】 +【android.text.util.Rfc822Token】 +【android.text.util.Rfc822Tokenizer】 +【android.transition.ArcMotion】 +【android.transition.AutoTransition】 +【android.transition.ChangeBounds】 +【android.transition.ChangeClipBounds】 +【android.transition.ChangeImageTransform】 +【android.transition.ChangeTransform】 +【android.transition.CircularPropagation】 +【android.transition.Explode】 +【android.transition.Fade】 +【android.transition.PathMotion】 +【android.transition.PatternPathMotion】 +【android.transition.Scene】 +【android.transition.SidePropagation】 +【android.transition.Slide】 +【android.transition.Transition$EpicenterCallback】 +【android.transition.Transition$TransitionListener】 +【android.transition.Transition】 +【android.transition.TransitionInflater】 +【android.transition.TransitionManager】 +【android.transition.TransitionPropagation】 +【android.transition.TransitionSet】 +【android.transition.TransitionValues】 +【android.transition.Visibility】 +【android.transition.VisibilityPropagation】 +【android.util.AndroidException】 +【android.util.AndroidRuntimeException】 +【android.util.ArrayMap】 +【android.util.AtomicFile】 +【android.util.AttributeSet】 +【android.util.Base64】 +【android.util.Base64DataException】 +【android.util.Base64InputStream】 +【android.util.Base64OutputStream】 +【android.util.Config】 +【android.util.DebugUtils】 +【android.util.DisplayMetrics】 +【android.util.EventLog$Event】 +【android.util.EventLog】 +【android.util.EventLogTags$Description】 +【android.util.EventLogTags】 +【android.util.FloatMath】 +【android.util.JsonReader】 +【android.util.JsonToken】 +【android.util.JsonWriter】 +【android.util.LayoutDirection】 +【android.util.Log】 +【android.util.LogPrinter】 +【android.util.LongSparseArray】 +【android.util.LruCache】 +【android.util.MalformedJsonException】 +【android.util.MonthDisplayHelper】 +【android.util.MutableBoolean】 +【android.util.MutableByte】 +【android.util.MutableChar】 +【android.util.MutableDouble】 +【android.util.MutableFloat】 +【android.util.MutableInt】 +【android.util.MutableLong】 +【android.util.MutableShort】 +【android.util.NoSuchPropertyException】 +【android.util.Pair】 +【android.util.Patterns】 +【android.util.Printer】 +【android.util.PrintStreamPrinter】 +【android.util.PrintWriterPrinter】 +【android.util.Property】 +【android.util.Range】 +【android.util.Rational】 +【android.util.Size】 +【android.util.SizeF】 +【android.util.SparseArray】 +【android.util.SparseBooleanArray】 +【android.util.SparseIntArray】 +【android.util.SparseLongArray】 +【android.util.StateSet】 +【android.util.StringBuilderPrinter】 +【android.util.TimeFormatException】 +【android.util.TimeUtils】 +【android.util.TimingLogger】 +【android.util.TypedValue】 +【android.util.Xml$Encoding】 +【android.util.Xml】 +【android.view.AbsSavedState】 +【android.view.accessibility.AccessibilityEvent】 +【android.view.accessibility.AccessibilityEventSource】 +【android.view.accessibility.AccessibilityManager$AccessibilityStateChangeListener】 +【android.view.accessibility.AccessibilityManager$TouchExplorationStateChangeListener】 +【android.view.accessibility.AccessibilityManager】 +【android.view.accessibility.AccessibilityNodeInfo$AccessibilityAction】 +【android.view.accessibility.AccessibilityNodeInfo$CollectionInfo】 +【android.view.accessibility.AccessibilityNodeInfo$CollectionItemInfo】 +【android.view.accessibility.AccessibilityNodeInfo$RangeInfo】 +【android.view.accessibility.AccessibilityNodeInfo】 +【android.view.accessibility.AccessibilityNodeProvider】 +【android.view.accessibility.AccessibilityRecord】 +【android.view.accessibility.AccessibilityWindowInfo】 +【android.view.accessibility.CaptioningManager$CaptioningChangeListener】 +【android.view.accessibility.CaptioningManager$CaptionStyle】 +【android.view.accessibility.CaptioningManager】 +【android.view.ActionMode$Callback】 +【android.view.ActionMode】 +【android.view.ActionProvider$VisibilityListener】 +【android.view.ActionProvider】 +【android.view.animation.AccelerateDecelerateInterpolator】 +【android.view.animation.AccelerateInterpolator】 +【android.view.animation.AlphaAnimation】 +【android.view.animation.Animation$AnimationListener】 +【android.view.animation.Animation$Description】 +【android.view.animation.Animation】 +【android.view.animation.AnimationSet】 +【android.view.animation.AnimationUtils】 +【android.view.animation.AnticipateInterpolator】 +【android.view.animation.AnticipateOvershootInterpolator】 +【android.view.animation.BaseInterpolator】 +【android.view.animation.BounceInterpolator】 +【android.view.animation.CycleInterpolator】 +【android.view.animation.DecelerateInterpolator】 +【android.view.animation.GridLayoutAnimationController$AnimationParameters】 +【android.view.animation.GridLayoutAnimationController】 +【android.view.animation.Interpolator】 +【android.view.animation.LayoutAnimationController$AnimationParameters】 +【android.view.animation.LayoutAnimationController】 +【android.view.animation.LinearInterpolator】 +【android.view.animation.OvershootInterpolator】 +【android.view.animation.PathInterpolator】 +【android.view.animation.RotateAnimation】 +【android.view.animation.ScaleAnimation】 +【android.view.animation.Transformation】 +【android.view.animation.TranslateAnimation】 +【android.view.Choreographer$FrameCallback】 +【android.view.Choreographer】 +【android.view.CollapsibleActionView】 +【android.view.ContextMenu$ContextMenuInfo】 +【android.view.ContextMenu】 +【android.view.ContextThemeWrapper】 +【android.view.Display】 +【android.view.DragEvent】 +【android.view.FocusFinder】 +【android.view.FrameStats】 +【android.view.GestureDetector$OnDoubleTapListener】 +【android.view.GestureDetector$OnGestureListener】 +【android.view.GestureDetector$SimpleOnGestureListener】 +【android.view.GestureDetector】 +【android.view.Gravity】 +【android.view.HapticFeedbackConstants】 +【android.view.InflateException】 +【android.view.InputDevice$MotionRange】 +【android.view.InputDevice】 +【android.view.InputEvent】 +【android.view.inputmethod.BaseInputConnection】 +【android.view.inputmethod.CompletionInfo】 +【android.view.inputmethod.CorrectionInfo】 +【android.view.inputmethod.CursorAnchorInfo$Builder】 +【android.view.inputmethod.CursorAnchorInfo】 +【android.view.inputmethod.EditorInfo】 +【android.view.inputmethod.ExtractedText】 +【android.view.inputmethod.ExtractedTextRequest】 +【android.view.inputmethod.InputBinding】 +【android.view.inputmethod.InputConnection】 +【android.view.inputmethod.InputConnectionWrapper】 +【android.view.inputmethod.InputMethod$SessionCallback】 +【android.view.inputmethod.InputMethod】 +【android.view.inputmethod.InputMethodInfo】 +【android.view.inputmethod.InputMethodManager】 +【android.view.inputmethod.InputMethodSession$EventCallback】 +【android.view.inputmethod.InputMethodSession】 +【android.view.inputmethod.InputMethodSubtype$InputMethodSubtypeBuilder】 +【android.view.inputmethod.InputMethodSubtype】 +【android.view.InputQueue$Callback】 +【android.view.InputQueue】 +【android.view.KeyCharacterMap$KeyData】 +【android.view.KeyCharacterMap$UnavailableException】 +【android.view.KeyCharacterMap】 +【android.view.KeyEvent$Callback】 +【android.view.KeyEvent$DispatcherState】 +【android.view.KeyEvent】 +【android.view.LayoutInflater$Factory】 +【android.view.LayoutInflater$Factory2】 +【android.view.LayoutInflater$Filter】 +【android.view.LayoutInflater】 +【android.view.Menu】 +【android.view.MenuInflater】 +【android.view.MenuItem$OnActionExpandListener】 +【android.view.MenuItem$OnMenuItemClickListener】 +【android.view.MenuItem】 +【android.view.MotionEvent$PointerCoords】 +【android.view.MotionEvent$PointerProperties】 +【android.view.MotionEvent】 +【android.view.OrientationEventListener】 +【android.view.OrientationListener】 +【android.view.ScaleGestureDetector$OnScaleGestureListener】 +【android.view.ScaleGestureDetector$SimpleOnScaleGestureListener】 +【android.view.ScaleGestureDetector】 +【android.view.SoundEffectConstants】 +【android.view.SubMenu】 +【android.view.Surface$OutOfResourcesException】 +【android.view.Surface】 +【android.view.SurfaceHolder$BadSurfaceTypeException】 +【android.view.SurfaceHolder$Callback】 +【android.view.SurfaceHolder$Callback2】 +【android.view.SurfaceHolder】 +【android.view.SurfaceView】 +【android.view.textservice.SentenceSuggestionsInfo】 +【android.view.textservice.SpellCheckerInfo】 +【android.view.textservice.SpellCheckerSession$SpellCheckerSessionListener】 +【android.view.textservice.SpellCheckerSession】 +【android.view.textservice.SpellCheckerSubtype】 +【android.view.textservice.SuggestionsInfo】 +【android.view.textservice.TextInfo】 +【android.view.textservice.TextServicesManager】 +【android.view.TextureView$SurfaceTextureListener】 +【android.view.TextureView】 +【android.view.TouchDelegate】 +【android.view.VelocityTracker】 +【android.view.View$AccessibilityDelegate】 +【android.view.View$BaseSavedState】 +【android.view.View$DragShadowBuilder】 +【android.view.View$MeasureSpec】 +【android.view.View$OnApplyWindowInsetsListener】 +【android.view.View$OnAttachStateChangeListener】 +【android.view.View$OnClickListener】 +【android.view.View$OnCreateContextMenuListener】 +【android.view.View$OnDragListener】 +【android.view.View$OnFocusChangeListener】 +【android.view.View$OnGenericMotionListener】 +【android.view.View$OnHoverListener】 +【android.view.View$OnKeyListener】 +【android.view.View$OnLayoutChangeListener】 +【android.view.View$OnLongClickListener】 +【android.view.View$OnSystemUiVisibilityChangeListener】 +【android.view.View$OnTouchListener】 +【android.view.View】 +【android.view.ViewAnimationUtils】 +【android.view.ViewConfiguration】 +【android.view.ViewDebug$CapturedViewProperty】 +【android.view.ViewDebug$ExportedProperty】 +【android.view.ViewDebug$FlagToString】 +【android.view.ViewDebug$HierarchyTraceType】 +【android.view.ViewDebug$IntToString】 +【android.view.ViewDebug$RecyclerTraceType】 +【android.view.ViewDebug】 +【android.view.ViewGroup$LayoutParams】 +【android.view.ViewGroup$MarginLayoutParams】 +【android.view.ViewGroup$OnHierarchyChangeListener】 +【android.view.ViewGroup】 +【android.view.ViewGroupOverlay】 +【android.view.ViewManager】 +【android.view.ViewOutlineProvider】 +【android.view.ViewOverlay】 +【android.view.ViewParent】 +【android.view.ViewPropertyAnimator】 +【android.view.ViewStub$OnInflateListener】 +【android.view.ViewStub】 +【android.view.ViewTreeObserver$OnDrawListener】 +【android.view.ViewTreeObserver$OnGlobalFocusChangeListener】 +【android.view.ViewTreeObserver$OnGlobalLayoutListener】 +【android.view.ViewTreeObserver$OnPreDrawListener】 +【android.view.ViewTreeObserver$OnScrollChangedListener】 +【android.view.ViewTreeObserver$OnTouchModeChangeListener】 +【android.view.ViewTreeObserver$OnWindowAttachListener】 +【android.view.ViewTreeObserver$OnWindowFocusChangeListener】 +【android.view.ViewTreeObserver】 +【android.view.Window$Callback】 +【android.view.Window】 +【android.view.WindowAnimationFrameStats】 +【android.view.WindowContentFrameStats】 +【android.view.WindowId$FocusObserver】 +【android.view.WindowId】 +【android.view.WindowInsets】 +【android.view.WindowManager$BadTokenException】 +【android.view.WindowManager$InvalidDisplayException】 +【android.view.WindowManager$LayoutParams】 +【android.view.WindowManager】 +【android.webkit.ClientCertRequest】 +【android.webkit.ConsoleMessage$MessageLevel】 +【android.webkit.ConsoleMessage】 +【android.webkit.CookieManager】 +【android.webkit.CookieSyncManager】 +【android.webkit.DateSorter】 +【android.webkit.DownloadListener】 +【android.webkit.GeolocationPermissions$Callback】 +【android.webkit.GeolocationPermissions】 +【android.webkit.HttpAuthHandler】 +【android.webkit.JavascriptInterface】 +【android.webkit.JsPromptResult】 +【android.webkit.JsResult】 +【android.webkit.MimeTypeMap】 +【android.webkit.PermissionRequest】 +【android.webkit.PluginStub】 +【android.webkit.SslErrorHandler】 +【android.webkit.URLUtil】 +【android.webkit.ValueCallback】 +【android.webkit.WebBackForwardList】 +【android.webkit.WebChromeClient$CustomViewCallback】 +【android.webkit.WebChromeClient$FileChooserParams】 +【android.webkit.WebChromeClient】 +【android.webkit.WebHistoryItem】 +【android.webkit.WebIconDatabase$IconListener】 +【android.webkit.WebIconDatabase】 +【android.webkit.WebResourceRequest】 +【android.webkit.WebResourceResponse】 +【android.webkit.WebSettings$LayoutAlgorithm】 +【android.webkit.WebSettings$PluginState】 +【android.webkit.WebSettings$RenderPriority】 +【android.webkit.WebSettings$TextSize】 +【android.webkit.WebSettings$ZoomDensity】 +【android.webkit.WebSettings】 +【android.webkit.WebStorage$Origin】 +【android.webkit.WebStorage$QuotaUpdater】 +【android.webkit.WebStorage】 +【android.webkit.WebSyncManager】 +【android.webkit.WebView$FindListener】 +【android.webkit.WebView$HitTestResult】 +【android.webkit.WebView$PictureListener】 +【android.webkit.WebView$WebViewTransport】 +【android.webkit.WebView】 +【android.webkit.WebViewClient】 +【android.webkit.WebViewDatabase】 +【android.webkit.WebViewFragment】 +【android.widget.AbsListView$LayoutParams】 +【android.widget.AbsListView$MultiChoiceModeListener】 +【android.widget.AbsListView$OnScrollListener】 +【android.widget.AbsListView$RecyclerListener】 +【android.widget.AbsListView$SelectionBoundsAdjuster】 +【android.widget.AbsListView】 +【android.widget.AbsoluteLayout$LayoutParams】 +【android.widget.AbsoluteLayout】 +【android.widget.AbsSeekBar】 +【android.widget.AbsSpinner】 +【android.widget.ActionMenuView$LayoutParams】 +【android.widget.ActionMenuView$OnMenuItemClickListener】 +【android.widget.ActionMenuView】 +【android.widget.Adapter】 +【android.widget.AdapterView$AdapterContextMenuInfo】 +【android.widget.AdapterView$OnItemClickListener】 +【android.widget.AdapterView$OnItemLongClickListener】 +【android.widget.AdapterView$OnItemSelectedListener】 +【android.widget.AdapterView】 +【android.widget.AdapterViewAnimator】 +【android.widget.AdapterViewFlipper】 +【android.widget.Advanceable】 +【android.widget.AlphabetIndexer】 +【android.widget.AnalogClock】 +【android.widget.ArrayAdapter】 +【android.widget.AutoCompleteTextView$OnDismissListener】 +【android.widget.AutoCompleteTextView$Validator】 +【android.widget.AutoCompleteTextView】 +【android.widget.BaseAdapter】 +【android.widget.BaseExpandableListAdapter】 +【android.widget.Button】 +【android.widget.CalendarView$OnDateChangeListener】 +【android.widget.CalendarView】 +【android.widget.Checkable】 +【android.widget.CheckBox】 +【android.widget.CheckedTextView】 +【android.widget.Chronometer$OnChronometerTickListener】 +【android.widget.Chronometer】 +【android.widget.CompoundButton$OnCheckedChangeListener】 +【android.widget.CompoundButton】 +【android.widget.CursorAdapter】 +【android.widget.CursorTreeAdapter】 +【android.widget.DatePicker$OnDateChangedListener】 +【android.widget.DatePicker】 +【android.widget.DialerFilter】 +【android.widget.DigitalClock】 +【android.widget.EdgeEffect】 +【android.widget.EditText】 +【android.widget.ExpandableListAdapter】 +【android.widget.ExpandableListView$ExpandableListContextMenuInfo】 +【android.widget.ExpandableListView$OnChildClickListener】 +【android.widget.ExpandableListView$OnGroupClickListener】 +【android.widget.ExpandableListView$OnGroupCollapseListener】 +【android.widget.ExpandableListView$OnGroupExpandListener】 +【android.widget.ExpandableListView】 +【android.widget.Filter$FilterListener】 +【android.widget.Filter$FilterResults】 +【android.widget.Filter】 +【android.widget.Filterable】 +【android.widget.FilterQueryProvider】 +【android.widget.FrameLayout$LayoutParams】 +【android.widget.FrameLayout】 +【android.widget.Gallery$LayoutParams】 +【android.widget.Gallery】 +【android.widget.GridLayout$Alignment】 +【android.widget.GridLayout$LayoutParams】 +【android.widget.GridLayout$Spec】 +【android.widget.GridLayout】 +【android.widget.GridView】 +【android.widget.HeaderViewListAdapter】 +【android.widget.HeterogeneousExpandableList】 +【android.widget.HorizontalScrollView】 +【android.widget.ImageButton】 +【android.widget.ImageSwitcher】 +【android.widget.ImageView$ScaleType】 +【android.widget.ImageView】 +【android.widget.LinearLayout$LayoutParams】 +【android.widget.LinearLayout】 +【android.widget.ListAdapter】 +【android.widget.ListPopupWindow】 +【android.widget.ListView$FixedViewInfo】 +【android.widget.ListView】 +【android.widget.MediaController$MediaPlayerControl】 +【android.widget.MediaController】 +【android.widget.MultiAutoCompleteTextView$CommaTokenizer】 +【android.widget.MultiAutoCompleteTextView$Tokenizer】 +【android.widget.MultiAutoCompleteTextView】 +【android.widget.NumberPicker$Formatter】 +【android.widget.NumberPicker$OnScrollListener】 +【android.widget.NumberPicker$OnValueChangeListener】 +【android.widget.NumberPicker】 +【android.widget.OverScroller】 +【android.widget.PopupMenu$OnDismissListener】 +【android.widget.PopupMenu$OnMenuItemClickListener】 +【android.widget.PopupMenu】 +【android.widget.PopupWindow$OnDismissListener】 +【android.widget.PopupWindow】 +【android.widget.ProgressBar】 +【android.widget.QuickContactBadge】 +【android.widget.RadioButton】 +【android.widget.RadioGroup$LayoutParams】 +【android.widget.RadioGroup$OnCheckedChangeListener】 +【android.widget.RadioGroup】 +【android.widget.RatingBar$OnRatingBarChangeListener】 +【android.widget.RatingBar】 +【android.widget.RelativeLayout$LayoutParams】 +【android.widget.RelativeLayout】 +【android.widget.RemoteViews$ActionException】 +【android.widget.RemoteViews$RemoteView】 +【android.widget.RemoteViews】 +【android.widget.RemoteViewsService$RemoteViewsFactory】 +【android.widget.RemoteViewsService】 +【android.widget.ResourceCursorAdapter】 +【android.widget.ResourceCursorTreeAdapter】 +【android.widget.Scroller】 +【android.widget.ScrollView】 +【android.widget.SearchView$OnCloseListener】 +【android.widget.SearchView$OnQueryTextListener】 +【android.widget.SearchView$OnSuggestionListener】 +【android.widget.SearchView】 +【android.widget.SectionIndexer】 +【android.widget.SeekBar$OnSeekBarChangeListener】 +【android.widget.SeekBar】 +【android.widget.ShareActionProvider$OnShareTargetSelectedListener】 +【android.widget.ShareActionProvider】 +【android.widget.SimpleAdapter$ViewBinder】 +【android.widget.SimpleAdapter】 +【android.widget.SimpleCursorAdapter$CursorToStringConverter】 +【android.widget.SimpleCursorAdapter$ViewBinder】 +【android.widget.SimpleCursorAdapter】 +【android.widget.SimpleCursorTreeAdapter$ViewBinder】 +【android.widget.SimpleCursorTreeAdapter】 +【android.widget.SimpleExpandableListAdapter】 +【android.widget.SlidingDrawer$OnDrawerCloseListener】 +【android.widget.SlidingDrawer$OnDrawerOpenListener】 +【android.widget.SlidingDrawer$OnDrawerScrollListener】 +【android.widget.SlidingDrawer】 +【android.widget.Space】 +【android.widget.Spinner】 +【android.widget.SpinnerAdapter】 +【android.widget.StackView】 +【android.widget.Switch】 +【android.widget.TabHost$OnTabChangeListener】 +【android.widget.TabHost$TabContentFactory】 +【android.widget.TabHost$TabSpec】 +【android.widget.TabHost】 +【android.widget.TableLayout$LayoutParams】 +【android.widget.TableLayout】 +【android.widget.TableRow$LayoutParams】 +【android.widget.TableRow】 +【android.widget.TabWidget】 +【android.widget.TextClock】 +【android.widget.TextSwitcher】 +【android.widget.TextView$BufferType】 +【android.widget.TextView$OnEditorActionListener】 +【android.widget.TextView$SavedState】 +【android.widget.TextView】 +【android.widget.TimePicker$OnTimeChangedListener】 +【android.widget.TimePicker】 +【android.widget.Toast】 +【android.widget.ToggleButton】 +【android.widget.Toolbar$LayoutParams】 +【android.widget.Toolbar$OnMenuItemClickListener】 +【android.widget.Toolbar】 +【android.widget.TwoLineListItem】 +【android.widget.VideoView】 +【android.widget.ViewAnimator】 +【android.widget.ViewFlipper】 +【android.widget.ViewSwitcher$ViewFactory】 +【android.widget.ViewSwitcher】 +【android.widget.WrapperListAdapter】 +【android.widget.ZoomButton】 +【android.widget.ZoomButtonsController$OnZoomListener】 +【android.widget.ZoomButtonsController】 +【android.widget.ZoomControls】 +【com.android.internal.util.Predicate】 +【dalvik.annotation.TestTarget】 +【dalvik.annotation.TestTargetClass】 +【dalvik.bytecode.OpcodeInfo】 +【dalvik.bytecode.Opcodes】 +【dalvik.system.BaseDexClassLoader】 +【dalvik.system.DexClassLoader】 +【dalvik.system.DexFile】 +【dalvik.system.PathClassLoader】 +【java.awt.font.NumericShaper】 +【java.awt.font.TextAttribute】 +【java.beans.IndexedPropertyChangeEvent】 +【java.beans.PropertyChangeEvent】 +【java.beans.PropertyChangeListener】 +【java.beans.PropertyChangeListenerProxy】 +【java.beans.PropertyChangeSupport】 +【java.io.BufferedInputStream】 +【java.io.BufferedOutputStream】 +【java.io.BufferedReader】 +【java.io.BufferedWriter】 +【java.io.ByteArrayInputStream】 +【java.io.ByteArrayOutputStream】 +【java.io.CharArrayReader】 +【java.io.CharArrayWriter】 +【java.io.CharConversionException】 +【java.io.Closeable】 +【java.io.Console】 +【java.io.DataInput】 +【java.io.DataInputStream】 +【java.io.DataOutput】 +【java.io.DataOutputStream】 +【java.io.EOFException】 +【java.io.Externalizable】 +【java.io.File】 +【java.io.FileDescriptor】 +【java.io.FileFilter】 +【java.io.FileInputStream】 +【java.io.FilenameFilter】 +【java.io.FileNotFoundException】 +【java.io.FileOutputStream】 +【java.io.FilePermission】 +【java.io.FileReader】 +【java.io.FileWriter】 +【java.io.FilterInputStream】 +【java.io.FilterOutputStream】 +【java.io.FilterReader】 +【java.io.FilterWriter】 +【java.io.Flushable】 +【java.io.InputStream】 +【java.io.InputStreamReader】 +【java.io.InterruptedIOException】 +【java.io.InvalidClassException】 +【java.io.InvalidObjectException】 +【java.io.IOError】 +【java.io.IOException】 +【java.io.LineNumberInputStream】 +【java.io.LineNumberReader】 +【java.io.NotActiveException】 +【java.io.NotSerializableException】 +【java.io.ObjectInput】 +【java.io.ObjectInputStream$GetField】 +【java.io.ObjectInputStream】 +【java.io.ObjectInputValidation】 +【java.io.ObjectOutput】 +【java.io.ObjectOutputStream$PutField】 +【java.io.ObjectOutputStream】 +【java.io.ObjectStreamClass】 +【java.io.ObjectStreamConstants】 +【java.io.ObjectStreamException】 +【java.io.ObjectStreamField】 +【java.io.OptionalDataException】 +【java.io.OutputStream】 +【java.io.OutputStreamWriter】 +【java.io.PipedInputStream】 +【java.io.PipedOutputStream】 +【java.io.PipedReader】 +【java.io.PipedWriter】 +【java.io.PrintStream】 +【java.io.PrintWriter】 +【java.io.PushbackInputStream】 +【java.io.PushbackReader】 +【java.io.RandomAccessFile】 +【java.io.Reader】 +【java.io.SequenceInputStream】 +【java.io.Serializable】 +【java.io.SerializablePermission】 +【java.io.StreamCorruptedException】 +【java.io.StreamTokenizer】 +【java.io.StringBufferInputStream】 +【java.io.StringReader】 +【java.io.StringWriter】 +【java.io.SyncFailedException】 +【java.io.UnsupportedEncodingException】 +【java.io.UTFDataFormatException】 +【java.io.WriteAbortedException】 +【java.io.Writer】 +【java.lang.AbstractMethodError】 +【java.lang.AbstractStringBuilder】 +【java.lang.annotation.Annotation】 +【java.lang.annotation.AnnotationFormatError】 +【java.lang.annotation.AnnotationTypeMismatchException】 +【java.lang.annotation.Documented】 +【java.lang.annotation.ElementType】 +【java.lang.annotation.IncompleteAnnotationException】 +【java.lang.annotation.Inherited】 +【java.lang.annotation.Retention】 +【java.lang.annotation.RetentionPolicy】 +【java.lang.annotation.Target】 +【java.lang.Appendable】 +【java.lang.ArithmeticException】 +【java.lang.ArrayIndexOutOfBoundsException】 +【java.lang.ArrayStoreException】 +【java.lang.AssertionError】 +【java.lang.AutoCloseable】 +【java.lang.Boolean】 +【java.lang.Byte】 +【java.lang.Character$Subset】 +【java.lang.Character$UnicodeBlock】 +【java.lang.Character】 +【java.lang.CharSequence】 +【java.lang.Class】 +【java.lang.ClassCastException】 +【java.lang.ClassCircularityError】 +【java.lang.ClassFormatError】 +【java.lang.ClassLoader】 +【java.lang.ClassNotFoundException】 +【java.lang.Cloneable】 +【java.lang.CloneNotSupportedException】 +【java.lang.Comparable】 +【java.lang.Compiler】 +【java.lang.Deprecated】 +【java.lang.Double】 +【java.lang.Enum】 +【java.lang.EnumConstantNotPresentException】 +【java.lang.Error】 +【java.lang.Exception】 +【java.lang.ExceptionInInitializerError】 +【java.lang.Float】 +【java.lang.IllegalAccessError】 +【java.lang.IllegalAccessException】 +【java.lang.IllegalArgumentException】 +【java.lang.IllegalMonitorStateException】 +【java.lang.IllegalStateException】 +【java.lang.IllegalThreadStateException】 +【java.lang.IncompatibleClassChangeError】 +【java.lang.IndexOutOfBoundsException】 +【java.lang.InheritableThreadLocal】 +【java.lang.InstantiationError】 +【java.lang.InstantiationException】 +【java.lang.Integer】 +【java.lang.InternalError】 +【java.lang.InterruptedException】 +【java.lang.Iterable】 +【java.lang.LinkageError】 +【java.lang.Long】 +【java.lang.Math】 +【java.lang.NegativeArraySizeException】 +【java.lang.NoClassDefFoundError】 +【java.lang.NoSuchFieldError】 +【java.lang.NoSuchFieldException】 +【java.lang.NoSuchMethodError】 +【java.lang.NoSuchMethodException】 +【java.lang.NullPointerException】 +【java.lang.Number】 +【java.lang.NumberFormatException】 +【java.lang.Object】 +【java.lang.OutOfMemoryError】 +【java.lang.Override】 +【java.lang.Package】 +【java.lang.Process】 +【java.lang.ProcessBuilder】 +【java.lang.Readable】 +【java.lang.ref.PhantomReference】 +【java.lang.ref.Reference】 +【java.lang.ref.ReferenceQueue】 +【java.lang.ref.SoftReference】 +【java.lang.ref.WeakReference】 +【java.lang.reflect.AccessibleObject】 +【java.lang.reflect.AnnotatedElement】 +【java.lang.reflect.Array】 +【java.lang.reflect.Constructor】 +【java.lang.reflect.Field】 +【java.lang.reflect.GenericArrayType】 +【java.lang.reflect.GenericDeclaration】 +【java.lang.reflect.GenericSignatureFormatError】 +【java.lang.reflect.InvocationHandler】 +【java.lang.reflect.InvocationTargetException】 +【java.lang.reflect.MalformedParameterizedTypeException】 +【java.lang.reflect.Member】 +【java.lang.reflect.Method】 +【java.lang.reflect.Modifier】 +【java.lang.reflect.ParameterizedType】 +【java.lang.reflect.Proxy】 +【java.lang.reflect.ReflectPermission】 +【java.lang.reflect.Type】 +【java.lang.reflect.TypeVariable】 +【java.lang.reflect.UndeclaredThrowableException】 +【java.lang.reflect.WildcardType】 +【java.lang.ReflectiveOperationException】 +【java.lang.Runnable】 +【java.lang.Runtime】 +【java.lang.RuntimeException】 +【java.lang.RuntimePermission】 +【java.lang.SafeVarargs】 +【java.lang.SecurityException】 +【java.lang.SecurityManager】 +【java.lang.Short】 +【java.lang.StackOverflowError】 +【java.lang.StackTraceElement】 +【java.lang.StrictMath】 +【java.lang.String】 +【java.lang.StringBuffer】 +【java.lang.StringBuilder】 +【java.lang.StringIndexOutOfBoundsException】 +【java.lang.SuppressWarnings】 +【java.lang.System】 +【java.lang.Thread$State】 +【java.lang.Thread$UncaughtExceptionHandler】 +【java.lang.Thread】 +【java.lang.ThreadDeath】 +【java.lang.ThreadGroup】 +【java.lang.ThreadLocal】 +【java.lang.Throwable】 +【java.lang.TypeNotPresentException】 +【java.lang.UnknownError】 +【java.lang.UnsatisfiedLinkError】 +【java.lang.UnsupportedClassVersionError】 +【java.lang.UnsupportedOperationException】 +【java.lang.VerifyError】 +【java.lang.VirtualMachineError】 +【java.lang.Void】 +【java.math.BigDecimal】 +【java.math.BigInteger】 +【java.math.MathContext】 +【java.math.RoundingMode】 +【java.net.Authenticator$RequestorType】 +【java.net.Authenticator】 +【java.net.BindException】 +【java.net.CacheRequest】 +【java.net.CacheResponse】 +【java.net.ConnectException】 +【java.net.ContentHandler】 +【java.net.ContentHandlerFactory】 +【java.net.CookieHandler】 +【java.net.CookieManager】 +【java.net.CookiePolicy】 +【java.net.CookieStore】 +【java.net.DatagramPacket】 +【java.net.DatagramSocket】 +【java.net.DatagramSocketImpl】 +【java.net.DatagramSocketImplFactory】 +【java.net.FileNameMap】 +【java.net.HttpCookie】 +【java.net.HttpRetryException】 +【java.net.HttpURLConnection】 +【java.net.IDN】 +【java.net.Inet4Address】 +【java.net.Inet6Address】 +【java.net.InetAddress】 +【java.net.InetSocketAddress】 +【java.net.InterfaceAddress】 +【java.net.JarURLConnection】 +【java.net.MalformedURLException】 +【java.net.MulticastSocket】 +【java.net.NetPermission】 +【java.net.NetworkInterface】 +【java.net.NoRouteToHostException】 +【java.net.PasswordAuthentication】 +【java.net.PortUnreachableException】 +【java.net.ProtocolException】 +【java.net.Proxy$Type】 +【java.net.Proxy】 +【java.net.ProxySelector】 +【java.net.ResponseCache】 +【java.net.SecureCacheResponse】 +【java.net.ServerSocket】 +【java.net.Socket】 +【java.net.SocketAddress】 +【java.net.SocketException】 +【java.net.SocketImpl】 +【java.net.SocketImplFactory】 +【java.net.SocketOptions】 +【java.net.SocketPermission】 +【java.net.SocketTimeoutException】 +【java.net.UnknownHostException】 +【java.net.UnknownServiceException】 +【java.net.URI】 +【java.net.URISyntaxException】 +【java.net.URL】 +【java.net.URLClassLoader】 +【java.net.URLConnection】 +【java.net.URLDecoder】 +【java.net.URLEncoder】 +【java.net.URLStreamHandler】 +【java.net.URLStreamHandlerFactory】 +【java.nio.Buffer】 +【java.nio.BufferOverflowException】 +【java.nio.BufferUnderflowException】 +【java.nio.ByteBuffer】 +【java.nio.ByteOrder】 +【java.nio.channels.AlreadyConnectedException】 +【java.nio.channels.AsynchronousCloseException】 +【java.nio.channels.ByteChannel】 +【java.nio.channels.CancelledKeyException】 +【java.nio.channels.Channel】 +【java.nio.channels.Channels】 +【java.nio.channels.ClosedByInterruptException】 +【java.nio.channels.ClosedChannelException】 +【java.nio.channels.ClosedSelectorException】 +【java.nio.channels.ConnectionPendingException】 +【java.nio.channels.DatagramChannel】 +【java.nio.channels.FileChannel$MapMode】 +【java.nio.channels.FileChannel】 +【java.nio.channels.FileLock】 +【java.nio.channels.FileLockInterruptionException】 +【java.nio.channels.GatheringByteChannel】 +【java.nio.channels.IllegalBlockingModeException】 +【java.nio.channels.IllegalSelectorException】 +【java.nio.channels.InterruptibleChannel】 +【java.nio.channels.NoConnectionPendingException】 +【java.nio.channels.NonReadableChannelException】 +【java.nio.channels.NonWritableChannelException】 +【java.nio.channels.NotYetBoundException】 +【java.nio.channels.NotYetConnectedException】 +【java.nio.channels.OverlappingFileLockException】 +【java.nio.channels.Pipe$SinkChannel】 +【java.nio.channels.Pipe$SourceChannel】 +【java.nio.channels.Pipe】 +【java.nio.channels.ReadableByteChannel】 +【java.nio.channels.ScatteringByteChannel】 +【java.nio.channels.SelectableChannel】 +【java.nio.channels.SelectionKey】 +【java.nio.channels.Selector】 +【java.nio.channels.ServerSocketChannel】 +【java.nio.channels.SocketChannel】 +【java.nio.channels.spi.AbstractInterruptibleChannel】 +【java.nio.channels.spi.AbstractSelectableChannel】 +【java.nio.channels.spi.AbstractSelectionKey】 +【java.nio.channels.spi.AbstractSelector】 +【java.nio.channels.spi.SelectorProvider】 +【java.nio.channels.UnresolvedAddressException】 +【java.nio.channels.UnsupportedAddressTypeException】 +【java.nio.channels.WritableByteChannel】 +【java.nio.CharBuffer】 +【java.nio.charset.CharacterCodingException】 +【java.nio.charset.Charset】 +【java.nio.charset.CharsetDecoder】 +【java.nio.charset.CharsetEncoder】 +【java.nio.charset.CoderMalfunctionError】 +【java.nio.charset.CoderResult】 +【java.nio.charset.CodingErrorAction】 +【java.nio.charset.IllegalCharsetNameException】 +【java.nio.charset.MalformedInputException】 +【java.nio.charset.spi.CharsetProvider】 +【java.nio.charset.StandardCharsets】 +【java.nio.charset.UnmappableCharacterException】 +【java.nio.charset.UnsupportedCharsetException】 +【java.nio.DoubleBuffer】 +【java.nio.FloatBuffer】 +【java.nio.IntBuffer】 +【java.nio.InvalidMarkException】 +【java.nio.LongBuffer】 +【java.nio.MappedByteBuffer】 +【java.nio.ReadOnlyBufferException】 +【java.nio.ShortBuffer】 +【java.security.AccessControlContext】 +【java.security.AccessControlException】 +【java.security.AccessController】 +【java.security.acl.Acl】 +【java.security.acl.AclEntry】 +【java.security.acl.AclNotFoundException】 +【java.security.acl.Group】 +【java.security.acl.LastOwnerException】 +【java.security.acl.NotOwnerException】 +【java.security.acl.Owner】 +【java.security.acl.Permission】 +【java.security.AlgorithmParameterGenerator】 +【java.security.AlgorithmParameterGeneratorSpi】 +【java.security.AlgorithmParameters】 +【java.security.AlgorithmParametersSpi】 +【java.security.AllPermission】 +【java.security.AuthProvider】 +【java.security.BasicPermission】 +【java.security.cert.Certificate$CertificateRep】 +【java.security.cert.Certificate】 +【java.security.cert.CertificateEncodingException】 +【java.security.cert.CertificateException】 +【java.security.cert.CertificateExpiredException】 +【java.security.cert.CertificateFactory】 +【java.security.cert.CertificateFactorySpi】 +【java.security.cert.CertificateNotYetValidException】 +【java.security.cert.CertificateParsingException】 +【java.security.cert.CertPath$CertPathRep】 +【java.security.cert.CertPath】 +【java.security.cert.CertPathBuilder】 +【java.security.cert.CertPathBuilderException】 +【java.security.cert.CertPathBuilderResult】 +【java.security.cert.CertPathBuilderSpi】 +【java.security.cert.CertPathParameters】 +【java.security.cert.CertPathValidator】 +【java.security.cert.CertPathValidatorException】 +【java.security.cert.CertPathValidatorResult】 +【java.security.cert.CertPathValidatorSpi】 +【java.security.cert.CertSelector】 +【java.security.cert.CertStore】 +【java.security.cert.CertStoreException】 +【java.security.cert.CertStoreParameters】 +【java.security.cert.CertStoreSpi】 +【java.security.cert.CollectionCertStoreParameters】 +【java.security.cert.CRL】 +【java.security.cert.CRLException】 +【java.security.cert.CRLSelector】 +【java.security.cert.LDAPCertStoreParameters】 +【java.security.cert.PKIXBuilderParameters】 +【java.security.cert.PKIXCertPathBuilderResult】 +【java.security.cert.PKIXCertPathChecker】 +【java.security.cert.PKIXCertPathValidatorResult】 +【java.security.cert.PKIXParameters】 +【java.security.cert.PolicyNode】 +【java.security.cert.PolicyQualifierInfo】 +【java.security.cert.TrustAnchor】 +【java.security.cert.X509Certificate】 +【java.security.cert.X509CertSelector】 +【java.security.cert.X509CRL】 +【java.security.cert.X509CRLEntry】 +【java.security.cert.X509CRLSelector】 +【java.security.cert.X509Extension】 +【java.security.Certificate】 +【java.security.CodeSigner】 +【java.security.CodeSource】 +【java.security.DigestException】 +【java.security.DigestInputStream】 +【java.security.DigestOutputStream】 +【java.security.DomainCombiner】 +【java.security.GeneralSecurityException】 +【java.security.Guard】 +【java.security.GuardedObject】 +【java.security.Identity】 +【java.security.IdentityScope】 +【java.security.interfaces.DSAKey】 +【java.security.interfaces.DSAKeyPairGenerator】 +【java.security.interfaces.DSAParams】 +【java.security.interfaces.DSAPrivateKey】 +【java.security.interfaces.DSAPublicKey】 +【java.security.interfaces.ECKey】 +【java.security.interfaces.ECPrivateKey】 +【java.security.interfaces.ECPublicKey】 +【java.security.interfaces.RSAKey】 +【java.security.interfaces.RSAMultiPrimePrivateCrtKey】 +【java.security.interfaces.RSAPrivateCrtKey】 +【java.security.interfaces.RSAPrivateKey】 +【java.security.interfaces.RSAPublicKey】 +【java.security.InvalidAlgorithmParameterException】 +【java.security.InvalidKeyException】 +【java.security.InvalidParameterException】 +【java.security.Key】 +【java.security.KeyException】 +【java.security.KeyFactory】 +【java.security.KeyFactorySpi】 +【java.security.KeyManagementException】 +【java.security.KeyPair】 +【java.security.KeyPairGenerator】 +【java.security.KeyPairGeneratorSpi】 +【java.security.KeyRep$Type】 +【java.security.KeyRep】 +【java.security.KeyStore$Builder】 +【java.security.KeyStore$CallbackHandlerProtection】 +【java.security.KeyStore$Entry】 +【java.security.KeyStore$LoadStoreParameter】 +【java.security.KeyStore$PasswordProtection】 +【java.security.KeyStore$PrivateKeyEntry】 +【java.security.KeyStore$ProtectionParameter】 +【java.security.KeyStore$SecretKeyEntry】 +【java.security.KeyStore$TrustedCertificateEntry】 +【java.security.KeyStore】 +【java.security.KeyStoreException】 +【java.security.KeyStoreSpi】 +【java.security.MessageDigest】 +【java.security.MessageDigestSpi】 +【java.security.NoSuchAlgorithmException】 +【java.security.NoSuchProviderException】 +【java.security.Permission】 +【java.security.PermissionCollection】 +【java.security.Permissions】 +【java.security.Policy$Parameters】 +【java.security.Policy】 +【java.security.PolicySpi】 +【java.security.Principal】 +【java.security.PrivateKey】 +【java.security.PrivilegedAction】 +【java.security.PrivilegedActionException】 +【java.security.PrivilegedExceptionAction】 +【java.security.ProtectionDomain】 +【java.security.Provider$Service】 +【java.security.Provider】 +【java.security.ProviderException】 +【java.security.PublicKey】 +【java.security.SecureClassLoader】 +【java.security.SecureRandom】 +【java.security.SecureRandomSpi】 +【java.security.Security】 +【java.security.SecurityPermission】 +【java.security.Signature】 +【java.security.SignatureException】 +【java.security.SignatureSpi】 +【java.security.SignedObject】 +【java.security.Signer】 +【java.security.spec.AlgorithmParameterSpec】 +【java.security.spec.DSAParameterSpec】 +【java.security.spec.DSAPrivateKeySpec】 +【java.security.spec.DSAPublicKeySpec】 +【java.security.spec.ECField】 +【java.security.spec.ECFieldF2m】 +【java.security.spec.ECFieldFp】 +【java.security.spec.ECGenParameterSpec】 +【java.security.spec.ECParameterSpec】 +【java.security.spec.ECPoint】 +【java.security.spec.ECPrivateKeySpec】 +【java.security.spec.ECPublicKeySpec】 +【java.security.spec.EllipticCurve】 +【java.security.spec.EncodedKeySpec】 +【java.security.spec.InvalidKeySpecException】 +【java.security.spec.InvalidParameterSpecException】 +【java.security.spec.KeySpec】 +【java.security.spec.MGF1ParameterSpec】 +【java.security.spec.PKCS8EncodedKeySpec】 +【java.security.spec.PSSParameterSpec】 +【java.security.spec.RSAKeyGenParameterSpec】 +【java.security.spec.RSAMultiPrimePrivateCrtKeySpec】 +【java.security.spec.RSAOtherPrimeInfo】 +【java.security.spec.RSAPrivateCrtKeySpec】 +【java.security.spec.RSAPrivateKeySpec】 +【java.security.spec.RSAPublicKeySpec】 +【java.security.spec.X509EncodedKeySpec】 +【java.security.Timestamp】 +【java.security.UnrecoverableEntryException】 +【java.security.UnrecoverableKeyException】 +【java.security.UnresolvedPermission】 +【java.sql.Array】 +【java.sql.BatchUpdateException】 +【java.sql.Blob】 +【java.sql.CallableStatement】 +【java.sql.ClientInfoStatus】 +【java.sql.Clob】 +【java.sql.Connection】 +【java.sql.DatabaseMetaData】 +【java.sql.DataTruncation】 +【java.sql.Date】 +【java.sql.Driver】 +【java.sql.DriverManager】 +【java.sql.DriverPropertyInfo】 +【java.sql.NClob】 +【java.sql.ParameterMetaData】 +【java.sql.PreparedStatement】 +【java.sql.Ref】 +【java.sql.ResultSet】 +【java.sql.ResultSetMetaData】 +【java.sql.RowId】 +【java.sql.RowIdLifetime】 +【java.sql.Savepoint】 +【java.sql.SQLClientInfoException】 +【java.sql.SQLData】 +【java.sql.SQLDataException】 +【java.sql.SQLException】 +【java.sql.SQLFeatureNotSupportedException】 +【java.sql.SQLInput】 +【java.sql.SQLIntegrityConstraintViolationException】 +【java.sql.SQLInvalidAuthorizationSpecException】 +【java.sql.SQLNonTransientConnectionException】 +【java.sql.SQLNonTransientException】 +【java.sql.SQLOutput】 +【java.sql.SQLPermission】 +【java.sql.SQLRecoverableException】 +【java.sql.SQLSyntaxErrorException】 +【java.sql.SQLTimeoutException】 +【java.sql.SQLTransactionRollbackException】 +【java.sql.SQLTransientConnectionException】 +【java.sql.SQLTransientException】 +【java.sql.SQLWarning】 +【java.sql.SQLXML】 +【java.sql.Statement】 +【java.sql.Struct】 +【java.sql.Time】 +【java.sql.Timestamp】 +【java.sql.Types】 +【java.sql.Wrapper】 +【java.text.Annotation】 +【java.text.AttributedCharacterIterator$Attribute】 +【java.text.AttributedCharacterIterator】 +【java.text.AttributedString】 +【java.text.Bidi】 +【java.text.BreakIterator】 +【java.text.CharacterIterator】 +【java.text.ChoiceFormat】 +【java.text.CollationElementIterator】 +【java.text.CollationKey】 +【java.text.Collator】 +【java.text.DateFormat$Field】 +【java.text.DateFormat】 +【java.text.DateFormatSymbols】 +【java.text.DecimalFormat】 +【java.text.DecimalFormatSymbols】 +【java.text.FieldPosition】 +【java.text.Format$Field】 +【java.text.Format】 +【java.text.MessageFormat$Field】 +【java.text.MessageFormat】 +【java.text.Normalizer$Form】 +【java.text.Normalizer】 +【java.text.NumberFormat$Field】 +【java.text.NumberFormat】 +【java.text.ParseException】 +【java.text.ParsePosition】 +【java.text.RuleBasedCollator】 +【java.text.SimpleDateFormat】 +【java.text.StringCharacterIterator】 +【java.util.AbstractCollection】 +【java.util.AbstractList】 +【java.util.AbstractMap$SimpleEntry】 +【java.util.AbstractMap$SimpleImmutableEntry】 +【java.util.AbstractMap】 +【java.util.AbstractQueue】 +【java.util.AbstractSequentialList】 +【java.util.AbstractSet】 +【java.util.ArrayDeque】 +【java.util.ArrayList】 +【java.util.Arrays】 +【java.util.BitSet】 +【java.util.Calendar】 +【java.util.Collection】 +【java.util.Collections】 +【java.util.Comparator】 +【java.util.concurrent.AbstractExecutorService】 +【java.util.concurrent.ArrayBlockingQueue】 +【java.util.concurrent.atomic.AtomicBoolean】 +【java.util.concurrent.atomic.AtomicInteger】 +【java.util.concurrent.atomic.AtomicIntegerArray】 +【java.util.concurrent.atomic.AtomicIntegerFieldUpdater】 +【java.util.concurrent.atomic.AtomicLong】 +【java.util.concurrent.atomic.AtomicLongArray】 +【java.util.concurrent.atomic.AtomicLongFieldUpdater】 +【java.util.concurrent.atomic.AtomicMarkableReference】 +【java.util.concurrent.atomic.AtomicReference】 +【java.util.concurrent.atomic.AtomicReferenceArray】 +【java.util.concurrent.atomic.AtomicReferenceFieldUpdater】 +【java.util.concurrent.atomic.AtomicStampedReference】 +【java.util.concurrent.BlockingDeque】 +【java.util.concurrent.BlockingQueue】 +【java.util.concurrent.BrokenBarrierException】 +【java.util.concurrent.Callable】 +【java.util.concurrent.CancellationException】 +【java.util.concurrent.CompletionService】 +【java.util.concurrent.ConcurrentHashMap】 +【java.util.concurrent.ConcurrentLinkedDeque】 +【java.util.concurrent.ConcurrentLinkedQueue】 +【java.util.concurrent.ConcurrentMap】 +【java.util.concurrent.ConcurrentNavigableMap】 +【java.util.concurrent.ConcurrentSkipListMap】 +【java.util.concurrent.ConcurrentSkipListSet】 +【java.util.concurrent.CopyOnWriteArrayList】 +【java.util.concurrent.CopyOnWriteArraySet】 +【java.util.concurrent.CountDownLatch】 +【java.util.concurrent.CyclicBarrier】 +【java.util.concurrent.Delayed】 +【java.util.concurrent.DelayQueue】 +【java.util.concurrent.Exchanger】 +【java.util.concurrent.ExecutionException】 +【java.util.concurrent.Executor】 +【java.util.concurrent.ExecutorCompletionService】 +【java.util.concurrent.Executors】 +【java.util.concurrent.ExecutorService】 +【java.util.concurrent.ForkJoinPool$ForkJoinWorkerThreadFactory】 +【java.util.concurrent.ForkJoinPool$ManagedBlocker】 +【java.util.concurrent.ForkJoinPool】 +【java.util.concurrent.ForkJoinTask】 +【java.util.concurrent.ForkJoinWorkerThread】 +【java.util.concurrent.Future】 +【java.util.concurrent.FutureTask】 +【java.util.concurrent.LinkedBlockingDeque】 +【java.util.concurrent.LinkedBlockingQueue】 +【java.util.concurrent.LinkedTransferQueue】 +【java.util.concurrent.locks.AbstractOwnableSynchronizer】 +【java.util.concurrent.locks.AbstractQueuedLongSynchronizer$ConditionObject】 +【java.util.concurrent.locks.AbstractQueuedLongSynchronizer】 +【java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject】 +【java.util.concurrent.locks.AbstractQueuedSynchronizer】 +【java.util.concurrent.locks.Condition】 +【java.util.concurrent.locks.Lock】 +【java.util.concurrent.locks.LockSupport】 +【java.util.concurrent.locks.ReadWriteLock】 +【java.util.concurrent.locks.ReentrantLock】 +【java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock】 +【java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock】 +【java.util.concurrent.locks.ReentrantReadWriteLock】 +【java.util.concurrent.Phaser】 +【java.util.concurrent.PriorityBlockingQueue】 +【java.util.concurrent.RecursiveAction】 +【java.util.concurrent.RecursiveTask】 +【java.util.concurrent.RejectedExecutionException】 +【java.util.concurrent.RejectedExecutionHandler】 +【java.util.concurrent.RunnableFuture】 +【java.util.concurrent.RunnableScheduledFuture】 +【java.util.concurrent.ScheduledExecutorService】 +【java.util.concurrent.ScheduledFuture】 +【java.util.concurrent.ScheduledThreadPoolExecutor】 +【java.util.concurrent.Semaphore】 +【java.util.concurrent.SynchronousQueue】 +【java.util.concurrent.ThreadFactory】 +【java.util.concurrent.ThreadLocalRandom】 +【java.util.concurrent.ThreadPoolExecutor$AbortPolicy】 +【java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy】 +【java.util.concurrent.ThreadPoolExecutor$DiscardOldestPolicy】 +【java.util.concurrent.ThreadPoolExecutor$DiscardPolicy】 +【java.util.concurrent.ThreadPoolExecutor】 +【java.util.concurrent.TimeoutException】 +【java.util.concurrent.TimeUnit】 +【java.util.concurrent.TransferQueue】 +【java.util.ConcurrentModificationException】 +【java.util.Currency】 +【java.util.Date】 +【java.util.Deque】 +【java.util.Dictionary】 +【java.util.DuplicateFormatFlagsException】 +【java.util.EmptyStackException】 +【java.util.Enumeration】 +【java.util.EnumMap】 +【java.util.EnumSet】 +【java.util.EventListener】 +【java.util.EventListenerProxy】 +【java.util.EventObject】 +【java.util.FormatFlagsConversionMismatchException】 +【java.util.Formattable】 +【java.util.FormattableFlags】 +【java.util.Formatter$BigDecimalLayoutForm】 +【java.util.Formatter】 +【java.util.FormatterClosedException】 +【java.util.GregorianCalendar】 +【java.util.HashMap】 +【java.util.HashSet】 +【java.util.Hashtable】 +【java.util.IdentityHashMap】 +【java.util.IllegalFormatCodePointException】 +【java.util.IllegalFormatConversionException】 +【java.util.IllegalFormatException】 +【java.util.IllegalFormatFlagsException】 +【java.util.IllegalFormatPrecisionException】 +【java.util.IllegalFormatWidthException】 +【java.util.IllformedLocaleException】 +【java.util.InputMismatchException】 +【java.util.InvalidPropertiesFormatException】 +【java.util.Iterator】 +【java.util.jar.Attributes$Name】 +【java.util.jar.Attributes】 +【java.util.jar.JarEntry】 +【java.util.jar.JarException】 +【java.util.jar.JarFile】 +【java.util.jar.JarInputStream】 +【java.util.jar.JarOutputStream】 +【java.util.jar.Manifest】 +【java.util.jar.Pack200$Packer】 +【java.util.jar.Pack200$Unpacker】 +【java.util.jar.Pack200】 +【java.util.LinkedHashMap】 +【java.util.LinkedHashSet】 +【java.util.LinkedList】 +【java.util.List】 +【java.util.ListIterator】 +【java.util.ListResourceBundle】 +【java.util.Locale$Builder】 +【java.util.Locale】 +【java.util.logging.ConsoleHandler】 +【java.util.logging.ErrorManager】 +【java.util.logging.FileHandler】 +【java.util.logging.Filter】 +【java.util.logging.Formatter】 +【java.util.logging.Handler】 +【java.util.logging.Level】 +【java.util.logging.Logger】 +【java.util.logging.LoggingMXBean】 +【java.util.logging.LoggingPermission】 +【java.util.logging.LogManager】 +【java.util.logging.LogRecord】 +【java.util.logging.MemoryHandler】 +【java.util.logging.SimpleFormatter】 +【java.util.logging.SocketHandler】 +【java.util.logging.StreamHandler】 +【java.util.logging.XMLFormatter】 +【java.util.Map$Entry】 +【java.util.Map】 +【java.util.MissingFormatArgumentException】 +【java.util.MissingFormatWidthException】 +【java.util.MissingResourceException】 +【java.util.NavigableMap】 +【java.util.NavigableSet】 +【java.util.NoSuchElementException】 +【java.util.Objects】 +【java.util.Observable】 +【java.util.Observer】 +【java.util.prefs.AbstractPreferences】 +【java.util.prefs.BackingStoreException】 +【java.util.prefs.InvalidPreferencesFormatException】 +【java.util.prefs.NodeChangeEvent】 +【java.util.prefs.NodeChangeListener】 +【java.util.prefs.PreferenceChangeEvent】 +【java.util.prefs.PreferenceChangeListener】 +【java.util.prefs.Preferences】 +【java.util.prefs.PreferencesFactory】 +【java.util.PriorityQueue】 +【java.util.Properties】 +【java.util.PropertyPermission】 +【java.util.PropertyResourceBundle】 +【java.util.Queue】 +【java.util.Random】 +【java.util.RandomAccess】 +【java.util.regex.Matcher】 +【java.util.regex.MatchResult】 +【java.util.regex.Pattern】 +【java.util.regex.PatternSyntaxException】 +【java.util.ResourceBundle$Control】 +【java.util.ResourceBundle】 +【java.util.Scanner】 +【java.util.ServiceConfigurationError】 +【java.util.ServiceLoader】 +【java.util.Set】 +【java.util.SimpleTimeZone】 +【java.util.SortedMap】 +【java.util.SortedSet】 +【java.util.Stack】 +【java.util.StringTokenizer】 +【java.util.Timer】 +【java.util.TimerTask】 +【java.util.TimeZone】 +【java.util.TooManyListenersException】 +【java.util.TreeMap】 +【java.util.TreeSet】 +【java.util.UnknownFormatConversionException】 +【java.util.UnknownFormatFlagsException】 +【java.util.UUID】 +【java.util.Vector】 +【java.util.WeakHashMap】 +【java.util.zip.Adler32】 +【java.util.zip.CheckedInputStream】 +【java.util.zip.CheckedOutputStream】 +【java.util.zip.Checksum】 +【java.util.zip.CRC32】 +【java.util.zip.DataFormatException】 +【java.util.zip.Deflater】 +【java.util.zip.DeflaterInputStream】 +【java.util.zip.DeflaterOutputStream】 +【java.util.zip.GZIPInputStream】 +【java.util.zip.GZIPOutputStream】 +【java.util.zip.Inflater】 +【java.util.zip.InflaterInputStream】 +【java.util.zip.InflaterOutputStream】 +【java.util.zip.ZipEntry】 +【java.util.zip.ZipError】 +【java.util.zip.ZipException】 +【java.util.zip.ZipFile】 +【java.util.zip.ZipInputStream】 +【java.util.zip.ZipOutputStream】 +【javax.crypto.AEADBadTagException】 +【javax.crypto.BadPaddingException】 +【javax.crypto.Cipher】 +【javax.crypto.CipherInputStream】 +【javax.crypto.CipherOutputStream】 +【javax.crypto.CipherSpi】 +【javax.crypto.EncryptedPrivateKeyInfo】 +【javax.crypto.ExemptionMechanism】 +【javax.crypto.ExemptionMechanismException】 +【javax.crypto.ExemptionMechanismSpi】 +【javax.crypto.IllegalBlockSizeException】 +【javax.crypto.interfaces.DHKey】 +【javax.crypto.interfaces.DHPrivateKey】 +【javax.crypto.interfaces.DHPublicKey】 +【javax.crypto.interfaces.PBEKey】 +【javax.crypto.KeyAgreement】 +【javax.crypto.KeyAgreementSpi】 +【javax.crypto.KeyGenerator】 +【javax.crypto.KeyGeneratorSpi】 +【javax.crypto.Mac】 +【javax.crypto.MacSpi】 +【javax.crypto.NoSuchPaddingException】 +【javax.crypto.NullCipher】 +【javax.crypto.SealedObject】 +【javax.crypto.SecretKey】 +【javax.crypto.SecretKeyFactory】 +【javax.crypto.SecretKeyFactorySpi】 +【javax.crypto.ShortBufferException】 +【javax.crypto.spec.DESedeKeySpec】 +【javax.crypto.spec.DESKeySpec】 +【javax.crypto.spec.DHGenParameterSpec】 +【javax.crypto.spec.DHParameterSpec】 +【javax.crypto.spec.DHPrivateKeySpec】 +【javax.crypto.spec.DHPublicKeySpec】 +【javax.crypto.spec.GCMParameterSpec】 +【javax.crypto.spec.IvParameterSpec】 +【javax.crypto.spec.OAEPParameterSpec】 +【javax.crypto.spec.PBEKeySpec】 +【javax.crypto.spec.PBEParameterSpec】 +【javax.crypto.spec.PSource$PSpecified】 +【javax.crypto.spec.PSource】 +【javax.crypto.spec.RC2ParameterSpec】 +【javax.crypto.spec.RC5ParameterSpec】 +【javax.crypto.spec.SecretKeySpec】 +【javax.microedition.khronos.egl.EGL】 +【javax.microedition.khronos.egl.EGL10】 +【javax.microedition.khronos.egl.EGL11】 +【javax.microedition.khronos.egl.EGLConfig】 +【javax.microedition.khronos.egl.EGLContext】 +【javax.microedition.khronos.egl.EGLDisplay】 +【javax.microedition.khronos.egl.EGLSurface】 +【javax.microedition.khronos.opengles.GL】 +【javax.microedition.khronos.opengles.GL10】 +【javax.microedition.khronos.opengles.GL10Ext】 +【javax.microedition.khronos.opengles.GL11】 +【javax.microedition.khronos.opengles.GL11Ext】 +【javax.microedition.khronos.opengles.GL11ExtensionPack】 +【javax.net.ServerSocketFactory】 +【javax.net.SocketFactory】 +【javax.net.ssl.CertPathTrustManagerParameters】 +【javax.net.ssl.HandshakeCompletedEvent】 +【javax.net.ssl.HandshakeCompletedListener】 +【javax.net.ssl.HostnameVerifier】 +【javax.net.ssl.HttpsURLConnection】 +【javax.net.ssl.KeyManager】 +【javax.net.ssl.KeyManagerFactory】 +【javax.net.ssl.KeyManagerFactorySpi】 +【javax.net.ssl.KeyStoreBuilderParameters】 +【javax.net.ssl.ManagerFactoryParameters】 +【javax.net.ssl.SSLContext】 +【javax.net.ssl.SSLContextSpi】 +【javax.net.ssl.SSLEngine】 +【javax.net.ssl.SSLEngineResult$HandshakeStatus】 +【javax.net.ssl.SSLEngineResult$Status】 +【javax.net.ssl.SSLEngineResult】 +【javax.net.ssl.SSLException】 +【javax.net.ssl.SSLHandshakeException】 +【javax.net.ssl.SSLKeyException】 +【javax.net.ssl.SSLParameters】 +【javax.net.ssl.SSLPeerUnverifiedException】 +【javax.net.ssl.SSLPermission】 +【javax.net.ssl.SSLProtocolException】 +【javax.net.ssl.SSLServerSocket】 +【javax.net.ssl.SSLServerSocketFactory】 +【javax.net.ssl.SSLSession】 +【javax.net.ssl.SSLSessionBindingEvent】 +【javax.net.ssl.SSLSessionBindingListener】 +【javax.net.ssl.SSLSessionContext】 +【javax.net.ssl.SSLSocket】 +【javax.net.ssl.SSLSocketFactory】 +【javax.net.ssl.TrustManager】 +【javax.net.ssl.TrustManagerFactory】 +【javax.net.ssl.TrustManagerFactorySpi】 +【javax.net.ssl.X509ExtendedKeyManager】 +【javax.net.ssl.X509KeyManager】 +【javax.net.ssl.X509TrustManager】 +【javax.security.auth.AuthPermission】 +【javax.security.auth.callback.Callback】 +【javax.security.auth.callback.CallbackHandler】 +【javax.security.auth.callback.PasswordCallback】 +【javax.security.auth.callback.UnsupportedCallbackException】 +【javax.security.auth.Destroyable】 +【javax.security.auth.DestroyFailedException】 +【javax.security.auth.login.LoginException】 +【javax.security.auth.PrivateCredentialPermission】 +【javax.security.auth.Subject】 +【javax.security.auth.SubjectDomainCombiner】 +【javax.security.auth.x500.X500Principal】 +【javax.security.cert.Certificate】 +【javax.security.cert.CertificateEncodingException】 +【javax.security.cert.CertificateException】 +【javax.security.cert.CertificateExpiredException】 +【javax.security.cert.CertificateNotYetValidException】 +【javax.security.cert.CertificateParsingException】 +【javax.security.cert.X509Certificate】 +【javax.sql.CommonDataSource】 +【javax.sql.ConnectionEvent】 +【javax.sql.ConnectionEventListener】 +【javax.sql.ConnectionPoolDataSource】 +【javax.sql.DataSource】 +【javax.sql.PooledConnection】 +【javax.sql.RowSet】 +【javax.sql.RowSetEvent】 +【javax.sql.RowSetInternal】 +【javax.sql.RowSetListener】 +【javax.sql.RowSetMetaData】 +【javax.sql.RowSetReader】 +【javax.sql.RowSetWriter】 +【javax.sql.StatementEvent】 +【javax.sql.StatementEventListener】 +【javax.xml.datatype.DatatypeConfigurationException】 +【javax.xml.datatype.DatatypeConstants$Field】 +【javax.xml.datatype.DatatypeConstants】 +【javax.xml.datatype.DatatypeFactory】 +【javax.xml.datatype.Duration】 +【javax.xml.datatype.XMLGregorianCalendar】 +【javax.xml.namespace.NamespaceContext】 +【javax.xml.namespace.QName】 +【javax.xml.parsers.DocumentBuilder】 +【javax.xml.parsers.DocumentBuilderFactory】 +【javax.xml.parsers.FactoryConfigurationError】 +【javax.xml.parsers.ParserConfigurationException】 +【javax.xml.parsers.SAXParser】 +【javax.xml.parsers.SAXParserFactory】 +【javax.xml.transform.dom.DOMLocator】 +【javax.xml.transform.dom.DOMResult】 +【javax.xml.transform.dom.DOMSource】 +【javax.xml.transform.ErrorListener】 +【javax.xml.transform.OutputKeys】 +【javax.xml.transform.Result】 +【javax.xml.transform.sax.SAXResult】 +【javax.xml.transform.sax.SAXSource】 +【javax.xml.transform.sax.SAXTransformerFactory】 +【javax.xml.transform.sax.TemplatesHandler】 +【javax.xml.transform.sax.TransformerHandler】 +【javax.xml.transform.Source】 +【javax.xml.transform.SourceLocator】 +【javax.xml.transform.stream.StreamResult】 +【javax.xml.transform.stream.StreamSource】 +【javax.xml.transform.Templates】 +【javax.xml.transform.Transformer】 +【javax.xml.transform.TransformerConfigurationException】 +【javax.xml.transform.TransformerException】 +【javax.xml.transform.TransformerFactory】 +【javax.xml.transform.TransformerFactoryConfigurationError】 +【javax.xml.transform.URIResolver】 +【javax.xml.validation.Schema】 +【javax.xml.validation.SchemaFactory】 +【javax.xml.validation.SchemaFactoryLoader】 +【javax.xml.validation.TypeInfoProvider】 +【javax.xml.validation.Validator】 +【javax.xml.validation.ValidatorHandler】 +【javax.xml.XMLConstants】 +【javax.xml.xpath.XPath】 +【javax.xml.xpath.XPathConstants】 +【javax.xml.xpath.XPathException】 +【javax.xml.xpath.XPathExpression】 +【javax.xml.xpath.XPathExpressionException】 +【javax.xml.xpath.XPathFactory】 +【javax.xml.xpath.XPathFactoryConfigurationException】 +【javax.xml.xpath.XPathFunction】 +【javax.xml.xpath.XPathFunctionException】 +【javax.xml.xpath.XPathFunctionResolver】 +【javax.xml.xpath.XPathVariableResolver】 +【junit.framework.Assert】 +【junit.framework.AssertionFailedError】 +【junit.framework.ComparisonFailure】 +【junit.framework.Protectable】 +【junit.framework.Test】 +【junit.framework.TestCase】 +【junit.framework.TestFailure】 +【junit.framework.TestListener】 +【junit.framework.TestResult】 +【junit.framework.TestSuite】 +【junit.runner.BaseTestRunner】 +【junit.runner.TestSuiteLoader】 +【junit.runner.Version】 +【org.apache.commons.logging.Log】 +【org.apache.http.auth.AUTH】 +【org.apache.http.auth.AuthenticationException】 +【org.apache.http.auth.AuthScheme】 +【org.apache.http.auth.AuthSchemeFactory】 +【org.apache.http.auth.AuthSchemeRegistry】 +【org.apache.http.auth.AuthScope】 +【org.apache.http.auth.AuthState】 +【org.apache.http.auth.BasicUserPrincipal】 +【org.apache.http.auth.Credentials】 +【org.apache.http.auth.InvalidCredentialsException】 +【org.apache.http.auth.MalformedChallengeException】 +【org.apache.http.auth.NTCredentials】 +【org.apache.http.auth.NTUserPrincipal】 +【org.apache.http.auth.params.AuthParamBean】 +【org.apache.http.auth.params.AuthParams】 +【org.apache.http.auth.params.AuthPNames】 +【org.apache.http.auth.UsernamePasswordCredentials】 +【org.apache.http.client.AuthenticationHandler】 +【org.apache.http.client.CircularRedirectException】 +【org.apache.http.client.ClientProtocolException】 +【org.apache.http.client.CookieStore】 +【org.apache.http.client.CredentialsProvider】 +【org.apache.http.client.entity.UrlEncodedFormEntity】 +【org.apache.http.client.HttpClient】 +【org.apache.http.client.HttpRequestRetryHandler】 +【org.apache.http.client.HttpResponseException】 +【org.apache.http.client.methods.AbortableHttpRequest】 +【org.apache.http.client.methods.HttpDelete】 +【org.apache.http.client.methods.HttpEntityEnclosingRequestBase】 +【org.apache.http.client.methods.HttpGet】 +【org.apache.http.client.methods.HttpHead】 +【org.apache.http.client.methods.HttpOptions】 +【org.apache.http.client.methods.HttpPost】 +【org.apache.http.client.methods.HttpPut】 +【org.apache.http.client.methods.HttpRequestBase】 +【org.apache.http.client.methods.HttpTrace】 +【org.apache.http.client.methods.HttpUriRequest】 +【org.apache.http.client.NonRepeatableRequestException】 +【org.apache.http.client.params.AllClientPNames】 +【org.apache.http.client.params.AuthPolicy】 +【org.apache.http.client.params.ClientParamBean】 +【org.apache.http.client.params.ClientPNames】 +【org.apache.http.client.params.CookiePolicy】 +【org.apache.http.client.params.HttpClientParams】 +【org.apache.http.client.protocol.ClientContext】 +【org.apache.http.client.protocol.ClientContextConfigurer】 +【org.apache.http.client.protocol.RequestAddCookies】 +【org.apache.http.client.protocol.RequestDefaultHeaders】 +【org.apache.http.client.protocol.RequestProxyAuthentication】 +【org.apache.http.client.protocol.RequestTargetAuthentication】 +【org.apache.http.client.protocol.ResponseProcessCookies】 +【org.apache.http.client.RedirectException】 +【org.apache.http.client.RedirectHandler】 +【org.apache.http.client.RequestDirector】 +【org.apache.http.client.ResponseHandler】 +【org.apache.http.client.UserTokenHandler】 +【org.apache.http.client.utils.CloneUtils】 +【org.apache.http.client.utils.URIUtils】 +【org.apache.http.client.utils.URLEncodedUtils】 +【org.apache.http.conn.BasicEofSensorWatcher】 +【org.apache.http.conn.BasicManagedEntity】 +【org.apache.http.conn.ClientConnectionManager】 +【org.apache.http.conn.ClientConnectionManagerFactory】 +【org.apache.http.conn.ClientConnectionOperator】 +【org.apache.http.conn.ClientConnectionRequest】 +【org.apache.http.conn.ConnectionKeepAliveStrategy】 +【org.apache.http.conn.ConnectionPoolTimeoutException】 +【org.apache.http.conn.ConnectionReleaseTrigger】 +【org.apache.http.conn.ConnectTimeoutException】 +【org.apache.http.conn.EofSensorInputStream】 +【org.apache.http.conn.EofSensorWatcher】 +【org.apache.http.conn.HttpHostConnectException】 +【org.apache.http.conn.ManagedClientConnection】 +【org.apache.http.conn.MultihomePlainSocketFactory】 +【org.apache.http.conn.OperatedClientConnection】 +【org.apache.http.conn.params.ConnConnectionParamBean】 +【org.apache.http.conn.params.ConnConnectionPNames】 +【org.apache.http.conn.params.ConnManagerParamBean】 +【org.apache.http.conn.params.ConnManagerParams】 +【org.apache.http.conn.params.ConnManagerPNames】 +【org.apache.http.conn.params.ConnPerRoute】 +【org.apache.http.conn.params.ConnPerRouteBean】 +【org.apache.http.conn.params.ConnRouteParamBean】 +【org.apache.http.conn.params.ConnRouteParams】 +【org.apache.http.conn.params.ConnRoutePNames】 +【org.apache.http.conn.routing.BasicRouteDirector】 +【org.apache.http.conn.routing.HttpRoute】 +【org.apache.http.conn.routing.HttpRouteDirector】 +【org.apache.http.conn.routing.HttpRoutePlanner】 +【org.apache.http.conn.routing.RouteInfo$LayerType】 +【org.apache.http.conn.routing.RouteInfo$TunnelType】 +【org.apache.http.conn.routing.RouteInfo】 +【org.apache.http.conn.routing.RouteTracker】 +【org.apache.http.conn.scheme.HostNameResolver】 +【org.apache.http.conn.scheme.LayeredSocketFactory】 +【org.apache.http.conn.scheme.PlainSocketFactory】 +【org.apache.http.conn.scheme.Scheme】 +【org.apache.http.conn.scheme.SchemeRegistry】 +【org.apache.http.conn.scheme.SocketFactory】 +【org.apache.http.conn.ssl.AbstractVerifier】 +【org.apache.http.conn.ssl.AllowAllHostnameVerifier】 +【org.apache.http.conn.ssl.BrowserCompatHostnameVerifier】 +【org.apache.http.conn.ssl.SSLSocketFactory】 +【org.apache.http.conn.ssl.StrictHostnameVerifier】 +【org.apache.http.conn.ssl.X509HostnameVerifier】 +【org.apache.http.conn.util.InetAddressUtils】 +【org.apache.http.ConnectionClosedException】 +【org.apache.http.ConnectionReuseStrategy】 +【org.apache.http.cookie.ClientCookie】 +【org.apache.http.cookie.Cookie】 +【org.apache.http.cookie.CookieAttributeHandler】 +【org.apache.http.cookie.CookieIdentityComparator】 +【org.apache.http.cookie.CookieOrigin】 +【org.apache.http.cookie.CookiePathComparator】 +【org.apache.http.cookie.CookieSpec】 +【org.apache.http.cookie.CookieSpecFactory】 +【org.apache.http.cookie.CookieSpecRegistry】 +【org.apache.http.cookie.MalformedCookieException】 +【org.apache.http.cookie.params.CookieSpecParamBean】 +【org.apache.http.cookie.params.CookieSpecPNames】 +【org.apache.http.cookie.SetCookie】 +【org.apache.http.cookie.SetCookie2】 +【org.apache.http.cookie.SM】 +【org.apache.http.entity.AbstractHttpEntity】 +【org.apache.http.entity.BasicHttpEntity】 +【org.apache.http.entity.BufferedHttpEntity】 +【org.apache.http.entity.ByteArrayEntity】 +【org.apache.http.entity.ContentLengthStrategy】 +【org.apache.http.entity.ContentProducer】 +【org.apache.http.entity.EntityTemplate】 +【org.apache.http.entity.FileEntity】 +【org.apache.http.entity.HttpEntityWrapper】 +【org.apache.http.entity.InputStreamEntity】 +【org.apache.http.entity.SerializableEntity】 +【org.apache.http.entity.StringEntity】 +【org.apache.http.FormattedHeader】 +【org.apache.http.Header】 +【org.apache.http.HeaderElement】 +【org.apache.http.HeaderElementIterator】 +【org.apache.http.HeaderIterator】 +【org.apache.http.HttpClientConnection】 +【org.apache.http.HttpConnection】 +【org.apache.http.HttpConnectionMetrics】 +【org.apache.http.HttpEntity】 +【org.apache.http.HttpEntityEnclosingRequest】 +【org.apache.http.HttpException】 +【org.apache.http.HttpHost】 +【org.apache.http.HttpInetConnection】 +【org.apache.http.HttpMessage】 +【org.apache.http.HttpRequest】 +【org.apache.http.HttpRequestFactory】 +【org.apache.http.HttpRequestInterceptor】 +【org.apache.http.HttpResponse】 +【org.apache.http.HttpResponseFactory】 +【org.apache.http.HttpResponseInterceptor】 +【org.apache.http.HttpServerConnection】 +【org.apache.http.HttpStatus】 +【org.apache.http.HttpVersion】 +【org.apache.http.io.HttpMessageParser】 +【org.apache.http.io.HttpMessageWriter】 +【org.apache.http.io.HttpTransportMetrics】 +【org.apache.http.io.SessionInputBuffer】 +【org.apache.http.io.SessionOutputBuffer】 +【org.apache.http.MalformedChunkCodingException】 +【org.apache.http.message.AbstractHttpMessage】 +【org.apache.http.message.BasicHeader】 +【org.apache.http.message.BasicHeaderElement】 +【org.apache.http.message.BasicHeaderElementIterator】 +【org.apache.http.message.BasicHeaderIterator】 +【org.apache.http.message.BasicHeaderValueFormatter】 +【org.apache.http.message.BasicHeaderValueParser】 +【org.apache.http.message.BasicHttpEntityEnclosingRequest】 +【org.apache.http.message.BasicHttpRequest】 +【org.apache.http.message.BasicHttpResponse】 +【org.apache.http.message.BasicLineFormatter】 +【org.apache.http.message.BasicLineParser】 +【org.apache.http.message.BasicListHeaderIterator】 +【org.apache.http.message.BasicNameValuePair】 +【org.apache.http.message.BasicRequestLine】 +【org.apache.http.message.BasicStatusLine】 +【org.apache.http.message.BasicTokenIterator】 +【org.apache.http.message.BufferedHeader】 +【org.apache.http.message.HeaderGroup】 +【org.apache.http.message.HeaderValueFormatter】 +【org.apache.http.message.HeaderValueParser】 +【org.apache.http.message.LineFormatter】 +【org.apache.http.message.LineParser】 +【org.apache.http.message.ParserCursor】 +【org.apache.http.MethodNotSupportedException】 +【org.apache.http.NameValuePair】 +【org.apache.http.NoHttpResponseException】 +【org.apache.http.params.AbstractHttpParams】 +【org.apache.http.params.BasicHttpParams】 +【org.apache.http.params.CoreConnectionPNames】 +【org.apache.http.params.CoreProtocolPNames】 +【org.apache.http.params.DefaultedHttpParams】 +【org.apache.http.params.HttpAbstractParamBean】 +【org.apache.http.params.HttpConnectionParamBean】 +【org.apache.http.params.HttpConnectionParams】 +【org.apache.http.params.HttpParams】 +【org.apache.http.params.HttpProtocolParamBean】 +【org.apache.http.params.HttpProtocolParams】 +【org.apache.http.ParseException】 +【org.apache.http.protocol.BasicHttpContext】 +【org.apache.http.protocol.BasicHttpProcessor】 +【org.apache.http.protocol.DefaultedHttpContext】 +【org.apache.http.protocol.ExecutionContext】 +【org.apache.http.protocol.HTTP】 +【org.apache.http.protocol.HttpContext】 +【org.apache.http.protocol.HttpDateGenerator】 +【org.apache.http.protocol.HttpExpectationVerifier】 +【org.apache.http.protocol.HttpProcessor】 +【org.apache.http.protocol.HttpRequestExecutor】 +【org.apache.http.protocol.HttpRequestHandler】 +【org.apache.http.protocol.HttpRequestHandlerRegistry】 +【org.apache.http.protocol.HttpRequestHandlerResolver】 +【org.apache.http.protocol.HttpRequestInterceptorList】 +【org.apache.http.protocol.HttpResponseInterceptorList】 +【org.apache.http.protocol.HttpService】 +【org.apache.http.protocol.RequestConnControl】 +【org.apache.http.protocol.RequestContent】 +【org.apache.http.protocol.RequestDate】 +【org.apache.http.protocol.RequestExpectContinue】 +【org.apache.http.protocol.RequestTargetHost】 +【org.apache.http.protocol.RequestUserAgent】 +【org.apache.http.protocol.ResponseConnControl】 +【org.apache.http.protocol.ResponseContent】 +【org.apache.http.protocol.ResponseDate】 +【org.apache.http.protocol.ResponseServer】 +【org.apache.http.protocol.SyncBasicHttpContext】 +【org.apache.http.protocol.UriPatternMatcher】 +【org.apache.http.ProtocolException】 +【org.apache.http.ProtocolVersion】 +【org.apache.http.ReasonPhraseCatalog】 +【org.apache.http.RequestLine】 +【org.apache.http.StatusLine】 +【org.apache.http.TokenIterator】 +【org.apache.http.UnsupportedHttpVersionException】 +【org.apache.http.util.ByteArrayBuffer】 +【org.apache.http.util.CharArrayBuffer】 +【org.apache.http.util.EncodingUtils】 +【org.apache.http.util.EntityUtils】 +【org.apache.http.util.ExceptionUtils】 +【org.apache.http.util.LangUtils】 +【org.apache.http.util.VersionInfo】 +【org.json.JSONArray】 +【org.json.JSONException】 +【org.json.JSONObject】 +【org.json.JSONStringer】 +【org.json.JSONTokener】 +【org.w3c.dom.Attr】 +【org.w3c.dom.CDATASection】 +【org.w3c.dom.CharacterData】 +【org.w3c.dom.Comment】 +【org.w3c.dom.Document】 +【org.w3c.dom.DocumentFragment】 +【org.w3c.dom.DocumentType】 +【org.w3c.dom.DOMConfiguration】 +【org.w3c.dom.DOMError】 +【org.w3c.dom.DOMErrorHandler】 +【org.w3c.dom.DOMException】 +【org.w3c.dom.DOMImplementation】 +【org.w3c.dom.DOMImplementationList】 +【org.w3c.dom.DOMImplementationSource】 +【org.w3c.dom.DOMLocator】 +【org.w3c.dom.DOMStringList】 +【org.w3c.dom.Element】 +【org.w3c.dom.Entity】 +【org.w3c.dom.EntityReference】 +【org.w3c.dom.ls.DOMImplementationLS】 +【org.w3c.dom.ls.LSException】 +【org.w3c.dom.ls.LSInput】 +【org.w3c.dom.ls.LSOutput】 +【org.w3c.dom.ls.LSParser】 +【org.w3c.dom.ls.LSParserFilter】 +【org.w3c.dom.ls.LSResourceResolver】 +【org.w3c.dom.ls.LSSerializer】 +【org.w3c.dom.NamedNodeMap】 +【org.w3c.dom.NameList】 +【org.w3c.dom.Node】 +【org.w3c.dom.NodeList】 +【org.w3c.dom.Notation】 +【org.w3c.dom.ProcessingInstruction】 +【org.w3c.dom.Text】 +【org.w3c.dom.TypeInfo】 +【org.w3c.dom.UserDataHandler】 +【org.xml.sax.AttributeList】 +【org.xml.sax.Attributes】 +【org.xml.sax.ContentHandler】 +【org.xml.sax.DocumentHandler】 +【org.xml.sax.DTDHandler】 +【org.xml.sax.EntityResolver】 +【org.xml.sax.ErrorHandler】 +【org.xml.sax.ext.Attributes2】 +【org.xml.sax.ext.Attributes2Impl】 +【org.xml.sax.ext.DeclHandler】 +【org.xml.sax.ext.DefaultHandler2】 +【org.xml.sax.ext.EntityResolver2】 +【org.xml.sax.ext.LexicalHandler】 +【org.xml.sax.ext.Locator2】 +【org.xml.sax.ext.Locator2Impl】 +【org.xml.sax.HandlerBase】 +【org.xml.sax.helpers.AttributeListImpl】 +【org.xml.sax.helpers.AttributesImpl】 +【org.xml.sax.helpers.DefaultHandler】 +【org.xml.sax.helpers.LocatorImpl】 +【org.xml.sax.helpers.NamespaceSupport】 +【org.xml.sax.helpers.ParserAdapter】 +【org.xml.sax.helpers.ParserFactory】 +【org.xml.sax.helpers.XMLFilterImpl】 +【org.xml.sax.helpers.XMLReaderAdapter】 +【org.xml.sax.helpers.XMLReaderFactory】 +【org.xml.sax.InputSource】 +【org.xml.sax.Locator】 +【org.xml.sax.Parser】 +【org.xml.sax.SAXException】 +【org.xml.sax.SAXNotRecognizedException】 +【org.xml.sax.SAXNotSupportedException】 +【org.xml.sax.SAXParseException】 +【org.xml.sax.XMLFilter】 +【org.xml.sax.XMLReader】 +【org.xmlpull.v1.sax2.Driver】【org.xmlpull.v1.XmlPullParser】【org.xmlpull.v1.XmlPullParserException】【org.xmlpull.v1.XmlPullParserFactory】【org.xmlpull.v1.XmlSerializer】]] diff --git a/app/src/main/assets/bin.lua b/app/src/main/assets/bin.lua new file mode 100644 index 0000000..f3fb2f3 --- /dev/null +++ b/app/src/main/assets/bin.lua @@ -0,0 +1,398 @@ +require "import" +import "java.util.zip.ZipOutputStream" +import "android.net.Uri" +import "java.io.File" +import "android.widget.Toast" +import "java.util.zip.CheckedInputStream" +import "java.io.FileInputStream" +import "android.content.Intent" +import "java.security.Signer" +import "java.util.ArrayList" +import "java.io.FileOutputStream" +import "java.io.BufferedOutputStream" +import "java.util.zip.ZipInputStream" +import "java.io.BufferedInputStream" +import "java.util.zip.ZipEntry" +import "android.app.ProgressDialog" +import "java.util.zip.CheckedOutputStream" +import "java.util.zip.Adler32" + +local bin_dlg, error_dlg +local function update(s) + bin_dlg.setMessage(s) +end + +local function callback(s) + LuaUtil.rmDir(File(activity.getLuaExtDir("bin/.temp"))) + bin_dlg.hide() + bin_dlg.Message = "" + if not s:find("成功") then + error_dlg.Message = s + error_dlg.show() + end +end + +local function create_bin_dlg() + if bin_dlg then + return + end + bin_dlg = ProgressDialog(activity); + bin_dlg.setTitle("正在打包"); + bin_dlg.setMax(100); +end + +local function create_error_dlg2() + if error_dlg then + return + end + error_dlg = AlertDialogBuilder(activity) + error_dlg.Title = "出错" + error_dlg.setPositiveButton("确定", nil) +end + +local function binapk(luapath, apkpath) + require "import" + import "console" + compile "mao" + compile "sign" + import "java.util.zip.*" + import "java.io.*" + import "mao.res.*" + import "apksigner.*" + local b = byte[2 ^ 16] + local function copy(input, output) + LuaUtil.copyFile(input, output) + input.close() + --[[local l=input.read(b) + while l>1 do + output.write(b,0,l) + l=input.read(b) + end]] + end + + local function copy2(input, output) + LuaUtil.copyFile(input, output) + end + + local temp = File(apkpath).getParentFile(); + if (not temp.exists()) then + + if (not temp.mkdirs()) then + + error("create file " .. temp.getName() .. " fail"); + end + end + + + local tmp = luajava.luadir .. "/tmp.apk" + local info = activity.getApplicationInfo() + local ver = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionName + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + + --local zip=ZipFile(info.publicSourceDir) + local zipFile = File(info.publicSourceDir) + local fis = FileInputStream(zipFile); + --local checksum = CheckedInputStream(fis, Adler32()); + local zis = ZipInputStream(BufferedInputStream(fis)); + + local fot = FileOutputStream(tmp) + --local checksum2 = CheckedOutputStream(fot, Adler32()); + + local out = ZipOutputStream(BufferedOutputStream(fot)) + local f = File(luapath) + local errbuffer = {} + local replace = {} + local checked = {} + local lualib = {} + local md5s = {} + local libs = File(activity.ApplicationInfo.nativeLibraryDir).list() + libs = luajava.astable(libs) + for k, v in ipairs(libs) do + --libs[k]="lib/armeabi/"..libs[k] + replace[v] = true + end + + local mdp = activity.Application.MdDir + local function getmodule(dir) + local mds = File(activity.Application.MdDir .. dir).listFiles() + mds = luajava.astable(mds) + for k, v in ipairs(mds) do + if mds[k].isDirectory() then + getmodule(dir .. mds[k].Name .. "/") + else + mds[k] = "lua" .. dir .. mds[k].Name + replace[mds[k]] = true + end + end + end + + getmodule("/") + + local function checklib(path) + if checked[path] then + return + end + local cp, lp + checked[path] = true + local f = io.open(path) + local s = f:read("*a") + f:close() + for m, n in s:gmatch("require *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + for m, n in s:gmatch("import *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + end + + replace["libluajava.so"] = false + + local function addDir(out, dir, f) + local entry = ZipEntry("assets/" .. dir) + out.putNextEntry(entry) + local ls = f.listFiles() + for n = 0, #ls - 1 do + local name = ls[n].getName() + if name==(".using") then + checklib(luapath .. dir .. name) + elseif name:find("%.apk$") or name:find("%.luac$") or name:find("^%.") then + elseif name:find("%.lua$") then + checklib(luapath .. dir .. name) + local path, err = console.build(luapath .. dir .. name) + if path then + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif name:find("%.aly$") then + local path, err = console.build_aly(luapath .. dir .. name) + if path then + name = name:gsub("aly$", "lua") + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif ls[n].isDirectory() then + addDir(out, dir .. name .. "/", ls[n]) + else + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + replace["assets/" .. dir .. name] = true + copy(FileInputStream(ls[n]), out) + table.insert(md5s, LuaUtil.getFileMD5(ls[n])) + end + end + end + + + this.update("正在编译..."); + if f.isDirectory() then + require "permission" + dofile(luapath .. "init.lua") + if user_permission then + for k, v in ipairs(user_permission) do + user_permission[v] = true + end + end + + + local ss, ee = pcall(addDir, out, "", f) + if not ss then + table.insert(errbuffer, ee) + end + --print(ee,dump(errbuffer),dump(replace)) + + + local wel = File(luapath .. "icon.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/icon.png") + out.putNextEntry(entry) + replace["res/drawable/icon.png"] = true + copy(FileInputStream(wel), out) + end + local wel = File(luapath .. "welcome.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/welcome.png") + out.putNextEntry(entry) + replace["res/drawable/welcome.png"] = true + copy(FileInputStream(wel), out) + end + else + return "error" + end + + --print(dump(lualib)) + for name, v in pairs(lualib) do + local path, err = console.build(v) + if path then + local entry = ZipEntry(name) + out.putNextEntry(entry) + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + end + + function touint32(i) + local code = string.format("%08x", i) + local uint = {} + for n in code:gmatch("..") do + table.insert(uint, 1, string.char(tonumber(n, 16))) + end + return table.concat(uint) + end + + this.update("正在打包..."); + local entry = zis.getNextEntry(); + while entry do + local name = entry.getName() + local lib = name:match("([^/]+%.so)$") + if replace[name] then + elseif lib and replace[lib] then + elseif name:find("^assets/") then + elseif name:find("^lua/") then + elseif name:find("META%-INF") then + else + local entry = ZipEntry(name) + out.putNextEntry(entry) + if entry.getName() == "AndroidManifest.xml" then + if path_pattern and #path_pattern > 1 then + path_pattern = ".*\\\\." .. path_pattern:match("%w+$") + end + local list = ArrayList() + local xml = AXmlDecoder.read(list, zis) + local req = { + [activity.getPackageName()] = packagename, + [info.nonLocalizedLabel] = appname, + [ver] = appver, + [".*\\\\.alp"] = path_pattern or "", + [".*\\\\.lua"] = "", + [".*\\\\.luac"] = "", + } + for n = 0, list.size() - 1 do + local v = list.get(n) + if req[v] then + list.set(n, req[v]) + elseif user_permission then + local p = v:match("%.permission%.([%w_]+)$") + if p and (not user_permission[p]) then + list.set(n, "android.permission.UNKNOWN") + end + end + end + local pt = activity.getLuaPath(".tmp") + local fo = FileOutputStream(pt) + xml.write(list, fo) + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + fo.close() + local f = io.open(pt) + local s = f:read("a") + f:close() + s = string.gsub(s, touint32(code), touint32(tointeger(appcode) or 1),1) + s = string.gsub(s, touint32(18), touint32(tointeger(appsdk) or 18),1) + + local f = io.open(pt, "w") + f:write(s) + f:close() + local fi = FileInputStream(pt) + copy(fi, out) + os.remove(pt) + elseif not entry.isDirectory() then + copy2(zis, out) + end + end + entry = zis.getNextEntry() + end + out.setComment(table.concat(md5s)) + --print(table.concat(md5s,"/n")) + zis.close(); + out.closeEntry() + out.close() + + if #errbuffer == 0 then + this.update("正在签名..."); + os.remove(apkpath) + Signer.sign(tmp, apkpath) + os.remove(tmp) + activity.installApk(apkpath) + --[[import "android.net.*" + import "android.content.*" + i = Intent(Intent.ACTION_VIEW); + i.setDataAndType(activity.getUriForFile(File(apkpath)), "application/vnd.android.package-archive"); + i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + this.update("正在打开..."); + activity.startActivityForResult(i, 0);]] + return "打包成功:" .. apkpath + else + os.remove(tmp) + this.update("打包出错:\n " .. table.concat(errbuffer, "\n")); + return "打包出错:\n " .. table.concat(errbuffer, "\n") + end +end + +--luabindir=activity.getLuaExtDir("bin") +--print(activity.getLuaExtPath("bin","a")) +local function bin(path) + local p = {} + local e, s = pcall(loadfile(path .. "init.lua", "bt", p)) + if e then + create_error_dlg2() + create_bin_dlg() + bin_dlg.show() + activity.newTask(binapk, update, callback).execute { path, activity.getLuaExtPath("bin", p.appname .. "_" .. p.appver .. ".apk") } + else + Toast.makeText(activity, "工程配置文件错误." .. s, Toast.LENGTH_SHORT).show() + end +end + +--bin(activity.getLuaExtDir("project/demo").."/") +return bin \ No newline at end of file diff --git a/app/src/main/assets/bmob.lua b/app/src/main/assets/bmob.lua new file mode 100644 index 0000000..65010a7 --- /dev/null +++ b/app/src/main/assets/bmob.lua @@ -0,0 +1,152 @@ +local Http=luajava.bindClass "com.androlua.Http" +local File=luajava.bindClass "java.io.File" +local pairs,tostring,print,dump,xpcall=pairs,tostring,print,dump,xpcall +local cjson=require "cjson" +local table=require "table" +local string=require "string" +local type=type +module "bmob" + +local function decode(s) + s=tostring(s) + return (s:gsub("%W",function(c) + return string.format("%%%02X",string.byte(c)) + end)) +end + +local function header(t) + return {["X-Bmob-Application-Id"]= t.id, + ["X-Bmob-REST-API-Key"]= t.key , + ["X-Bmob-Session-Token"]= t.token , + ["Content-Type:"]= "application/json"} +end + +local function callback(code,json,func) + if code~=-1 then + json=cjson.decode(json) + end + func(code,json) +end + +local function format(t) + local ret={} + for k,v in pairs(t) do + if type(v)=="table" then + table.insert(ret,k.."="..decode(cjson.encode(v))) + else + table.insert(ret,k.."="..decode(v)) + end + end + return table.concat(ret,"&") +end + +function new(self,id,key) + self.id=id + self.key=key +end + +function query(self,...) + local arg={...} + local c=arg[#arg] + table.remove(arg) + local fmt + if type(arg[#arg])=="table" then + fmt=format(arg[#arg]) + table.remove(arg) + end + local t=table.concat(arg,"/")..("?"..(fmt or "")) + Http.get("https://api2.bmob.cn/1/classes/"..t,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end) +end + +function insert(self,t,d,c) + if type(d)=="table" then + d=cjson.encode(d) + end + Http.post("https://api2.bmob.cn/1/classes/"..t,d,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end) +end + +function update(self,t,i,d,c) + if type(d)=="table" then + d=cjson.encode(d) + end + Http.put("https://api2.bmob.cn/1/classes/"..t.."/"..i,d,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end) +end + +function increment(self,t,i,k,v,c) + local d={[k]={__op="Increment",amount=v}} + if type(d)=="table" then + d=cjson.encode(d) + end + Http.put("https://api2.bmob.cn/1/classes/"..t.."/"..i,d,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end) +end + +function delete(self,t,i,c) + Http.delete("https://api2.bmob.cn/1/classes/"..t.."/"..i,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end) +end + +function upload(self,f,c) + f=File(f) + Http.HttpTask("https://api2.bmob.cn/2/files/"..f.Name,"POST",nil,nil,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end).execute{f} +end + +function remove(self,i,c) + Http.delete("https://api2.bmob.cn/2/files/"..i,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end) +end + +function sign(self,u,p,e,c) + local d={username=u,password=p,email=e} + if type(d)=="table" then + d=cjson.encode(d) + end + Http.post("https://api2.bmob.cn/1/users",d,header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + end + c(code,json) + end) +end + +function login(self,u,p,c) + Http.get("https://api2.bmob.cn/1/login/?username="..decode(u).."&password="..decode(p),header(self),function(code,json) + if code~=-1 and code>=200 and code<400 then + json=cjson.decode(json) + self.token=json.sessionToken + end + c(code,json) + end) +end diff --git a/app/src/main/assets/color.lua b/app/src/main/assets/color.lua new file mode 100644 index 0000000..e0b407c --- /dev/null +++ b/app/src/main/assets/color.lua @@ -0,0 +1,447 @@ +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色5=0xff303030 + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色5=0x5FFFFFFF + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end +local L0_656, L1_657 +function L0_656(A0_658, A1_659, A2_660, A3_661) + import("android.graphics.PorterDuff") + import("android.graphics.PorterDuffColorFilter") + function CircleButton(A0_662, A1_663) + import("android.graphics.drawable.GradientDrawable") + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(A1_663) + drawable.setCornerRadii({ + 360, + 360, + 360, + 360, + 360, + 360, + 360, + 360 + }) + A0_662.setBackgroundDrawable(drawable) + end + + yuxuan = { + LinearLayout, + orientation = "vertical", + layout_height = "fill", + layout_width = "fill", + gravity = "center", + { + CardView, + layout_height = "100dp", + layout_width = "100dp", + layout_marginTop = "20dp", + backgroundColor=颜色1, + id = "mmp5" + }, + { + EditText, + text = "", + id = "mmp4", + background = "0", + layout_marginLeft = "10dp", + layout_marginRight = "10dp", + layout_width = "match_parent", + layout_height = "50dp", + gravity = "center" + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + { + TextView, + text = "A", + textColor=颜色7, + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + }, + { + SeekBar, + id = "seek_Ap", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "FF", + textColor=颜色7, + id = "mmp6", + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + { + TextView, + text = "R", + textColor=颜色7, + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + }, + { + SeekBar, + id = "seek_red", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + textColor=颜色7, + id = "mmp1", + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + { + TextView, + text = "G", + textColor=颜色7, + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + }, + { + SeekBar, + id = "seek_green", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp2", + textColor=颜色7, + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + { + TextView, + text = "B", + textColor=颜色7, + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + }, + { + SeekBar, + id = "seek_blue", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp3", + textColor=颜色7, + layout_width = "10%w", + layout_height = "50dp", + gravity = "center" + } + } + } + AlertDialog.Builder(this).setTitle(A0_658).setView(loadlayout(yuxuan)).setPositiveButton(getLS("L_Determine"), {onClick = A2_660}).setNeutralButton(getLS("L_The_default"), { + onClick = function(A0_664) + if A3_661 == "1" then + gxlua("BackgroundColor", "0xffffffff") + sxys() + elseif A3_661 == "2" then + gxlua("TextColor", "0xff333333") + sxys() + elseif A3_661 == "3" then + gxlua("KeywordColor", "0xff3f7fb5") + sxys() + elseif A3_661 == "4" then + gxlua("UserwordColor", "0xff6e81d9") + sxys() + elseif A3_661 == "5" then + gxlua("BasewordColor", "0xff6e81d9") + sxys() + elseif A3_661 == "6" then + gxlua("StringColor", bjzt()) + sxys() + elseif A3_661 == "7" then + gxlua("CommentColor", "0xffa0a0a0") + sxys() + elseif A3_661 == "8" then + gxlua("PanelBackgroundColor", "0xffFFFFFF") + sxys() + elseif A3_661 == "9" then + gxlua("PanelTextColor", bjzt()) + sxys() + elseif A3_661 == "10" then + array = activity.getTheme().obtainStyledAttributes({ + android.R.attr.colorBackground, + android.R.attr.textColorPrimary, + android.R.attr.colorPrimary, + android.R.attr.colorPrimaryDark, + android.R.attr.colorAccent + }) + colorBackground = array.getColor(0, 16711935) + textColorPrimary = array.getColor(1, 16711935) + colorPrimary = array.getColor(2, 16711935) + colorPrimaryDark = array.getColor(3, 16711935) + colorAccent = array.getColor(4, 16711935) + bjzt2 = tostring("0x" .. tostring(string.upper(Integer.toHexString(colorPrimary)))) + io.open(activity.getLuaDir() .. "/res/set205.LY", "w"):write(bjzt2):close() + sxys() + end + end + + }).setNegativeButton(getLS("L_Cancel"), nil).show() + mmp4.setText(A1_659) + seek_Ap.setMax(255) + seek_Ap.setProgress(255) + seek_red.setMax(255) + seek_red.setProgress(1) + seek_green.setMax(255) + seek_green.setProgress(1) + seek_blue.setMax(255) + seek_blue.setProgress(1) + seek_red.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4294901760, PorterDuff.Mode.SRC_ATOP)) + seek_red.Thumb.setColorFilter(PorterDuffColorFilter(4294901760, PorterDuff.Mode.SRC_ATOP)) + seek_green.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4278255360, PorterDuff.Mode.SRC_ATOP)) + seek_green.Thumb.setColorFilter(PorterDuffColorFilter(4278255360, PorterDuff.Mode.SRC_ATOP)) + seek_blue.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4278190335, PorterDuff.Mode.SRC_ATOP)) + seek_blue.Thumb.setColorFilter(PorterDuffColorFilter(4278190335, PorterDuff.Mode.SRC_ATOP)) + import("android.graphics.drawable.GradientDrawable") + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(tointeger(A1_659)) + drawable.setCornerRadii({ + 360, + 360, + 360, + 360, + 360, + 360, + 360, + 360 + }) + mmp5.setBackgroundDrawable(drawable) + seek_Ap.setOnSeekBarChangeListener({ + onProgressChanged = function(A0_665, A1_666) + A1_666 = A1_666 + 1 + e = Integer.toHexString(A1_666 - 1) + e = string.upper(e) + if #e == 1 then + e = "0" .. e + mmp6.setText(e) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp6.setText(e) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_red.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_667, L1_668 + end + , + onStopTrackingTouch = function() + local L0_669, L1_670 + end + , + onProgressChanged = function(A0_671, A1_672) + A1_672 = A1_672 + 1 + a = Integer.toHexString(A1_672 - 1) + a = string.upper(a) + if #a == 1 then + a = "0" .. a + mmp1.setText(a) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp1.setText(a) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_green.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_673, L1_674 + end + , + onStopTrackingTouch = function() + local L0_675, L1_676 + end + , + onProgressChanged = function(A0_677, A1_678) + A1_678 = A1_678 + 1 + A0_658 = Integer.toHexString(A1_678 - 1) + A0_658 = string.upper(A0_658) + if #A0_658 == 1 then + A0_658 = "0" .. A0_658 + mmp2.setText(A0_658) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp2.setText(A0_658) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_blue.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_679, L1_680 + end + , + onStopTrackingTouch = function() + local L0_681, L1_682 + end + , + onProgressChanged = function(A0_683, A1_684) + A1_684 = A1_684 + 1 + c = Integer.toHexString(A1_684 - 1) + c = string.upper(c) + if #c == 1 then + c = "0" .. c + mmp3.setText(c) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp3.setText(c) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + ak = string.sub(A1_659, 3, 4) + seek_Ap.setProgress(tonumber(ak, 16)) + a2 = string.sub(A1_659, 5, 6) + seek_red.setProgress(tonumber(a2, 16)) + a3 = string.sub(A1_659, 7, 8) + seek_green.setProgress(tonumber(a3, 16)) + a4 = string.sub(A1_659, 9, 10) + seek_blue.setProgress(tonumber(a4, 16)) +end + +yss = L0_656 +function L0_656() + gxlua("BackgroundColor", mmp4.Text) + sxys() +end + +sj = L0_656 +function L0_656() + gxlua("TextColor", mmp4.Text) + sxys() +end + +sj1 = L0_656 +function L0_656() + gxlua("KeywordColor", mmp4.Text) + sxys() +end + +sj2 = L0_656 +function L0_656() + gxlua("UserwordColor", mmp4.Text) + sxys() +end + +sj3 = L0_656 +function L0_656() + gxlua("BasewordColor", mmp4.Text) + sxys() +end + +sj4 = L0_656 +function L0_656() + gxlua("StringColor", mmp4.Text) + sxys() +end + +sj5 = L0_656 +function L0_656() + gxlua("CommentColor", mmp4.Text) + sxys() +end + +sj6 = L0_656 +function L0_656() + gxlua("PanelBackgroundColor", mmp4.Text) + sxys() +end + +sj7 = L0_656 +function L0_656() + gxlua("PanelTextColor", mmp4.Text) + sxys() +end + +sj8 = L0_656 +function L0_656() + io.open(activity.getLuaDir() .. "/res/set205.LY", "w"):write(mmp4.Text):close() + sxys() +end + +sj10 = L0_656 \ No newline at end of file diff --git a/app/src/main/assets/color1.lua b/app/src/main/assets/color1.lua new file mode 100644 index 0000000..84059cf --- /dev/null +++ b/app/src/main/assets/color1.lua @@ -0,0 +1,875 @@ +import "android.app.AlertDialog" +import "android.view.Gravity" +import "android.view.WindowManager" +import "java.lang.Integer" +import "android.graphics.drawable.GradientDrawable" +import "android.graphics.drawable.RippleDrawable" +import "android.content.res.ColorStateList" +import "android.graphics.drawable.StateListDrawable" +import "ThomeLua" +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色6=0xffffffff + 颜色5=0xff212121 + 颜色7=0xEBFFFFFF + 颜色8=0xFF000000 + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色1=0xFFFFFFFF + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色6=0xff757575 + 颜色5=0x5FFFFFFF + 颜色7=0xff303030 + 颜色8=0xFF000000 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end +function yss1(A0_687,A1_688,按钮,位数) + import("android.graphics.PorterDuff") + import("android.graphics.PorterDuffColorFilter") + function CircleButton(A0_689, A1_690) + import("android.graphics.drawable.GradientDrawable") + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(A1_690) + drawable.setCornerRadii({ + 360, + 360, + 360, + 360, + 360, + 360, + 360, + 360 + }) + A0_689.setBackgroundDrawable(drawable) + end + + import "android.graphics.drawable.ColorDrawable" + import "android.widget.*"; + + yuxuan = + + { + LinearLayout, + orientation = "vertical", + layout_height = "fill", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + id="圆不溜秋", + { + TextView; + layout_gravity="center"; + layout_marginTop = "10dp", + text="调色板"; + textColor=颜色7; + textSize="20sp"; + }; + { + CardView, + layout_height = "100dp", + layout_width = "100dp", + layout_marginTop = "20dp", + id = "mmp5", + --backgroundColor=颜色1; + }, + + { + TextView, + text = "", + id = "mmp4", + layout_marginLeft = "10dp", + layout_marginRight = "10dp", + layout_width = "match_parent", + layout_height = "50dp", + gravity = "center", + textColor=颜色7, + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + TextView, + text = "A", + layout_width = "10%w", + layout_height = "50dp", + gravity = "center", + textColor=颜色7, + }, + { + SeekBar, + id = "seek_Ap", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "FF", + id = "mmp6", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + TextView, + text = "R", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + { + SeekBar, + id = "seek_red", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp1", + layout_width = "10%w", + textColor=颜色7, + layout_height = "50dp", + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + TextView, + text = "G", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + { + SeekBar, + id = "seek_green", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp2", + layout_width = "10%w", + textColor=颜色7, + layout_height = "50dp", + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + TextView, + text = "B", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + { + SeekBar, + id = "seek_blue", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp3", + layout_width = "10%w", + textColor=颜色7, + layout_height = "50dp", + gravity = "center" + }; + }; + { + LinearLayout; + layout_width="fill"; + gravity="right"; + layout_height="90dp"; + backgroundColor=颜色1; + { + Button; + id="关闭调色板"; + textColor="0xFF383A3D", + --backgroundColor=颜色1; + text="取消"; + layout_marginRight="10dp", + layout_height="40dp", + }; + { + Button; + textColor="0xFF03A9F4", + id="复制"; + text=按钮; + layout_height="40dp", + --backgroundColor=颜色1; + layout_marginRight="5dp"; + }; + }; + }; + + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(yuxuan)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + + + + --颜色1=0x5FFFFFFF + import "android.graphics.Typeface" + local Text_Type=Typeface.defaultFromStyle(Typeface.BOLD) + local sd = StateListDrawable() + import "android.graphics.Color" + import "android.content.res.ColorStateList" + import "android.graphics.drawable.RippleDrawable" + import "android.content.Context" + appt={C_Bacgg=function(mBinding,radiu,InsideColor,S,S2,T1) + local drawable = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{}); + drawable.setCornerRadius(radiu); + drawable.setColor(颜色5) + drawable.setStroke(3,0xCFB0B0B0) + drawable.setGradientType(GradientDrawable.RECTANGLE); + mBinding.setTextColor(T1) + mBinding.setTypeface(Text_Type) + return drawable + end} + 美化按钮2=function(mBinding,radiu,InsideColor,T1) + stateList = { + {android.R.attr.state_pressed}, + {android.R.attr.state_focused}, + {android.R.attr.state_activated}, + {android.R.attr.selectableItemBackground}, + }; + sd.addState({ android.R.attr.state_enabled}, appt.C_Bacgg(mBinding,radiu,InsideColor,S,S2,T1)) + pressedColor =InsideColor --Color.parseColor("#7ab946ff"); + stateColorList ={ + pressedColor, + pressedColor, + pressedColor, + normalColor + }; + colorStateList = ColorStateList(stateList, stateColorList); + rippleDrawable = RippleDrawable(colorStateList,sd,nil); + mBinding.setBackground(rippleDrawable); + end + + + -- }).setNegativeButton(("取消"), nil).show() + 美化按钮2(关闭调色板,10,0x7E000000,颜色7) + 美化按钮2(复制,10,0x7a00bfff,0xFF03A9F4) + 复制.onClick=function() + switch 复制.Text + case "复制" + import("android.content.*") + a = mmp4.getText() + activity.getSystemService(Context.CLIPBOARD_SERVICE).setText(a) + print("颜色已复制") + dialog1.dismiss() +default +a=mmp4.getText() +switch 位数 +case 1 +io.open(activity.getLuaDir().."/Verify/set5.XY","w"):write(a):close() +q.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 2 +io.open(activity.getLuaDir().."/Verify/set6.XY","w"):write(a):close() +qq.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 3 +io.open(activity.getLuaDir().."/Verify/set7.XY","w"):write(a):close() +qqq.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 4 +io.open(activity.getLuaDir().."/Verify/set8.XY","w"):write(a):close() +qqqq.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 5 +io.open(activity.getLuaDir().."/Verify/set9.XY","w"):write(a):close() +qqqqq.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 6 +io.open(activity.getLuaDir().."/Verify/set10.XY","w"):write(a):close() +qqqqqq.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 7 +io.open(activity.getLuaDir().."/Verify/set11.XY","w"):write(a):close() +qqqqqqq.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 8 +io.open(activity.getLuaDir().."/Verify/set12.XY","w"):write(a):close() +qqqqqqqq.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 33 +io.open(activity.getLuaDir().."/Verify/setb.XY","w"):write(a):close() +b.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +case 333 +io.open(activity.getLuaDir().."/Verify/setbb.XY","w"):write(a):close() +bb.backgroundColor=tonumber(a) +print("颜色已更换") +dialog1.dismiss() +end +end +end + + + 关闭调色板.onClick=function() + dialog1.dismiss() + end + + 控件圆角(圆不溜秋,颜色1,30) + + mmp4.setText(A1_688) + seek_Ap.setMax(255) + seek_Ap.setProgress(255) + seek_red.setMax(255) + seek_red.setProgress(1) + seek_green.setMax(255) + seek_green.setProgress(1) + seek_blue.setMax(255) + seek_blue.setProgress(1) + seek_red.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4294901760, PorterDuff.Mode.SRC_ATOP)) + seek_red.Thumb.setColorFilter(PorterDuffColorFilter(4294901760, PorterDuff.Mode.SRC_ATOP)) + seek_green.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4278255360, PorterDuff.Mode.SRC_ATOP)) + seek_green.Thumb.setColorFilter(PorterDuffColorFilter(4278255360, PorterDuff.Mode.SRC_ATOP)) + seek_blue.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4278190335, PorterDuff.Mode.SRC_ATOP)) + seek_blue.Thumb.setColorFilter(PorterDuffColorFilter(4278190335, PorterDuff.Mode.SRC_ATOP)) + import("android.graphics.drawable.GradientDrawable") + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(tointeger(A1_688)) + drawable.setCornerRadii({ + 360, + 360, + 360, + 360, + 360, + 360, + 360, + 360 + }) + mmp5.setBackgroundDrawable(drawable) + function CircleButto(A0_689, A1_690) + import("android.graphics.drawable.GradientDrawable") + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(0x5FFFFFFF) + drawable.setCornerRadii({ + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30 + }) + 圆不溜秋.setBackgroundDrawable(drawable) + end + --CircleButto() + + seek_Ap.setOnSeekBarChangeListener({ + onProgressChanged = function(A0_696, A1_697) + A1_697 = A1_697 + 1 + e = Integer.toHexString(A1_697 - 1) + e = string.upper(e) + if #e == 1 then + e = "0" .. e + mmp6.setText(e) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp6.setText(e) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_red.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_698, L1_699 + end + , + onStopTrackingTouch = function() + local L0_700, L1_701 + end + , + onProgressChanged = function(A0_702, A1_703) + A1_703 = A1_703 + 1 + a = Integer.toHexString(A1_703 - 1) + a = string.upper(a) + if #a == 1 then + a = "0" .. a + mmp1.setText(a) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp1.setText(a) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_green.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_704, L1_705 + end + , + onStopTrackingTouch = function() + local L0_706, L1_707 + end + , + onProgressChanged = function(A0_708, A1_709) + A1_709 = A1_709 + 1 + A0_687 = Integer.toHexString(A1_709 - 1) + A0_687 = string.upper(A0_687) + if #A0_687 == 1 then + A0_687 = "0" .. A0_687 + mmp2.setText(A0_687) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp2.setText(A0_687) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_blue.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_710, L1_711 + end + , + onStopTrackingTouch = function() + local L0_712, L1_713 + end + , + onProgressChanged = function(A0_714, A1_715) + A1_715 = A1_715 + 1 + c = Integer.toHexString(A1_715 - 1) + c = string.upper(c) + if #c == 1 then + c = "0" .. c + mmp3.setText(c) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp3.setText(c) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + ak = string.sub(A1_688, 3, 4) + seek_Ap.setProgress(tonumber(ak, 16)) + a2 = string.sub(A1_688, 5, 6) + seek_red.setProgress(tonumber(a2, 16)) + a3 = string.sub(A1_688, 7, 8) + seek_green.setProgress(tonumber(a3, 16)) + a4 = string.sub(A1_688, 9, 10) + seek_blue.setProgress(tonumber(a4, 16)) +end + +function yss(A0_716, A1_717, A2_718) + import("android.graphics.PorterDuff") + import("android.graphics.PorterDuffColorFilter") + function CircleButton(A0_719, A1_720) + import("android.graphics.drawable.GradientDrawable") + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(A1_720) + drawable.setCornerRadii({ + 360, + 360, + 360, + 360, + 360, + 360, + 360, + 360 + }) + A0_719.setBackgroundDrawable(drawable) + end + + yuxuan = { + LinearLayout, + orientation = "vertical", + layout_height = "fill", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + CardView, + layout_height = "100dp", + layout_width = "100dp", + layout_marginTop = "20dp", + backgroundColor=颜色1; + id = "mmp5" + }, + { + TextView, + text = "", + id = "mmp4", + layout_marginLeft = "10dp", + layout_marginRight = "10dp", + layout_width = "match_parent", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + textColor=颜色7, + { + TextView, + text = "A", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + { + SeekBar, + id = "seek_Ap", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "FF", + id = "mmp6", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + TextView, + text = "R", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + { + SeekBar, + id = "seek_red", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp1", + layout_width = "10%w", + textColor=颜色7, + layout_height = "50dp", + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "50dp", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + TextView, + text = "G", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + { + SeekBar, + id = "seek_green", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp2", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + } + }, + { + LinearLayout, + orientation = "horizontal", + layout_height = "fill", + layout_width = "fill", + gravity = "center", + backgroundColor=颜色1; + { + TextView, + text = "B", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + }, + { + SeekBar, + id = "seek_blue", + layout_width = "65%w", + layout_height = "50dp" + }, + { + TextView, + text = "00", + id = "mmp3", + layout_width = "10%w", + layout_height = "50dp", + textColor=颜色7, + gravity = "center" + } + } + } + AlertDialog.Builder(this).setTitle(A0_716).setView(loadlayout(yuxuan)).setPositiveButton(getLS("L_Determine"), { + onClick = function(A0_721) + if A2_718 == true then + LuaEditor.paste("#" .. string.sub(mmp4.getText(), 5, -1)) + else + LuaEditor.paste(mmp4.getText()) + end + end + + }).setNegativeButton(getLS("L_Cancel"), nil).show() + mmp4.setText(A1_717) + seek_Ap.setMax(255) + seek_Ap.setProgress(255) + seek_red.setMax(255) + seek_red.setProgress(1) + seek_green.setMax(255) + seek_green.setProgress(1) + seek_blue.setMax(255) + seek_blue.setProgress(1) + seek_red.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4294901760, PorterDuff.Mode.SRC_ATOP)) + seek_red.Thumb.setColorFilter(PorterDuffColorFilter(4294901760, PorterDuff.Mode.SRC_ATOP)) + seek_green.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4278255360, PorterDuff.Mode.SRC_ATOP)) + seek_green.Thumb.setColorFilter(PorterDuffColorFilter(4278255360, PorterDuff.Mode.SRC_ATOP)) + seek_blue.ProgressDrawable.setColorFilter(PorterDuffColorFilter(4278190335, PorterDuff.Mode.SRC_ATOP)) + seek_blue.Thumb.setColorFilter(PorterDuffColorFilter(4278190335, PorterDuff.Mode.SRC_ATOP)) + import("android.graphics.drawable.GradientDrawable") + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(tointeger(A1_717)) + drawable.setCornerRadii({ + 360, + 360, + 360, + 360, + 360, + 360, + 360, + 360 + }) + mmp5.setBackgroundDrawable(drawable) + seek_Ap.setOnSeekBarChangeListener({ + onProgressChanged = function(A0_722, A1_723) + A1_723 = A1_723 + 1 + e = Integer.toHexString(A1_723 - 1) + e = string.upper(e) + if #e == 1 then + e = "0" .. e + mmp6.setText(e) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp6.setText(e) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_red.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_724, L1_725 + end + , + onStopTrackingTouch = function() + local L0_726, L1_727 + end + , + onProgressChanged = function(A0_728, A1_729) + A1_729 = A1_729 + 1 + a = Integer.toHexString(A1_729 - 1) + a = string.upper(a) + if #a == 1 then + a = "0" .. a + mmp1.setText(a) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp1.setText(a) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_green.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_730, L1_731 + end + , + onStopTrackingTouch = function() + local L0_732, L1_733 + end + , + onProgressChanged = function(A0_734, A1_735) + A1_735 = A1_735 + 1 + A0_716 = Integer.toHexString(A1_735 - 1) + A0_716 = string.upper(A0_716) + if #A0_716 == 1 then + A0_716 = "0" .. A0_716 + mmp2.setText(A0_716) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp2.setText(A0_716) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + seek_blue.setOnSeekBarChangeListener({ + onStartTrackingTouch = function() + local L0_736, L1_737 + end + , + onStopTrackingTouch = function() + local L0_738, L1_739 + end + , + onProgressChanged = function(A0_740, A1_741) + A1_741 = A1_741 + 1 + c = Integer.toHexString(A1_741 - 1) + c = string.upper(c) + if #c == 1 then + c = "0" .. c + mmp3.setText(c) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + else + mmp3.setText(c) + d = mmp6.getText() .. mmp1.getText() .. mmp2.getText() .. mmp3.getText() + mmp4.setText("0x" .. d) + ys = int("0x" .. d) + CircleButton(mmp5, ys) + end + end + + }) + ak = string.sub(A1_717, 3, 4) + seek_Ap.setProgress(tonumber(ak, 16)) + a2 = string.sub(A1_717, 5, 6) + seek_red.setProgress(tonumber(a2, 16)) + a3 = string.sub(A1_717, 7, 8) + seek_green.setProgress(tonumber(a3, 16)) + a4 = string.sub(A1_717, 9, 10) + seek_blue.setProgress(tonumber(a4, 16)) +end \ No newline at end of file diff --git a/app/src/main/assets/dj.lua b/app/src/main/assets/dj.lua new file mode 100644 index 0000000..e6a67a4 --- /dev/null +++ b/app/src/main/assets/dj.lua @@ -0,0 +1,89 @@ +function 其他.onClick() + pop=PopupMenu(activity,其他) + menu=pop.Menu + menu.add("创建工程").onMenuItemClick=function(a) + 创建工程() + end + menu.add("导入工程").onMenuItemClick=function(a) + activity.newActivity("file",android.R.anim.fade_in,android.R.anim.fade_out,{"选择源码(*.alp)",Environment.getExternalStorageDirectory().toString(),{".alp"}}) + function onResult(name,arg) + if name=="file" then + sx.setRefreshing(true); + task(10,function() + sx.setRefreshing(false); + 刷新项目() + print("导入成功") + end) + else + end + end + end + + pop.show() +end +--[[项目列表.onItemClick=function(l,v,p,i) + activity.newActivity("main2",android.R.anim.fade_in,android.R.anim.fade_out,{项目文件夹.."/"..v.tag.软件名.text,true,v.tag.软件名.text,"/storage/emulated/0/ThomeLua+/project/"..v.tag.软件名.text}) + return true +end]] + +import "android.view.animation.Animation$AnimationListener" +import "android.view.animation.ScaleAnimation" +import "android.view.animation.ScaleAnimation" +function CircleButton (InsideColor,radiu,...) + import "android.graphics.drawable.GradientDrawable" + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(InsideColor) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + for k,v in ipairs({...}) do + v.setBackgroundDrawable(drawable) + end +end +CircleButton(0xff20d0d0,100,bt,bt1,bt2) +bt.onClick=function(v) + if bt1.getVisibility()==0 then + bt2.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(100)) + bt2.setVisibility(View.INVISIBLE) + bt1.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(200)) + bt1.setVisibility(View.INVISIBLE) + bt.text="+" + + else + bt1.setVisibility(View.VISIBLE) + bt2.setVisibility(View.VISIBLE) + bt1.startAnimation(ScaleAnimation(0.0, 1.0, 0.0, 1.0,1, 0.5, 1, 0.5).setDuration(100)) + bt2.startAnimation(ScaleAnimation(0.0, 1.0, 0.0, 1.0,1, 0.5, 1, 0.5).setDuration(200)) + bt.text="-" + bt1.Text="导入" + bt2.Text="新建" + end +end +bt1.onClick=function(v) + bt1.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(100)) + bt1.setVisibility(View.INVISIBLE) + bt2.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(200)) + bt2.setVisibility(View.INVISIBLE) + bt.text="+" + activity.newActivity("file",android.R.anim.fade_in,android.R.anim.fade_out,{"选择源码(*.alp)",Environment.getExternalStorageDirectory().toString(),{".alp"}}) + function onResult(name,arg) + if name=="file" then + sx.setRefreshing(true); + task(10,function() + sx.setRefreshing(false); + 刷新项目() + print("导入成功") + end) + else + end + end +end +bt2.onClick=function(v) + bt1.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(100)) + bt1.setVisibility(View.INVISIBLE) + bt2.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(200)) + bt2.setVisibility(View.INVISIBLE) + bt.text="+" + 创建工程() +end + + diff --git a/app/src/main/assets/file.lua b/app/src/main/assets/file.lua new file mode 100644 index 0000000..a48475d --- /dev/null +++ b/app/src/main/assets/file.lua @@ -0,0 +1,608 @@ +require "import" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "android.app.*" +import "android.graphics.Typeface" +import "android.content.Intent" +import "android.content.Context" +import "android.content.pm.PackageManager" +import "android.graphics.drawable.ColorDrawable" +import "android.content.Intent" +import "java.io.File" +import "other" +import "Dialog" +import "toast" +import "main6" +import "com.androlua.LuaAdapter" +import "android.graphics.drawable.StateListDrawable" +import "android.graphics.drawable.GradientDrawable" +import "com.androlua.LuaUtil" + +title,StartPath,filterTypes=... +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色5=0xff303030 + 颜色6=0xEBFFFFFF + 颜色7=0xFF03A9F4 + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色1=0x5FFFFFFF + 颜色3=0xff303030 + 颜色4=0xffffffff + 颜色5=0x5FFFFFFF + 颜色2=0xFFF2F1F6 + 颜色6=0xff303030 + 颜色7=0xFF03A9F4 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end +item={ + LinearLayout; + layout_height="fill"; + layout_width="fill"; + { + LinearLayout; + layout_width="match_parent"; + layout_height="70dp"; + gravity="center"; + { + CardView; + radius=25; + layout_height="50dp"; + layout_width="340dp"; + CardElevation="0dp"; + backgroundColor=颜色1; + { + LinearLayout; + orientation="horizontal"; + layout_width="match_parent"; + layout_height="match_parent"; + { + ImageView; + src="file.png"; + ColorFilter=颜色6, + layout_marginLeft="10dp"; + layout_gravity="center"; + id="img"; + }; + { + TextView; + layout_height="20dp"; + id="file"; + textColor=颜色6; + layout_marginLeft="10dp"; + layout_width="250dp"; + layout_gravity="center"; + }; + }; + }; + }; +}; +layout={ + LinearLayout; + backgroundColor=颜色2, + layout_height="fill"; + orientation="vertical"; + layout_width="fill"; + { + LinearLayout; + backgroundColor=颜色1; + layout_height="106dp"; + orientation="vertical"; + layout_width="match_parent"; + { + TextView; + layout_marginTop="5dp"; + text="选择源码(*.alp)"; + layout_marginLeft="10dp"; + textSize="16sp"; + textColor="0xFF03A9F4"; + }; + { + TextView; + layout_marginTop="5dp"; + layout_marginLeft="10dp"; + singleLine=true; + textColor="0xFF03A9F4"; + text="路径"; + focusable=true; + ellipsize="marquee"; + layout_width="300dp"; + focusableInTouchMode=true; + id="cp"; + }; + { + LinearLayout; + layout_height="fill"; + orientation="horizontal"; + layout_width="fill"; + gravity="center", + { + Button, + layout_marginRight="2dp", + text="ThomeLua", + AllCaps=false, + id="XX", + }, + { + Button, + layout_marginRight="2dp", + text="系统下载", + id="系统", + }, + { + Button, + layout_marginRight="2dp", + text="内部存储", + textColor=颜色3, + id="内部", + }, + }, + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + { + ListView; + id="lv", + layout_height="match_parent"; + DividerHeight=0;--设置无隔断线 + layout_width="match_parent"; + }; + }; +}; +activity.setContentView(layout) +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +--导入类 +local context=activity or service + +local LuaBitmap=luajava.bindClass "com.androlua.LuaBitmap" +local function loadbitmap(path) + if not path:find("^https*://") and not path:find("%.%a%a%a%a?$") then + path=path..".png" + end + if path:find("^https*://") then + return LuaBitmap.getHttpBitmap(context,path) + elseif not path:find("^/") then + return LuaBitmap.getLocalBitmap(context,string.format("%s/%s",luajava.luadir,path)) + else + return LuaBitmap.getLocalBitmap(context,path) + end +end +import "android.graphics.Typeface" +local Text_Type=Typeface.defaultFromStyle(Typeface.BOLD) +local sd = StateListDrawable() +import "android.graphics.Color" +import "android.content.res.ColorStateList" +import "android.graphics.drawable.RippleDrawable" +import "android.content.Context" +appt={C_Bacgg=function(mBinding,radiu,InsideColor,S,S2,T1) + local drawable = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{}); + drawable.setCornerRadius(radiu); + drawable.setColor(颜色5) + drawable.setStroke(3, 0xCFB0B0B0) + drawable.setGradientType(GradientDrawable.RECTANGLE); + mBinding.setTextColor(T1) + mBinding.setTypeface(Text_Type) + return drawable + end} +美化按钮1=function(mBinding,radiu,InsideColor,T1) + stateList = { + {android.R.attr.state_pressed}, + {android.R.attr.state_focused}, + {android.R.attr.state_activated}, + {android.R.attr.selectableItemBackground}, + }; + sd.addState({ android.R.attr.state_enabled}, appt.C_Bacgg(mBinding,radiu,InsideColor,S,S2,T1)) + pressedColor =InsideColor --Color.parseColor("#7ab946ff"); + stateColorList ={ + pressedColor, + pressedColor, + pressedColor, + normalColor + }; + colorStateList = ColorStateList(stateList, stateColorList); + rippleDrawable = RippleDrawable(colorStateList,sd,nil); + mBinding.setBackground(rippleDrawable); +end +--美化按钮1(QQ,10,0x7a00bfff,0x7a00bfff) +美化按钮1(XX,10,0x7E000000,颜色6) +美化按钮1(系统,10,0x7E000000,颜色6) +美化按钮1(内部,10,0x7E000000,颜色6) +function getExtension(str) + return str:match(".+%.(%w+)$") +end +import "android.widget.ArrayAdapter" +import "android.widget.LinearLayout" +import "android.widget.TextView" +import "java.io.File" +import "android.widget.ListView" +import "android.app.AlertDialog" +data={} +adp=LuaAdapter(activity,data,item) +lv.setAdapter(adp) +function attrdir(path) + for file in lfs.dir(path) do + if file ~= "." and file ~= ".." then + local f = path.."/"..file + local attr = lfs.attributes(f) + switch attr.mode + case "directory" + adp.add{file=file,img="folder.png"} + default + task(1,function() + adp.add{file=file,img="file.png"} + end) + end + end + end +end +attrdir("/sdcard") +cp.Text="/sdcard" +require "import" +import "android.widget.*" +import "android.view.*" +import "android.content.*" +import "android.net.*" +import "android.provider.*" +import "java.io.File" +--[[import "android.support.v4.provider.*" +import "android.net.Uri" +import "android.provider.DocumentsContract" +local data={} + +data.requestPermission=function() + local parse = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata"); + + local intent = Intent("android.intent.action.OPEN_DOCUMENT_TREE"); + + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION + | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION + | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); + + + intent.putExtra("android.provider.extra.INITIAL_URI",DocumentsContract.buildDocumentUriUsingTree(parse, DocumentsContract.getTreeDocumentId(parse))); + + activity.startActivityForResult(intent, 11); + +end + + +data.savePermission=function(requestCode, resultCode, data) + if (data == nil) then + return; + end + local uri = data.getData() + local uri1 = "^content://com.android.externalstorage.documents/tree/.+%%3AAndroid%%2Fdata%%?2?F?$" + if (tostring(uri):find(uri1) && requestCode == 11 && uri ~= nil) then + activity.getContentResolver().takePersistableUriPermission(uri, data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION));--关键是这里,这个就是保存这个目录的访问权限 + return true + else + return false + end +end + + +data.getSingleDoucmentFile=function(path) + local path=String(path) + if path.endsWith("/") then + path = path.substring(0, path.length() - 1); + end + local path2 = path.replace("/storage/emulated/0/", ""):gsub("/sdcard/",""):gsub("/", "%%2F"); + return DocumentFile.fromSingleUri(activity, Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata/document/primary%3A" .. path2)); + +end + +data.getDoucmentFile=function(path) + local path=path:gsub("/sdcard/Android/data",""):gsub("/storage/emulated/0/Android/data", "") + if path:sub(1,1)=="/" then + path=utf8.sub(path,2,utf8.len(path)) + end + local pathTab=luajava.astable(String(path).split("/")) + + local doucmentfile=DocumentFile.fromTreeUri(activity, Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata")); + if utf8.len(path)==0 then + return doucmentfile + end + + for i=1,#pathTab do + local doucmentfile2=doucmentfile.findFile(pathTab[i]) + + if doucmentfile2==nil then + if pathTab[i]:find("%.(.+)") then + -- doucmentfile2=doucmentfile.createFile("*/*",pathTab[i]) + else + -- doucmentfile2=doucmentfile.createDirectory(pathTab[i]) + end + end + + doucmentfile=doucmentfile2 + + end + return doucmentfile +end + +data.getFileLastModified=function(path) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + + return data.getDoucmentFile(parentPath).findFile(name).lastModified() +end + + +data.getFileLastModified=function(path) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + + return data.getDoucmentFile(parentPath).findFile(name).lastModified() +end + + +data.getFileList=function(path) + local list=luajava.astable(data.getDoucmentFile(path).listFiles()) + local s=utf8.sub(path,-1) + + table.foreach(list,function(k,v) + list[k]=path..(s=="/" and "" or "/")..v.name + end) + return list +end + +data.exists=function(path) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + + return data.getDoucmentFile(parentPath).findFile(name).exists() + +end + +data.isDirectory=function(path) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + return data.getDoucmentFile(parentPath).findFile(name).isDirectory() + +end + + +data.isFile=function(path) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + return data.getDoucmentFile(parentPath).findFile(name).isFile() +end + + +data.createFile=function(path) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + return data.getDoucmentFile(parentPath).createFile("*/*",name) +end + +data.isGrant=function() + for k,uriPermission in pairs(luajava.astable(activity.getContentResolver().getPersistedUriPermissions())) do + if (uriPermission.isReadPermission() && uriPermission.getUri().toString():find("content://com.android.externalstorage.documents/tree/primary%%3AAndroid%%2Fdata")) then + return true; + end + end + return false; +end + + +data.createDirectory=function(path) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + return data.getDoucmentFile(parentPath).createDirectory(name) +end + +data.renameTo=function(path,nameTo) + local file=File(path) + local parentPath=file.parentFile.path + local name=file.name + return data.getDoucmentFile(parentPath).findFile(name).renameTo(File(nameTo).name) +end + +data.getFileLength=function(path) + local singleDoucmentFile=data.getSingleDoucmentFile(path) + return singleDoucmentFile.length() +end + +data.deleteFile=function(path) + local singleDoucmentFile=data.getSingleDoucmentFile(path) + return singleDoucmentFile.delete() +end + +data.getFileOutputStream=function(path) + local singleDoucmentFile=data.getSingleDoucmentFile(path) + return activity.getContentResolver().openOutputStream(singleDoucmentFile.uri) +end + +data.getFileInputStream=function(path) + local singleDoucmentFile=data.getSingleDoucmentFile(path) + return activity.getContentResolver().openInputStream(singleDoucmentFile.uri) +end +function QQ.onClick() + if not data.isGrant() then + data.requestPermission() + else + adp.clear() + ls=data.getFileList("/sdcard/Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/") + for index,c in ipairs(ls) do + adp.add{file=c:match("/sdcard/Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/(.+)"),img="file.png"} + end + lv.onItemClick=function(l,v,p,s) + io.open("/sdcard/ThomeLua/dq.alp","w"):write(tostring(String(LuaUtil.readAll(data.getFileInputStream("/sdcard/Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/"..v.tag.file.text))))):close() + end + end + + function onActivityResult(a,b,c) + if a==11 + if not data.savePermission(a,b,c) then + print("获取权限失败") + --activity.finish() + else + adp.clear() + ls=data.getFileList("/sdcard/Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/") + for index,c in ipairs(ls) do + adp.add{file=c:match("/sdcard/Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/(.+)"),img="file.png"} + end + lv.onItemClick=function(l,v,p,s) + print(tostring(String(LuaUtil.readAll( + data.getFileInputStream(path))))) + end + end + end + end +end]] +function XX.onClick() + adp.clear() + attrdir("/sdcard/ThomeLua") + cp.Text="/sdcard/ThomeLua" +end +function 系统.onClick() + adp.clear() + attrdir("/sdcard/Download") + cp.Text="/sdcard/Download" +end +function 内部.onClick() + adp.clear() + attrdir("/sdcard") + cp.Text="/sdcard" +end +lv.onItemClick=function(l,v,p,s) + local 路径=tostring(cp.Text) + local 文件名=tostring(v.tag.file.Text) + switch 文件名 + case "返回上级目录" + adp.clear() + local up=tostring(File(cp.Text).getParentFile()) + switch up + case "/sdcard" + attrdir(up) + cp.Text=up + default + adp.add{file="返回上级目录",img="folder.png"} + attrdir(up) + cp.Text=up + end + default + switch lfs.attributes(路径.."/"..文件名)["mode"] + case "directory" + adp.clear() + adp.add{file="返回上级目录",img="folder.png"} + attrdir(路径.."/"..文件名) + cp.Text=路径.."/"..文件名 + default + switch getExtension(tostring(路径.."/"..文件名)) + case "alp" + + local sc={ + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="280dp"; + layout_width="match_parent"; + backgroundColor=颜色2, + radius=20; + { + TextView; + layout_marginLeft="25dp"; + layout_marginTop="10dp"; + textSize="20sp"; + textColor="0xFF03A9F4"; + text="提示"; + }; + { + TextView; + textSize="15sp"; + textColor=颜色6, + layout_marginLeft="25dp"; + text="是否导入此工程?"; + layout_marginTop="45dp"; + }; + { + LinearLayout; + layout_marginBottom="50dp"; + layout_gravity="bottom"; + layout_marginTop="20dp"; + layout_width="match_parent"; + layout_height="50dp"; + { + Button; + text="取消"; + layout_gravity="center"; + layout_marginLeft="20dp"; + id="取消导入工程"; + layout_height="40dp"; + }; + { + LinearLayout; + layout_width="match_parent"; + gravity="right"; + layout_height="match_parent"; + { + Button; + layout_marginRight="20dp"; + layout_gravity="center"; + text="导入"; + layout_height="40dp"; + id="确定导入工程"; + }; + }; + }; + }; + }; + + dialog2= AlertDialog.Builder(this) + dialog3=dialog2.show() + dialog3.getWindow().setContentView(loadlayout(sc)); + dialog3.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog3.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog3.getWindow().getAttributes().width=(activity.Width); + dialog3.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + 美化按钮1(取消导入工程,10,0x7E000000,颜色6) + 美化按钮1(确定导入工程,10,0x7a00bfff,颜色7) + function 取消导入工程.onClick() + dialog3.dismiss() + end + function 确定导入工程.onClick() + import "java.io.File" + local a=File(tostring(路径.."/"..文件名)).getName() + local b=a:match("(.-).alp") + local c=项目文件夹.."/"..a + local d=项目文件夹.."/"..b..".zip" + local e=项目文件夹.."/"..b + LuaUtil.copyDir(tostring(路径.."/"..文件名),c) + File(c).renameTo(File(d)) + LuaUtil.unZip(d,e) + os.remove(d) + dialog3.dismiss() + activity.result{true} + end + default + print"暂不支持导入此工程" + end + end + end +end \ No newline at end of file diff --git a/app/src/main/assets/file.png b/app/src/main/assets/file.png new file mode 100644 index 0000000..5c5a117 Binary files /dev/null and b/app/src/main/assets/file.png differ diff --git a/app/src/main/assets/folder.png b/app/src/main/assets/folder.png new file mode 100644 index 0000000..d52509b Binary files /dev/null and b/app/src/main/assets/folder.png differ diff --git a/app/src/main/assets/font/a.ttf b/app/src/main/assets/font/a.ttf new file mode 100644 index 0000000..99c0856 Binary files /dev/null and b/app/src/main/assets/font/a.ttf differ diff --git a/app/src/main/assets/font/b.ttf b/app/src/main/assets/font/b.ttf new file mode 100644 index 0000000..323cc27 Binary files /dev/null and b/app/src/main/assets/font/b.ttf differ diff --git a/app/src/main/assets/font/update b/app/src/main/assets/font/update new file mode 100644 index 0000000..f32a580 --- /dev/null +++ b/app/src/main/assets/font/update @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/app/src/main/assets/icon.png b/app/src/main/assets/icon.png new file mode 100644 index 0000000..9010bd7 Binary files /dev/null and b/app/src/main/assets/icon.png differ diff --git a/app/src/main/assets/image/a0.png b/app/src/main/assets/image/a0.png new file mode 100644 index 0000000..1ac6d7b Binary files /dev/null and b/app/src/main/assets/image/a0.png differ diff --git a/app/src/main/assets/image/a1.png b/app/src/main/assets/image/a1.png new file mode 100644 index 0000000..a20292d Binary files /dev/null and b/app/src/main/assets/image/a1.png differ diff --git a/app/src/main/assets/image/a10.png b/app/src/main/assets/image/a10.png new file mode 100644 index 0000000..2e921ff Binary files /dev/null and b/app/src/main/assets/image/a10.png differ diff --git a/app/src/main/assets/image/a11.png b/app/src/main/assets/image/a11.png new file mode 100644 index 0000000..ff671ed Binary files /dev/null and b/app/src/main/assets/image/a11.png differ diff --git a/app/src/main/assets/image/a2.png b/app/src/main/assets/image/a2.png new file mode 100644 index 0000000..78673a7 Binary files /dev/null and b/app/src/main/assets/image/a2.png differ diff --git a/app/src/main/assets/image/a3.png b/app/src/main/assets/image/a3.png new file mode 100644 index 0000000..39e6edf Binary files /dev/null and b/app/src/main/assets/image/a3.png differ diff --git a/app/src/main/assets/image/a4.png b/app/src/main/assets/image/a4.png new file mode 100644 index 0000000..82be56c Binary files /dev/null and b/app/src/main/assets/image/a4.png differ diff --git a/app/src/main/assets/image/a5.png b/app/src/main/assets/image/a5.png new file mode 100644 index 0000000..bf52e65 Binary files /dev/null and b/app/src/main/assets/image/a5.png differ diff --git a/app/src/main/assets/image/a6.png b/app/src/main/assets/image/a6.png new file mode 100644 index 0000000..7a49fad Binary files /dev/null and b/app/src/main/assets/image/a6.png differ diff --git a/app/src/main/assets/image/a7.png b/app/src/main/assets/image/a7.png new file mode 100644 index 0000000..daa92f3 Binary files /dev/null and b/app/src/main/assets/image/a7.png differ diff --git a/app/src/main/assets/image/a8.png b/app/src/main/assets/image/a8.png new file mode 100644 index 0000000..1449948 Binary files /dev/null and b/app/src/main/assets/image/a8.png differ diff --git a/app/src/main/assets/image/a9.png b/app/src/main/assets/image/a9.png new file mode 100644 index 0000000..6d09aa5 Binary files /dev/null and b/app/src/main/assets/image/a9.png differ diff --git a/app/src/main/assets/img/a1.png b/app/src/main/assets/img/a1.png new file mode 100644 index 0000000..ad666cc Binary files /dev/null and b/app/src/main/assets/img/a1.png differ diff --git a/app/src/main/assets/img/a2.png b/app/src/main/assets/img/a2.png new file mode 100644 index 0000000..3a11e48 Binary files /dev/null and b/app/src/main/assets/img/a2.png differ diff --git a/app/src/main/assets/img/a3.png b/app/src/main/assets/img/a3.png new file mode 100644 index 0000000..abed57d Binary files /dev/null and b/app/src/main/assets/img/a3.png differ diff --git a/app/src/main/assets/img/a4.png b/app/src/main/assets/img/a4.png new file mode 100644 index 0000000..34dbe7c Binary files /dev/null and b/app/src/main/assets/img/a4.png differ diff --git a/app/src/main/assets/img/a5.png b/app/src/main/assets/img/a5.png new file mode 100644 index 0000000..7ae4c4c Binary files /dev/null and b/app/src/main/assets/img/a5.png differ diff --git a/app/src/main/assets/img/b1.png b/app/src/main/assets/img/b1.png new file mode 100644 index 0000000..57200b7 Binary files /dev/null and b/app/src/main/assets/img/b1.png differ diff --git a/app/src/main/assets/img/b2.png b/app/src/main/assets/img/b2.png new file mode 100644 index 0000000..4c83bc1 Binary files /dev/null and b/app/src/main/assets/img/b2.png differ diff --git a/app/src/main/assets/img/c1.png b/app/src/main/assets/img/c1.png new file mode 100644 index 0000000..949299e Binary files /dev/null and b/app/src/main/assets/img/c1.png differ diff --git a/app/src/main/assets/img/c2.png b/app/src/main/assets/img/c2.png new file mode 100644 index 0000000..7dedfdd Binary files /dev/null and b/app/src/main/assets/img/c2.png differ diff --git a/app/src/main/assets/img/c3.png b/app/src/main/assets/img/c3.png new file mode 100644 index 0000000..6215bd7 Binary files /dev/null and b/app/src/main/assets/img/c3.png differ diff --git a/app/src/main/assets/img/c4.png b/app/src/main/assets/img/c4.png new file mode 100644 index 0000000..4d480e9 Binary files /dev/null and b/app/src/main/assets/img/c4.png differ diff --git a/app/src/main/assets/img/check_off.png b/app/src/main/assets/img/check_off.png new file mode 100644 index 0000000..aaf0442 Binary files /dev/null and b/app/src/main/assets/img/check_off.png differ diff --git a/app/src/main/assets/img/check_on.png b/app/src/main/assets/img/check_on.png new file mode 100644 index 0000000..997e07f Binary files /dev/null and b/app/src/main/assets/img/check_on.png differ diff --git a/app/src/main/assets/img/d1.png b/app/src/main/assets/img/d1.png new file mode 100644 index 0000000..7ff89a7 Binary files /dev/null and b/app/src/main/assets/img/d1.png differ diff --git a/app/src/main/assets/img/data b/app/src/main/assets/img/data new file mode 100644 index 0000000..fcaf2bf --- /dev/null +++ b/app/src/main/assets/img/data @@ -0,0 +1 @@ +7225fae6e4 \ No newline at end of file diff --git a/app/src/main/assets/img/e1.png b/app/src/main/assets/img/e1.png new file mode 100644 index 0000000..2d087b4 Binary files /dev/null and b/app/src/main/assets/img/e1.png differ diff --git a/app/src/main/assets/img/e2.png b/app/src/main/assets/img/e2.png new file mode 100644 index 0000000..66c91d0 Binary files /dev/null and b/app/src/main/assets/img/e2.png differ diff --git a/app/src/main/assets/img/f1.png b/app/src/main/assets/img/f1.png new file mode 100644 index 0000000..18465f5 Binary files /dev/null and b/app/src/main/assets/img/f1.png differ diff --git a/app/src/main/assets/img/f10.png b/app/src/main/assets/img/f10.png new file mode 100644 index 0000000..9ddbba9 Binary files /dev/null and b/app/src/main/assets/img/f10.png differ diff --git a/app/src/main/assets/img/f11.png b/app/src/main/assets/img/f11.png new file mode 100644 index 0000000..e83eef3 Binary files /dev/null and b/app/src/main/assets/img/f11.png differ diff --git a/app/src/main/assets/img/f12.png b/app/src/main/assets/img/f12.png new file mode 100644 index 0000000..7059834 Binary files /dev/null and b/app/src/main/assets/img/f12.png differ diff --git a/app/src/main/assets/img/f2.png b/app/src/main/assets/img/f2.png new file mode 100644 index 0000000..0077c99 Binary files /dev/null and b/app/src/main/assets/img/f2.png differ diff --git a/app/src/main/assets/img/f3.png b/app/src/main/assets/img/f3.png new file mode 100644 index 0000000..e21dc8b Binary files /dev/null and b/app/src/main/assets/img/f3.png differ diff --git a/app/src/main/assets/img/f4.png b/app/src/main/assets/img/f4.png new file mode 100644 index 0000000..0ff5a34 Binary files /dev/null and b/app/src/main/assets/img/f4.png differ diff --git a/app/src/main/assets/img/f5.png b/app/src/main/assets/img/f5.png new file mode 100644 index 0000000..47b8b54 Binary files /dev/null and b/app/src/main/assets/img/f5.png differ diff --git a/app/src/main/assets/img/f6.png b/app/src/main/assets/img/f6.png new file mode 100644 index 0000000..fd82722 Binary files /dev/null and b/app/src/main/assets/img/f6.png differ diff --git a/app/src/main/assets/img/f7.png b/app/src/main/assets/img/f7.png new file mode 100644 index 0000000..6ab986a Binary files /dev/null and b/app/src/main/assets/img/f7.png differ diff --git a/app/src/main/assets/img/f8.png b/app/src/main/assets/img/f8.png new file mode 100644 index 0000000..caadb9e Binary files /dev/null and b/app/src/main/assets/img/f8.png differ diff --git a/app/src/main/assets/img/f9.png b/app/src/main/assets/img/f9.png new file mode 100644 index 0000000..a858e63 Binary files /dev/null and b/app/src/main/assets/img/f9.png differ diff --git a/app/src/main/assets/imgs/A1.png b/app/src/main/assets/imgs/A1.png new file mode 100644 index 0000000..7f422d6 Binary files /dev/null and b/app/src/main/assets/imgs/A1.png differ diff --git a/app/src/main/assets/imgs/A2.png b/app/src/main/assets/imgs/A2.png new file mode 100644 index 0000000..d9f0f9c Binary files /dev/null and b/app/src/main/assets/imgs/A2.png differ diff --git a/app/src/main/assets/imgs/A3.png b/app/src/main/assets/imgs/A3.png new file mode 100644 index 0000000..51c5c70 Binary files /dev/null and b/app/src/main/assets/imgs/A3.png differ diff --git a/app/src/main/assets/imgs/A4.png b/app/src/main/assets/imgs/A4.png new file mode 100644 index 0000000..ee0cce8 Binary files /dev/null and b/app/src/main/assets/imgs/A4.png differ diff --git a/app/src/main/assets/imgs/Add.png b/app/src/main/assets/imgs/Add.png new file mode 100644 index 0000000..ec89a9c Binary files /dev/null and b/app/src/main/assets/imgs/Add.png differ diff --git a/app/src/main/assets/imgs/Community.png b/app/src/main/assets/imgs/Community.png new file mode 100644 index 0000000..8c7dd10 Binary files /dev/null and b/app/src/main/assets/imgs/Community.png differ diff --git a/app/src/main/assets/imgs/Donate.png b/app/src/main/assets/imgs/Donate.png new file mode 100644 index 0000000..e895cc1 Binary files /dev/null and b/app/src/main/assets/imgs/Donate.png differ diff --git a/app/src/main/assets/imgs/Item.png b/app/src/main/assets/imgs/Item.png new file mode 100644 index 0000000..c72726c Binary files /dev/null and b/app/src/main/assets/imgs/Item.png differ diff --git a/app/src/main/assets/imgs/Logout.png b/app/src/main/assets/imgs/Logout.png new file mode 100644 index 0000000..09ac361 Binary files /dev/null and b/app/src/main/assets/imgs/Logout.png differ diff --git a/app/src/main/assets/imgs/My.png b/app/src/main/assets/imgs/My.png new file mode 100644 index 0000000..c1e3b79 Binary files /dev/null and b/app/src/main/assets/imgs/My.png differ diff --git a/app/src/main/assets/imgs/Other.png b/app/src/main/assets/imgs/Other.png new file mode 100644 index 0000000..7fe2c54 Binary files /dev/null and b/app/src/main/assets/imgs/Other.png differ diff --git a/app/src/main/assets/imgs/Search.png b/app/src/main/assets/imgs/Search.png new file mode 100644 index 0000000..15ad8d3 Binary files /dev/null and b/app/src/main/assets/imgs/Search.png differ diff --git a/app/src/main/assets/imgs/Send.png b/app/src/main/assets/imgs/Send.png new file mode 100644 index 0000000..61aab75 Binary files /dev/null and b/app/src/main/assets/imgs/Send.png differ diff --git a/app/src/main/assets/imgs/Set.png b/app/src/main/assets/imgs/Set.png new file mode 100644 index 0000000..c34c1f6 Binary files /dev/null and b/app/src/main/assets/imgs/Set.png differ diff --git a/app/src/main/assets/imgs/Source Code.png b/app/src/main/assets/imgs/Source Code.png new file mode 100644 index 0000000..580de7e Binary files /dev/null and b/app/src/main/assets/imgs/Source Code.png differ diff --git a/app/src/main/assets/imgs/Teach.png b/app/src/main/assets/imgs/Teach.png new file mode 100644 index 0000000..52cf916 Binary files /dev/null and b/app/src/main/assets/imgs/Teach.png differ diff --git a/app/src/main/assets/imgs/ThomeLua1.png b/app/src/main/assets/imgs/ThomeLua1.png new file mode 100644 index 0000000..078f936 Binary files /dev/null and b/app/src/main/assets/imgs/ThomeLua1.png differ diff --git a/app/src/main/assets/imgs/ThomeLua2.png b/app/src/main/assets/imgs/ThomeLua2.png new file mode 100644 index 0000000..493777d Binary files /dev/null and b/app/src/main/assets/imgs/ThomeLua2.png differ diff --git a/app/src/main/assets/imgs/ThomeLua3.png b/app/src/main/assets/imgs/ThomeLua3.png new file mode 100644 index 0000000..c90178e Binary files /dev/null and b/app/src/main/assets/imgs/ThomeLua3.png differ diff --git a/app/src/main/assets/imgs/ThomeLua4.png b/app/src/main/assets/imgs/ThomeLua4.png new file mode 100644 index 0000000..a1419d0 Binary files /dev/null and b/app/src/main/assets/imgs/ThomeLua4.png differ diff --git a/app/src/main/assets/imgs/User.png b/app/src/main/assets/imgs/User.png new file mode 100644 index 0000000..5ecd337 Binary files /dev/null and b/app/src/main/assets/imgs/User.png differ diff --git a/app/src/main/assets/imgs/clear.png b/app/src/main/assets/imgs/clear.png new file mode 100644 index 0000000..e86ea2d Binary files /dev/null and b/app/src/main/assets/imgs/clear.png differ diff --git a/app/src/main/assets/imgs/find.png b/app/src/main/assets/imgs/find.png new file mode 100644 index 0000000..09c4e94 Binary files /dev/null and b/app/src/main/assets/imgs/find.png differ diff --git a/app/src/main/assets/imgs/qq.png b/app/src/main/assets/imgs/qq.png new file mode 100644 index 0000000..3285618 Binary files /dev/null and b/app/src/main/assets/imgs/qq.png differ diff --git a/app/src/main/assets/init.lua b/app/src/main/assets/init.lua new file mode 100644 index 0000000..a793941 --- /dev/null +++ b/app/src/main/assets/init.lua @@ -0,0 +1,39 @@ +appname="ThomeLua" +appver="5.0-beta1" +appcode="5" +appsdk="15" +path_pattern="" +packagename="com.ThomeLua.IDE" +--theme="Theme_DeviceDefault_Light_NoActionBar" +app_key="" +app_channel="" +developer="" +description="" +debugmode=true +user_permission={ + "ACCESS_COARSE_LOCATION", + "ACCESS_FINE_LOCATION", + "ACCESS_NETWORK_STATE", + "ACCESS_WIFI_STATE", + "BIND_ACCESSIBILITY_SERVICE", + "CAMERA", + "CHANGE_NETWORK_STATE", + "CHANGE_WIFI_STATE", + "DOWNLOAD_WITHOUT_NOTIFICATION", + "GET_PACKAGE_SIZE", + "INSTALL_SHORTCUT", + "INTERNET", + "KILL_BACKGROUND_PROCESSES", + "READ_CONTACTS", + "READ_EXTERNAL_STORAGE", + "READ_PHONE_STATE", + "RECORD_AUDIO", + "REQUEST_INSTALL_PACKAGES", + "SEND_SMS", + "SET_WALLPAPER", + "SYSTEM_ALERT_WINDOW", + "VIBRATE", + "WRITE_CALL_LOG", + "WRITE_CONTACTS", + "WRITE_EXTERNAL_STORAGE" +} diff --git a/app/src/main/assets/javaapi/android.lua b/app/src/main/assets/javaapi/android.lua new file mode 100644 index 0000000..b1dd279 --- /dev/null +++ b/app/src/main/assets/javaapi/android.lua @@ -0,0 +1,4510 @@ +return { +"android.app.FloatWindow$ContentView", +"android.app.FloatWindow$TitleBar", +"android.app.FloatWindow$TitleView", +"android.app.FloatWindow", +"android.content.FileProvider$PathStrategy", +"android.content.FileProvider$SimplePathStrategy", +"android.content.FileProvider", +"android.support.annotation.Keep", +"android.widget.ArrayExpandableListAdapter", +"android.widget.ArrayListAdapter$ArrayFilter", +"android.widget.ArrayListAdapter", +"android.widget.ArrayPageAdapter", +"android.widget.BasePageAdapter", +"android.widget.CardView", +"android.widget.CircleImageView", +"android.widget.DrawerLayout$DrawerListener", +"android.widget.DrawerLayout$EdgeGravity", +"android.widget.DrawerLayout$LayoutParams", +"android.widget.DrawerLayout$LockMode", +"android.widget.DrawerLayout$SavedState", +"android.widget.DrawerLayout$SimpleDrawerListener", +"android.widget.DrawerLayout$State", +"android.widget.DrawerLayout$ViewDragCallback", +"android.widget.DrawerLayout", +"android.widget.ExListView", +"android.widget.FloatButton", +"android.widget.HorizontalListView$OnScrollStateChangedListener", +"android.widget.HorizontalListView", +"android.widget.PageAdapter", +"android.widget.PageLayout$OnPageChangeListener", +"android.widget.PageLayout", +"android.widget.PageView$Decor", +"android.widget.PageView$ItemInfo", +"android.widget.PageView$LayoutParams", +"android.widget.PageView$OnAdapterChangeListener", +"android.widget.PageView$OnPageChangeListener", +"android.widget.PageView$PageTransformer", +"android.widget.PageView$PagerObserver", +"android.widget.PageView$SavedState", +"android.widget.PageView$SimpleOnPageChangeListener", +"android.widget.PageView$ViewPositionComparator", +"android.widget.PageView", +"android.widget.PullingLayout$AutoRefreshAndLoadTask", +"android.widget.PullingLayout$FailDrawable2", +"android.widget.PullingLayout$FailDrawable", +"android.widget.PullingLayout$FootView", +"android.widget.PullingLayout$HeadView", +"android.widget.PullingLayout$LoadingDrawable2", +"android.widget.PullingLayout$LoadingDrawable", +"android.widget.PullingLayout$MyTimer$MyTask", +"android.widget.PullingLayout$MyTimer", +"android.widget.PullingLayout$OnLoadMoreListener", +"android.widget.PullingLayout$OnPullDownListener", +"android.widget.PullingLayout$OnPullUpListener", +"android.widget.PullingLayout$OnRefreshListener", +"android.widget.PullingLayout", +"android.widget.RippleHelper", +"android.widget.RippleLayout", +"android.widget.RoundRectDrawable", +"android.widget.RoundRectDrawableWithShadow", +"android.widget.SlidingLayout$OnMenuClosedListener", +"android.widget.SlidingLayout$OnMenuOpenedListener", +"android.widget.SlidingLayout$OnMenuStateChangeListener", +"android.widget.SlidingLayout", +"android.widget.ToolBar$OnLogoClickListener", +"android.widget.ToolBar$OnMenuItemClickListener", +"android.widget.ToolBar$OnNaviClickListener", +"android.widget.ToolBar", +"android.widget.ViewDragHelper$Callback", +"android.widget.ViewDragHelper", +"com.androlua.BuildConfig", +"com.androlua.CrashHandler", +"com.androlua.Download$DownloadBroadcastReceiver", +"com.androlua.Download$OnDownloadCompleteListener", +"com.androlua.Download", +"com.androlua.GifDecoder$GifAction", +"com.androlua.GifDecoder$GifFrame", +"com.androlua.GifDecoder", +"com.androlua.Http$HttpTask", +"com.androlua.Http", +"com.androlua.LoadingDrawable", +"com.androlua.LuaAccessibilityService$AccessibilityServiceCallbacks", +"com.androlua.LuaAccessibilityService", +"com.androlua.LuaActivity", +"com.androlua.LuaAdapter", +"com.androlua.LuaAnimation", +"com.androlua.LuaApplication", +"com.androlua.LuaArrayAdapter", +"com.androlua.LuaAssetLoader", +"com.androlua.LuaAsyncTask", +"com.androlua.LuaBitmap", +"com.androlua.LuaBitmapDrawable", +"com.androlua.LuaBroadcastReceiver$OnReceiveListener", +"com.androlua.LuaBroadcastReceiver", +"com.androlua.LuaCameraView", +"com.androlua.LuaClient$OnReadLineListener", +"com.androlua.LuaClient$SocketThread", +"com.androlua.LuaClient", +"com.androlua.LuaContentObserver$OnChangeListener", +"com.androlua.LuaContentObserver", +"com.androlua.LuaContext", +"com.androlua.LuaDexClassLoader", +"com.androlua.LuaDexLoader", +"com.androlua.LuaDialog$OnClickListener", +"com.androlua.LuaDialog", +"com.androlua.LuaDrawable", +"com.androlua.LuaEditor", +"com.androlua.LuaEnhancer", +"com.androlua.LuaExAdapter", +"com.androlua.LuaExpandableListAdapter", +"com.androlua.LuaFileObserver$OnEventListener", +"com.androlua.LuaFileObserver", +"com.androlua.LuaFragment", +"com.androlua.LuaGcable", +"com.androlua.LuaLexer$CharSeqReader", +"com.androlua.LuaLexer", +"com.androlua.LuaMultiAdapter", +"com.androlua.LuaPreferenceFragment", +"com.androlua.LuaResources", +"com.androlua.LuaRunnable", +"com.androlua.LuaServer$OnReadLineListener", +"com.androlua.LuaServer$ServerThread", +"com.androlua.LuaServer$SocketThread", +"com.androlua.LuaServer", +"com.androlua.LuaService$LuaBinder", +"com.androlua.LuaService", +"com.androlua.LuaThread", +"com.androlua.LuaTimer", +"com.androlua.LuaTimerTask", +"com.androlua.LuaTokenTypes", +"com.androlua.LuaUtil", +"com.androlua.LuaView", +"com.androlua.LuaWebView$Download", +"com.androlua.LuaWebView$DownloadBroadcastReceiver", +"com.androlua.LuaWebView$JsInterface", +"com.androlua.LuaWebView$JsObject", +"com.androlua.LuaWebView$LuaJavaScriptInterface", +"com.androlua.LuaWebView$LuaWebChromeClient", +"com.androlua.LuaWebView$LuaWebViewClient", +"com.androlua.LuaWebView$OnDownloadCompleteListener", +"com.androlua.LuaWebView$OnDownloadStartListener", +"com.androlua.LuaWebView$SimpleLuaWebViewClient", +"com.androlua.LuaWebView", +"com.androlua.NineBitmapDrawable", +"com.androlua.R$drawable", +"com.androlua.R$string", +"com.androlua.R$style", +"com.androlua.R$xml", +"com.androlua.Ticker$OnTickListener", +"com.androlua.Ticker", +"com.androlua.ZipUtil", +"com.androlua.util.AsyncTaskX$AsyncTaskResult", +"com.androlua.util.AsyncTaskX$SerialExecutor", +"com.androlua.util.AsyncTaskX$Status", +"com.androlua.util.AsyncTaskX$WorkerRunnable", +"com.androlua.util.AsyncTaskX", +"com.androlua.util.ClickRunnable$ClickCallback", +"com.androlua.util.ClickRunnable", +"com.androlua.util.GlobalActionAutomator", +"com.androlua.util.RSASecurity", +"com.androlua.util.RootUtil", +"com.androlua.util.ScreenMetrics", +"com.androlua.util.TimerTaskX", +"com.androlua.util.TimerX$FinalizerHelper", +"com.androlua.util.TimerX$TimerImpl$TimerHeap", +"com.androlua.util.TimerX$TimerImpl", +"com.androlua.util.TimerX", +"com.androlua.util.VolatileBox", +"com.androlua.util.VolatileDispose", +"com.androlua.util.ZipUtil", +"com.nirenr.Color", +"com.nirenr.ColorFinder", +"com.nirenr.ColorPoint", +"com.nirenr.Point", +"com.nirenr.SplitEditView$EditDialog", +"com.nirenr.SplitEditView$OnSaveListener", +"com.nirenr.SplitEditView", +"android.Manifest", +"android.nfc.NfcAdapter", +"android.nfc.Tag", + +"android.nfc.NfcAdapter$CreateBeamUrisCallback", +"android.nfc.NfcManager", +"android.nfc.NdefMessage", +"android.nfc.cardemulation.OffHostApduService", +"android.nfc.cardemulation.HostNfcFService", +"android.nfc.cardemulation.CardEmulation", +"android.nfc.cardemulation.NfcFCardEmulation", +"android.nfc.cardemulation.HostApduService", +"android.nfc.NfcAdapter$ReaderCallback", +"android.nfc.NfcEvent", +"android.nfc.NdefRecord", +"android.nfc.NfcAdapter$CreateNdefMessageCallback", +"android.nfc.NfcAdapter$OnNdefPushCompleteCallback", + +"android.nfc.NfcAdapter$OnTagRemovedListener", +"android.nfc.tech.MifareClassic", +"android.nfc.tech.NfcA", +"android.nfc.tech.NfcB", +"android.nfc.tech.MifareUltralight", +"android.nfc.tech.NfcBarcode", +"android.nfc.tech.NfcV", +"android.nfc.tech.NfcF", +"android.nfc.tech.TagTechnology", +"android.nfc.tech.Ndef", +"android.nfc.tech.NdefFormatable", +"android.nfc.tech.IsoDep", +"android.renderscript.ScriptIntrinsicConvolve5x5", +"android.renderscript.Double2", +"android.renderscript.Matrix3f", +"android.renderscript.Long2", +"android.renderscript.Script$InvokeID", +"android.renderscript.Matrix2f", +"android.renderscript.Short4", +"android.renderscript.RenderScript$Priority", +"android.renderscript.ScriptIntrinsicBlend", +"android.renderscript.BaseObj", +"android.renderscript.Sampler$Value", +"android.renderscript.Sampler$Builder", +"android.renderscript.Allocation$MipmapControl", +"android.renderscript.Allocation", +"android.renderscript.Float3", +"android.renderscript.Allocation$OnBufferAvailableListener", +"android.renderscript.Long4", +"android.renderscript.ScriptC", +"android.renderscript.ScriptIntrinsicBLAS", +"android.renderscript.Matrix4f", +"android.renderscript.Float2", +"android.renderscript.ScriptGroup$Builder", +"android.renderscript.ScriptGroup$Future", +"android.renderscript.Sampler", +"android.renderscript.ScriptGroup$Input", +"android.renderscript.Long3", +"android.renderscript.RenderScript$RSMessageHandler", +"android.renderscript.Type", +"android.renderscript.Element$Builder", +"android.renderscript.Script$LaunchOptions", +"android.renderscript.ScriptIntrinsicLUT", +"android.renderscript.Short3", +"android.renderscript.Byte2", + +"android.renderscript.Byte3", + +"android.renderscript.ScriptIntrinsicColorMatrix", +"android.renderscript.Element$DataKind", +"android.renderscript.ScriptIntrinsic", + +"android.renderscript.AllocationAdapter", +"android.renderscript.RenderScript", +"android.renderscript.Script$KernelID", +"android.renderscript.ScriptIntrinsicHistogram", +"android.renderscript.Double4", +"android.renderscript.Int2", +"android.renderscript.ScriptGroup$Closure", +"android.renderscript.ScriptIntrinsicConvolve3x3", +"android.renderscript.Float4", +"android.renderscript.Type$CubemapFace", +"android.renderscript.FieldPacker", +"android.renderscript.ScriptIntrinsicResize", +"android.renderscript.Int4", +"android.renderscript.ScriptIntrinsicYuvToRGB", +"android.renderscript.RenderScript$RSErrorHandler", +"android.renderscript.ScriptGroup", +"android.renderscript.Script$Builder", + +"android.renderscript.Int3", +"android.renderscript.Type$Builder", +"android.renderscript.Double3", +"android.renderscript.RenderScript$ContextType", +"android.renderscript.Element", +"android.renderscript.ScriptGroup$Binding", +"android.renderscript.Script$FieldID", +"android.renderscript.Script", +"android.renderscript.Short2", +"android.renderscript.Element$DataType", +"android.renderscript.ScriptIntrinsicBlur", +"android.renderscript.Byte4", +"android.renderscript.ScriptGroup$Builder2", +"android.renderscript.Script$FieldBase", +"android.renderscript.ScriptIntrinsic3DLUT", +"android.telecom.Conference", +"android.telecom.VideoProfile$CameraCapabilities", +"android.telecom.Connection$VideoProvider", +"android.telecom.ConnectionService", +"android.telecom.PhoneAccount$Builder", +"android.telecom.RemoteConnection$Callback", +"android.telecom.StatusHints", +"android.telecom.TelecomManager", +"android.telecom.RemoteConference$Callback", +"android.telecom.PhoneAccount", +"android.telecom.GatewayInfo", +"android.telecom.RemoteConference", +"android.telecom.CallScreeningService$CallResponse$Builder", +"android.telecom.Call$Details", +"android.telecom.DisconnectCause", +"android.telecom.Connection$RttModifyStatus", +"android.telecom.InCallService", +"android.telecom.Connection", +"android.telecom.CallScreeningService$CallResponse", +"android.telecom.CallAudioState", +"android.telecom.CallScreeningService", +"android.telecom.RemoteConnection$VideoProvider$Callback", +"android.telecom.VideoProfile", +"android.telecom.PhoneAccountHandle", +"android.telecom.ConnectionRequest", +"android.telecom.Call", +"android.telecom.RemoteConnection$VideoProvider", +"android.telecom.InCallService$VideoCall", +"android.telecom.InCallService$VideoCall$Callback", +"android.telecom.Call$RttCall", +"android.telecom.RemoteConnection", +"android.telecom.Call$Callback", +"android.telecom.Conferenceable", +"android.telecom.Connection$RttTextStream", +"android.companion.CompanionDeviceManager", +"android.companion.BluetoothLeDeviceFilter$Builder", +"android.companion.CompanionDeviceManager$Callback", +"android.companion.DeviceFilter", +"android.companion.AssociationRequest$Builder", +"android.companion.AssociationRequest", +"android.companion.WifiDeviceFilter$Builder", +"android.companion.BluetoothDeviceFilter$Builder", +"android.companion.BluetoothDeviceFilter", +"android.companion.BluetoothLeDeviceFilter", +"android.companion.WifiDeviceFilter", +"android.R$drawable", +"android.R$bool", +"android.se.omapi.SEService", +"android.se.omapi.Reader", +"android.se.omapi.Channel", +"android.se.omapi.Session", +"android.se.omapi.SEService$OnConnectedListener", +"android.database.DefaultDatabaseErrorHandler", +"android.database.DatabaseUtils$InsertHelper", +"android.database.MatrixCursor", +"android.database.CursorJoiner", +"android.database.Cursor", +"android.database.DatabaseErrorHandler", +"android.database.ContentObservable", +"android.database.CursorWindow", +"android.database.ContentObserver", + +"android.database.Observable", +"android.database.MergeCursor", +"android.database.CharArrayBuffer", +"android.database.DataSetObservable", +"android.database.sqlite.SQLiteQueryBuilder", +"android.database.sqlite.SQLiteQuery", +"android.database.sqlite.SQLiteDatabase$OpenParams", +"android.database.sqlite.SQLiteStatement", + +"android.database.sqlite.SQLiteDatabase$CursorFactory", +"android.database.sqlite.SQLiteCursorDriver", + + +"android.database.sqlite.SQLiteProgram", +"android.database.sqlite.SQLiteTransactionListener", + + + + + +"android.database.sqlite.SQLiteCursor", +"android.database.sqlite.SQLiteDatabase$OpenParams$Builder", +"android.database.sqlite.SQLiteDatabase", + +"android.database.sqlite.SQLiteOpenHelper", +"android.database.sqlite.SQLiteClosable", + + + + + + + + + + + +"android.database.MatrixCursor$RowBuilder", + +"android.database.DataSetObserver", +"android.database.DatabaseUtils", + +"android.database.CursorWrapper", +"android.database.CrossProcessCursorWrapper", +"android.database.CursorJoiner$Result", +"android.database.CrossProcessCursor", +"android.bluetooth.BluetoothGattDescriptor", +"android.bluetooth.le.AdvertiseData$Builder", +"android.bluetooth.le.AdvertiseSettings", +"android.bluetooth.le.BluetoothLeAdvertiser", +"android.bluetooth.le.ScanFilter", +"android.bluetooth.le.ScanSettings", +"android.bluetooth.le.AdvertiseCallback", +"android.bluetooth.le.BluetoothLeScanner", +"android.bluetooth.le.ScanResult", +"android.bluetooth.le.ScanCallback", +"android.bluetooth.le.AdvertiseSettings$Builder", +"android.bluetooth.le.ScanSettings$Builder", +"android.bluetooth.le.PeriodicAdvertisingParameters", +"android.bluetooth.le.AdvertisingSet", +"android.bluetooth.le.AdvertiseData", +"android.bluetooth.le.AdvertisingSetCallback", +"android.bluetooth.le.ScanFilter$Builder", +"android.bluetooth.le.PeriodicAdvertisingParameters$Builder", +"android.bluetooth.le.ScanRecord", +"android.bluetooth.le.AdvertisingSetParameters$Builder", +"android.bluetooth.le.AdvertisingSetParameters", +"android.bluetooth.BluetoothGattCallback", +"android.bluetooth.BluetoothGattServer", +"android.bluetooth.BluetoothSocket", +"android.bluetooth.BluetoothHeadset", +"android.bluetooth.BluetoothManager", +"android.bluetooth.BluetoothClass$Service", +"android.bluetooth.BluetoothHidDevice", +"android.bluetooth.BluetoothHidDevice$Callback", +"android.bluetooth.BluetoothClass", +"android.bluetooth.BluetoothHealthCallback", +"android.bluetooth.BluetoothAssignedNumbers", +"android.bluetooth.BluetoothGattCharacteristic", +"android.bluetooth.BluetoothGatt", +"android.bluetooth.BluetoothServerSocket", +"android.bluetooth.BluetoothHidDeviceAppSdpSettings", +"android.bluetooth.BluetoothAdapter$LeScanCallback", +"android.bluetooth.BluetoothHidDeviceAppQosSettings", +"android.bluetooth.BluetoothA2dp", +"android.bluetooth.BluetoothDevice", +"android.bluetooth.BluetoothGattService", +"android.bluetooth.BluetoothClass$Device$Major", +"android.bluetooth.BluetoothProfile$ServiceListener", +"android.bluetooth.BluetoothProfile", +"android.bluetooth.BluetoothHealthAppConfiguration", +"android.bluetooth.BluetoothHealth", +"android.bluetooth.BluetoothGattServerCallback", +"android.bluetooth.BluetoothAdapter", +"android.bluetooth.BluetoothClass$Device", +"android.transition.Transition$EpicenterCallback", +"android.transition.TransitionListenerAdapter", +"android.transition.SidePropagation", +"android.transition.Fade", +"android.transition.CircularPropagation", +"android.transition.VisibilityPropagation", +"android.transition.AutoTransition", +"android.transition.ChangeClipBounds", +"android.transition.TransitionManager", +"android.transition.TransitionPropagation", +"android.transition.ChangeBounds", +"android.transition.TransitionSet", +"android.transition.ChangeTransform", +"android.transition.Transition", +"android.transition.Transition$TransitionListener", +"android.transition.ArcMotion", +"android.transition.Visibility", +"android.transition.PatternPathMotion", +"android.transition.Slide", +"android.transition.ChangeScroll", +"android.transition.PathMotion", +"android.transition.Explode", +"android.transition.Scene", +"android.transition.TransitionInflater", +"android.transition.ChangeImageTransform", +"android.transition.TransitionValues", +"android.speech.SpeechRecognizer", +"android.speech.RecognizerIntent", +"android.speech.tts.TextToSpeech$OnUtteranceCompletedListener", +"android.speech.tts.UtteranceProgressListener", +"android.speech.tts.SynthesisRequest", +"android.speech.tts.TextToSpeech", +"android.speech.tts.SynthesisCallback", +"android.speech.tts.TextToSpeechService", +"android.speech.tts.TextToSpeech$Engine", +"android.speech.tts.TextToSpeech$OnInitListener", +"android.speech.tts.Voice", +"android.speech.tts.TextToSpeech$EngineInfo", +"android.speech.RecognitionListener", +"android.speech.RecognitionService$Callback", +"android.speech.RecognizerResultsIntent", +"android.speech.RecognitionService", +"android.text.PrecomputedText$Params$Builder", +"android.text.InputFilter$AllCaps", +"android.text.BoringLayout", +"android.text.Spannable$Factory", +"android.text.ParcelableSpan", +"android.text.BoringLayout$Metrics", +"android.text.Layout$Alignment", +"android.text.method.BaseMovementMethod", +"android.text.method.TimeKeyListener", +"android.text.method.PasswordTransformationMethod", +"android.text.method.CharacterPickerDialog", +"android.text.method.DateTimeKeyListener", +"android.text.method.BaseKeyListener", +"android.text.method.ReplacementTransformationMethod", +"android.text.method.DialerKeyListener", +"android.text.method.TextKeyListener$Capitalize", +"android.text.method.MultiTapKeyListener", +"android.text.method.TransformationMethod", +"android.text.method.MetaKeyKeyListener", +"android.text.method.TextKeyListener", +"android.text.method.LinkMovementMethod", +"android.text.method.SingleLineTransformationMethod", +"android.text.method.DateKeyListener", +"android.text.method.NumberKeyListener", +"android.text.method.KeyListener", +"android.text.method.ScrollingMovementMethod", +"android.text.method.ArrowKeyMovementMethod", +"android.text.method.HideReturnsTransformationMethod", +"android.text.method.QwertyKeyListener", +"android.text.method.MovementMethod", +"android.text.method.Touch", +"android.text.method.DigitsKeyListener", +"android.text.TextUtils", +"android.text.LoginFilter$UsernameFilterGeneric", +"android.text.Html$TagHandler", +"android.text.NoCopySpan$Concrete", +"android.text.SpannedString", +"android.text.Editable", +"android.text.Spanned", +"android.text.TextDirectionHeuristics", +"android.text.Html$ImageGetter", +"android.text.AutoText", +"android.text.BidiFormatter$Builder", +"android.text.format.Formatter", +"android.text.format.DateFormat", +"android.text.format.DateUtils", +"android.text.format.Time", +"android.text.AlteredCharSequence", +"android.text.InputType", +"android.text.TextPaint", +"android.text.Editable$Factory", +"android.text.InputFilter$LengthFilter", +"android.text.GetChars", +"android.text.PrecomputedText", +"android.text.TextUtils$SimpleStringSplitter", +"android.text.AndroidCharacter", +"android.text.style.TtsSpan$MoneyBuilder", +"android.text.style.IconMarginSpan", +"android.text.style.LineHeightSpan$WithDensity", +"android.text.style.TtsSpan$MeasureBuilder", +"android.text.style.URLSpan", +"android.text.style.TtsSpan$VerbatimBuilder", +"android.text.style.TtsSpan$ElectronicBuilder", +"android.text.style.TtsSpan$OrdinalBuilder", +"android.text.style.TtsSpan$DateBuilder", +"android.text.style.LeadingMarginSpan$LeadingMarginSpan2", +"android.text.style.AlignmentSpan$Standard", +"android.text.style.RelativeSizeSpan", +"android.text.style.UnderlineSpan", +"android.text.style.ScaleXSpan", +"android.text.style.TtsSpan$Builder", +"android.text.style.BulletSpan", +"android.text.style.MetricAffectingSpan", +"android.text.style.AlignmentSpan", +"android.text.style.DrawableMarginSpan", +"android.text.style.TypefaceSpan", +"android.text.style.SuggestionSpan", +"android.text.style.TextAppearanceSpan", +"android.text.style.BackgroundColorSpan", +"android.text.style.LeadingMarginSpan$Standard", +"android.text.style.LocaleSpan", +"android.text.style.LeadingMarginSpan", +"android.text.style.SuperscriptSpan", +"android.text.style.UpdateLayout", +"android.text.style.TtsSpan$DecimalBuilder", +"android.text.style.ForegroundColorSpan", +"android.text.style.UpdateAppearance", +"android.text.style.ReplacementSpan", +"android.text.style.AbsoluteSizeSpan", +"android.text.style.StrikethroughSpan", +"android.text.style.WrapTogetherSpan", +"android.text.style.LineBackgroundSpan", +"android.text.style.EasyEditSpan", +"android.text.style.CharacterStyle", +"android.text.style.TtsSpan$CardinalBuilder", +"android.text.style.TtsSpan$FractionBuilder", +"android.text.style.TabStopSpan$Standard", +"android.text.style.ImageSpan", +"android.text.style.DynamicDrawableSpan", +"android.text.style.ClickableSpan", +"android.text.style.StyleSpan", +"android.text.style.TtsSpan$TelephoneBuilder", +"android.text.style.TtsSpan$DigitsBuilder", +"android.text.style.TtsSpan$TextBuilder", +"android.text.style.MaskFilterSpan", +"android.text.style.QuoteSpan", +"android.text.style.TtsSpan", +"android.text.style.LineHeightSpan", +"android.text.style.SubscriptSpan", +"android.text.style.TtsSpan$TimeBuilder", +"android.text.style.TabStopSpan", +"android.text.style.TtsSpan$SemioticClassBuilder", +"android.text.style.ParagraphStyle", +"android.text.util.Linkify$MatchFilter", +"android.text.util.Rfc822Tokenizer", +"android.text.util.Rfc822Token", +"android.text.util.Linkify", +"android.text.util.Linkify$TransformFilter", +"android.text.PrecomputedText$Params", +"android.text.Selection", +"android.text.SpannableStringBuilder", +"android.text.ClipboardManager", +"android.text.SpannableString", +"android.text.TextWatcher", +"android.text.Spannable", +"android.text.TextUtils$EllipsizeCallback", +"android.text.NoCopySpan", +"android.text.TextUtils$TruncateAt", +"android.text.TextUtils$StringSplitter", +"android.text.SpanWatcher", +"android.text.BidiFormatter", +"android.text.Layout", +"android.text.InputFilter", +"android.text.TextDirectionHeuristic", +"android.text.DynamicLayout$Builder", +"android.text.Html", +"android.text.LoginFilter$PasswordFilterGMail", +"android.text.DynamicLayout", +"android.text.StaticLayout", +"android.text.Annotation", +"android.text.Layout$Directions", +"android.text.LoginFilter$UsernameFilterGMail", +"android.text.StaticLayout$Builder", +"android.text.LoginFilter", +"android.hardware.SensorEventCallback", +"android.hardware.TriggerEventListener", +"android.hardware.Camera$AutoFocusCallback", +"android.hardware.Camera$OnZoomChangeListener", +"android.hardware.Camera$Parameters", +"android.hardware.Camera$PreviewCallback", +"android.hardware.Camera$FaceDetectionListener", +"android.hardware.usb.UsbConstants", +"android.hardware.usb.UsbEndpoint", +"android.hardware.usb.UsbAccessory", +"android.hardware.usb.UsbDevice", +"android.hardware.usb.UsbManager", +"android.hardware.usb.UsbRequest", +"android.hardware.usb.UsbConfiguration", +"android.hardware.usb.UsbDeviceConnection", +"android.hardware.usb.UsbInterface", +"android.hardware.ConsumerIrManager$CarrierFrequencyRange", +"android.hardware.Camera$Area", +"android.hardware.display.VirtualDisplay$Callback", +"android.hardware.display.DisplayManager", +"android.hardware.display.VirtualDisplay", +"android.hardware.display.DisplayManager$DisplayListener", +"android.hardware.SensorManager", +"android.hardware.SensorListener", +"android.hardware.biometrics.BiometricPrompt$AuthenticationResult", +"android.hardware.biometrics.BiometricPrompt", +"android.hardware.biometrics.BiometricPrompt$Builder", +"android.hardware.biometrics.BiometricPrompt$AuthenticationCallback", +"android.hardware.biometrics.BiometricPrompt$CryptoObject", +"android.hardware.Camera$Size", +"android.hardware.SensorDirectChannel", +"android.hardware.TriggerEvent", +"android.hardware.Camera$AutoFocusMoveCallback", +"android.hardware.Sensor", +"android.hardware.Camera$PictureCallback", +"android.hardware.SensorAdditionalInfo", +"android.hardware.Camera", +"android.hardware.SensorManager$DynamicSensorCallback", +"android.hardware.HardwareBuffer", +"android.hardware.Camera$ShutterCallback", +"android.hardware.fingerprint.FingerprintManager$AuthenticationCallback", +"android.hardware.fingerprint.FingerprintManager$CryptoObject", +"android.hardware.fingerprint.FingerprintManager$AuthenticationResult", +"android.hardware.fingerprint.FingerprintManager", +"android.hardware.input.InputManager$InputDeviceListener", +"android.hardware.input.InputManager", +"android.hardware.GeomagneticField", +"android.hardware.Camera$CameraInfo", +"android.hardware.SensorEventListener", +"android.hardware.Camera$ErrorCallback", +"android.hardware.SensorEventListener2", +"android.hardware.ConsumerIrManager", +"android.hardware.Camera$Face", +"android.hardware.SensorEvent", +"android.hardware.camera2.CameraDevice$StateCallback", +"android.hardware.camera2.CaptureRequest$Key", +"android.hardware.camera2.CaptureResult", +"android.hardware.camera2.CameraCaptureSession$CaptureCallback", +"android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession", + +"android.hardware.camera2.CameraCharacteristics", +"android.hardware.camera2.CaptureFailure", +"android.hardware.camera2.CameraDevice", +"android.hardware.camera2.CameraManager$TorchCallback", +"android.hardware.camera2.CameraCharacteristics$Key", +"android.hardware.camera2.CameraCaptureSession", +"android.hardware.camera2.CameraManager", +"android.hardware.camera2.DngCreator", +"android.hardware.camera2.params.OutputConfiguration", +"android.hardware.camera2.params.RggbChannelVector", +"android.hardware.camera2.params.LensShadingMap", +"android.hardware.camera2.params.Face", +"android.hardware.camera2.params.BlackLevelPattern", +"android.hardware.camera2.params.InputConfiguration", +"android.hardware.camera2.params.ColorSpaceTransform", +"android.hardware.camera2.params.StreamConfigurationMap", +"android.hardware.camera2.params.SessionConfiguration", +"android.hardware.camera2.params.MeteringRectangle", +"android.hardware.camera2.params.OisSample", +"android.hardware.camera2.params.TonemapCurve", +"android.hardware.camera2.CameraMetadata", +"android.hardware.camera2.CameraCaptureSession$StateCallback", +"android.hardware.camera2.CaptureRequest", +"android.hardware.camera2.CameraManager$AvailabilityCallback", +"android.hardware.camera2.CaptureRequest$Builder", +"android.hardware.camera2.TotalCaptureResult", +"android.hardware.camera2.CaptureResult$Key", +"android.R$color", +"android.R$animator", +"android.service.restrictions.RestrictionsReceiver", +"android.service.notification.NotificationListenerService", +"android.service.notification.NotificationListenerService$RankingMap", +"android.service.notification.NotificationListenerService$Ranking", +"android.service.notification.ConditionProviderService", +"android.service.notification.Condition", +"android.service.notification.StatusBarNotification", +"android.service.autofill.Dataset$Builder", +"android.service.autofill.FillEventHistory$Event", +"android.service.autofill.CustomDescription", +"android.service.autofill.FieldClassification", +"android.service.autofill.Transformation", +"android.service.autofill.Dataset", +"android.service.autofill.CustomDescription$Builder", +"android.service.autofill.FillEventHistory", +"android.service.autofill.SaveCallback", +"android.service.autofill.TextValueSanitizer", +"android.service.autofill.FillContext", +"android.service.autofill.UserData", +"android.service.autofill.ImageTransformation$Builder", +"android.service.autofill.SaveRequest", +"android.service.autofill.BatchUpdates$Builder", +"android.service.autofill.UserData$Builder", +"android.service.autofill.FillResponse", +"android.service.autofill.SaveInfo", +"android.service.autofill.CharSequenceTransformation$Builder", +"android.service.autofill.AutofillService", +"android.service.autofill.FillRequest", +"android.service.autofill.Sanitizer", +"android.service.autofill.DateTransformation", +"android.service.autofill.DateValueSanitizer", +"android.service.autofill.Validator", +"android.service.autofill.CharSequenceTransformation", +"android.service.autofill.FieldClassification$Match", +"android.service.autofill.ImageTransformation", +"android.service.autofill.LuhnChecksumValidator", +"android.service.autofill.RegexValidator", +"android.service.autofill.FillCallback", +"android.service.autofill.Validators", +"android.service.autofill.BatchUpdates", +"android.service.autofill.SaveInfo$Builder", +"android.service.autofill.FillResponse$Builder", +"android.service.textservice.SpellCheckerService", +"android.service.textservice.SpellCheckerService$Session", +"android.service.vr.VrListenerService", +"android.service.quicksettings.Tile", +"android.service.quicksettings.TileService", +"android.service.media.MediaBrowserService$Result", +"android.service.media.MediaBrowserService$BrowserRoot", +"android.service.media.MediaBrowserService", +"android.service.media.CameraPrewarmService", +"android.service.chooser.ChooserTarget", +"android.service.chooser.ChooserTargetService", +"android.service.voice.AlwaysOnHotwordDetector", +"android.service.voice.VoiceInteractionSessionService", +"android.service.voice.VoiceInteractionSession$Insets", +"android.service.voice.VoiceInteractionSession$ConfirmationRequest", +"android.service.voice.AlwaysOnHotwordDetector$Callback", +"android.service.voice.VoiceInteractionSession$AbortVoiceRequest", +"android.service.voice.VoiceInteractionService", +"android.service.voice.VoiceInteractionSession$CompleteVoiceRequest", +"android.service.voice.VoiceInteractionSession$PickOptionRequest", +"android.service.voice.VoiceInteractionSession", +"android.service.voice.VoiceInteractionSession$Request", +"android.service.voice.VoiceInteractionSession$CommandRequest", +"android.service.voice.AlwaysOnHotwordDetector$EventPayload", +"android.service.wallpaper.WallpaperService$Engine", +"android.service.wallpaper.WallpaperService", +"android.service.dreams.DreamService", +"android.service.carrier.CarrierIdentifier", +"android.service.carrier.CarrierMessagingService$SendMmsResult", +"android.service.carrier.CarrierService", +"android.service.carrier.CarrierMessagingService", +"android.service.carrier.CarrierMessagingService$SendMultipartSmsResult", +"android.service.carrier.MessagePdu", +"android.service.carrier.CarrierMessagingService$SendSmsResult", +"android.service.carrier.CarrierMessagingService$ResultCallback", +"android.webkit.HttpAuthHandler", +"android.webkit.WebChromeClient$FileChooserParams", +"android.webkit.WebView$VisualStateCallback", +"android.webkit.WebStorage", +"android.webkit.ConsoleMessage", +"android.webkit.JavascriptInterface", +"android.webkit.WebStorage$Origin", +"android.webkit.JsResult", +"android.webkit.WebView$HitTestResult", +"android.webkit.WebMessagePort$WebMessageCallback", +"android.webkit.ServiceWorkerWebSettings", +"android.webkit.CookieManager", +"android.webkit.WebViewClient", +"android.webkit.WebMessage", +"android.webkit.WebResourceRequest", +"android.webkit.TracingConfig$Builder", +"android.webkit.JsPromptResult", +"android.webkit.WebHistoryItem", +"android.webkit.WebSettings$ZoomDensity", +"android.webkit.SafeBrowsingResponse", +"android.webkit.TracingController", +"android.webkit.WebChromeClient$CustomViewCallback", +"android.webkit.WebViewDatabase", +"android.webkit.ClientCertRequest", +"android.webkit.DownloadListener", +"android.webkit.MimeTypeMap", +"android.webkit.WebSettings$LayoutAlgorithm", +"android.webkit.WebView$FindListener", +"android.webkit.WebResourceError", +"android.webkit.WebIconDatabase$IconListener", +"android.webkit.SslErrorHandler", +"android.webkit.WebResourceResponse", +"android.webkit.WebMessagePort", +"android.webkit.WebSettings$TextSize", +"android.webkit.WebChromeClient", +"android.webkit.DateSorter", +"android.webkit.GeolocationPermissions", +"android.webkit.WebSettings$RenderPriority", +"android.webkit.WebBackForwardList", +"android.webkit.PermissionRequest", +"android.webkit.WebSettings$PluginState", +"android.webkit.ServiceWorkerClient", +"android.webkit.WebSettings", +"android.webkit.WebView$PictureListener", +"android.webkit.PluginStub", +"android.webkit.ValueCallback", +"android.webkit.TracingConfig", +"android.webkit.WebIconDatabase", +"android.webkit.WebStorage$QuotaUpdater", +"android.webkit.GeolocationPermissions$Callback", +"android.webkit.CookieSyncManager", +"android.webkit.WebView$WebViewTransport", +"android.webkit.WebViewFragment", +"android.webkit.URLUtil", +"android.webkit.RenderProcessGoneDetail", +"android.webkit.WebView", +"android.webkit.ServiceWorkerController", +"android.webkit.ConsoleMessage$MessageLevel", +"android.app.Activity", +"android.app.ExpandableListActivity", +"android.app.WallpaperManager", +"android.app.Instrumentation$ActivityMonitor", +"android.app.VoiceInteractor$AbortVoiceRequest", +"android.app.TabActivity", +"android.app.Notification$Style", +"android.app.VoiceInteractor", +"android.app.LoaderManager$LoaderCallbacks", +"android.app.AppOpsManager$OnOpChangedListener", +"android.app.FragmentContainer", +"android.app.FragmentManager$FragmentLifecycleCallbacks", +"android.app.ActivityGroup", +"android.app.SharedElementCallback$OnSharedElementsReadyListener", +"android.app.Notification$WearableExtender", +"android.app.DatePickerDialog$OnDateSetListener", +"android.app.ActionBar", +"android.app.ActivityManager$RunningAppProcessInfo", +"android.app.TimePickerDialog", +"android.app.SearchManager", +"android.app.ApplicationErrorReport$CrashInfo", +"android.app.NotificationChannelGroup", +"android.app.ActivityManager$RunningServiceInfo", +"android.app.NotificationManager", +"android.app.Notification$Action$WearableExtender", +"android.app.Application$ActivityLifecycleCallbacks", +"android.app.DownloadManager$Query", +"android.app.ApplicationErrorReport$RunningServiceInfo", +"android.app.LocalActivityManager", +"android.app.FragmentManager$OnBackStackChangedListener", +"android.app.Fragment", +"android.app.RemoteAction", +"android.app.ActivityManager$ProcessErrorStateInfo", +"android.app.IntentService", +"android.app.SharedElementCallback", +"android.app.Notification$CarExtender", +"android.app.Application", + +"android.app.Instrumentation$ActivityResult", +"android.app.PictureInPictureParams", +"android.app.Notification$MessagingStyle$Message", +"android.app.Notification$Action$Extender", +"android.app.KeyguardManager$OnKeyguardExitResult", +"android.app.FragmentManager$BackStackEntry", +"android.app.VoiceInteractor$Prompt", +"android.app.Presentation", +"android.app.MediaRouteActionProvider", +"android.app.ActionBar$Tab", +"android.app.FragmentHostCallback", +"android.app.VoiceInteractor$CompleteVoiceRequest", +"android.app.assist.AssistStructure$WindowNode", +"android.app.assist.AssistContent", +"android.app.assist.AssistStructure", +"android.app.assist.AssistStructure$ViewNode", +"android.app.TaskStackBuilder", +"android.app.RemoteInput", +"android.app.ActivityManager$AppTask", +"android.app.VoiceInteractor$Request", +"android.app.Notification$Action", +"android.app.ActivityOptions", +"android.app.VoiceInteractor$PickOptionRequest$Option", +"android.app.PendingIntent$OnFinished", + +"android.app.ActivityManager$TaskDescription", +"android.app.AutomaticZenRule", +"android.app.FragmentManagerNonConfig", +"android.app.ActivityManager", +"android.app.VoiceInteractor$ConfirmationRequest", +"android.app.ApplicationErrorReport$BatteryInfo", + +"android.app.AlarmManager$AlarmClockInfo", +"android.app.Notification$CarExtender$Builder", +"android.app.VoiceInteractor$CommandRequest", +"android.app.TimePickerDialog$OnTimeSetListener", +"android.app.Notification$MessagingStyle", +"android.app.LauncherActivity", +"android.app.usage.UsageStats", +"android.app.usage.NetworkStats", +"android.app.usage.UsageStatsManager", +"android.app.usage.StorageStatsManager", +"android.app.usage.ConfigurationStats", +"android.app.usage.StorageStats", +"android.app.usage.UsageEvents$Event", +"android.app.usage.EventStats", +"android.app.usage.NetworkStatsManager", +"android.app.usage.NetworkStatsManager$UsageCallback", +"android.app.usage.ExternalStorageStats", +"android.app.usage.NetworkStats$Bucket", +"android.app.usage.UsageEvents", +"android.app.ActionBar$TabListener", +"android.app.UiAutomation", +"android.app.Dialog", +"android.app.KeyguardManager", +"android.app.VoiceInteractor$PickOptionRequest", +"android.app.Notification$BigPictureStyle", +"android.app.UiAutomation$AccessibilityEventFilter", +"android.app.AlertDialog$Builder", +"android.app.Person", +"android.app.AppComponentFactory", +"android.app.NotificationChannel", +"android.app.AppOpsManager", +"android.app.ActivityManager$MemoryInfo", +"android.app.DownloadManager", +"android.app.PendingIntent", +"android.app.ApplicationErrorReport$AnrInfo", +"android.app.Notification$Builder", +"android.app.Notification", +"android.app.SearchManager$OnDismissListener", +"android.app.ProgressDialog", +"android.app.ActionBar$OnNavigationListener", +"android.app.LoaderManager", +"android.app.Fragment$SavedState", +"android.app.DialogFragment", +"android.app.KeyguardManager$KeyguardDismissCallback", +"android.app.WallpaperInfo", +"android.app.SearchableInfo", +"android.app.LauncherActivity$IconResizer", +"android.app.FragmentController", +"android.app.Notification$Action$Builder", +"android.app.LauncherActivity$ListItem", +"android.app.FragmentTransaction", +"android.app.AlarmManager", +"android.app.FragmentBreadCrumbs$OnBreadCrumbClickListener", +"android.app.FragmentManager", +"android.app.AlarmManager$OnAlarmListener", +"android.app.Notification$DecoratedCustomViewStyle", +"android.app.SearchManager$OnCancelListener", +"android.app.Service", +"android.app.job.JobInfo", +"android.app.job.JobInfo$TriggerContentUri", +"android.app.job.JobService", +"android.app.job.JobWorkItem", +"android.app.job.JobInfo$Builder", +"android.app.job.JobServiceEngine", +"android.app.job.JobParameters", +"android.app.job.JobScheduler", +"android.app.NotificationManager$Policy", +"android.app.Person$Builder", +"android.app.WallpaperColors", +"android.app.AlertDialog", +"android.app.MediaRouteButton", +"android.app.Notification$DecoratedMediaCustomViewStyle", +"android.app.Notification$Extender", +"android.app.UiAutomation$OnAccessibilityEventListener", +"android.app.NativeActivity", +"android.app.PictureInPictureParams$Builder", +"android.app.FragmentBreadCrumbs", +"android.app.ActivityManager$RecentTaskInfo", +"android.app.ActionBar$OnMenuVisibilityListener", +"android.app.DownloadManager$Request", +"android.app.ActivityManager$RunningTaskInfo", +"android.app.UiModeManager", +"android.app.WallpaperManager$OnColorsChangedListener", +"android.app.Application$OnProvideAssistDataListener", +"android.app.Notification$MediaStyle", +"android.app.Notification$CarExtender$UnreadConversation", +"android.app.KeyguardManager$KeyguardLock", +"android.app.admin.SecurityLog", +"android.app.admin.DeviceAdminService", +"android.app.admin.DevicePolicyManager", +"android.app.admin.DnsEvent", +"android.app.admin.NetworkEvent", +"android.app.admin.ConnectEvent", +"android.app.admin.DeviceAdminReceiver", +"android.app.admin.SystemUpdateInfo", +"android.app.admin.SystemUpdatePolicy", + +"android.app.admin.DeviceAdminInfo", +"android.app.admin.DevicePolicyManager$OnClearApplicationUserDataListener", +"android.app.admin.SecurityLog$SecurityEvent", +"android.app.admin.FreezePeriod", +"android.app.Notification$BigTextStyle", +"android.app.ActionBar$LayoutParams", +"android.app.ListFragment", +"android.app.ListActivity", +"android.app.RemoteInput$Builder", +"android.app.backup.FileBackupHelper", +"android.app.backup.BackupDataInput", +"android.app.backup.FullBackupDataOutput", +"android.app.backup.BackupDataOutput", +"android.app.backup.BackupDataInputStream", +"android.app.backup.SharedPreferencesBackupHelper", +"android.app.backup.BackupAgentHelper", +"android.app.backup.BackupHelper", +"android.app.backup.RestoreObserver", +"android.app.backup.BackupAgent", +"android.app.backup.BackupManager", +"android.app.Instrumentation", +"android.app.AliasActivity", +"android.app.DatePickerDialog", +"android.app.ApplicationErrorReport", +"android.app.Notification$InboxStyle", +"android.app.slice.SliceProvider", +"android.app.slice.SliceManager", +"android.app.slice.Slice", +"android.app.slice.Slice$Builder", +"android.app.slice.SliceMetrics", +"android.app.slice.SliceSpec", +"android.app.slice.SliceItem", +"android.Manifest$permission", +"android.accessibilityservice.AccessibilityService$SoftKeyboardController$OnShowModeChangedListener", +"android.accessibilityservice.AccessibilityService", +"android.accessibilityservice.GestureDescription$Builder", +"android.accessibilityservice.AccessibilityService$MagnificationController$OnMagnificationChangedListener", +"android.accessibilityservice.AccessibilityService$SoftKeyboardController", +"android.accessibilityservice.FingerprintGestureController$FingerprintGestureCallback", +"android.accessibilityservice.AccessibilityService$GestureResultCallback", +"android.accessibilityservice.GestureDescription", +"android.accessibilityservice.FingerprintGestureController", +"android.accessibilityservice.AccessibilityServiceInfo", +"android.accessibilityservice.GestureDescription$StrokeDescription", +"android.accessibilityservice.AccessibilityButtonController$AccessibilityButtonCallback", +"android.accessibilityservice.AccessibilityService$MagnificationController", +"android.accessibilityservice.AccessibilityButtonController", +"android.R$xml", +"android.preference.PreferenceDataStore", +"android.preference.PreferenceActivity", +"android.preference.DialogPreference", +"android.preference.CheckBoxPreference", +"android.preference.PreferenceManager$OnActivityStopListener", +"android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback", +"android.preference.PreferenceFragment", +"android.preference.RingtonePreference", +"android.preference.Preference$OnPreferenceChangeListener", +"android.preference.PreferenceActivity$Header", +"android.preference.PreferenceCategory", +"android.preference.PreferenceGroup", +"android.preference.PreferenceScreen", +"android.preference.EditTextPreference", +"android.preference.Preference$BaseSavedState", +"android.preference.TwoStatePreference", +"android.preference.SwitchPreference", +"android.preference.PreferenceManager$OnActivityDestroyListener", +"android.preference.ListPreference", +"android.preference.Preference", +"android.preference.Preference$OnPreferenceClickListener", +"android.preference.MultiSelectListPreference", +"android.preference.PreferenceManager$OnActivityResultListener", +"android.preference.PreferenceManager", + +"android.accounts.Account", +"android.accounts.AccountManager", + +"android.accounts.AccountAuthenticatorActivity", +"android.accounts.AccountManagerFuture", +"android.accounts.OnAccountsUpdateListener", +"android.accounts.AccountManagerCallback", +"android.accounts.AccountAuthenticatorResponse", + + +"android.accounts.AuthenticatorDescription", + +"android.provider.ContactsContract$DataColumnsWithJoins", +"android.provider.Contacts$Intents$Insert", +"android.provider.ContactsContract$PhoneticNameStyle", +"android.provider.CalendarContract$CalendarCacheColumns", +"android.provider.Contacts$OrganizationColumns", +"android.provider.Telephony$Sms$Conversations", +"android.provider.MediaStore$Video$VideoColumns", +"android.provider.ContactsContract$Contacts$Data", +"android.provider.SyncStateContract$Helpers", +"android.provider.ContactsContract$QuickContact", +"android.provider.Contacts$Intents", +"android.provider.Contacts$Settings", +"android.provider.CalendarContract$EventsEntity", +"android.provider.ContactsContract$Presence", +"android.provider.Settings$System", +"android.provider.ContactsContract$Settings", +"android.provider.ContactsContract$SyncColumns", +"android.provider.ContactsContract$RawContacts", +"android.provider.MediaStore$Files", +"android.provider.SyncStateContract$Constants", +"android.provider.ContactsContract$DataUsageStatColumns", +"android.provider.UserDictionary$Words", +"android.provider.ContactsContract$CommonDataKinds$Contactables", +"android.provider.MediaStore$Audio$Playlists$Members", +"android.provider.CalendarContract$SyncState", +"android.provider.ContactsContract$Directory", +"android.provider.OpenableColumns", +"android.provider.ContactsContract$CommonDataKinds$Callable", +"android.provider.ContactsContract$CommonDataKinds", +"android.provider.Contacts$People$Phones", +"android.provider.Telephony$ServiceStateTable", +"android.provider.ContactsContract$ContactsColumns", +"android.provider.VoicemailContract$Status", +"android.provider.MediaStore$Audio$ArtistColumns", +"android.provider.Telephony$TextBasedSmsColumns", + +"android.provider.Contacts$PhonesColumns", +"android.provider.Contacts$GroupMembership", +"android.provider.FontsContract$FontInfo", +"android.provider.Contacts$People$Extensions", +"android.provider.Settings", +"android.provider.MediaStore$Audio$Radio", +"android.provider.Telephony$Sms$Outbox", +"android.provider.ContactsContract$CommonDataKinds$CommonColumns", +"android.provider.CalendarContract$ColorsColumns", +"android.provider.ContactsContract$Contacts", +"android.provider.CalendarContract$EventDaysColumns", +"android.provider.Telephony$Mms$Addr", +"android.provider.ContactsContract$ContactOptionsColumns", +"android.provider.Contacts$Groups", +"android.provider.ContactsContract$RawContacts$Data", +"android.provider.BlockedNumberContract$BlockedNumbers", +"android.provider.ContactsContract$Groups", +"android.provider.Contacts$PeopleColumns", +"android.provider.DocumentsContract$Path", +"android.provider.ContactsContract$Data", +"android.provider.Telephony$Sms$Inbox", +"android.provider.AlarmClock", +"android.provider.ContactsContract$CommonDataKinds$GroupMembership", +"android.provider.ContactsContract$DisplayPhoto", +"android.provider.ContactsContract$CommonDataKinds$Im", +"android.provider.BaseColumns", +"android.provider.SearchRecentSuggestions", +"android.provider.Telephony$Sms", +"android.provider.CalendarContract", +"android.provider.ContactsContract$CommonDataKinds$BaseTypes", +"android.provider.MediaStore$Video$Media", +"android.provider.VoicemailContract$Voicemails", +"android.provider.FontsContract$Columns", +"android.provider.MediaStore$Audio$Genres$Members", +"android.provider.MediaStore$Audio$Artists", +"android.provider.MediaStore$MediaColumns", +"android.provider.ContactsContract$Contacts$AggregationSuggestions$Builder", +"android.provider.ContactsContract$CommonDataKinds$Nickname", +"android.provider.Contacts$ExtensionsColumns", +"android.provider.CalendarContract$CalendarEntity", +"android.provider.MediaStore$Audio$AudioColumns", +"android.provider.Telephony$Mms$Rate", +"android.provider.CalendarContract$RemindersColumns", +"android.provider.DocumentsContract$Document", +"android.provider.MediaStore$Images$ImageColumns", +"android.provider.CalendarContract$Instances", +"android.provider.UserDictionary", +"android.provider.ContactsContract$Intents", +"android.provider.Telephony$CarrierId", +"android.provider.ContactsContract$RawContactsEntity", +"android.provider.Contacts$Intents$UI", +"android.provider.MediaStore", +"android.provider.ContactsContract$CommonDataKinds$Note", +"android.provider.ContactsContract$Contacts$Entity", +"android.provider.Contacts$Organizations", +"android.provider.ContactsContract$RawContacts$Entity", +"android.provider.ContactsContract$CommonDataKinds$Organization", +"android.provider.CalendarContract$Reminders", +"android.provider.CallLog$Calls", +"android.provider.ContactsContract$StatusColumns", +"android.provider.ContactsContract$CommonDataKinds$Email", +"android.provider.CalendarContract$CalendarSyncColumns", + +"android.provider.ContactsContract$ContactStatusColumns", +"android.provider.FontsContract", +"android.provider.Telephony$Mms$Inbox", +"android.provider.CalendarContract$Attendees", +"android.provider.ContactsContract$CommonDataKinds$StructuredPostal", +"android.provider.ContactsContract$DisplayNameSources", +"android.provider.ContactsContract$CommonDataKinds$Event", +"android.provider.Telephony$Sms$Intents", +"android.provider.CalendarContract$Events", +"android.provider.Telephony$Sms$Sent", +"android.provider.FontRequest", +"android.provider.ContactsContract$CommonDataKinds$Website", +"android.provider.CalendarContract$CalendarAlerts", +"android.provider.ContactsContract$CommonDataKinds$SipAddress", +"android.provider.Telephony$Sms$Draft", +"android.provider.Telephony$Mms$Sent", +"android.provider.SyncStateContract$Columns", +"android.provider.ContactsContract$PhoneLookupColumns", +"android.provider.Contacts$Extensions", +"android.provider.MediaStore$Video$Thumbnails", +"android.provider.MediaStore$Images$Thumbnails", +"android.provider.ContactsContract$DeletedContactsColumns", +"android.provider.CalendarContract$Calendars", +"android.provider.SyncStateContract", +"android.provider.ContactsContract$GroupsColumns", +"android.provider.Contacts$Phones", +"android.provider.ContactsContract$SearchSnippets", +"android.provider.Contacts", +"android.provider.Telephony$Mms$Draft", +"android.provider.Contacts$PhotosColumns", +"android.provider.MediaStore$Audio", +"android.provider.MediaStore$Audio$Albums", +"android.provider.Settings$Global", +"android.provider.ContactsContract$ProfileSyncState", +"android.provider.ContactsContract$FullNameStyle", +"android.provider.Telephony$MmsSms", +"android.provider.ContactsContract$RawContacts$DisplayPhoto", +"android.provider.CalendarContract$ExtendedPropertiesColumns", +"android.provider.Settings$Secure", +"android.provider.FontsContract$FontFamilyResult", +"android.provider.MediaStore$Files$FileColumns", +"android.provider.MediaStore$Video", +"android.provider.BlockedNumberContract", +"android.provider.Telephony$Mms$Intents", +"android.provider.MediaStore$Audio$Genres", +"android.provider.ContactsContract$ProviderStatus", +"android.provider.CalendarContract$Colors", +"android.provider.ContactsContract$Contacts$Photo", +"android.provider.MediaStore$Audio$GenresColumns", +"android.provider.ContactsContract$CommonDataKinds$Phone", +"android.provider.SettingsSlicesContract", +"android.provider.Telephony$Threads", +"android.provider.Contacts$SettingsColumns", +"android.provider.CalendarContract$CalendarColumns", +"android.provider.CalendarContract$CalendarCache", +"android.provider.CalendarContract$EventsColumns", +"android.provider.Telephony", +"android.provider.ContactsContract$CommonDataKinds$StructuredName", +"android.provider.Telephony$BaseMmsColumns", +"android.provider.MediaStore$Audio$Artists$Albums", +"android.provider.Contacts$People$ContactMethods", +"android.provider.ContactsContract$PresenceColumns", +"android.provider.ContactsContract$PhoneLookup", +"android.provider.VoicemailContract", +"android.provider.MediaStore$Images", +"android.provider.DocumentsContract", +"android.provider.LiveFolders", +"android.provider.ContactsContract$ContactNameColumns", +"android.provider.MediaStore$Audio$Playlists", +"android.provider.Settings$NameValueTable", +"android.provider.ContactsContract$SyncState", +"android.provider.ContactsContract$DataUsageFeedback", +"android.provider.ContactsContract$DataColumns", +"android.provider.ContactsContract", +"android.provider.Contacts$ContactMethods", +"android.provider.ContactsContract$Intents$Insert", +"android.provider.DocumentsContract$Root", +"android.provider.ContactsContract$RawContactsColumns", +"android.provider.Contacts$GroupsColumns", +"android.provider.ContactsContract$DeletedContacts", +"android.provider.Contacts$ContactMethodsColumns", +"android.provider.ContactsContract$CommonDataKinds$Relation", +"android.provider.CalendarContract$ExtendedProperties", +"android.provider.Telephony$ThreadsColumns", +"android.provider.ContactsContract$Contacts$AggregationSuggestions", +"android.provider.FontsContract$FontRequestCallback", +"android.provider.Browser", +"android.provider.ContactsContract$StatusUpdates", +"android.provider.ContactsContract$Profile", +"android.provider.Telephony$Mms", +"android.provider.ContactsContract$SettingsColumns", +"android.provider.CalendarContract$AttendeesColumns", +"android.provider.ContactsContract$PinnedPositions", +"android.provider.DocumentsProvider", +"android.provider.ContactsContract$BaseSyncColumns", +"android.provider.MediaStore$Audio$PlaylistsColumns", +"android.provider.Telephony$Carriers", +"android.provider.CalendarContract$SyncColumns", +"android.provider.CalendarContract$EventDays", +"android.provider.Contacts$People", +"android.provider.Telephony$CanonicalAddressesColumns", +"android.provider.ContactsContract$CommonDataKinds$Identity", +"android.provider.Telephony$Mms$Part", +"android.provider.Telephony$MmsSms$PendingMessages", +"android.provider.CalendarContract$CalendarAlertsColumns", +"android.provider.MediaStore$Images$Media", +"android.provider.Contacts$Photos", +"android.provider.ContactsContract$CommonDataKinds$Photo", +"android.provider.MediaStore$Audio$Media", +"android.provider.Telephony$Mms$Outbox", +"android.provider.CallLog", +"android.provider.Contacts$PresenceColumns", +"android.provider.MediaStore$Audio$AlbumColumns", +"android.os.StrictMode$ThreadPolicy$Builder", +"android.os.MessageQueue", +"android.os.Trace", +"android.os.Parcelable$ClassLoaderCreator", +"android.os.IInterface", +"android.os.RecoverySystem", +"android.os.ParcelFileDescriptor$AutoCloseInputStream", +"android.os.StrictMode", +"android.os.Bundle", +"android.os.AsyncTask", +"android.os.VibrationEffect", +"android.os.DropBoxManager$Entry", +"android.os.Debug$MemoryInfo", +"android.os.Vibrator", +"android.os.HandlerThread", + +"android.os.StatFs", +"android.os.Parcelable$Creator", +"android.os.PowerManager$WakeLock", +"android.os.StrictMode$VmPolicy$Builder", +"android.os.ResultReceiver", +"android.os.FileObserver", +"android.os.PersistableBundle", +"android.os.IBinder$DeathRecipient", +"android.os.MessageQueue$OnFileDescriptorEventListener", +"android.os.StrictMode$OnThreadViolationListener", +"android.os.BatteryManager", +"android.os.Debug", + + +"android.os.Message", +"android.os.Messenger", +"android.os.Build$VERSION", +"android.os.UserManager", +"android.os.Debug$InstructionCount", +"android.os.CountDownTimer", +"android.os.Binder", +"android.os.Environment", +"android.os.storage.StorageManager", +"android.os.storage.OnObbStateChangeListener", +"android.os.storage.StorageVolume", +"android.os.WorkSource", +"android.os.RecoverySystem$ProgressListener", +"android.os.HardwarePropertiesManager", +"android.os.StrictMode$VmPolicy", +"android.os.Process", +"android.os.ParcelUuid", +"android.os.BaseBundle", + +"android.os.Looper", +"android.os.TokenWatcher", +"android.os.ParcelFileDescriptor", +"android.os.ParcelFileDescriptor$OnCloseListener", +"android.os.Parcel", +"android.os.PowerManager", +"android.os.MessageQueue$IdleHandler", + +"android.os.StrictMode$OnVmViolationListener", +"android.os.CancellationSignal$OnCancelListener", +"android.os.PatternMatcher", + +"android.os.Build$VERSION_CODES", +"android.os.CpuUsageInfo", +"android.os.Handler", +"android.os.ParcelFileDescriptor$AutoCloseOutputStream", +"android.os.StrictMode$ThreadPolicy", +"android.os.ProxyFileDescriptorCallback", +"android.os.health.HealthStats", +"android.os.health.ProcessHealthStats", +"android.os.health.UidHealthStats", +"android.os.health.TimerStat", +"android.os.health.SystemHealthManager", +"android.os.health.PidHealthStats", +"android.os.health.PackageHealthStats", +"android.os.health.ServiceHealthStats", +"android.os.SharedMemory", +"android.os.Handler$Callback", + +"android.os.ConditionVariable", + +"android.os.RemoteCallbackList", +"android.os.strictmode.WebViewMethodCalledOnWrongThreadViolation", +"android.os.strictmode.NonSdkApiUsedViolation", +"android.os.strictmode.LeakedClosableViolation", +"android.os.strictmode.DiskReadViolation", +"android.os.strictmode.NetworkViolation", +"android.os.strictmode.ContentUriWithoutPermissionViolation", +"android.os.strictmode.CleartextNetworkViolation", +"android.os.strictmode.InstanceCountViolation", +"android.os.strictmode.SqliteObjectLeakedViolation", +"android.os.strictmode.Violation", +"android.os.strictmode.ResourceMismatchViolation", +"android.os.strictmode.DiskWriteViolation", +"android.os.strictmode.UntaggedSocketViolation", +"android.os.strictmode.UnbufferedIoViolation", +"android.os.strictmode.ServiceConnectionLeakedViolation", +"android.os.strictmode.CustomViolation", +"android.os.strictmode.FileUriExposedViolation", +"android.os.strictmode.IntentReceiverLeakedViolation", + +"android.os.TestLooperManager", +"android.os.AsyncTask$Status", +"android.os.IBinder", +"android.os.UserHandle", + +"android.os.LocaleList", +"android.os.Build", +"android.os.DropBoxManager", +"android.os.MemoryFile", +"android.os.CancellationSignal", +"android.os.SystemClock", +"android.os.Parcelable", + +"android.R$fraction", +"android.system.StructStatVfs", +"android.system.OsConstants", + +"android.system.Os", +"android.system.StructUtsname", +"android.system.Int64Ref", +"android.system.StructPollfd", +"android.system.StructStat", +"android.system.StructTimespec", +"android.R$array", +"android.printservice.PrintService", +"android.printservice.CustomPrinterIconCallback", +"android.printservice.PrintDocument", +"android.printservice.PrinterDiscoverySession", +"android.printservice.PrintJob", +"android.R$layout", +"android.content.DialogInterface$OnCancelListener", +"android.content.SyncResult", +"android.content.DialogInterface$OnShowListener", +"android.content.ContentProviderOperation$Builder", +"android.content.DialogInterface$OnClickListener", +"android.content.BroadcastReceiver", +"android.content.DialogInterface$OnDismissListener", +"android.content.ContentProvider$PipeDataWriter", +"android.content.pm.ServiceInfo", +"android.content.pm.LabeledIntent", +"android.content.pm.FeatureInfo", +"android.content.pm.ApplicationInfo", +"android.content.pm.ShortcutInfo", +"android.content.pm.PackageInfo", +"android.content.pm.CrossProfileApps", +"android.content.pm.PackageInstaller$SessionParams", +"android.content.pm.PermissionInfo", +"android.content.pm.ActivityInfo$WindowLayout", +"android.content.pm.PackageStats", +"android.content.pm.PackageInstaller$Session", +"android.content.pm.ApplicationInfo$DisplayNameComparator", + +"android.content.pm.ChangedPackages", +"android.content.pm.Signature", +"android.content.pm.PackageManager", +"android.content.pm.PackageInstaller$SessionInfo", +"android.content.pm.FeatureGroupInfo", +"android.content.pm.ProviderInfo", +"android.content.pm.ShortcutInfo$Builder", +"android.content.pm.PackageItemInfo", +"android.content.pm.ComponentInfo", +"android.content.pm.LauncherApps$ShortcutQuery", +"android.content.pm.VersionedPackage", +"android.content.pm.SharedLibraryInfo", +"android.content.pm.LauncherApps", +"android.content.pm.PathPermission", +"android.content.pm.PackageInstaller$SessionCallback", +"android.content.pm.LauncherActivityInfo", +"android.content.pm.ResolveInfo", +"android.content.pm.SigningInfo", +"android.content.pm.InstrumentationInfo", +"android.content.pm.PermissionGroupInfo", +"android.content.pm.ConfigurationInfo", +"android.content.pm.PackageItemInfo$DisplayNameComparator", +"android.content.pm.ActivityInfo", +"android.content.pm.ResolveInfo$DisplayNameComparator", +"android.content.pm.LauncherApps$PinItemRequest", +"android.content.pm.PackageInstaller", +"android.content.pm.LauncherApps$Callback", +"android.content.pm.ShortcutManager", +"android.content.ContentProviderResult", +"android.content.ClipData$Item", +"android.content.Entity$NamedContentValues", +"android.content.SyncStats", +"android.content.SyncInfo", + +"android.content.ComponentName", +"android.content.IntentSender$OnFinished", +"android.content.ContextWrapper", +"android.content.BroadcastReceiver$PendingResult", +"android.content.IntentFilter$AuthorityEntry", +"android.content.ContentProvider", +"android.content.ClipboardManager$OnPrimaryClipChangedListener", +"android.content.CursorLoader", +"android.content.DialogInterface$OnKeyListener", +"android.content.ContentProviderClient", +"android.content.UriPermission", +"android.content.SyncAdapterType", +"android.content.IntentSender", +"android.content.DialogInterface", +"android.content.DialogInterface$OnMultiChoiceClickListener", +"android.content.Entity", +"android.content.SyncRequest", +"android.content.ContentValues", +"android.content.Context", +"android.content.ContentProviderOperation", +"android.content.UriMatcher", +"android.content.SyncRequest$Builder", +"android.content.ContentQueryMap", +"android.content.ContentResolver", +"android.content.RestrictionsManager", +"android.content.EntityIterator", + +"android.content.Loader$ForceLoadContentObserver", +"android.content.AsyncQueryHandler$WorkerArgs", +"android.content.Loader", +"android.content.ContentUris", +"android.content.ClipboardManager", +"android.content.QuickViewConstants", +"android.content.AsyncQueryHandler", +"android.content.ComponentCallbacks", + +"android.content.SharedPreferences", +"android.content.ClipData", +"android.content.AsyncQueryHandler$WorkerHandler", +"android.content.MutableContextWrapper", +"android.content.PeriodicSync", +"android.content.Loader$OnLoadCanceledListener", +"android.content.SyncContext", + +"android.content.ClipDescription", +"android.content.ComponentCallbacks2", +"android.content.Intent$ShortcutIconResource", +"android.content.RestrictionEntry", +"android.content.ServiceConnection", +"android.content.Intent$FilterComparison", +"android.content.IntentFilter", +"android.content.SearchRecentSuggestionsProvider", +"android.content.SharedPreferences$Editor", +"android.content.Intent", +"android.content.Loader$OnLoadCompleteListener", +"android.content.res.ColorStateList", +"android.content.res.XmlResourceParser", +"android.content.res.ObbScanner", +"android.content.res.AssetFileDescriptor$AutoCloseInputStream", +"android.content.res.Configuration", +"android.content.res.AssetFileDescriptor", +"android.content.res.ObbInfo", +"android.content.res.AssetManager$AssetInputStream", +"android.content.res.AssetManager", +"android.content.res.Resources$Theme", +"android.content.res.AssetFileDescriptor$AutoCloseOutputStream", +"android.content.res.Resources", + +"android.content.res.TypedArray", +"android.content.SyncStatusObserver", + + +"android.content.AsyncTaskLoader", +"android.content.SharedPreferences$OnSharedPreferenceChangeListener", +"android.R$anim", +"android.R$dimen", +"android.drm.DrmErrorEvent", +"android.drm.DrmManagerClient$OnInfoListener", +"android.drm.DrmEvent", +"android.drm.DrmManagerClient", +"android.drm.DrmStore$RightsStatus", +"android.drm.DrmUtils", +"android.drm.DrmInfoStatus", +"android.drm.DrmStore$DrmObjectType", +"android.drm.DrmManagerClient$OnEventListener", +"android.drm.DrmStore$Action", +"android.drm.DrmStore$Playback", +"android.drm.DrmInfoEvent", +"android.drm.DrmStore", +"android.drm.DrmConvertedStatus", +"android.drm.DrmStore$ConstraintsColumns", +"android.drm.DrmInfo", +"android.drm.ProcessedData", +"android.drm.DrmUtils$ExtendedMetadataParser", +"android.drm.DrmInfoRequest", +"android.drm.DrmRights", +"android.drm.DrmSupportInfo", +"android.drm.DrmManagerClient$OnErrorListener", +"android.util.MutableChar", +"android.util.FloatProperty", +"android.util.Base64InputStream", +"android.util.ArrayMap", +"android.util.JsonWriter", +"android.util.Patterns", +"android.util.Xml", +"android.util.TimeUtils", +"android.util.EventLogTags", +"android.util.FloatMath", +"android.util.MutableShort", +"android.util.LruCache", +"android.util.MutableBoolean", +"android.util.SizeF", + +"android.util.StateSet", +"android.util.Printer", +"android.util.Base64", +"android.util.MutableLong", +"android.util.LogPrinter", +"android.util.ArraySet", +"android.util.StatsLog", +"android.util.LongSparseArray", +"android.util.Config", +"android.util.JsonReader", +"android.util.DisplayMetrics", +"android.util.MutableFloat", +"android.util.MutableInt", +"android.util.Range", +"android.util.IntProperty", +"android.util.JsonToken", +"android.util.EventLog", +"android.util.AttributeSet", +"android.util.Base64OutputStream", +"android.util.PrintWriterPrinter", + +"android.util.EventLog$Event", +"android.util.Property", +"android.util.Pair", +"android.util.SparseLongArray", +"android.util.MonthDisplayHelper", +"android.util.SparseArray", +"android.util.Half", +"android.util.MutableDouble", +"android.util.StringBuilderPrinter", +"android.util.Xml$Encoding", +"android.util.PrintStreamPrinter", +"android.util.Log", +"android.util.Size", + +"android.util.EventLogTags$Description", +"android.util.Rational", + +"android.util.MutableByte", +"android.util.TypedValue", +"android.util.SparseIntArray", +"android.util.DebugUtils", +"android.util.AtomicFile", +"android.util.LayoutDirection", + +"android.util.SparseBooleanArray", + +"android.util.TimingLogger", +"android.print.PrintAttributes$Resolution", +"android.print.PrintJobInfo$Builder", +"android.print.PrinterCapabilitiesInfo$Builder", +"android.print.PrintJobInfo", +"android.print.PrinterInfo", +"android.print.PrinterId", +"android.print.PrintDocumentAdapter", +"android.print.PrintDocumentInfo$Builder", +"android.print.PrintDocumentAdapter$LayoutResultCallback", +"android.print.PrintAttributes$Margins", +"android.print.PrinterInfo$Builder", +"android.print.PageRange", +"android.print.PrintManager", +"android.print.PrintAttributes$MediaSize", +"android.print.PrinterCapabilitiesInfo", +"android.print.pdf.PrintedPdfDocument", +"android.print.PrintJob", +"android.print.PrintJobId", +"android.print.PrintDocumentAdapter$WriteResultCallback", +"android.print.PrintAttributes", +"android.print.PrintAttributes$Builder", +"android.print.PrintDocumentInfo", +"android.media.FaceDetector$Face", +"android.media.MediaPlayer$OnCompletionListener", + +"android.media.MediaScannerConnection$OnScanCompletedListener", +"android.media.MediaTimestamp", +"android.media.ImageWriter", + +"android.media.VolumeAutomation", +"android.media.AudioManager", + +"android.media.browse.MediaBrowser$MediaItem", +"android.media.browse.MediaBrowser$SubscriptionCallback", +"android.media.browse.MediaBrowser$ItemCallback", +"android.media.browse.MediaBrowser$ConnectionCallback", +"android.media.browse.MediaBrowser", +"android.media.AudioTrack$OnRoutingChangedListener", +"android.media.Ringtone", +"android.media.MediaDrm$HdcpLevel", +"android.media.AudioTrack$MetricsConstants", +"android.media.MediaPlayer$MetricsConstants", +"android.media.MediaCodec$MetricsConstants", +"android.media.ImageWriter$OnImageReleasedListener", +"android.media.MediaMetadata", +"android.media.MediaSync$OnErrorListener", +"android.media.MediaRouter$VolumeCallback", + +"android.media.RemoteControlClient$OnGetPlaybackPositionListener", +"android.media.MediaPlayer$OnVideoSizeChangedListener", + +"android.media.session.MediaSession$Callback", +"android.media.session.MediaSession$QueueItem", +"android.media.session.MediaController$TransportControls", +"android.media.session.MediaSession$Token", +"android.media.session.PlaybackState$CustomAction$Builder", +"android.media.session.MediaSessionManager", +"android.media.session.PlaybackState", +"android.media.session.MediaController", +"android.media.session.MediaSessionManager$RemoteUserInfo", +"android.media.session.PlaybackState$CustomAction", +"android.media.session.MediaSessionManager$OnActiveSessionsChangedListener", +"android.media.session.PlaybackState$Builder", +"android.media.session.MediaController$PlaybackInfo", +"android.media.session.MediaController$Callback", +"android.media.session.MediaSession", +"android.media.AudioAttributes", +"android.media.AudioFocusRequest", +"android.media.MediaDrm$OnExpirationUpdateListener", +"android.media.MediaCas$EventListener", +"android.media.MediaSyncEvent", +"android.media.RemoteControlClient$OnPlaybackPositionUpdateListener", +"android.media.RemoteController$MetadataEditor", +"android.media.MediaCodecInfo$EncoderCapabilities", +"android.media.ImageReader", +"android.media.ThumbnailUtils", +"android.media.CameraProfile", +"android.media.AudioFormat$Builder", +"android.media.MediaPlayer$OnErrorListener", +"android.media.AudioDeviceCallback", +"android.media.AudioAttributes$Builder", + +"android.media.DrmInitData$SchemeInitData", +"android.media.MediaFormat", +"android.media.RemoteControlClient", +"android.media.MediaCrypto", + +"android.media.MediaCodecInfo$VideoCapabilities", +"android.media.MediaCodecList", +"android.media.AsyncPlayer", +"android.media.MicrophoneInfo", +"android.media.AudioRecord$OnRecordPositionUpdateListener", +"android.media.TimedMetaData", +"android.media.MediaRecorder$OnErrorListener", +"android.media.MediaPlayer$OnSubtitleDataListener", +"android.media.MediaDrm$SecurityLevel", +"android.media.MediaCodecInfo$CodecProfileLevel", +"android.media.MediaPlayer$OnPreparedListener", + +"android.media.SubtitleData", +"android.media.effect.EffectContext", +"android.media.effect.EffectUpdateListener", +"android.media.effect.Effect", +"android.media.effect.EffectFactory", +"android.media.VolumeShaper", +"android.media.ImageReader$OnImageAvailableListener", +"android.media.MediaPlayer$OnDrmInfoListener", +"android.media.MediaScannerConnection", +"android.media.AudioTrack$OnPlaybackPositionUpdateListener", +"android.media.MediaRecorder$AudioEncoder", +"android.media.AudioTimestamp", +"android.media.AudioRecord", + +"android.media.AudioTrack", +"android.media.AudioPlaybackConfiguration", +"android.media.MediaMetadata$Builder", +"android.media.tv.TvContract$Channels", +"android.media.tv.TvTrackInfo$Builder", +"android.media.tv.TvContract$Programs", +"android.media.tv.TvInputManager$TvInputCallback", +"android.media.tv.TvContract$WatchNextPrograms", +"android.media.tv.TvView$OnUnhandledInputEventListener", +"android.media.tv.TvContract$Programs$Genres", +"android.media.tv.TvContract$RecordedPrograms", +"android.media.tv.TvView$TimeShiftPositionCallback", +"android.media.tv.TvInputInfo", +"android.media.tv.TvTrackInfo", +"android.media.tv.TvContract$PreviewPrograms", +"android.media.tv.TvView", +"android.media.tv.TvContract$BaseTvColumns", +"android.media.tv.TvRecordingClient", +"android.media.tv.TvView$TvInputCallback", +"android.media.tv.TvInputInfo$Builder", +"android.media.tv.TvInputManager", +"android.media.tv.TvInputService$HardwareSession", +"android.media.tv.TvContract", +"android.media.tv.TvInputService$RecordingSession", +"android.media.tv.TvRecordingClient$RecordingCallback", +"android.media.tv.TvInputService$Session", +"android.media.tv.TvContract$Channels$Logo", +"android.media.tv.TvInputService", +"android.media.tv.TvContentRating", +"android.media.MediaPlayer$OnDrmPreparedListener", +"android.media.MediaExtractor", +"android.media.MediaPlayer", +"android.media.MediaRecorder", +"android.media.MediaRouter$RouteInfo", +"android.media.projection.MediaProjectionManager", +"android.media.projection.MediaProjection", +"android.media.projection.MediaProjection$Callback", +"android.media.MediaPlayer$TrackInfo", +"android.media.RemoteControlClient$OnMetadataUpdateListener", +"android.media.MediaRecorder$VideoEncoder", +"android.media.Rating", +"android.media.AudioRouting$OnRoutingChangedListener", +"android.media.MediaPlayer$OnSeekCompleteListener", +"android.media.RemoteController", + +"android.media.AudioDeviceInfo", + +"android.media.MediaCodec$Callback", +"android.media.AudioManager$AudioRecordingCallback", +"android.media.MediaSync", +"android.media.MediaMuxer", +"android.media.SoundPool", +"android.media.DrmInitData", + +"android.media.MicrophoneInfo$Coordinate3F", +"android.media.AudioFormat", +"android.media.MediaCodec$BufferInfo", + +"android.media.FaceDetector", + +"android.media.MediaMetadataRetriever$BitmapParams", +"android.media.MediaDescription", +"android.media.MediaCodec", +"android.media.MediaExtractor$CasInfo", +"android.media.Image$Plane", +"android.media.AudioRecord$MetricsConstants", +"android.media.SoundPool$Builder", +"android.media.ExifInterface", +"android.media.VolumeShaper$Configuration$Builder", +"android.media.RemoteControlClient$MetadataEditor", +"android.media.AudioManager$OnAudioFocusChangeListener", +"android.media.MediaMetadataRetriever", +"android.media.MediaSync$Callback", +"android.media.VolumeShaper$Operation", +"android.media.MediaMetadataEditor", +"android.media.MediaPlayer$DrmInfo", +"android.media.MediaPlayer$OnBufferingUpdateListener", +"android.media.RemoteController$OnClientUpdateListener", +"android.media.MediaPlayer$OnMediaTimeDiscontinuityListener", +"android.media.SoundPool$OnLoadCompleteListener", +"android.media.AudioPresentation", +"android.media.MediaRecorder$OutputFormat", +"android.media.MediaMuxer$OutputFormat", +"android.media.MediaDescription$Builder", +"android.media.MediaDescrambler", +"android.media.MediaCodec$CryptoInfo$Pattern", +"android.media.MediaDrm$OnEventListener", +"android.media.MediaCodec$CryptoInfo", +"android.media.MediaDrm$KeyStatus", +"android.media.MediaCas", +"android.media.MediaRouter$RouteGroup", +"android.media.MediaPlayer$OnTimedTextListener", +"android.media.TimedText", +"android.media.MediaDrm$KeyRequest", +"android.media.JetPlayer$OnJetEventListener", +"android.media.RingtoneManager", +"android.media.MediaCodec$OnFrameRenderedListener", +"android.media.AudioRouting", + +"android.media.MediaDrm$ProvisionRequest", +"android.media.MediaDrm$MetricsConstants", +"android.media.MediaDrm", +"android.media.AudioFocusRequest$Builder", +"android.media.Image", +"android.media.MediaPlayer$OnDrmConfigHelper", +"android.media.PlaybackParams", +"android.media.MediaDrm$CryptoSession", +"android.media.MediaDrm$OnKeyStatusChangeListener", + +"android.media.MediaScannerConnection$MediaScannerConnectionClient", +"android.media.MediaCas$PluginDescriptor", +"android.media.AudioManager$AudioPlaybackCallback", + +"android.media.midi.MidiOutputPort", +"android.media.midi.MidiManager", +"android.media.midi.MidiDeviceStatus", +"android.media.midi.MidiManager$DeviceCallback", +"android.media.midi.MidiDevice$MidiConnection", +"android.media.midi.MidiDevice", +"android.media.midi.MidiSender", +"android.media.midi.MidiManager$OnDeviceOpenedListener", +"android.media.midi.MidiReceiver", +"android.media.midi.MidiDeviceInfo$PortInfo", +"android.media.midi.MidiDeviceService", +"android.media.midi.MidiDeviceInfo", +"android.media.midi.MidiInputPort", +"android.media.AudioRecord$Builder", +"android.media.MediaDataSource", +"android.media.MediaActionSound", +"android.media.MediaRecorder$MetricsConstants", +"android.media.SyncParams", +"android.media.CamcorderProfile", +"android.media.MediaPlayer$OnTimedMetaDataAvailableListener", +"android.media.JetPlayer", +"android.media.AudioRecordingConfiguration", +"android.media.MediaRouter$RouteCategory", +"android.media.VolumeProvider", +"android.media.AudioTrack$Builder", +"android.media.MediaRecorder$AudioSource", + +"android.media.MediaExtractor$MetricsConstants", +"android.media.VolumeShaper$Configuration", +"android.media.MediaRouter$SimpleCallback", +"android.media.MediaRouter$UserRouteInfo", +"android.media.ToneGenerator", +"android.media.AudioRecord$OnRoutingChangedListener", +"android.media.MediaRouter$Callback", +"android.media.MediaRecorder$VideoSource", +"android.media.MediaRecorder$OnInfoListener", +"android.media.MediaCodecInfo", +"android.media.MediaRouter", +"android.media.MediaCodecInfo$AudioCapabilities", + +"android.media.MediaPlayer$OnInfoListener", +"android.media.audiofx.AudioEffect$OnEnableStatusChangeListener", +"android.media.audiofx.DynamicsProcessing$Channel", +"android.media.audiofx.Visualizer$OnDataCaptureListener", +"android.media.audiofx.BassBoost", +"android.media.audiofx.Virtualizer$OnParameterChangeListener", +"android.media.audiofx.DynamicsProcessing$Config", +"android.media.audiofx.PresetReverb", +"android.media.audiofx.DynamicsProcessing$MbcBand", +"android.media.audiofx.Virtualizer", +"android.media.audiofx.Equalizer$Settings", +"android.media.audiofx.Visualizer", +"android.media.audiofx.DynamicsProcessing$BandBase", +"android.media.audiofx.DynamicsProcessing$Limiter", +"android.media.audiofx.EnvironmentalReverb$Settings", +"android.media.audiofx.BassBoost$Settings", +"android.media.audiofx.AudioEffect$OnControlStatusChangeListener", +"android.media.audiofx.DynamicsProcessing$Config$Builder", +"android.media.audiofx.AudioEffect", +"android.media.audiofx.DynamicsProcessing$Eq", +"android.media.audiofx.EnvironmentalReverb$OnParameterChangeListener", +"android.media.audiofx.Equalizer$OnParameterChangeListener", +"android.media.audiofx.BassBoost$OnParameterChangeListener", +"android.media.audiofx.DynamicsProcessing$Mbc", +"android.media.audiofx.LoudnessEnhancer", +"android.media.audiofx.DynamicsProcessing$Stage", +"android.media.audiofx.AcousticEchoCanceler", +"android.media.audiofx.AudioEffect$Descriptor", +"android.media.audiofx.Equalizer", +"android.media.audiofx.DynamicsProcessing$BandStage", +"android.media.audiofx.PresetReverb$Settings", +"android.media.audiofx.Virtualizer$Settings", +"android.media.audiofx.AutomaticGainControl", +"android.media.audiofx.Visualizer$MeasurementPeakRms", +"android.media.audiofx.DynamicsProcessing$EqBand", +"android.media.audiofx.DynamicsProcessing", +"android.media.audiofx.PresetReverb$OnParameterChangeListener", +"android.media.audiofx.NoiseSuppressor", +"android.media.audiofx.EnvironmentalReverb", +"android.media.MediaCas$Session", +"android.media.MediaCodecInfo$CodecCapabilities", +"android.R$integer", +"android.graphics.Bitmap$Config", +"android.graphics.ImageDecoder$Source", +"android.graphics.SurfaceTexture$OnFrameAvailableListener", +"android.graphics.CornerPathEffect", +"android.graphics.MaskFilter", +"android.graphics.Shader$TileMode", +"android.graphics.Bitmap", +"android.graphics.ImageFormat", +"android.graphics.Color", +"android.graphics.ColorSpace$Connector", +"android.graphics.YuvImage", +"android.graphics.PaintFlagsDrawFilter", +"android.graphics.Rect", +"android.graphics.LinearGradient", +"android.graphics.PathEffect", +"android.graphics.Paint$Cap", + +"android.graphics.Picture", +"android.graphics.RadialGradient", +"android.graphics.Typeface$Builder", +"android.graphics.ColorSpace$Adaptation", +"android.graphics.ComposeShader", +"android.graphics.Paint$Align", +"android.graphics.DrawFilter", +"android.graphics.Region", +"android.graphics.BlurMaskFilter$Blur", +"android.graphics.PorterDuff$Mode", +"android.graphics.SumPathEffect", +"android.graphics.ColorSpace$Rgb$TransferParameters", +"android.graphics.ColorMatrixColorFilter", +"android.graphics.BitmapShader", +"android.graphics.ImageDecoder$ImageInfo", +"android.graphics.Interpolator", +"android.graphics.Outline", +"android.graphics.ColorSpace$RenderIntent", +"android.graphics.Xfermode", +"android.graphics.ColorSpace", +"android.graphics.LightingColorFilter", +"android.graphics.Canvas", +"android.graphics.Path$Op", +"android.graphics.ColorSpace$Model", +"android.graphics.BlurMaskFilter", +"android.graphics.PointF", +"android.graphics.drawable.Icon$OnDrawableLoadedListener", +"android.graphics.drawable.Icon", +"android.graphics.drawable.StateListDrawable", +"android.graphics.drawable.LevelListDrawable", +"android.graphics.drawable.Animatable2", +"android.graphics.drawable.DrawableContainer", +"android.graphics.drawable.Animatable2$AnimationCallback", +"android.graphics.drawable.AnimatedImageDrawable", +"android.graphics.drawable.DrawableContainer$DrawableContainerState", +"android.graphics.drawable.Drawable", +"android.graphics.drawable.AnimatedStateListDrawable", +"android.graphics.drawable.Drawable$Callback", +"android.graphics.drawable.LayerDrawable", +"android.graphics.drawable.GradientDrawable$Orientation", +"android.graphics.drawable.RotateDrawable", +"android.graphics.drawable.Animatable", +"android.graphics.drawable.AnimatedVectorDrawable", +"android.graphics.drawable.VectorDrawable", +"android.graphics.drawable.PaintDrawable", +"android.graphics.drawable.AnimationDrawable", +"android.graphics.drawable.GradientDrawable", +"android.graphics.drawable.ColorDrawable", +"android.graphics.drawable.ShapeDrawable$ShaderFactory", +"android.graphics.drawable.AdaptiveIconDrawable", +"android.graphics.drawable.RippleDrawable", +"android.graphics.drawable.shapes.Shape", +"android.graphics.drawable.shapes.PathShape", +"android.graphics.drawable.shapes.RectShape", +"android.graphics.drawable.shapes.RoundRectShape", +"android.graphics.drawable.shapes.ArcShape", +"android.graphics.drawable.shapes.OvalShape", +"android.graphics.drawable.PictureDrawable", +"android.graphics.drawable.ShapeDrawable", +"android.graphics.drawable.BitmapDrawable", +"android.graphics.drawable.InsetDrawable", +"android.graphics.drawable.NinePatchDrawable", +"android.graphics.drawable.TransitionDrawable", +"android.graphics.drawable.DrawableWrapper", +"android.graphics.drawable.ClipDrawable", +"android.graphics.drawable.Drawable$ConstantState", +"android.graphics.drawable.ScaleDrawable", +"android.graphics.EmbossMaskFilter", +"android.graphics.Paint$FontMetrics", +"android.graphics.ImageDecoder", +"android.graphics.Matrix", +"android.graphics.Shader", +"android.graphics.ColorSpace$Rgb", +"android.graphics.PathDashPathEffect$Style", +"android.graphics.Canvas$VertexMode", +"android.graphics.Typeface", +"android.graphics.PostProcessor", +"android.graphics.BitmapRegionDecoder", +"android.graphics.Point", +"android.graphics.ColorMatrix", +"android.graphics.BitmapFactory", +"android.graphics.Bitmap$CompressFormat", +"android.graphics.DashPathEffect", +"android.graphics.Camera", +"android.graphics.PorterDuffXfermode", +"android.graphics.SurfaceTexture", +"android.graphics.PorterDuff", +"android.graphics.Path$FillType", +"android.graphics.Path$Direction", +"android.graphics.Paint$Style", +"android.graphics.fonts.FontVariationAxis", +"android.graphics.Region$Op", +"android.graphics.PorterDuffColorFilter", + +"android.graphics.pdf.PdfDocument", +"android.graphics.pdf.PdfRenderer$Page", +"android.graphics.pdf.PdfDocument$PageInfo", +"android.graphics.pdf.PdfDocument$PageInfo$Builder", +"android.graphics.pdf.PdfRenderer", +"android.graphics.pdf.PdfDocument$Page", +"android.graphics.Paint$Join", +"android.graphics.RectF", +"android.graphics.Paint", +"android.graphics.Canvas$EdgeType", +"android.graphics.Paint$FontMetricsInt", +"android.graphics.RegionIterator", +"android.graphics.Interpolator$Result", +"android.graphics.BitmapFactory$Options", +"android.graphics.ImageDecoder$OnHeaderDecodedListener", +"android.graphics.Matrix$ScaleToFit", +"android.graphics.ColorFilter", +"android.graphics.SweepGradient", +"android.graphics.Path", +"android.graphics.PixelFormat", +"android.graphics.PathDashPathEffect", +"android.graphics.ComposePathEffect", +"android.graphics.Movie", +"android.graphics.PathMeasure", +"android.graphics.NinePatch", +"android.graphics.ImageDecoder$OnPartialImageListener", +"android.graphics.DiscretePathEffect", +"android.graphics.ColorSpace$Named", +"android.R$id", +"android.gesture.GesturePoint", +"android.gesture.GestureOverlayView$OnGesturePerformedListener", +"android.gesture.GestureOverlayView", +"android.gesture.OrientedBoundingBox", +"android.gesture.GestureStroke", +"android.gesture.GestureOverlayView$OnGestureListener", +"android.gesture.GestureLibraries", +"android.gesture.Prediction", +"android.gesture.GestureLibrary", +"android.gesture.GestureUtils", +"android.gesture.GestureStore", +"android.gesture.Gesture", +"android.gesture.GestureOverlayView$OnGesturingListener", +"android.annotation.TargetApi", +"android.annotation.SuppressLint", +"android.location.LocationProvider", +"android.location.Address", +"android.location.GpsStatus$Listener", +"android.location.GnssMeasurementsEvent", +"android.location.Geocoder", +"android.location.GnssMeasurementsEvent$Callback", +"android.location.GpsSatellite", +"android.location.GnssStatus", +"android.location.GnssStatus$Callback", +"android.location.GnssMeasurement", +"android.location.LocationListener", +"android.location.GnssNavigationMessage", +"android.location.GpsStatus$NmeaListener", +"android.location.Location", +"android.location.GpsStatus", +"android.location.Criteria", +"android.location.GnssClock", +"android.location.GnssNavigationMessage$Callback", +"android.location.LocationManager", +"android.location.SettingInjectorService", +"android.location.OnNmeaMessageListener", +"android.icu.lang.UCharacterEnums$ECharacterCategory", +"android.icu.lang.UCharacterEnums$ECharacterDirection", +"android.icu.lang.UCharacter$SentenceBreak", +"android.icu.lang.UCharacterCategory", +"android.icu.lang.UCharacter$JoiningGroup", +"android.icu.lang.UCharacter$EastAsianWidth", +"android.icu.lang.UCharacterEnums", +"android.icu.lang.UCharacter$UnicodeBlock", +"android.icu.lang.UProperty$NameChoice", +"android.icu.lang.UCharacter$LineBreak", +"android.icu.lang.UCharacter$JoiningType", +"android.icu.lang.UCharacter$BidiPairedBracketType", +"android.icu.lang.UCharacter", +"android.icu.lang.UCharacter$HangulSyllableType", +"android.icu.lang.UScript$ScriptUsage", +"android.icu.lang.UCharacter$NumericType", +"android.icu.lang.UCharacterDirection", +"android.icu.lang.UCharacter$DecompositionType", +"android.icu.lang.UCharacter$WordBreak", +"android.icu.lang.UProperty", +"android.icu.lang.UScript", +"android.icu.lang.UCharacter$GraphemeClusterBreak", +"android.icu.text.SymbolTable", +"android.icu.text.AlphabeticIndex$Bucket$LabelType", +"android.icu.text.Collator$ReorderCodes", +"android.icu.text.DateFormat$Field", +"android.icu.text.RuleBasedCollator", +"android.icu.text.RelativeDateTimeFormatter", +"android.icu.text.PluralFormat", +"android.icu.text.DecimalFormatSymbols", +"android.icu.text.Normalizer2$Mode", +"android.icu.text.SearchIterator", +"android.icu.text.MessagePattern$ApostropheMode", +"android.icu.text.LocaleDisplayNames$DialectHandling", +"android.icu.text.NumberFormat$Field", +"android.icu.text.UnicodeFilter", +"android.icu.text.DisplayContext", +"android.icu.text.UnicodeSetIterator", +"android.icu.text.LocaleDisplayNames$UiListItem", +"android.icu.text.TimeZoneFormat$ParseOption", +"android.icu.text.PluralRules", +"android.icu.text.StringSearch", +"android.icu.text.CollationKey$BoundMode", +"android.icu.text.DateIntervalInfo$PatternInfo", +"android.icu.text.UnicodeSetSpanner$CountMethod", +"android.icu.text.SelectFormat", +"android.icu.text.CompactDecimalFormat", +"android.icu.text.DateTimePatternGenerator", +"android.icu.text.CollationKey", +"android.icu.text.IDNA", +"android.icu.text.CurrencyPluralInfo", +"android.icu.text.RelativeDateTimeFormatter$Direction", +"android.icu.text.TimeZoneFormat$GMTOffsetPatternType", +"android.icu.text.DateIntervalFormat", +"android.icu.text.Normalizer$QuickCheckResult", +"android.icu.text.UnicodeSetSpanner$TrimOption", +"android.icu.text.DateFormatSymbols", +"android.icu.text.CollationElementIterator", +"android.icu.text.AlphabeticIndex$ImmutableIndex", +"android.icu.text.ScientificNumberFormatter", +"android.icu.text.MessagePattern$Part$Type", +"android.icu.text.MeasureFormat$FormatWidth", +"android.icu.text.DateIntervalInfo", +"android.icu.text.UnicodeMatcher", +"android.icu.text.UnicodeSet", +"android.icu.text.DateFormat$BooleanAttribute", +"android.icu.text.DateTimePatternGenerator$PatternInfo", +"android.icu.text.AlphabeticIndex$Record", +"android.icu.text.IDNA$Info", +"android.icu.text.AlphabeticIndex", +"android.icu.text.UnicodeSet$EntryRange", + +"android.icu.text.MessagePattern", +"android.icu.text.SimpleDateFormat", +"android.icu.text.TimeZoneNames$NameType", +"android.icu.text.MeasureFormat", +"android.icu.text.LocaleDisplayNames", +"android.icu.text.RelativeDateTimeFormatter$AbsoluteUnit", +"android.icu.text.Normalizer2", +"android.icu.text.MessagePattern$Part", +"android.icu.text.MessageFormat$Field", +"android.icu.text.TimeZoneFormat", +"android.icu.text.DecimalFormat", +"android.icu.text.MessageFormat", +"android.icu.text.IDNA$Error", +"android.icu.text.Replaceable", +"android.icu.text.NumberFormat", +"android.icu.text.AlphabeticIndex$Bucket", +"android.icu.text.UnicodeSetSpanner", +"android.icu.text.TimeZoneFormat$Style", +"android.icu.text.UFormat", +"android.icu.text.Collator", +"android.icu.text.ListFormatter", +"android.icu.text.TimeZoneNames", +"android.icu.text.Normalizer", +"android.icu.text.DateFormat", +"android.icu.text.NumberingSystem", +"android.icu.text.SearchIterator$ElementComparisonType", +"android.icu.text.BreakIterator", +"android.icu.text.MessagePattern$ArgType", +"android.icu.text.RelativeDateTimeFormatter$Style", +"android.icu.text.CompactDecimalFormat$CompactStyle", +"android.icu.text.TimeZoneFormat$TimeType", +"android.icu.text.PluralRules$PluralType", +"android.icu.text.UnicodeSet$SpanCondition", +"android.icu.text.UnicodeSet$ComparisonStyle", +"android.icu.text.UCharacterIterator", +"android.icu.text.RelativeDateTimeFormatter$RelativeUnit", +"android.icu.text.RelativeDateTimeFormatter$RelativeDateTimeUnit", +"android.icu.text.DisplayContext$Type", +"android.icu.math.MathContext", +"android.icu.math.BigDecimal", +"android.icu.util.ValueIterator$Element", +"android.icu.util.Calendar$WeekData", +"android.icu.util.ChineseCalendar", +"android.icu.util.VersionInfo", +"android.icu.util.LocaleData$MeasurementSystem", +"android.icu.util.Calendar", +"android.icu.util.TimeZone$SystemTimeZoneType", +"android.icu.util.ULocale$Builder", +"android.icu.util.ULocale$Category", +"android.icu.util.UniversalTimeScale", +"android.icu.util.DateInterval", + +"android.icu.util.Freezable", +"android.icu.util.TimeUnit", +"android.icu.util.CopticCalendar", +"android.icu.util.BuddhistCalendar", +"android.icu.util.ValueIterator", +"android.icu.util.TimeZone", +"android.icu.util.Output", +"android.icu.util.JapaneseCalendar", +"android.icu.util.RangeValueIterator", +"android.icu.util.TaiwanCalendar", +"android.icu.util.LocaleData$PaperSize", +"android.icu.util.Currency", +"android.icu.util.LocaleData", +"android.icu.util.HebrewCalendar", +"android.icu.util.Currency$CurrencyUsage", +"android.icu.util.EthiopicCalendar", +"android.icu.util.RangeValueIterator$Element", +"android.icu.util.GregorianCalendar", +"android.icu.util.CurrencyAmount", +"android.icu.util.IslamicCalendar", + +"android.icu.util.IslamicCalendar$CalculationType", +"android.icu.util.ULocale", +"android.icu.util.Measure", +"android.icu.util.MeasureUnit", +"android.icu.util.IndianCalendar", +"android.net.IpSecTransform$Builder", +"android.net.NetworkInfo$State", +"android.net.IpSecManager$UdpEncapsulationSocket", +"android.net.UrlQuerySanitizer", +"android.net.Uri", +"android.net.LocalSocketAddress", +"android.net.ConnectivityManager$NetworkCallback", +"android.net.IpSecManager", +"android.net.IpSecManager$SecurityParameterIndex", +"android.net.NetworkRequest$Builder", +"android.net.wifi.WifiConfiguration$Protocol", +"android.net.wifi.WifiEnterpriseConfig$Eap", +"android.net.wifi.WifiEnterpriseConfig", +"android.net.wifi.WifiConfiguration", +"android.net.wifi.WifiInfo", +"android.net.wifi.WifiManager$LocalOnlyHotspotCallback", +"android.net.wifi.WifiConfiguration$KeyMgmt", +"android.net.wifi.WifiConfiguration$Status", +"android.net.wifi.WifiManager$WifiLock", +"android.net.wifi.aware.WifiAwareManager", +"android.net.wifi.aware.PeerHandle", +"android.net.wifi.aware.IdentityChangedListener", +"android.net.wifi.aware.DiscoverySession", +"android.net.wifi.aware.PublishConfig$Builder", +"android.net.wifi.aware.PublishDiscoverySession", +"android.net.wifi.aware.DiscoverySessionCallback", +"android.net.wifi.aware.SubscribeConfig", +"android.net.wifi.aware.SubscribeDiscoverySession", +"android.net.wifi.aware.PublishConfig", +"android.net.wifi.aware.WifiAwareSession", +"android.net.wifi.aware.SubscribeConfig$Builder", +"android.net.wifi.aware.AttachCallback", +"android.net.wifi.aware.Characteristics", +"android.net.wifi.ScanResult", +"android.net.wifi.WifiManager$MulticastLock", +"android.net.wifi.WifiConfiguration$PairwiseCipher", +"android.net.wifi.rtt.RangingResultCallback", +"android.net.wifi.rtt.RangingResult", +"android.net.wifi.rtt.WifiRttManager", +"android.net.wifi.rtt.RangingRequest$Builder", +"android.net.wifi.rtt.RangingRequest", +"android.net.wifi.WifiManager", +"android.net.wifi.WpsInfo", +"android.net.wifi.SupplicantState", +"android.net.wifi.WifiConfiguration$AuthAlgorithm", +"android.net.wifi.WifiConfiguration$GroupCipher", +"android.net.wifi.WifiManager$LocalOnlyHotspotReservation", +"android.net.wifi.WifiEnterpriseConfig$Phase2", +"android.net.wifi.hotspot2.ConfigParser", +"android.net.wifi.hotspot2.PasspointConfiguration", +"android.net.wifi.hotspot2.pps.Credential$UserCredential", +"android.net.wifi.hotspot2.pps.Credential", +"android.net.wifi.hotspot2.pps.Credential$SimCredential", +"android.net.wifi.hotspot2.pps.HomeSp", +"android.net.wifi.hotspot2.pps.Credential$CertificateCredential", +"android.net.wifi.hotspot2.omadm.PpsMoParser", +"android.net.wifi.p2p.WifiP2pManager$DnsSdServiceResponseListener", +"android.net.wifi.p2p.WifiP2pManager$UpnpServiceResponseListener", +"android.net.wifi.p2p.WifiP2pDevice", +"android.net.wifi.p2p.WifiP2pGroup", +"android.net.wifi.p2p.WifiP2pManager$DnsSdTxtRecordListener", +"android.net.wifi.p2p.WifiP2pManager$ActionListener", +"android.net.wifi.p2p.WifiP2pManager$ConnectionInfoListener", +"android.net.wifi.p2p.WifiP2pManager$Channel", +"android.net.wifi.p2p.WifiP2pConfig", +"android.net.wifi.p2p.WifiP2pInfo", +"android.net.wifi.p2p.WifiP2pManager$ChannelListener", +"android.net.wifi.p2p.WifiP2pManager", +"android.net.wifi.p2p.WifiP2pDeviceList", +"android.net.wifi.p2p.WifiP2pManager$GroupInfoListener", +"android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo", +"android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest", +"android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo", +"android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest", +"android.net.wifi.p2p.nsd.WifiP2pServiceRequest", +"android.net.wifi.p2p.nsd.WifiP2pServiceInfo", +"android.net.wifi.p2p.WifiP2pManager$PeerListListener", +"android.net.wifi.p2p.WifiP2pManager$ServiceResponseListener", +"android.net.wifi.WifiManager$WpsCallback", +"android.net.Uri$Builder", +"android.net.UrlQuerySanitizer$IllegalCharacterValueSanitizer", +"android.net.IpSecTransform", + +"android.net.Network", + +"android.net.Credentials", + +"android.net.RouteInfo", +"android.net.ConnectivityManager", +"android.net.MailTo", +"android.net.sip.SipErrorCode", +"android.net.sip.SipSession", +"android.net.sip.SipProfile", +"android.net.sip.SipSession$State", +"android.net.sip.SipSession$Listener", +"android.net.sip.SipProfile$Builder", +"android.net.sip.SipManager", +"android.net.sip.SipAudioCall", +"android.net.sip.SipRegistrationListener", + +"android.net.sip.SipAudioCall$Listener", +"android.net.DhcpInfo", +"android.net.LocalServerSocket", +"android.net.UrlQuerySanitizer$ValueSanitizer", +"android.net.IpSecAlgorithm", +"android.net.LocalSocketAddress$Namespace", +"android.net.NetworkInfo$DetailedState", +"android.net.http.HttpResponseCache", +"android.net.http.SslCertificate$DName", +"android.net.http.SslError", +"android.net.http.SslCertificate", +"android.net.http.X509TrustManagerExtensions", +"android.net.CaptivePortal", +"android.net.NetworkInfo", +"android.net.VpnService$Builder", +"android.net.NetworkRequest", +"android.net.rtp.RtpStream", +"android.net.rtp.AudioStream", +"android.net.rtp.AudioCodec", +"android.net.rtp.AudioGroup", +"android.net.NetworkSpecifier", +"android.net.ConnectivityManager$OnNetworkActiveListener", +"android.net.SSLCertificateSocketFactory", +"android.net.ProxyInfo", +"android.net.TrafficStats", +"android.net.SSLSessionCache", +"android.net.LinkAddress", +"android.net.MacAddress", +"android.net.VpnService", +"android.net.IpPrefix", +"android.net.LocalSocket", +"android.net.UrlQuerySanitizer$ParameterValuePair", +"android.net.nsd.NsdManager$DiscoveryListener", +"android.net.nsd.NsdManager$ResolveListener", +"android.net.nsd.NsdServiceInfo", +"android.net.nsd.NsdManager$RegistrationListener", +"android.net.nsd.NsdManager", +"android.net.Proxy", +"android.net.NetworkCapabilities", +"android.net.LinkProperties", +"android.R$style", +"android.telephony.PhoneNumberUtils", +"android.telephony.TelephonyScanManager$NetworkScanCallback", +"android.telephony.SubscriptionPlan", +"android.telephony.TelephonyScanManager", +"android.telephony.SignalStrength", +"android.telephony.gsm.GsmCellLocation", +"android.telephony.gsm.SmsMessage", +"android.telephony.gsm.SmsManager", +"android.telephony.gsm.SmsMessage$SubmitPdu", +"android.telephony.gsm.SmsMessage$MessageClass", +"android.telephony.AccessNetworkConstants$UtranBand", +"android.telephony.MbmsDownloadSession", +"android.telephony.AccessNetworkConstants$AccessNetworkType", +"android.telephony.SubscriptionPlan$Builder", +"android.telephony.cdma.CdmaCellLocation", +"android.telephony.VisualVoicemailSms", +"android.telephony.SubscriptionInfo", +"android.telephony.CellSignalStrengthLte", +"android.telephony.CellSignalStrengthGsm", +"android.telephony.SmsMessage", +"android.telephony.PhoneStateListener", +"android.telephony.CellIdentityGsm", +"android.telephony.ServiceState", +"android.telephony.TelephonyManager$UssdResponseCallback", +"android.telephony.CellIdentity", +"android.telephony.CellInfoWcdma", +"android.telephony.AccessNetworkConstants$GeranBand", +"android.telephony.CellInfoGsm", +"android.telephony.VisualVoicemailService$VisualVoicemailTask", +"android.telephony.CellInfoCdma", +"android.telephony.MbmsStreamingSession", +"android.telephony.NeighboringCellInfo", +"android.telephony.CellSignalStrength", +"android.telephony.mbms.ServiceInfo", +"android.telephony.mbms.MbmsErrors$InitializationErrors", +"android.telephony.mbms.MbmsErrors$DownloadErrors", +"android.telephony.mbms.StreamingService", +"android.telephony.mbms.DownloadRequest", +"android.telephony.mbms.StreamingServiceCallback", +"android.telephony.mbms.MbmsStreamingSessionCallback", +"android.telephony.mbms.MbmsErrors$StreamingErrors", +"android.telephony.mbms.FileInfo", +"android.telephony.mbms.StreamingServiceInfo", +"android.telephony.mbms.MbmsErrors$GeneralErrors", +"android.telephony.mbms.DownloadProgressListener", +"android.telephony.mbms.MbmsDownloadReceiver", +"android.telephony.mbms.DownloadRequest$Builder", +"android.telephony.mbms.FileServiceInfo", +"android.telephony.mbms.MbmsErrors", +"android.telephony.mbms.MbmsDownloadSessionCallback", +"android.telephony.mbms.DownloadStatusListener", +"android.telephony.NetworkScan", +"android.telephony.CellLocation", +"android.telephony.RadioAccessSpecifier", +"android.telephony.SmsManager", +"android.telephony.NetworkScanRequest", +"android.telephony.data.ApnSetting$Builder", +"android.telephony.data.ApnSetting", +"android.telephony.CellIdentityWcdma", +"android.telephony.CellIdentityTdscdma", +"android.telephony.IccOpenLogicalChannelResponse", +"android.telephony.CellInfo", +"android.telephony.AccessNetworkConstants", +"android.telephony.SmsMessage$SubmitPdu", +"android.telephony.PhoneNumberFormattingTextWatcher", +"android.telephony.SubscriptionManager", +"android.telephony.CellInfoLte", +"android.telephony.CellIdentityLte", +"android.telephony.SubscriptionManager$OnSubscriptionsChangedListener", +"android.telephony.CellSignalStrengthWcdma", +"android.telephony.SmsMessage$MessageClass", +"android.telephony.VisualVoicemailService", +"android.telephony.CarrierConfigManager", +"android.telephony.euicc.EuiccManager", +"android.telephony.euicc.DownloadableSubscription", +"android.telephony.euicc.EuiccInfo", +"android.telephony.CellSignalStrengthCdma", +"android.telephony.AccessNetworkConstants$EutranBand", +"android.telephony.VisualVoicemailSmsFilterSettings", +"android.telephony.CellIdentityCdma", +"android.telephony.VisualVoicemailSmsFilterSettings$Builder", +"android.telephony.TelephonyManager", +"android.R$interpolator", +"android.security.KeyChain", +"android.security.AttestedKeyPair", +"android.security.KeyStoreParameter$Builder", + +"android.security.KeyChainAliasCallback", + +"android.security.NetworkSecurityPolicy", +"android.security.KeyPairGeneratorSpec", +"android.security.ConfirmationCallback", +"android.security.ConfirmationPrompt", +"android.security.KeyPairGeneratorSpec$Builder", +"android.security.KeyStoreParameter", +"android.security.ConfirmationPrompt$Builder", +"android.security.keystore.KeyGenParameterSpec", +"android.security.keystore.KeyProperties", + +"android.security.keystore.KeyProtection$Builder", + +"android.security.keystore.WrappedKeyEntry", +"android.security.keystore.KeyGenParameterSpec$Builder", + + + +"android.security.keystore.KeyInfo", + + +"android.security.keystore.KeyProtection", + +"android.R$raw", +"android.view.OrientationListener", + +"android.view.InputEvent", +"android.view.View$OnUnhandledKeyEventListener", +"android.view.GestureDetector$OnGestureListener", +"android.view.Window$Callback", +"android.view.View$OnGenericMotionListener", +"android.view.View$OnScrollChangeListener", +"android.view.textclassifier.TextSelection$Builder", +"android.view.textclassifier.TextClassification$Request", +"android.view.textclassifier.TextSelection", +"android.view.textclassifier.TextSelection$Request$Builder", +"android.view.textclassifier.SelectionEvent", +"android.view.textclassifier.TextLinks$Builder", +"android.view.textclassifier.TextClassificationContext", +"android.view.textclassifier.TextSelection$Request", +"android.view.textclassifier.TextClassificationContext$Builder", +"android.view.textclassifier.TextLinks$TextLink", +"android.view.textclassifier.TextLinks$Request$Builder", +"android.view.textclassifier.TextClassifier", +"android.view.textclassifier.TextLinks$TextLinkSpan", +"android.view.textclassifier.TextClassificationSessionFactory", +"android.view.textclassifier.TextLinks", +"android.view.textclassifier.TextClassification$Builder", +"android.view.textclassifier.TextClassification", +"android.view.textclassifier.TextClassifier$EntityConfig", +"android.view.textclassifier.TextLinks$Request", +"android.view.textclassifier.TextClassificationSessionId", +"android.view.textclassifier.TextClassificationManager", +"android.view.textclassifier.TextClassification$Request$Builder", +"android.view.PixelCopy", +"android.view.Window$OnFrameMetricsAvailableListener", +"android.view.ViewDebug$RecyclerTraceType", +"android.view.InputQueue", +"android.view.OrientationEventListener", +"android.view.ActionMode", +"android.view.View$OnAttachStateChangeListener", +"android.view.GestureDetector$OnDoubleTapListener", +"android.view.ViewStructure", +"android.view.View$OnSystemUiVisibilityChangeListener", +"android.view.ViewOverlay", +"android.view.MenuItem$OnMenuItemClickListener", +"android.view.ViewTreeObserver", +"android.view.autofill.AutofillId", +"android.view.autofill.AutofillManager$AutofillCallback", +"android.view.autofill.AutofillManager", +"android.view.autofill.AutofillValue", +"android.view.TextureView$SurfaceTextureListener", +"android.view.WindowInsets", +"android.view.MotionEvent", +"android.view.ViewDebug$ExportedProperty", +"android.view.ContextThemeWrapper", +"android.view.View$OnCreateContextMenuListener", +"android.view.ContextMenu$ContextMenuInfo", +"android.view.textservice.SpellCheckerSession$SpellCheckerSessionListener", +"android.view.textservice.TextInfo", +"android.view.textservice.SpellCheckerInfo", +"android.view.textservice.SpellCheckerSubtype", +"android.view.textservice.SentenceSuggestionsInfo", +"android.view.textservice.SpellCheckerSession", +"android.view.textservice.TextServicesManager", +"android.view.textservice.SuggestionsInfo", +"android.view.LayoutInflater", +"android.view.ViewStub$OnInflateListener", + +"android.view.KeyCharacterMap$KeyData", + +"android.view.InputDevice", + +"android.view.ViewDebug$CapturedViewProperty", + +"android.view.AbsSavedState", +"android.view.View$OnCapturedPointerListener", +"android.view.FocusFinder", +"android.view.SurfaceHolder", +"android.view.FrameMetrics", +"android.view.KeyboardShortcutGroup", +"android.view.InputQueue$Callback", +"android.view.ViewDebug$IntToString", +"android.view.KeyCharacterMap", +"android.view.View$OnClickListener", +"android.view.ViewDebug$HierarchyTraceType", +"android.view.WindowId$FocusObserver", +"android.view.ViewTreeObserver$OnGlobalFocusChangeListener", +"android.view.ActionMode$Callback", +"android.view.GestureDetector", +"android.view.View", +"android.view.Window$OnRestrictedCaptionAreaChangedListener", +"android.view.ViewDebug", +"android.view.MotionEvent$PointerProperties", +"android.view.SurfaceView", +"android.view.MenuInflater", +"android.view.FrameStats", +"android.view.Choreographer", +"android.view.SoundEffectConstants", +"android.view.ViewTreeObserver$OnGlobalLayoutListener", +"android.view.Display$HdrCapabilities", +"android.view.DragAndDropPermissions", +"android.view.View$AccessibilityDelegate", +"android.view.ActionProvider$VisibilityListener", +"android.view.ViewGroup$LayoutParams", +"android.view.SearchEvent", +"android.view.Menu", +"android.view.WindowContentFrameStats", +"android.view.View$BaseSavedState", +"android.view.TouchDelegate", +"android.view.KeyEvent$DispatcherState", +"android.view.ViewManager", +"android.view.Gravity", +"android.view.ScaleGestureDetector$SimpleOnScaleGestureListener", +"android.view.ContextMenu", +"android.view.KeyEvent$Callback", +"android.view.LayoutInflater$Filter", +"android.view.ViewTreeObserver$OnWindowAttachListener", +"android.view.View$MeasureSpec", +"android.view.ScaleGestureDetector$OnScaleGestureListener", +"android.view.ViewTreeObserver$OnDrawListener", +"android.view.WindowManager$LayoutParams", +"android.view.MotionEvent$PointerCoords", +"android.view.HapticFeedbackConstants", +"android.view.WindowManager", +"android.view.ViewStub", +"android.view.PointerIcon", +"android.view.ActionProvider", +"android.view.SurfaceHolder$Callback2", +"android.view.Display$Mode", +"android.view.View$OnKeyListener", +"android.view.ViewStructure$HtmlInfo", +"android.view.ViewTreeObserver$OnPreDrawListener", +"android.view.accessibility.CaptioningManager$CaptioningChangeListener", +"android.view.accessibility.AccessibilityEvent", +"android.view.accessibility.CaptioningManager$CaptionStyle", +"android.view.accessibility.AccessibilityManager", +"android.view.accessibility.AccessibilityNodeInfo$CollectionItemInfo", +"android.view.accessibility.AccessibilityNodeInfo", +"android.view.accessibility.AccessibilityRecord", +"android.view.accessibility.AccessibilityNodeInfo$RangeInfo", +"android.view.accessibility.AccessibilityRequestPreparer", +"android.view.accessibility.AccessibilityManager$AccessibilityStateChangeListener", +"android.view.accessibility.AccessibilityEventSource", +"android.view.accessibility.AccessibilityNodeProvider", +"android.view.accessibility.AccessibilityWindowInfo", +"android.view.accessibility.CaptioningManager", +"android.view.accessibility.AccessibilityNodeInfo$CollectionInfo", +"android.view.accessibility.AccessibilityManager$TouchExplorationStateChangeListener", +"android.view.accessibility.AccessibilityNodeInfo$AccessibilityAction", +"android.view.SubMenu", +"android.view.View$OnHoverListener", +"android.view.InputDevice$MotionRange", +"android.view.ViewGroup$OnHierarchyChangeListener", +"android.view.ViewParent", +"android.view.View$OnLayoutChangeListener", +"android.view.ViewGroupOverlay", +"android.view.LayoutInflater$Factory2", +"android.view.ViewDebug$FlagToString", +"android.view.ViewOutlineProvider", +"android.view.Surface", +"android.view.SurfaceHolder$Callback", +"android.view.ActionMode$Callback2", +"android.view.KeyboardShortcutInfo", +"android.view.DisplayCutout", +"android.view.View$DragShadowBuilder", +"android.view.VelocityTracker", +"android.view.GestureDetector$OnContextClickListener", +"android.view.ViewConfiguration", +"android.view.Window", +"android.view.View$OnLongClickListener", +"android.view.TextureView", +"android.view.ViewTreeObserver$OnWindowFocusChangeListener", +"android.view.View$OnTouchListener", +"android.view.MenuItem", +"android.view.Choreographer$FrameCallback", +"android.view.ViewAnimationUtils", +"android.view.View$OnContextClickListener", +"android.view.ScaleGestureDetector", +"android.view.KeyEvent", +"android.view.ViewGroup$MarginLayoutParams", +"android.view.DragEvent", +"android.view.ViewTreeObserver$OnTouchModeChangeListener", +"android.view.View$OnApplyWindowInsetsListener", +"android.view.Display", +"android.view.animation.AccelerateInterpolator", +"android.view.animation.LayoutAnimationController$AnimationParameters", +"android.view.animation.Transformation", +"android.view.animation.AlphaAnimation", +"android.view.animation.Interpolator", +"android.view.animation.AnticipateInterpolator", +"android.view.animation.AnticipateOvershootInterpolator", +"android.view.animation.Animation$AnimationListener", +"android.view.animation.DecelerateInterpolator", +"android.view.animation.AnimationSet", +"android.view.animation.BaseInterpolator", +"android.view.animation.LayoutAnimationController", +"android.view.animation.RotateAnimation", +"android.view.animation.Animation", +"android.view.animation.CycleInterpolator", +"android.view.animation.GridLayoutAnimationController", +"android.view.animation.GridLayoutAnimationController$AnimationParameters", +"android.view.animation.PathInterpolator", +"android.view.animation.TranslateAnimation", +"android.view.animation.ScaleAnimation", +"android.view.animation.BounceInterpolator", +"android.view.animation.LinearInterpolator", +"android.view.animation.AnimationUtils", +"android.view.animation.OvershootInterpolator", +"android.view.animation.Animation$Description", +"android.view.animation.AccelerateDecelerateInterpolator", + +"android.view.ViewPropertyAnimator", +"android.view.PixelCopy$OnPixelCopyFinishedListener", +"android.view.WindowId", +"android.view.inputmethod.EditorInfo", +"android.view.inputmethod.InputConnection", +"android.view.inputmethod.InputMethodManager", +"android.view.inputmethod.CursorAnchorInfo$Builder", +"android.view.inputmethod.InputMethod", +"android.view.inputmethod.CorrectionInfo", +"android.view.inputmethod.InputMethodSubtype$InputMethodSubtypeBuilder", +"android.view.inputmethod.InputMethodSession", +"android.view.inputmethod.CursorAnchorInfo", +"android.view.inputmethod.InputBinding", +"android.view.inputmethod.InputContentInfo", +"android.view.inputmethod.InputMethodSubtype", +"android.view.inputmethod.InputConnectionWrapper", +"android.view.inputmethod.InputMethodSession$EventCallback", +"android.view.inputmethod.BaseInputConnection", +"android.view.inputmethod.InputMethodInfo", +"android.view.inputmethod.CompletionInfo", +"android.view.inputmethod.ExtractedTextRequest", +"android.view.inputmethod.InputMethod$SessionCallback", +"android.view.inputmethod.ExtractedText", +"android.view.ViewStructure$HtmlInfo$Builder", +"android.view.View$OnFocusChangeListener", +"android.view.MenuItem$OnActionExpandListener", +"android.view.ViewGroup", +"android.view.WindowAnimationFrameStats", +"android.view.CollapsibleActionView", +"android.view.View$OnDragListener", +"android.view.GestureDetector$SimpleOnGestureListener", +"android.view.LayoutInflater$Factory", +"android.view.ViewTreeObserver$OnScrollChangedListener", +"android.opengl.GLES32$DebugProc", +"android.opengl.GLES31", +"android.opengl.EGLExt", +"android.opengl.ETC1Util", +"android.opengl.GLSurfaceView$EGLWindowSurfaceFactory", +"android.opengl.GLU", + +"android.opengl.GLES20", +"android.opengl.GLES31Ext$DebugProcKHR", +"android.opengl.GLES11", +"android.opengl.EGLConfig", +"android.opengl.GLDebugHelper", +"android.opengl.EGLContext", +"android.opengl.Matrix", +"android.opengl.GLES11Ext", +"android.opengl.GLSurfaceView$EGLConfigChooser", +"android.opengl.GLSurfaceView$EGLContextFactory", +"android.opengl.Visibility", +"android.opengl.GLES31Ext", +"android.opengl.GLSurfaceView$GLWrapper", +"android.opengl.GLSurfaceView", +"android.opengl.GLES10", +"android.opengl.GLUtils", +"android.opengl.GLSurfaceView$Renderer", +"android.opengl.ETC1Util$ETC1Texture", +"android.opengl.ETC1", +"android.opengl.GLES30", +"android.opengl.EGL14", +"android.opengl.GLES32", +"android.opengl.EGLObjectHandle", +"android.opengl.EGLSurface", +"android.opengl.GLES10Ext", +"android.opengl.EGLDisplay", +"android.R$transition", +"android.widget.ListView", +"android.widget.TableRow", +"android.widget.Filter$FilterListener", +"android.widget.TwoLineListItem", +"android.widget.AbsoluteLayout$LayoutParams", +"android.widget.Filter", +"android.widget.VideoView", +"android.widget.Button", +"android.widget.AutoCompleteTextView$OnDismissListener", +"android.widget.AutoCompleteTextView", +"android.widget.SimpleCursorAdapter$CursorToStringConverter", +"android.widget.OverScroller", +"android.widget.Switch", +"android.widget.ToggleButton", +"android.widget.BaseAdapter", +"android.widget.SlidingDrawer", +"android.widget.TimePicker$OnTimeChangedListener", +"android.widget.TextView$SavedState", +"android.widget.RemoteViewsService$RemoteViewsFactory", +"android.widget.Gallery$LayoutParams", +"android.widget.HorizontalScrollView", +"android.widget.Gallery", +"android.widget.DatePicker", +"android.widget.ViewSwitcher", +"android.widget.Chronometer", +"android.widget.Magnifier", +"android.widget.RemoteViews$RemoteView", +"android.widget.WrapperListAdapter", +"android.widget.CursorTreeAdapter", +"android.widget.AbsListView$LayoutParams", +"android.widget.NumberPicker", +"android.widget.AbsoluteLayout", +"android.widget.Toolbar", +"android.widget.Checkable", +"android.widget.HeaderViewListAdapter", +"android.widget.ViewFlipper", +"android.widget.SimpleAdapter$ViewBinder", +"android.widget.Filterable", +"android.widget.ZoomButtonsController$OnZoomListener", +"android.widget.AbsListView$RecyclerListener", +"android.widget.CursorAdapter", +"android.widget.TabHost$TabContentFactory", +"android.widget.ProgressBar", +"android.widget.ListView$FixedViewInfo", +"android.widget.SlidingDrawer$OnDrawerOpenListener", +"android.widget.AbsSeekBar", +"android.widget.TabHost", +"android.widget.LinearLayout", +"android.widget.ShareActionProvider$OnShareTargetSelectedListener", +"android.widget.ImageButton", +"android.widget.PopupMenu$OnDismissListener", +"android.widget.DatePicker$OnDateChangedListener", +"android.widget.FrameLayout", +"android.widget.RatingBar", +"android.widget.StackView", +"android.widget.GridLayout$LayoutParams", +"android.widget.CheckBox", +"android.widget.Advanceable", +"android.widget.TabHost$TabSpec", +"android.widget.TextSwitcher", +"android.widget.EdgeEffect", +"android.widget.AbsListView", +"android.widget.Toolbar$LayoutParams", +"android.widget.NumberPicker$Formatter", +"android.widget.AdapterView", +"android.widget.RelativeLayout", +"android.widget.GridLayout$Spec", +"android.widget.CompoundButton", +"android.widget.RadioButton", +"android.widget.ImageView$ScaleType", +"android.widget.Toast", +"android.widget.LinearLayout$LayoutParams", +"android.widget.ImageSwitcher", +"android.widget.Spinner", +"android.widget.SectionIndexer", +"android.widget.PopupMenu$OnMenuItemClickListener", +"android.widget.Filter$FilterResults", +"android.widget.SeekBar", +"android.widget.Chronometer$OnChronometerTickListener", +"android.widget.RemoteViews", +"android.widget.EditText", +"android.widget.FrameLayout$LayoutParams", +"android.widget.MediaController", +"android.widget.Toolbar$OnMenuItemClickListener", +"android.widget.ZoomButtonsController", +"android.widget.SlidingDrawer$OnDrawerCloseListener", +"android.widget.AdapterView$AdapterContextMenuInfo", +"android.widget.ImageView", + +"android.widget.SearchView$OnQueryTextListener", +"android.widget.TextView$BufferType", +"android.widget.NumberPicker$OnValueChangeListener", +"android.widget.AbsListView$OnScrollListener", +"android.widget.MultiAutoCompleteTextView$Tokenizer", +"android.widget.BaseExpandableListAdapter", +"android.widget.AbsSpinner", +"android.widget.TextClock", +"android.widget.SlidingDrawer$OnDrawerScrollListener", +"android.widget.ListAdapter", +"android.widget.DigitalClock", +"android.widget.SimpleCursorTreeAdapter", +"android.widget.AdapterView$OnItemSelectedListener", +"android.widget.MultiAutoCompleteTextView", +"android.widget.QuickContactBadge", +"android.widget.GridLayout$Alignment", +"android.widget.ExpandableListView$OnGroupCollapseListener", +"android.widget.ShareActionProvider", +"android.widget.TableLayout$LayoutParams", +"android.widget.ExpandableListAdapter", +"android.widget.ExpandableListView$OnGroupClickListener", +"android.widget.ExpandableListView", +"android.widget.AdapterViewFlipper", +"android.widget.TextView$OnEditorActionListener", +"android.widget.DialerFilter", +"android.widget.ZoomButton", +"android.widget.AlphabetIndexer", +"android.widget.TimePicker", +"android.widget.TableLayout", +"android.widget.GridView", +"android.widget.SimpleCursorAdapter", +"android.widget.MediaController$MediaPlayerControl", +"android.widget.Adapter", +"android.widget.TableRow$LayoutParams", +"android.widget.SearchView", +"android.widget.SpinnerAdapter", +"android.widget.ActionMenuView", +"android.widget.ScrollView", +"android.widget.AutoCompleteTextView$Validator", +"android.widget.AbsListView$MultiChoiceModeListener", +"android.widget.RadioGroup$LayoutParams", +"android.widget.SearchView$OnCloseListener", +"android.widget.AbsListView$SelectionBoundsAdjuster", +"android.widget.ArrayAdapter", +"android.widget.ThemedSpinnerAdapter", +"android.widget.SeekBar$OnSeekBarChangeListener", +"android.widget.TextView", +"android.widget.TabHost$OnTabChangeListener", +"android.widget.ActionMenuView$LayoutParams", +"android.widget.SimpleCursorAdapter$ViewBinder", +"android.widget.Scroller", +"android.widget.CalendarView$OnDateChangeListener", +"android.widget.TabWidget", +"android.widget.AdapterView$OnItemLongClickListener", +"android.widget.ExpandableListView$OnGroupExpandListener", +"android.widget.CompoundButton$OnCheckedChangeListener", +"android.widget.RatingBar$OnRatingBarChangeListener", +"android.widget.RemoteViewsService", +"android.widget.Space", +"android.widget.ListPopupWindow", +"android.widget.AdapterViewAnimator", +"android.widget.RadioGroup$OnCheckedChangeListener", +"android.widget.CheckedTextView", +"android.widget.SimpleExpandableListAdapter", +"android.widget.PopupWindow$OnDismissListener", +"android.widget.AdapterView$OnItemClickListener", +"android.widget.ResourceCursorTreeAdapter", +"android.widget.HeterogeneousExpandableList", +"android.widget.GridLayout", +"android.widget.ViewAnimator", +"android.widget.RadioGroup", +"android.widget.ZoomControls", +"android.widget.PopupMenu", +"android.widget.SimpleCursorTreeAdapter$ViewBinder", +"android.widget.AnalogClock", +"android.widget.ViewSwitcher$ViewFactory", +"android.widget.MultiAutoCompleteTextView$CommaTokenizer", +"android.widget.CalendarView", +"android.widget.ExpandableListView$OnChildClickListener", +"android.widget.FilterQueryProvider", +"android.widget.RelativeLayout$LayoutParams", +"android.widget.SearchView$OnSuggestionListener", +"android.widget.SimpleAdapter", +"android.widget.PopupWindow", +"android.widget.NumberPicker$OnScrollListener", +"android.widget.ActionMenuView$OnMenuItemClickListener", +"android.widget.ExpandableListView$ExpandableListContextMenuInfo", +"android.widget.ResourceCursorAdapter", +"android.R$string", +"android.appwidget.AppWidgetManager", +"android.appwidget.AppWidgetHost", +"android.appwidget.AppWidgetProvider", +"android.appwidget.AppWidgetHostView", +"android.appwidget.AppWidgetProviderInfo", +"android.R$plurals", +"android.inputmethodservice.Keyboard$Row", +"android.inputmethodservice.InputMethodService", +"android.inputmethodservice.InputMethodService$InputMethodSessionImpl", +"android.inputmethodservice.KeyboardView", +"android.inputmethodservice.InputMethodService$Insets", +"android.inputmethodservice.Keyboard", + +"android.inputmethodservice.InputMethodService$InputMethodImpl", + +"android.inputmethodservice.ExtractEditText", + +"android.inputmethodservice.KeyboardView$OnKeyboardActionListener", +"android.inputmethodservice.Keyboard$Key", +"android.R$attr", +"android.sax.EndElementListener", +"android.sax.EndTextElementListener", +"android.sax.StartElementListener", +"android.sax.TextElementListener", +"android.sax.ElementListener", +"android.sax.RootElement", +"android.sax.Element", +"android.R$mipmap", +"android.animation.TypeConverter", +"android.animation.TimeAnimator", +"android.animation.Animator$AnimatorListener", +"android.animation.Keyframe", +"android.animation.TimeInterpolator", +"android.animation.PointFEvaluator", +"android.animation.RectEvaluator", +"android.animation.TimeAnimator$TimeListener", +"android.animation.IntArrayEvaluator", +"android.animation.TypeEvaluator", +"android.animation.FloatEvaluator", +"android.animation.PropertyValuesHolder", +"android.animation.ArgbEvaluator", +"android.animation.Animator$AnimatorPauseListener", +"android.animation.StateListAnimator", +"android.animation.BidirectionalTypeConverter", +"android.animation.AnimatorSet$Builder", +"android.animation.AnimatorSet", +"android.animation.AnimatorInflater", +"android.animation.LayoutTransition", +"android.animation.ObjectAnimator", +"android.animation.AnimatorListenerAdapter", +"android.animation.LayoutTransition$TransitionListener", +"android.animation.IntEvaluator", +"android.animation.Animator", +"android.animation.ValueAnimator$AnimatorUpdateListener", +"android.animation.FloatArrayEvaluator", +"android.animation.ValueAnimator", +"android.R$menu", +"android.mtp.MtpObjectInfo$Builder", +"android.mtp.MtpDevice", +"android.mtp.MtpStorageInfo", +"android.mtp.MtpEvent", +"android.mtp.MtpObjectInfo", +"android.mtp.MtpDeviceInfo", +"android.mtp.MtpConstants", +"android.Manifest$permission_group", +"java.nio.DoubleBuffer", + +"java.nio.CharBuffer", + +"java.nio.channels.WritableByteChannel", + + + + +"java.nio.channels.spi.SelectorProvider", +"java.nio.channels.spi.AsynchronousChannelProvider", +"java.nio.channels.AsynchronousChannelGroup", +"java.nio.channels.CompletionHandler", + +"java.nio.channels.InterruptibleChannel", + +"java.nio.channels.SeekableByteChannel", +"java.nio.channels.AsynchronousFileChannel", +"java.nio.channels.ServerSocketChannel", +"java.nio.channels.ReadableByteChannel", + +"java.nio.channels.AsynchronousChannel", + +"java.nio.channels.SelectionKey", +"java.nio.channels.AsynchronousServerSocketChannel", +"java.nio.channels.Pipe$SinkChannel", + +"java.nio.channels.Pipe", +"java.nio.channels.Selector", +"java.nio.channels.GatheringByteChannel", + +"java.nio.channels.ScatteringByteChannel", +"java.nio.channels.ByteChannel", +"java.nio.channels.Channel", +"java.nio.channels.FileChannel$MapMode", + + + + + + +"java.nio.channels.Pipe$SourceChannel", +"java.nio.channels.MulticastChannel", + +"java.nio.channels.FileChannel", + +"java.nio.channels.NetworkChannel", + +"java.nio.channels.Channels", + +"java.nio.channels.FileLock", +"java.nio.channels.SocketChannel", + +"java.nio.channels.MembershipKey", + + +"java.nio.channels.AsynchronousSocketChannel", + + +"java.nio.channels.SelectableChannel", +"java.nio.channels.AsynchronousByteChannel", +"java.nio.channels.DatagramChannel", + + + +"java.nio.IntBuffer", +"java.nio.ByteBuffer", +"java.nio.LongBuffer", +"java.nio.file.FileVisitor", +"java.nio.file.spi.FileSystemProvider", +"java.nio.file.spi.FileTypeDetector", +"java.nio.file.FileStore", + +"java.nio.file.OpenOption", + +"java.nio.file.SecureDirectoryStream", +"java.nio.file.StandardOpenOption", + + +"java.nio.file.DirectoryStream", +"java.nio.file.SimpleFileVisitor", + + + + +"java.nio.file.DirectoryStream$Filter", +"java.nio.file.FileSystems", +"java.nio.file.WatchService", +"java.nio.file.WatchEvent$Kind", + + + +"java.nio.file.Watchable", +"java.nio.file.AccessMode", +"java.nio.file.FileVisitResult", + + + + +"java.nio.file.LinkOption", +"java.nio.file.StandardWatchEventKinds", +"java.nio.file.FileVisitOption", +"java.nio.file.Path", +"java.nio.file.WatchEvent$Modifier", +"java.nio.file.LinkPermission", +"java.nio.file.Files", +"java.nio.file.StandardCopyOption", +"java.nio.file.WatchEvent", + +"java.nio.file.attribute.UserDefinedFileAttributeView", +"java.nio.file.attribute.BasicFileAttributes", +"java.nio.file.attribute.AclEntry", +"java.nio.file.attribute.FileTime", +"java.nio.file.attribute.AclEntry$Builder", +"java.nio.file.attribute.GroupPrincipal", +"java.nio.file.attribute.UserPrincipal", + +"java.nio.file.attribute.AclEntryType", +"java.nio.file.attribute.DosFileAttributeView", +"java.nio.file.attribute.BasicFileAttributeView", +"java.nio.file.attribute.AclFileAttributeView", +"java.nio.file.attribute.FileStoreAttributeView", +"java.nio.file.attribute.PosixFileAttributes", +"java.nio.file.attribute.PosixFilePermission", +"java.nio.file.attribute.PosixFilePermissions", +"java.nio.file.attribute.FileOwnerAttributeView", +"java.nio.file.attribute.AclEntryPermission", +"java.nio.file.attribute.FileAttributeView", +"java.nio.file.attribute.AttributeView", +"java.nio.file.attribute.AclEntryFlag", +"java.nio.file.attribute.FileAttribute", +"java.nio.file.attribute.PosixFileAttributeView", +"java.nio.file.attribute.DosFileAttributes", +"java.nio.file.attribute.UserPrincipalLookupService", + +"java.nio.file.Paths", +"java.nio.file.PathMatcher", + +"java.nio.file.WatchKey", +"java.nio.file.CopyOption", + +"java.nio.file.FileSystem", +"java.nio.ByteOrder", + +"java.nio.MappedByteBuffer", +"java.nio.ShortBuffer", +"java.nio.Buffer", + + +"java.nio.charset.spi.CharsetProvider", + +"java.nio.charset.CoderMalfunctionError", +"java.nio.charset.CoderResult", +"java.nio.charset.CharsetDecoder", +"java.nio.charset.CodingErrorAction", + + +"java.nio.charset.CharsetEncoder", + +"java.nio.charset.Charset", +"java.nio.charset.StandardCharsets", + +"java.nio.FloatBuffer", + +"java.lang.OutOfMemoryError", +"java.lang.StringBuffer", + +"java.lang.ProcessBuilder", +"java.lang.Math", +"java.lang.VerifyError", +"java.lang.InheritableThreadLocal", +"java.lang.BootstrapMethodError", + +"java.lang.RuntimePermission", + +"java.lang.LinkageError", + + +"java.lang.Short", +"java.lang.Package", + +"java.lang.Integer", +"java.lang.ref.SoftReference", +"java.lang.ref.WeakReference", +"java.lang.ref.ReferenceQueue", +"java.lang.ref.PhantomReference", +"java.lang.ref.Reference", +"java.lang.AutoCloseable", +"java.lang.reflect.AccessibleObject", +"java.lang.reflect.Member", +"java.lang.reflect.TypeVariable", +"java.lang.reflect.Constructor", +"java.lang.reflect.ParameterizedType", + + +"java.lang.reflect.Method", +"java.lang.reflect.WildcardType", +"java.lang.reflect.Type", +"java.lang.reflect.GenericSignatureFormatError", +"java.lang.reflect.GenericDeclaration", +"java.lang.reflect.Array", +"java.lang.reflect.GenericArrayType", +"java.lang.reflect.Executable", +"java.lang.reflect.Parameter", +"java.lang.reflect.Field", + +"java.lang.reflect.AnnotatedElement", + +"java.lang.reflect.InvocationHandler", +"java.lang.reflect.Modifier", +"java.lang.reflect.ReflectPermission", +"java.lang.reflect.Proxy", +"java.lang.VirtualMachineError", +"java.lang.Character$UnicodeBlock", + +"java.lang.ClassLoader", +"java.lang.invoke.ConstantCallSite", +"java.lang.invoke.MutableCallSite", + +"java.lang.invoke.CallSite", +"java.lang.invoke.VolatileCallSite", +"java.lang.invoke.MethodType", +"java.lang.invoke.MethodHandles", +"java.lang.invoke.MethodHandleInfo", +"java.lang.invoke.MethodHandles$Lookup", + +"java.lang.invoke.MethodHandle", +"java.lang.UnsupportedClassVersionError", +"java.lang.ThreadDeath", + +"java.lang.Compiler", +"java.lang.Boolean", +"java.lang.Comparable", +"java.lang.Runtime", + + +"java.lang.SuppressWarnings", +"java.lang.Class", +"java.lang.NoSuchMethodError", + +"java.lang.ClassCircularityError", +"java.lang.NoClassDefFoundError", +"java.lang.Byte", + +"java.lang.StackOverflowError", +"java.lang.SafeVarargs", +"java.lang.Error", +"java.lang.Thread$State", + +"java.lang.Process", +"java.lang.Character$Subset", + + +"java.lang.StringBuilder", +"java.lang.ClassFormatError", +"java.lang.String", +"java.lang.StrictMath", + +"java.lang.System", + +"java.lang.Runnable", +"java.lang.annotation.Repeatable", + +"java.lang.annotation.Native", +"java.lang.annotation.AnnotationFormatError", +"java.lang.annotation.Target", +"java.lang.annotation.ElementType", +"java.lang.annotation.Documented", + +"java.lang.annotation.RetentionPolicy", +"java.lang.annotation.Retention", +"java.lang.annotation.Annotation", +"java.lang.annotation.Inherited", +"java.lang.NoSuchFieldError", +"java.lang.Object", +"java.lang.Iterable", + +"java.lang.Long", +"java.lang.Deprecated", + +"java.lang.Character", +"java.lang.Appendable", +"java.lang.Throwable", +"java.lang.Cloneable", + +"java.lang.Void", +"java.lang.Float", +"java.lang.Enum", +"java.lang.IllegalAccessError", +"java.lang.InternalError", + + +"java.lang.StackTraceElement", + +"java.lang.CharSequence", +"java.lang.Thread", + + +"java.lang.Readable", +"java.lang.UnsatisfiedLinkError", +"java.lang.Override", + +"java.lang.FunctionalInterface", +"java.lang.UnknownError", +"java.lang.Character$UnicodeScript", +"java.lang.Number", + + +"java.lang.InstantiationError", +"java.lang.SecurityManager", +"java.lang.ProcessBuilder$Redirect", +"java.lang.AssertionError", +"java.lang.ThreadGroup", +"java.lang.Double", +"java.lang.ProcessBuilder$Redirect$Type", + +"java.lang.IncompatibleClassChangeError", +"java.lang.ThreadLocal", +"java.text.DateFormat$Field", +"java.text.RuleBasedCollator", +"java.text.DecimalFormatSymbols", +"java.text.NumberFormat$Field", +"java.text.Normalizer$Form", +"java.text.Format$Field", +"java.text.CollationKey", +"java.text.Bidi", + +"java.text.DateFormatSymbols", +"java.text.Format", +"java.text.CollationElementIterator", +"java.text.AttributedCharacterIterator", +"java.text.CharacterIterator", +"java.text.SimpleDateFormat", +"java.text.MessageFormat$Field", +"java.text.DecimalFormat", +"java.text.AttributedString", +"java.text.ParsePosition", +"java.text.MessageFormat", +"java.text.NumberFormat", +"java.text.FieldPosition", +"java.text.Collator", +"java.text.Normalizer", +"java.text.DateFormat", +"java.text.StringCharacterIterator", +"java.text.ChoiceFormat", +"java.text.BreakIterator", +"java.text.Annotation", +"java.text.AttributedCharacterIterator$Attribute", +"java.math.RoundingMode", +"java.math.BigInteger", +"java.math.MathContext", +"java.math.BigDecimal", +"java.io.ByteArrayInputStream", +"java.io.CharArrayReader", +"java.io.InputStreamReader", +"java.io.PrintStream", +"java.io.ObjectInput", +"java.io.InputStream", + +"java.io.ObjectOutput", +"java.io.Closeable", + +"java.io.Writer", +"java.io.SequenceInputStream", +"java.io.CharArrayWriter", +"java.io.DataInputStream", +"java.io.PrintWriter", +"java.io.BufferedInputStream", +"java.io.DataOutput", +"java.io.PushbackInputStream", +"java.io.BufferedOutputStream", +"java.io.SerializablePermission", +"java.io.OutputStream", +"java.io.ObjectStreamConstants", +"java.io.OutputStreamWriter", + +"java.io.StreamTokenizer", + +"java.io.Reader", + +"java.io.RandomAccessFile", + + +"java.io.FileWriter", +"java.io.ObjectStreamClass", +"java.io.ObjectInputStream", +"java.io.FileFilter", +"java.io.FilterReader", +"java.io.ObjectInputValidation", + +"java.io.Console", +"java.io.StringWriter", + +"java.io.FilterInputStream", +"java.io.Serializable", +"java.io.Externalizable", + + +"java.io.PipedWriter", +"java.io.StringBufferInputStream", +"java.io.ObjectInputStream$GetField", + +"java.io.PipedInputStream", +"java.io.FilterOutputStream", +"java.io.Flushable", +"java.io.PipedOutputStream", +"java.io.BufferedWriter", +"java.io.LineNumberInputStream", +"java.io.FileReader", +"java.io.StringReader", + +"java.io.File", +"java.io.ByteArrayOutputStream", +"java.io.PipedReader", +"java.io.FilePermission", +"java.io.ObjectOutputStream", +"java.io.IOError", +"java.io.FileInputStream", +"java.io.ObjectOutputStream$PutField", +"java.io.FileDescriptor", +"java.io.FilenameFilter", + + +"java.io.ObjectStreamField", +"java.io.PushbackReader", + +"java.io.BufferedReader", +"java.io.DataOutputStream", + +"java.io.LineNumberReader", +"java.io.FileOutputStream", +"java.io.FilterWriter", +"java.io.DataInput", +"java.beans.IndexedPropertyChangeEvent", +"java.beans.PropertyChangeEvent", +"java.beans.PropertyChangeListener", +"java.beans.PropertyChangeSupport", +"java.beans.PropertyChangeListenerProxy", +"java.awt.font.NumericShaper$Range", +"java.awt.font.NumericShaper", +"java.awt.font.TextAttribute", +"java.util.TreeSet", + +"java.util.Objects", +"java.util.Set", +"java.util.prefs.PreferenceChangeListener", +"java.util.prefs.PreferenceChangeEvent", +"java.util.prefs.NodeChangeEvent", + +"java.util.prefs.PreferencesFactory", +"java.util.prefs.Preferences", +"java.util.prefs.NodeChangeListener", + + +"java.util.Locale$Builder", +"java.util.concurrent.ConcurrentSkipListMap", +"java.util.concurrent.locks.ReentrantLock", +"java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock", + +"java.util.concurrent.locks.ReentrantReadWriteLock", + +"java.util.concurrent.locks.ReadWriteLock", +"java.util.concurrent.locks.Lock", +"java.util.concurrent.locks.LockSupport", + + +"java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock", +"java.util.concurrent.locks.Condition", +"java.util.concurrent.locks.StampedLock", + + +"java.util.concurrent.TransferQueue", +"java.util.concurrent.Future", +"java.util.concurrent.SynchronousQueue", +"java.util.concurrent.Delayed", +"java.util.concurrent.BlockingDeque", +"java.util.concurrent.CopyOnWriteArrayList", +"java.util.concurrent.ForkJoinTask", +"java.util.concurrent.Phaser", +"java.util.concurrent.RunnableScheduledFuture", +"java.util.concurrent.ThreadPoolExecutor$AbortPolicy", +"java.util.concurrent.ConcurrentNavigableMap", +"java.util.concurrent.TimeUnit", +"java.util.concurrent.ScheduledExecutorService", +"java.util.concurrent.ForkJoinWorkerThread", +"java.util.concurrent.ForkJoinPool$ForkJoinWorkerThreadFactory", +"java.util.concurrent.ConcurrentHashMap", +"java.util.concurrent.ThreadFactory", +"java.util.concurrent.ConcurrentMap", +"java.util.concurrent.CompletionStage", +"java.util.concurrent.RunnableFuture", +"java.util.concurrent.Exchanger", +"java.util.concurrent.ThreadLocalRandom", +"java.util.concurrent.ConcurrentHashMap$KeySetView", +"java.util.concurrent.ForkJoinPool$ManagedBlocker", +"java.util.concurrent.CompletableFuture", +"java.util.concurrent.CountDownLatch", +"java.util.concurrent.ExecutorService", +"java.util.concurrent.LinkedBlockingDeque", + +"java.util.concurrent.ScheduledFuture", +"java.util.concurrent.ThreadPoolExecutor$DiscardPolicy", +"java.util.concurrent.ForkJoinPool", + +"java.util.concurrent.ThreadPoolExecutor$DiscardOldestPolicy", +"java.util.concurrent.atomic.AtomicLongFieldUpdater", +"java.util.concurrent.atomic.AtomicIntegerArray", +"java.util.concurrent.atomic.LongAccumulator", +"java.util.concurrent.atomic.AtomicReference", +"java.util.concurrent.atomic.LongAdder", +"java.util.concurrent.atomic.AtomicLong", +"java.util.concurrent.atomic.DoubleAccumulator", +"java.util.concurrent.atomic.AtomicStampedReference", +"java.util.concurrent.atomic.AtomicBoolean", +"java.util.concurrent.atomic.AtomicMarkableReference", +"java.util.concurrent.atomic.AtomicLongArray", +"java.util.concurrent.atomic.AtomicIntegerFieldUpdater", +"java.util.concurrent.atomic.AtomicInteger", +"java.util.concurrent.atomic.AtomicReferenceArray", +"java.util.concurrent.atomic.DoubleAdder", +"java.util.concurrent.atomic.AtomicReferenceFieldUpdater", +"java.util.concurrent.ConcurrentSkipListSet", +"java.util.concurrent.ConcurrentLinkedDeque", +"java.util.concurrent.CyclicBarrier", +"java.util.concurrent.RejectedExecutionHandler", +"java.util.concurrent.DelayQueue", +"java.util.concurrent.Executors", + +"java.util.concurrent.ThreadPoolExecutor", +"java.util.concurrent.LinkedBlockingQueue", +"java.util.concurrent.CompletionService", + +"java.util.concurrent.FutureTask", +"java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy", +"java.util.concurrent.LinkedTransferQueue", +"java.util.concurrent.RecursiveAction", + +"java.util.concurrent.CopyOnWriteArraySet", +"java.util.concurrent.ArrayBlockingQueue", +"java.util.concurrent.Semaphore", +"java.util.concurrent.Callable", +"java.util.concurrent.Executor", +"java.util.concurrent.CompletableFuture$AsynchronousCompletionTask", +"java.util.concurrent.ConcurrentLinkedQueue", +"java.util.concurrent.ScheduledThreadPoolExecutor", +"java.util.concurrent.PriorityBlockingQueue", + +"java.util.concurrent.BlockingQueue", +"java.util.concurrent.CountedCompleter", +"java.util.concurrent.RecursiveTask", +"java.util.concurrent.ExecutorCompletionService", +"java.util.NavigableMap", + + +"java.util.Calendar$Builder", + +"java.util.Calendar", +"java.util.SimpleTimeZone", +"java.util.ListResourceBundle", + +"java.util.ArrayList", +"java.util.Locale", +"java.util.Arrays", +"java.util.jar.Manifest", +"java.util.jar.JarOutputStream", +"java.util.jar.JarEntry", +"java.util.jar.JarFile", +"java.util.jar.JarInputStream", +"java.util.jar.Pack200$Unpacker", +"java.util.jar.Attributes$Name", +"java.util.jar.Pack200", +"java.util.jar.Attributes", +"java.util.jar.Pack200$Packer", + + +"java.util.SplittableRandom", +"java.util.function.ToIntBiFunction", +"java.util.function.ToDoubleBiFunction", +"java.util.function.DoubleFunction", +"java.util.function.ObjLongConsumer", +"java.util.function.BinaryOperator", +"java.util.function.LongBinaryOperator", +"java.util.function.IntToLongFunction", +"java.util.function.BooleanSupplier", +"java.util.function.LongFunction", +"java.util.function.DoubleSupplier", +"java.util.function.BiConsumer", +"java.util.function.Predicate", +"java.util.function.LongUnaryOperator", +"java.util.function.BiPredicate", +"java.util.function.DoubleConsumer", +"java.util.function.DoubleToLongFunction", +"java.util.function.ObjDoubleConsumer", +"java.util.function.DoublePredicate", +"java.util.function.LongConsumer", +"java.util.function.Function", +"java.util.function.Supplier", +"java.util.function.DoubleBinaryOperator", +"java.util.function.ToDoubleFunction", +"java.util.function.IntToDoubleFunction", +"java.util.function.IntConsumer", +"java.util.function.UnaryOperator", +"java.util.function.ToLongBiFunction", +"java.util.function.IntBinaryOperator", +"java.util.function.LongToIntFunction", +"java.util.function.IntPredicate", +"java.util.function.IntUnaryOperator", +"java.util.function.ObjIntConsumer", +"java.util.function.IntFunction", +"java.util.function.BiFunction", +"java.util.function.Consumer", +"java.util.function.DoubleToIntFunction", +"java.util.function.ToLongFunction", +"java.util.function.DoubleUnaryOperator", +"java.util.function.IntSupplier", +"java.util.function.LongToDoubleFunction", +"java.util.function.ToIntFunction", +"java.util.function.LongPredicate", +"java.util.function.LongSupplier", +"java.util.LinkedList", +"java.util.PrimitiveIterator", +"java.util.LongSummaryStatistics", +"java.util.Base64$Encoder", +"java.util.Formattable", +"java.util.UUID", + +"java.util.PropertyPermission", +"java.util.stream.Stream", +"java.util.stream.StreamSupport", +"java.util.stream.IntStream$Builder", +"java.util.stream.LongStream", +"java.util.stream.Collector", +"java.util.stream.DoubleStream", +"java.util.stream.Stream$Builder", +"java.util.stream.IntStream", +"java.util.stream.BaseStream", +"java.util.stream.Collector$Characteristics", +"java.util.stream.Collectors", +"java.util.stream.LongStream$Builder", +"java.util.stream.DoubleStream$Builder", +"java.util.LinkedHashSet", + +"java.util.Deque", +"java.util.zip.Inflater", +"java.util.zip.Adler32", +"java.util.zip.Deflater", +"java.util.zip.DeflaterOutputStream", +"java.util.zip.ZipError", +"java.util.zip.Checksum", +"java.util.zip.ZipEntry", +"java.util.zip.ZipInputStream", +"java.util.zip.ZipFile", + +"java.util.zip.CheckedOutputStream", + +"java.util.zip.CRC32", +"java.util.zip.InflaterInputStream", +"java.util.zip.GZIPOutputStream", +"java.util.zip.ZipOutputStream", +"java.util.zip.GZIPInputStream", +"java.util.zip.CheckedInputStream", +"java.util.zip.DeflaterInputStream", +"java.util.zip.InflaterOutputStream", +"java.util.StringJoiner", +"java.util.Base64", +"java.util.OptionalInt", +"java.util.HashMap", +"java.util.Locale$FilteringMode", +"java.util.Stack", +"java.util.Observer", +"java.util.EventListenerProxy", +"java.util.Vector", +"java.util.NavigableSet", +"java.util.regex.Matcher", +"java.util.regex.Pattern", +"java.util.regex.MatchResult", + +"java.util.PropertyResourceBundle", +"java.util.HashSet", +"java.util.SortedMap", +"java.util.FormattableFlags", +"java.util.List", +"java.util.TimeZone", +"java.util.Formatter", + + + +"java.util.Optional", + +"java.util.EnumMap", +"java.util.Timer", + +"java.util.IdentityHashMap", +"java.util.ServiceLoader", +"java.util.PrimitiveIterator$OfInt", + +"java.util.logging.FileHandler", +"java.util.logging.Filter", +"java.util.logging.SimpleFormatter", +"java.util.logging.LoggingMXBean", +"java.util.logging.Formatter", +"java.util.logging.MemoryHandler", +"java.util.logging.StreamHandler", +"java.util.logging.ErrorManager", +"java.util.logging.ConsoleHandler", +"java.util.logging.SocketHandler", +"java.util.logging.LoggingPermission", +"java.util.logging.XMLFormatter", +"java.util.logging.Level", +"java.util.logging.LogManager", +"java.util.logging.Logger", +"java.util.logging.Handler", +"java.util.logging.LogRecord", +"java.util.Properties", +"java.util.Enumeration", +"java.util.Base64$Decoder", + +"java.util.LinkedHashMap", +"java.util.Spliterator", +"java.util.Random", +"java.util.Observable", +"java.util.RandomAccess", + + +"java.util.PrimitiveIterator$OfLong", + +"java.util.IntSummaryStatistics", +"java.util.StringTokenizer", +"java.util.Queue", +"java.util.Spliterator$OfLong", +"java.util.OptionalLong", +"java.util.TreeMap", +"java.util.Collection", +"java.util.Dictionary", + +"java.util.Currency", + +"java.util.SortedSet", +"java.util.Spliterator$OfPrimitive", + +"java.util.Locale$LanguageRange", +"java.util.Map", +"java.util.BitSet", +"java.util.WeakHashMap", +"java.util.EnumSet", + +"java.util.ArrayDeque", +"java.util.Iterator", +"java.util.Locale$Category", + +"java.util.Date", + + +"java.util.GregorianCalendar", +"java.util.EventListener", +"java.util.PrimitiveIterator$OfDouble", + +"java.util.Formatter$BigDecimalLayoutForm", +"java.util.Scanner", +"java.util.ResourceBundle$Control", +"java.util.DoubleSummaryStatistics", +"java.util.Spliterator$OfInt", +"java.util.ResourceBundle", +"java.util.ServiceConfigurationError", + +"java.util.EventObject", + + + + + +"java.util.Hashtable", + +"java.util.Spliterator$OfDouble", +"java.util.ListIterator", +"java.util.Map$Entry", +"java.util.TimerTask", +"java.util.OptionalDouble", +"java.util.Spliterators", +"java.util.Comparator", +"java.util.PriorityQueue", +"java.util.Collections", +"java.time.LocalDateTime", +"java.time.LocalTime", +"java.time.ZonedDateTime", +"java.time.MonthDay", +"java.time.Year", +"java.time.format.ResolverStyle", +"java.time.format.FormatStyle", +"java.time.format.DateTimeFormatterBuilder", + +"java.time.format.DecimalStyle", +"java.time.format.DateTimeFormatter", +"java.time.format.TextStyle", +"java.time.format.SignStyle", +"java.time.OffsetDateTime", +"java.time.Duration", +"java.time.LocalDate", +"java.time.OffsetTime", +"java.time.ZoneOffset", +"java.time.Month", +"java.time.Clock", +"java.time.temporal.TemporalField", +"java.time.temporal.TemporalQuery", +"java.time.temporal.JulianFields", +"java.time.temporal.ValueRange", +"java.time.temporal.IsoFields", +"java.time.temporal.TemporalQueries", +"java.time.temporal.TemporalAmount", +"java.time.temporal.TemporalUnit", +"java.time.temporal.ChronoUnit", + +"java.time.temporal.ChronoField", +"java.time.temporal.Temporal", +"java.time.temporal.TemporalAdjusters", +"java.time.temporal.TemporalAdjuster", +"java.time.temporal.TemporalAccessor", +"java.time.temporal.WeekFields", +"java.time.YearMonth", + +"java.time.ZoneId", +"java.time.chrono.MinguoEra", +"java.time.chrono.ThaiBuddhistDate", +"java.time.chrono.JapaneseEra", +"java.time.chrono.ChronoPeriod", +"java.time.chrono.JapaneseChronology", +"java.time.chrono.MinguoChronology", +"java.time.chrono.ChronoZonedDateTime", +"java.time.chrono.MinguoDate", +"java.time.chrono.ThaiBuddhistEra", +"java.time.chrono.HijrahEra", +"java.time.chrono.Era", +"java.time.chrono.IsoChronology", +"java.time.chrono.HijrahChronology", +"java.time.chrono.ChronoLocalDateTime", +"java.time.chrono.JapaneseDate", +"java.time.chrono.IsoEra", +"java.time.chrono.HijrahDate", +"java.time.chrono.Chronology", +"java.time.chrono.ChronoLocalDate", +"java.time.chrono.ThaiBuddhistChronology", + +"java.time.Period", +"java.time.DayOfWeek", +"java.time.zone.ZoneOffsetTransitionRule$TimeDefinition", +"java.time.zone.ZoneOffsetTransitionRule", + +"java.time.zone.ZoneOffsetTransition", +"java.time.zone.ZoneRules", +"java.time.Instant", + +"java.net.StandardProtocolFamily", +"java.net.URLClassLoader", +"java.net.DatagramSocketImplFactory", +"java.net.SocketImplFactory", +"java.net.FileNameMap", +"java.net.DatagramSocket", +"java.net.CookieHandler", +"java.net.PasswordAuthentication", +"java.net.ProtocolFamily", +"java.net.CookieManager", +"java.net.SocketImpl", +"java.net.URI", +"java.net.Inet4Address", + + +"java.net.URLStreamHandlerFactory", +"java.net.URLConnection", +"java.net.URL", +"java.net.InterfaceAddress", +"java.net.ResponseCache", +"java.net.DatagramPacket", + +"java.net.ProxySelector", +"java.net.JarURLConnection", +"java.net.URLEncoder", +"java.net.SocketOption", +"java.net.Socket", + +"java.net.Authenticator", +"java.net.SecureCacheResponse", +"java.net.CookiePolicy", + +"java.net.SocketPermission", + +"java.net.MulticastSocket", +"java.net.HttpURLConnection", +"java.net.Inet6Address", + +"java.net.Authenticator$RequestorType", +"java.net.ContentHandlerFactory", +"java.net.CookieStore", +"java.net.Proxy$Type", +"java.net.InetSocketAddress", + +"java.net.DatagramSocketImpl", +"java.net.NetPermission", + +"java.net.SocketAddress", +"java.net.HttpCookie", +"java.net.CacheResponse", +"java.net.InetAddress", +"java.net.StandardSocketOptions", +"java.net.NetworkInterface", +"java.net.ContentHandler", +"java.net.URLStreamHandler", + + +"java.net.ServerSocket", +"java.net.SocketOptions", +"java.net.Proxy", +"java.net.IDN", +"java.net.URLDecoder", +"java.net.CacheRequest", +"java.security.PKCS12Attribute", +"java.security.KeyFactory", +"java.security.MessageDigestSpi", +"java.security.KeyStore$LoadStoreParameter", +"java.security.Security", +"java.security.Timestamp", +"java.security.SecureRandomSpi", +"java.security.Key", +"java.security.SignedObject", + +"java.security.Certificate", +"java.security.MessageDigest", +"java.security.Guard", +"java.security.KeyStore$TrustedCertificateEntry", +"java.security.SignatureSpi", +"java.security.SecurityPermission", + +"java.security.Signer", +"java.security.KeyPairGeneratorSpi", + +"java.security.CodeSource", +"java.security.DigestOutputStream", +"java.security.BasicPermission", +"java.security.SecureClassLoader", +"java.security.UnresolvedPermission", +"java.security.spec.DSAPublicKeySpec", +"java.security.spec.ECParameterSpec", +"java.security.spec.ECPoint", +"java.security.spec.RSAPrivateKeySpec", +"java.security.spec.ECFieldFp", + +"java.security.spec.EllipticCurve", +"java.security.spec.RSAOtherPrimeInfo", +"java.security.spec.EncodedKeySpec", +"java.security.spec.ECPrivateKeySpec", +"java.security.spec.DSAPrivateKeySpec", +"java.security.spec.X509EncodedKeySpec", +"java.security.spec.KeySpec", +"java.security.spec.ECField", +"java.security.spec.RSAKeyGenParameterSpec", +"java.security.spec.RSAPublicKeySpec", +"java.security.spec.DSAParameterSpec", +"java.security.spec.MGF1ParameterSpec", +"java.security.spec.PSSParameterSpec", +"java.security.spec.ECFieldF2m", +"java.security.spec.ECGenParameterSpec", +"java.security.spec.RSAMultiPrimePrivateCrtKeySpec", + +"java.security.spec.PKCS8EncodedKeySpec", +"java.security.spec.AlgorithmParameterSpec", +"java.security.spec.RSAPrivateCrtKeySpec", +"java.security.spec.ECPublicKeySpec", +"java.security.PolicySpi", +"java.security.PublicKey", +"java.security.AccessControlContext", +"java.security.Permissions", +"java.security.SecureRandom", +"java.security.KeyStore$PasswordProtection", +"java.security.KeyPairGenerator", +"java.security.KeyStore$ProtectionParameter", + +"java.security.Signature", +"java.security.KeyStore$Entry", +"java.security.KeyStore$Builder", +"java.security.CodeSigner", +"java.security.AlgorithmParametersSpi", +"java.security.KeyStore$PrivateKeyEntry", +"java.security.KeyStoreSpi", + +"java.security.IdentityScope", +"java.security.AccessController", +"java.security.interfaces.DSAPrivateKey", +"java.security.interfaces.RSAKey", +"java.security.interfaces.ECPublicKey", +"java.security.interfaces.RSAPrivateCrtKey", +"java.security.interfaces.ECKey", +"java.security.interfaces.DSAParams", +"java.security.interfaces.RSAPublicKey", +"java.security.interfaces.ECPrivateKey", +"java.security.interfaces.RSAPrivateKey", +"java.security.interfaces.DSAKeyPairGenerator", +"java.security.interfaces.DSAKey", +"java.security.interfaces.DSAPublicKey", +"java.security.interfaces.RSAMultiPrimePrivateCrtKey", +"java.security.Principal", +"java.security.PermissionCollection", +"java.security.GuardedObject", + +"java.security.CryptoPrimitive", +"java.security.Policy", + + + +"java.security.AlgorithmConstraints", + +"java.security.Provider", +"java.security.Identity", +"java.security.cert.CRLSelector", +"java.security.cert.CertPathValidator", +"java.security.cert.CertStoreParameters", +"java.security.cert.X509CRLSelector", +"java.security.cert.Certificate", + +"java.security.cert.PKIXCertPathChecker", +"java.security.cert.X509CRL", +"java.security.cert.LDAPCertStoreParameters", +"java.security.cert.X509CRLEntry", +"java.security.cert.PKIXCertPathBuilderResult", +"java.security.cert.CertPathParameters", +"java.security.cert.TrustAnchor", +"java.security.cert.CertPathBuilderSpi", +"java.security.cert.CertPathValidatorResult", + +"java.security.cert.X509CertSelector", + +"java.security.cert.PKIXParameters", +"java.security.cert.CertPath", +"java.security.cert.PKIXRevocationChecker", + +"java.security.cert.CertStore", +"java.security.cert.CertificateFactorySpi", +"java.security.cert.CertStoreSpi", +"java.security.cert.PKIXRevocationChecker$Option", + +"java.security.cert.PolicyQualifierInfo", +"java.security.cert.PKIXCertPathValidatorResult", + +"java.security.cert.CertPathBuilder", +"java.security.cert.CertPathBuilderResult", +"java.security.cert.CertPathValidatorSpi", +"java.security.cert.CertSelector", +"java.security.cert.PKIXReason", + +"java.security.cert.PKIXBuilderParameters", +"java.security.cert.PolicyNode", + +"java.security.cert.Extension", +"java.security.cert.CertPath$CertPathRep", +"java.security.cert.CRL", + +"java.security.cert.X509Certificate", + +"java.security.cert.X509Extension", +"java.security.cert.CRLReason", + +"java.security.cert.CertPathChecker", +"java.security.cert.CollectionCertStoreParameters", +"java.security.cert.CertificateFactory", +"java.security.cert.Certificate$CertificateRep", + +"java.security.AlgorithmParameterGenerator", + +"java.security.acl.AclEntry", +"java.security.acl.Owner", + +"java.security.acl.Group", + +"java.security.acl.Permission", +"java.security.acl.Acl", +"java.security.KeyStore$Entry$Attribute", + +"java.security.Provider$Service", +"java.security.KeyPair", +"java.security.Policy$Parameters", +"java.security.AllPermission", + +"java.security.KeyStore$SecretKeyEntry", +"java.security.KeyRep", +"java.security.DigestInputStream", + +"java.security.AlgorithmParameterGeneratorSpi", +"java.security.KeyFactorySpi", + +"java.security.ProtectionDomain", +"java.security.PrivateKey", + +"java.security.KeyStore", +"java.security.DomainLoadStoreParameter", +"java.security.AuthProvider", + +"java.security.Permission", +"java.security.AlgorithmParameters", +"java.security.KeyRep$Type", +"java.security.PrivilegedAction", +"java.security.DomainCombiner", +"java.security.KeyStore$CallbackHandlerProtection", + +"java.sql.DriverPropertyInfo", +"java.sql.Timestamp", +"java.sql.SQLPermission", + +"java.sql.RowId", +"java.sql.SQLData", +"java.sql.SQLXML", + +"java.sql.NClob", +"java.sql.Statement", +"java.sql.Blob", +"java.sql.DriverManager", +"java.sql.CallableStatement", + + + +"java.sql.DatabaseMetaData", + +"java.sql.SQLOutput", +"java.sql.Connection", +"java.sql.Array", +"java.sql.Ref", +"java.sql.PreparedStatement", + +"java.sql.Struct", + + + + +"java.sql.Wrapper", +"java.sql.RowIdLifetime", +"java.sql.ParameterMetaData", +"java.sql.Types", +"java.sql.SQLInput", +"java.sql.DataTruncation", + +"java.sql.Date", +"java.sql.Clob", +"java.sql.Savepoint", +"java.sql.ClientInfoStatus", +"java.sql.SQLWarning", +"java.sql.Driver", + +"java.sql.ResultSet", + +"java.sql.Time", +"java.sql.ResultSetMetaData", + +"javax.microedition.khronos.opengles.GL10Ext", +"javax.microedition.khronos.opengles.GL11Ext", +"javax.microedition.khronos.opengles.GL11", +"javax.microedition.khronos.opengles.GL", +"javax.microedition.khronos.opengles.GL11ExtensionPack", +"javax.microedition.khronos.opengles.GL10", +"javax.microedition.khronos.egl.EGL11", +"javax.microedition.khronos.egl.EGL", +"javax.microedition.khronos.egl.EGLConfig", +"javax.microedition.khronos.egl.EGLContext", +"javax.microedition.khronos.egl.EGL10", +"javax.microedition.khronos.egl.EGLSurface", +"javax.microedition.khronos.egl.EGLDisplay", +"javax.crypto.CipherInputStream", +"javax.crypto.KeyAgreementSpi", +"javax.crypto.CipherSpi", +"javax.crypto.NullCipher", + +"javax.crypto.KeyGeneratorSpi", +"javax.crypto.KeyGenerator", + +"javax.crypto.spec.DHGenParameterSpec", +"javax.crypto.spec.PSource$PSpecified", +"javax.crypto.spec.PBEKeySpec", +"javax.crypto.spec.PSource", +"javax.crypto.spec.PBEParameterSpec", +"javax.crypto.spec.DHPrivateKeySpec", +"javax.crypto.spec.DHParameterSpec", +"javax.crypto.spec.SecretKeySpec", +"javax.crypto.spec.DESKeySpec", +"javax.crypto.spec.DESedeKeySpec", +"javax.crypto.spec.RC5ParameterSpec", +"javax.crypto.spec.OAEPParameterSpec", +"javax.crypto.spec.IvParameterSpec", +"javax.crypto.spec.GCMParameterSpec", +"javax.crypto.spec.DHPublicKeySpec", +"javax.crypto.spec.RC2ParameterSpec", +"javax.crypto.SecretKeyFactory", +"javax.crypto.MacSpi", +"javax.crypto.interfaces.DHPublicKey", +"javax.crypto.interfaces.DHPrivateKey", +"javax.crypto.interfaces.PBEKey", +"javax.crypto.interfaces.DHKey", +"javax.crypto.Cipher", +"javax.crypto.ExemptionMechanismSpi", +"javax.crypto.SecretKeyFactorySpi", + +"javax.crypto.SecretKey", +"javax.crypto.KeyAgreement", +"javax.crypto.SealedObject", +"javax.crypto.CipherOutputStream", + +"javax.crypto.Mac", +"javax.crypto.EncryptedPrivateKeyInfo", +"javax.crypto.ExemptionMechanism", + + +"javax.xml.transform.TransformerFactory", +"javax.xml.transform.stream.StreamResult", +"javax.xml.transform.stream.StreamSource", +"javax.xml.transform.Source", +"javax.xml.transform.URIResolver", +"javax.xml.transform.SourceLocator", +"javax.xml.transform.Transformer", +"javax.xml.transform.Result", +"javax.xml.transform.Templates", +"javax.xml.transform.ErrorListener", +"javax.xml.transform.OutputKeys", +"javax.xml.transform.sax.TemplatesHandler", +"javax.xml.transform.sax.TransformerHandler", +"javax.xml.transform.sax.SAXSource", +"javax.xml.transform.sax.SAXTransformerFactory", +"javax.xml.transform.sax.SAXResult", +"javax.xml.transform.dom.DOMSource", +"javax.xml.transform.dom.DOMResult", +"javax.xml.transform.dom.DOMLocator", + +"javax.xml.transform.TransformerFactoryConfigurationError", + +"javax.xml.xpath.XPathExpression", +"javax.xml.xpath.XPath", +"javax.xml.xpath.XPathVariableResolver", +"javax.xml.xpath.XPathFunction", + +"javax.xml.xpath.XPathFactory", +"javax.xml.xpath.XPathFunctionResolver", +"javax.xml.xpath.XPathConstants", + + + +"javax.xml.namespace.NamespaceContext", +"javax.xml.namespace.QName", +"javax.xml.validation.SchemaFactory", +"javax.xml.validation.SchemaFactoryLoader", +"javax.xml.validation.TypeInfoProvider", +"javax.xml.validation.Validator", +"javax.xml.validation.Schema", +"javax.xml.validation.ValidatorHandler", +"javax.xml.datatype.Duration", + +"javax.xml.datatype.XMLGregorianCalendar", +"javax.xml.datatype.DatatypeFactory", +"javax.xml.datatype.DatatypeConstants$Field", +"javax.xml.datatype.DatatypeConstants", +"javax.xml.parsers.SAXParserFactory", +"javax.xml.parsers.DocumentBuilderFactory", +"javax.xml.parsers.SAXParser", +"javax.xml.parsers.DocumentBuilder", + +"javax.xml.parsers.FactoryConfigurationError", +"javax.xml.XMLConstants", +"javax.net.ServerSocketFactory", +"javax.net.ssl.X509ExtendedKeyManager", +"javax.net.ssl.X509TrustManager", +"javax.net.ssl.X509KeyManager", +"javax.net.ssl.SSLEngineResult$HandshakeStatus", +"javax.net.ssl.SSLServerSocket", +"javax.net.ssl.SSLSession", +"javax.net.ssl.HandshakeCompletedListener", +"javax.net.ssl.SSLEngineResult$Status", +"javax.net.ssl.SSLContextSpi", +"javax.net.ssl.SSLSocketFactory", +"javax.net.ssl.SSLSessionBindingEvent", +"javax.net.ssl.KeyManager", +"javax.net.ssl.KeyManagerFactorySpi", +"javax.net.ssl.TrustManagerFactorySpi", +"javax.net.ssl.SSLSessionContext", +"javax.net.ssl.SSLSessionBindingListener", +"javax.net.ssl.HttpsURLConnection", +"javax.net.ssl.SSLParameters", +"javax.net.ssl.HandshakeCompletedEvent", +"javax.net.ssl.SSLPermission", +"javax.net.ssl.TrustManagerFactory", + +"javax.net.ssl.HostnameVerifier", +"javax.net.ssl.StandardConstants", +"javax.net.ssl.SNIServerName", + +"javax.net.ssl.X509ExtendedTrustManager", +"javax.net.ssl.ExtendedSSLSession", +"javax.net.ssl.SNIMatcher", +"javax.net.ssl.CertPathTrustManagerParameters", +"javax.net.ssl.SSLEngineResult", +"javax.net.ssl.TrustManager", +"javax.net.ssl.SSLServerSocketFactory", + +"javax.net.ssl.SSLSocket", +"javax.net.ssl.SSLEngine", +"javax.net.ssl.KeyStoreBuilderParameters", + +"javax.net.ssl.SSLContext", +"javax.net.ssl.ManagerFactoryParameters", +"javax.net.ssl.KeyManagerFactory", + +"javax.net.ssl.SNIHostName", +"javax.net.SocketFactory", +"javax.security.cert.Certificate", + + + +"javax.security.cert.X509Certificate", + + +"javax.security.auth.Destroyable", +"javax.security.auth.PrivateCredentialPermission", + +"javax.security.auth.Subject", +"javax.security.auth.x500.X500Principal", + + +"javax.security.auth.callback.PasswordCallback", +"javax.security.auth.callback.Callback", +"javax.security.auth.callback.CallbackHandler", +"javax.security.auth.AuthPermission", +"javax.security.auth.SubjectDomainCombiner", +"javax.sql.RowSetEvent", +"javax.sql.DataSource", +"javax.sql.StatementEvent", +"javax.sql.ConnectionEvent", +"javax.sql.RowSetListener", +"javax.sql.StatementEventListener", +"javax.sql.RowSetWriter", +"javax.sql.RowSet", +"javax.sql.RowSetMetaData", +"javax.sql.RowSetReader", +"javax.sql.ConnectionPoolDataSource", +"javax.sql.ConnectionEventListener", +"javax.sql.CommonDataSource", +"javax.sql.RowSetInternal", +"javax.sql.PooledConnection", +"AndroidManifest.xml", +"androidx.annotation.RecentlyNullable", +"androidx.annotation.RecentlyNonNull", +"org.apache.http.params.HttpParams", +"org.apache.http.params.HttpConnectionParams", +"org.apache.http.params.CoreConnectionPNames", + +"org.apache.http.conn.ssl.StrictHostnameVerifier", +"org.apache.http.conn.ssl.X509HostnameVerifier", +"org.apache.http.conn.ssl.BrowserCompatHostnameVerifier", +"org.apache.http.conn.ssl.SSLSocketFactory", +"org.apache.http.conn.ssl.AllowAllHostnameVerifier", + +"org.apache.http.conn.scheme.HostNameResolver", +"org.apache.http.conn.scheme.SocketFactory", +"org.apache.http.conn.scheme.LayeredSocketFactory", +"org.xmlpull.v1.XmlPullParserFactory", +"org.xmlpull.v1.XmlSerializer", +"org.xmlpull.v1.XmlPullParser", + +"org.xmlpull.v1.sax2.Driver", +"org.xml.sax.helpers.AttributesImpl", +"org.xml.sax.helpers.DefaultHandler", +"org.xml.sax.helpers.LocatorImpl", +"org.xml.sax.helpers.XMLReaderFactory", +"org.xml.sax.helpers.NamespaceSupport", +"org.xml.sax.helpers.XMLFilterImpl", +"org.xml.sax.helpers.XMLReaderAdapter", +"org.xml.sax.helpers.AttributeListImpl", +"org.xml.sax.helpers.ParserAdapter", +"org.xml.sax.helpers.ParserFactory", +"org.xml.sax.ErrorHandler", +"org.xml.sax.Locator", +"org.xml.sax.AttributeList", +"org.xml.sax.DocumentHandler", +"org.xml.sax.DTDHandler", + + +"org.xml.sax.XMLFilter", +"org.xml.sax.XMLReader", +"org.xml.sax.InputSource", +"org.xml.sax.HandlerBase", +"org.xml.sax.Parser", +"org.xml.sax.Attributes", + + +"org.xml.sax.ContentHandler", +"org.xml.sax.EntityResolver", +"org.xml.sax.ext.LexicalHandler", +"org.xml.sax.ext.DefaultHandler2", +"org.xml.sax.ext.Attributes2", +"org.xml.sax.ext.DeclHandler", +"org.xml.sax.ext.Attributes2Impl", +"org.xml.sax.ext.EntityResolver2", +"org.xml.sax.ext.Locator2Impl", +"org.xml.sax.ext.Locator2", +"org.json.JSONStringer", +"org.json.JSONTokener", + +"org.json.JSONObject", +"org.json.JSONArray", +"org.w3c.dom.DOMStringList", +"org.w3c.dom.TypeInfo", +"org.w3c.dom.ProcessingInstruction", +"org.w3c.dom.Text", +"org.w3c.dom.NamedNodeMap", +"org.w3c.dom.EntityReference", +"org.w3c.dom.Document", +"org.w3c.dom.Notation", +"org.w3c.dom.NameList", +"org.w3c.dom.NodeList", +"org.w3c.dom.Entity", +"org.w3c.dom.UserDataHandler", +"org.w3c.dom.ls.LSInput", + +"org.w3c.dom.ls.LSParser", +"org.w3c.dom.ls.LSOutput", +"org.w3c.dom.ls.LSSerializer", +"org.w3c.dom.ls.DOMImplementationLS", +"org.w3c.dom.ls.LSParserFilter", +"org.w3c.dom.ls.LSResourceResolver", +"org.w3c.dom.Node", +"org.w3c.dom.Attr", +"org.w3c.dom.Comment", +"org.w3c.dom.CDATASection", +"org.w3c.dom.DOMImplementationList", +"org.w3c.dom.DOMError", +"org.w3c.dom.CharacterData", +"org.w3c.dom.DOMImplementation", +"org.w3c.dom.DOMConfiguration", +"org.w3c.dom.DocumentType", +"org.w3c.dom.Element", +"org.w3c.dom.DOMLocator", + +"org.w3c.dom.DOMImplementationSource", +"org.w3c.dom.DocumentFragment", +"org.w3c.dom.DOMErrorHandler", +"dalvik.bytecode.OpcodeInfo", +"dalvik.bytecode.Opcodes", +"dalvik.system.DexFile", +"dalvik.system.InMemoryDexClassLoader", +"dalvik.system.DelegateLastClassLoader", +"dalvik.system.PathClassLoader", +"dalvik.system.DexClassLoader", +"dalvik.system.BaseDexClassLoader", +"dalvik.annotation.TestTarget", +"dalvik.annotation.TestTargetClass"} \ No newline at end of file diff --git a/app/src/main/assets/javaapi/clayout.aly b/app/src/main/assets/javaapi/clayout.aly new file mode 100644 index 0000000..ff434da --- /dev/null +++ b/app/src/main/assets/javaapi/clayout.aly @@ -0,0 +1,22 @@ +{ + LinearLayout; + { + LinearLayout; + { + EditText; + id="edit"; + singleLine=true; + layout_weight="1"; + layout_width="fill"; + }; + layout_width="fill"; + }; + { + ListView; + id="clist"; + FastScrollEnabled=true; + layout_width="fill"; + items=classes; + }; + orientation="vertical"; +}; \ No newline at end of file diff --git a/app/src/main/assets/javaapi/fiximport.lua b/app/src/main/assets/javaapi/fiximport.lua new file mode 100644 index 0000000..6960e9c --- /dev/null +++ b/app/src/main/assets/javaapi/fiximport.lua @@ -0,0 +1,131 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "com.myopicmobile.textwarrior.common.*" +import "android.content.*" +import "layout" +classes=require "android" +activity.setTitle('需要导入的类') +dir,path=... +function getFilesDir() + return "/data/user/0/"..activity.getPackageName().."/files/" +end +local a=io.open(getFilesDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + activity.setTheme(android.R.style.Theme_DeviceDefault) + else + activity.setTheme(android.R.style.Theme_DeviceDefault_Light) +end +activity.setContentView(loadlayout(layout)) + + + + + +function fiximport(path) + require "import" + import "android.app.*" + import "android.os.*" + import "android.widget.*" + import "android.view.*" + import "com.myopicmobile.textwarrior.common.*" + import "layout" + classes=require "android" + local searchpath=path:gsub("[^/]+%.lua","?.lua;")..path:gsub("[^/]+%.lua","?.aly;") + local cache={} + function checkclass(path,ret) + if cache[path] then + return + end + cache[path]=true + local f=io.open(path) + local str=f:read("a") + f:close() + if not str then + return + end + for s,e,t in str:gfind("(import \"[%w%.]+%*\")") do + --local p=package.searchpath(t,searchpath) + --print(t,p) + end + for s,e,t in str:gfind("import \"([%w%.]+)\"") do + local p=package.searchpath(t,searchpath) + if p then + checkclass(p,ret) + end + end + local lex=LuaLexer(str) + local buf={} + local last=nil + while true do + local t=lex.advance() + if not t then + break + end + if last~=LuaTokenTypes.DOT and t==LuaTokenTypes.NAME then + local text=lex.yytext() + buf[text]=true + end + last=t + end + table.sort(buf) + + for k,v in pairs(buf) do + k="[%.$]"..k.."$" + for a,b in ipairs(classes) do + if string.find(b,k) then + if cache[b]==nil then + table.insert(ret,b) + cache[b]=true + end + end + end + end + end + local ret={} + checkclass(path,ret) + + return String(ret) +end + +list=ListView(activity) +list.ChoiceMode=ListView.CHOICE_MODE_MULTIPLE; +task(fiximport,path,function(v) + rs=v + adp=ArrayListAdapter(activity,android.R.layout.simple_list_item_multiple_choice,v) + list.Adapter=adp + activity.setContentView(list) +end) +--Toast.makeText(activity,"正在分析。。。",1000).show() +function onCreateOptionsMenu(menu) + menu.add("全选").setShowAsAction(1) + menu.add("复制").setShowAsAction(1) +end + +cm=activity.getSystemService(Context.CLIPBOARD_SERVICE) + +function onOptionsItemSelected(item) + if item.Title=="复制" then + local buf={} + + local cs=list.getCheckedItemPositions() + local buf={} + for n=0,#rs-1 do + if cs.get(n) then + table.insert(buf,string.format("import \"%s\"",rs[n])) + end + end + + local str=table.concat(buf,"\n") + local cd = ClipData.newPlainText("label", str) + cm.setPrimaryClip(cd) + Toast.makeText(activity,"已复制的剪切板",1000).show() + else + for n=0,#rs-1 do + list.setItemChecked(n,not list.isItemChecked(n)) + end + end +end diff --git a/app/src/main/assets/javaapi/init.lua b/app/src/main/assets/javaapi/init.lua new file mode 100644 index 0000000..5dd9a57 --- /dev/null +++ b/app/src/main/assets/javaapi/init.lua @@ -0,0 +1,7 @@ +appname="Java方法浏览器" +appver="1.0" +packagename="com.androlua.JavaAPI" +user_permission={ + "INTERNET", + "WRITE_EXTERNAL_STORAGE", +} diff --git a/app/src/main/assets/javaapi/layout.aly b/app/src/main/assets/javaapi/layout.aly new file mode 100644 index 0000000..7f7302e --- /dev/null +++ b/app/src/main/assets/javaapi/layout.aly @@ -0,0 +1,12 @@ +{ + LinearLayout; + orientation="horizontal"; + { + ProgressBar; + }; + { + TextView; + textSize="24sp"; + text="正在分析..."; + }; +}; diff --git a/app/src/main/assets/javaapi/main.lua b/app/src/main/assets/javaapi/main.lua new file mode 100644 index 0000000..15726de --- /dev/null +++ b/app/src/main/assets/javaapi/main.lua @@ -0,0 +1,163 @@ +require "import" +import "android.widget.*" +import "android.view.*" +import "android.app.*" +local classes=require "android" +import "clayout" +import "mlayout" +import "autotheme" + +activity.Title="Java API浏览器" +activity.setTheme(autotheme()) +function adapter(t) + local ls=ArrayList() + for k,v in ipairs(t) do + ls.add(v) + end + return ArrayAdapter(activity,android.R.layout.simple_list_item_1, ls) +end + +import "android.content.*" +cm=activity.getSystemService(activity.CLIPBOARD_SERVICE) + +function copy(str) + local cd = ClipData.newPlainText("label",str) + cm.setPrimaryClip(cd) + Toast.makeText(activity,"已复制的剪切板",1000).show() +end + + +dlg=Dialog(activity,autotheme()) +dlg.setContentView(loadlayout(mlayout)) +curr_class=nil +curt_adapter=nil +activity.setContentView(clayout) +clist.setAdapter(adapter(classes)) + +clist.onItemClick=function(l,v) + local s=tostring(v.Text) + local class=luajava.bindClass(s) + curr_class=class + local t={} + local fs={} + local ms={} + local es={} + local ss={} + local gs={} + local super=class.getSuperclass() + super=super and " extends "..tostring(super.getName()) or "" + table.insert(t,tostring(class)..super) + + table.insert(t,"构建方法") + local cs=class.getConstructors() + for n=0,#cs-1 do + table.insert(t,tostring(cs[n])) + end + + + + curr_ms=class.getMethods() + for n=0,#curr_ms-1 do + local str=tostring(curr_ms[n]) + table.insert(ms,str) + local e1=str:match("%.setOn(%a+)Listener") + local s1,s2=str:match("%.set(%a+)(%([%a$%.]+%))") + local g1,g2=str:match("([%a$%.]+) [%a$%.]+%.get(%a+)%(%)") + if e1 then + table.insert(es,"on"..e1) + elseif s1 then + table.insert(ss,s1..s2) + end + if g1 then + table.insert(gs,string.format("(%s)%s",g1,g2)) + end + end + table.insert(t,"公有事件") + for k,v in ipairs(es) do + table.insert(t,v) + end + table.insert(t,"公有getter") + for k,v in ipairs(gs) do + table.insert(t,v) + end + table.insert(t,"公有setter") + for k,v in ipairs(ss) do + table.insert(t,v) + end + + curr_fs=class.getFields() + table.insert(t,"公有字段") + for n=0,#curr_fs-1 do + table.insert(t,tostring(curr_fs[n])) + end + + table.insert(t,"公有方法") + for k,v in ipairs(ms) do + table.insert(t,v) + end + + dlg.Title=tostring(s) + curt_adapter=adapter(t) + mlist.setAdapter(curt_adapter) + dlg.show() +end + +clist.onItemLongClick=function(l,v) + local s=tostring(v.Text) + copy(s) + return true +end + +mlist.onItemLongClick=function(l,v) + local s=tostring(v.Text) + if s:find("%w%(") then + s=s:match("(%w+)%(") + else + s=s:match("(%w+)$") + end + copy(s) + return true +end + +medit.addTextChangedListener{ + onTextChanged=function(c) + local s=tostring(c) + if #s==0 then + mlist.setAdapter(curt_adapter) + return true + end + local class=curr_class + local t={} + local fs=curr_fs + table.insert(t,"公有字段") + for n=0,#fs-1 do + if fs[n].Name:find(s,1,true) then + table.insert(t,tostring(fs[n])) + end + end + local ms=curr_ms + table.insert(t,"公有方法") + for n=0,#ms-1 do + if ms[n].Name:find(s,1,true) then + table.insert(t,tostring(ms[n])) + end + end + mlist.setAdapter(adapter(t)) + end +} + +edit.addTextChangedListener{ + onTextChanged=function(c) + local s=tostring(c) + if #s==0 then + clist.setAdapter(adapter(classes)) + end + local t={} + for k,v in ipairs(classes) do + if v:find(s,1,true) then + table.insert(t,v) + end + end + clist.setAdapter(adapter(t)) + end +} diff --git a/app/src/main/assets/javaapi/mlayout.aly b/app/src/main/assets/javaapi/mlayout.aly new file mode 100644 index 0000000..49d3270 --- /dev/null +++ b/app/src/main/assets/javaapi/mlayout.aly @@ -0,0 +1,21 @@ +{ + LinearLayout; + { + LinearLayout; + { + EditText; + id="medit"; + singleLine=true; + layout_weight="1"; + layout_width="fill"; + }; + layout_width="fill"; + }; + { + ListView; + id="mlist"; + FastScrollEnabled=true; + layout_width="fill"; + }; + orientation="vertical"; +}; \ No newline at end of file diff --git a/app/src/main/assets/keys/keystore.ks b/app/src/main/assets/keys/keystore.ks new file mode 100644 index 0000000..ac875a9 Binary files /dev/null and b/app/src/main/assets/keys/keystore.ks differ diff --git a/app/src/main/assets/keys/platform.pk8 b/app/src/main/assets/keys/platform.pk8 new file mode 100644 index 0000000..e27a393 Binary files /dev/null and b/app/src/main/assets/keys/platform.pk8 differ diff --git a/app/src/main/assets/keys/testkey.pk8 b/app/src/main/assets/keys/testkey.pk8 new file mode 100644 index 0000000..586c1bd Binary files /dev/null and b/app/src/main/assets/keys/testkey.pk8 differ diff --git a/app/src/main/assets/keys/testkey.sbt b/app/src/main/assets/keys/testkey.sbt new file mode 100644 index 0000000..37b7151 Binary files /dev/null and b/app/src/main/assets/keys/testkey.sbt differ diff --git a/app/src/main/assets/keys/testkey.x509.pem b/app/src/main/assets/keys/testkey.x509.pem new file mode 100644 index 0000000..a70544f --- /dev/null +++ b/app/src/main/assets/keys/testkey.x509.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE +AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G +A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI +hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM +qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 +wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy +4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU +RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s +zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw +HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ +AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH +QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG +CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa +J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y +LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe ++ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX +31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr +sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0= +-----END CERTIFICATE----- diff --git a/app/src/main/assets/layout.aly b/app/src/main/assets/layout.aly new file mode 100644 index 0000000..4d27f13 --- /dev/null +++ b/app/src/main/assets/layout.aly @@ -0,0 +1,220 @@ +{ + LinearLayout; + orientation="vertical"; + backgroundColor=颜色5; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + orientation="vertical"; + backgroundColor=颜色5; + layout_width="fill"; + paddingTop="8dp"; + id="actionbar", + visibility=0; + layout_height="8.2%h"; + { + LinearLayout; + paddingBottom="2dp"; + layout_height="40dp"; + paddingTop="4dp"; + paddingRight="16dp"; + layout_width="fill"; + paddingLeft="16dp"; + { + CircleImageView; + layout_width="9.7%w"; + layout_gravity="center"; + layout_marginRight="5.5%w"; + src="icon.png"; + layout_height="5.1%h"; + }; + { + CardView; + Elevation=0; + radius="6dp"; + BackgroundColor=颜色2; + layout_width="57%w"; + layout_height="fill"; + --layout_gravity="center"; + { + LinearLayout; + layout_width="fill"; + Gravity="center", + layout_height="fill"; + --[[ { + TextView, + textColor="#FF000000", + layout_width="9%w"; + id="dism", + visibility=8; + layout_height="fill", + gravity="center", + Text="取消", + },]] + { + LinearLayout; + layout_width="fill"; + Gravity="center", + id="findbar", + layout_height="56dp"; + + { + ImageView; + layout_height="fill"; + src="imgs/find.png"; + id="findimag"; + padding="10dp"; + layout_width="30dp"; + ColorFilter=颜色3; + }; + + { + TextView; + textColor=颜色3, + textSize="12dp"; + gravity="center|left"; + text="搜索项目..."; + layout_width="fill"; + layout_height="fill"; + }; + }, + + { + LinearLayout; + layout_width="fill"; + id="inbar", + BackgroundColor=颜色5, + layout_height="56dp"; + + + { + EditText, + layout_height="56dp"; + hint="请输入项目名称..", + id="edit", + visibility=8; + layout_width="44%w"; + BackgroundColor=颜色5, + }, + { + TextView; + layout_width="8%w"; + id="dism", + visibility=8; + layout_height="fill", + gravity="center", + textColor=颜色3, + Text="取消", + }; + }; + + }, + }; + { + ImageView; + ColorFilter=颜色3; + layout_width="9.7%w"; + layout_gravity="center"; + id="其他"; + src="imgs/Other.png"; + layout_height="5.1%h"; + layout_marginLeft="7%w"; + }; + }; + }; + + + + --[[ { + LinearLayout; + orientation="vertical"; + layout_width="fill"; + layout_height="fill"; +{ + ImageView; + ColorFilter=颜色3; + layout_width="9.7%w"; + layout_gravity="center"; + layout_marginRight="15dp"; + id="添加"; + src="imgs/Add.png"; + layout_height="5.1%h"; + }; + { + ImageView; + ColorFilter=颜色3; + layout_width="9.7%w"; + layout_gravity="center"; + id="其他"; + src="imgs/Other.png"; + layout_height="5.1%h"; + + }; + };]] + --[[ { + LinearLayout; + gravity="center"; + layout_height="8.2%h"; + orientation="horizontal"; + visibility=8; + id="标题栏", + backgroundColor=颜色1; + layout_width="fill"; + { + CircleImageView; + layout_width="9.7%w"; + layout_gravity="center"; + layout_marginRight="5.5%w"; + src="icon.png"; + layout_height="5.1%h"; + }; + { + LinearLayout; + layout_marginRight="5.5%w"; + layout_height="5.1%h"; + layout_width="47.2%w"; + layout_gravity="center"; + { + TextView; + textSize="16sp"; + textColor=颜色3; + layout_gravity="center"; + layout_marginLeft="5.5%w"; + id="用户名"; + text="AndLuaX+"; + }; + }; + { + ImageView; + ColorFilter=颜色3; + layout_width="9.7%w"; + layout_gravity="center"; + layout_marginRight="15dp"; + id="添加"; + src="imgs/Add.png"; + layout_height="5.1%h"; + }; + { + ImageView; + ColorFilter=颜色3; + layout_width="9.7%w"; + layout_gravity="center"; + id="其他"; + src="imgs/Other.png"; + layout_height="5.1%h"; + }; + };]] + { + + PageView; + pages={ + project; + --Community; + --code; + --My; + }; + id="pagev"; + --layout_height="81.5%h"; + }; +}; \ No newline at end of file diff --git a/app/src/main/assets/layouthelper/.using b/app/src/main/assets/layouthelper/.using new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/layouthelper/init.lua b/app/src/main/assets/layouthelper/init.lua new file mode 100644 index 0000000..1a0f90e --- /dev/null +++ b/app/src/main/assets/layouthelper/init.lua @@ -0,0 +1,15 @@ +appname="布局助手" +appver="1.1" +appcode="1" +appsdk="15" +path_pattern="" +packagename="com.androlua.layouthelper" +app_key="" +app_channel="QQ 1284321744" +developer="nirenr wsdx233(improve)" +description="快速布局工具" +debugmode=true +user_permission={ + "INTERNET", + "WRITE_EXTERNAL_STORAGE" +} diff --git a/app/src/main/assets/layouthelper/layout.lua b/app/src/main/assets/layouthelper/layout.lua new file mode 100644 index 0000000..66f2a11 --- /dev/null +++ b/app/src/main/assets/layouthelper/layout.lua @@ -0,0 +1,38 @@ +layout={ + main={ + LinearLayout, + orientation="vertical", + }, + + dlg={ + LinearLayout, + orientation="vertical", + {TextView, + id="label", + }, + {EditText, + id="fld", + layout_width="fill", + }, + {Button, + text="确定", + onClick="ok", + }, + + }, + + ck={ + LinearLayout; + { + RadioGroup; + layout_weight="1"; + id="ck_rg"; + }; + { + Button; + Text="确定"; + id="ck_bt"; + }; + orientation="vertical"; + }; +} diff --git a/app/src/main/assets/layouthelper/loadlayout2.lua b/app/src/main/assets/layouthelper/loadlayout2.lua new file mode 100644 index 0000000..0fc2a2d --- /dev/null +++ b/app/src/main/assets/layouthelper/loadlayout2.lua @@ -0,0 +1,628 @@ +local require = require +local table = require "table" +local _G = _G +local insert = table.insert +local new = luajava.new +local bindClass = luajava.bindClass +local ids = {} +local ltrs = {} +local id = 0x7f000000 + +local context = activity or service + +local ViewGroup = bindClass("android.view.ViewGroup") +local String = bindClass("java.lang.String") +local Gravity = bindClass("android.view.Gravity") +local OnClickListener = bindClass("android.view.View$OnClickListener") +local TypedValue = luajava.bindClass("android.util.TypedValue") +local BitmapDrawable = luajava.bindClass("android.graphics.drawable.BitmapDrawable") +local LuaDrawable = luajava.bindClass "com.androlua.LuaDrawable" +local TruncateAt = bindClass("android.text.TextUtils$TruncateAt") +local ArrayAdapter = bindClass("android.widget.ArrayAdapter") +local ScaleType = bindClass("android.widget.ImageView$ScaleType") +local scaleTypes = ScaleType.values() +local android_R = bindClass("android.R") + +local Context = bindClass "android.content.Context" +local DisplayMetrics = bindClass "android.util.DisplayMetrics" + +local wm = context.getSystemService(Context.WINDOW_SERVICE); +local outMetrics = DisplayMetrics(); +wm.getDefaultDisplay().getMetrics(outMetrics); +local W = outMetrics.widthPixels; +local H = outMetrics.heightPixels; + +local dm = context.getResources().getDisplayMetrics() +local toint = { +--android:drawingCacheQuality + auto = 0, + low = 1, + high = 2, + +--android:importantForAccessibility + auto = 0, + yes = 1, + no = 2, + +--android:layerType + none = 0, + software = 1, + hardware = 2, + +--android:layoutDirection + ltr = 0, + rtl = 1, + inherit = 2, + locale = 3, + +--android:scrollbarStyle + insideOverlay = 0x0, + insideInset = 0x01000000, + outsideOverlay = 0x02000000, + outsideInset = 0x03000000, + +--android:visibility + visible = 0, + invisible = 1, + gone = 2, + + wrap_content = -2, + fill_parent = -1, + match_parent = -1, + wrap = -2, + fill = -1, + match = -1, + +--android:autoLink + none = 0x00, + web = 0x01, + email = 0x02, + phon = 0x04, + map = 0x08, + all = 0x0f, + +--android:orientation + vertical = 1, + horizontal = 0, + +--android:gravity + axis_clip = 8, + axis_pull_after = 4, + axis_pull_before = 2, + axis_specified = 1, + axis_x_shift = 0, + axis_y_shift = 4, + bottom = 80, + center = 17, + center_horizontal = 1, + center_vertical = 16, + clip_horizontal = 8, + clip_vertical = 128, + display_clip_horizontal = 16777216, + display_clip_vertical = 268435456, +--fill = 119, + fill_horizontal = 7, + fill_vertical = 112, + horizontal_gravity_mask = 7, + left = 3, + no_gravity = 0, + relative_horizontal_gravity_mask = 8388615, + relative_layout_direction = 8388608, + right = 5, + start = 8388611, + top = 48, + vertical_gravity_mask = 112, + ["end"] = 8388613, + +--android:textAlignment + inherit = 0, + gravity = 1, + textStart = 2, + textEnd = 3, + textCenter = 4, + viewStart = 5, + viewEnd = 6, + +--android:inputType + none = 0x00000000, + text = 0x00000001, + textCapCharacters = 0x00001001, + textCapWords = 0x00002001, + textCapSentences = 0x00004001, + textAutoCorrect = 0x00008001, + textAutoComplete = 0x00010001, + textMultiLine = 0x00020001, + textImeMultiLine = 0x00040001, + textNoSuggestions = 0x00080001, + textUri = 0x00000011, + textEmailAddress = 0x00000021, + textEmailSubject = 0x00000031, + textShortMessage = 0x00000041, + textLongMessage = 0x00000051, + textPersonName = 0x00000061, + textPostalAddress = 0x00000071, + textPassword = 0x00000081, + textVisiblePassword = 0x00000091, + textWebEditText = 0x000000a1, + textFilter = 0x000000b1, + textPhonetic = 0x000000c1, + textWebEmailAddress = 0x000000d1, + textWebPassword = 0x000000e1, + number = 0x00000002, + numberSigned = 0x00001002, + numberDecimal = 0x00002002, + numberPassword = 0x00000012, + phone = 0x00000003, + datetime = 0x00000004, + date = 0x00000014, + time = 0x00000024, + +--android:imeOptions + normal = 0x00000000, + actionUnspecified = 0x00000000, + actionNone = 0x00000001, + actionGo = 0x00000002, + actionSearch = 0x00000003, + actionSend = 0x00000004, + actionNext = 0x00000005, + actionDone = 0x00000006, + actionPrevious = 0x00000007, + flagNoFullscreen = 0x2000000, + flagNavigatePrevious = 0x4000000, + flagNavigateNext = 0x8000000, + flagNoExtractUi = 0x10000000, + flagNoAccessoryAction = 0x20000000, + flagNoEnterAction = 0x40000000, + flagForceAscii = 0x80000000, + +} + +local scaleType = { +--android:scaleType + matrix = 0, + fitXY = 1, + fitStart = 2, + fitCenter = 3, + fitEnd = 4, + center = 5, + centerCrop = 6, + centerInside = 7, +} + +local rules = { + layout_above = 2, + layout_alignBaseline = 4, + layout_alignBottom = 8, + layout_alignEnd = 19, + layout_alignLeft = 5, + layout_alignParentBottom = 12, + layout_alignParentEnd = 21, + layout_alignParentLeft = 9, + layout_alignParentRight = 11, + layout_alignParentStart = 20, + layout_alignParentTop = 10, + layout_alignRight = 7, + layout_alignStart = 18, + layout_alignTop = 6, + layout_alignWithParentIfMissing = 0, + layout_below = 3, + layout_centerHorizontal = 14, + layout_centerInParent = 13, + layout_centerVertical = 15, + layout_toEndOf = 17, + layout_toLeftOf = 0, + layout_toRightOf = 1, + layout_toStartOf = 16 +} + +local types = { + px = 0, + dp = 1, + sp = 2, + pt = 3, + ["in"] = 4, + mm = 5 +} + +local function checkType(v) + local n, ty = string.match(v, "^(%-?%d+)(%a%a)$") + return tonumber(n), types[ty] +end + +local function checkPercent(v) + local n, ty = string.match(v, "^(%-?[%.%d]+)%%([wh])$") + if ty == nil then + return nil + elseif ty == "w" then + return tonumber(n) * W / 100 + elseif ty == "h" then + return tonumber(n) * H / 100 + end +end + +local function split(s, t) + local idx = 1 + local l = #s + return function() + local i = s:find(t, idx) + if idx >= l then + return nil + end + if i == nil then + i = l + 1 + end + local sub = s:sub(idx, i - 1) + idx = i + 1 + return sub + end +end +local function checkint(s) + local ret = 0 + for n in split(s, "|") do + if toint[n] then + ret = ret | toint[n] + else + return nil + end + end + return ret +end + +local function checkNumber(var) + if type(var) == "string" then + if var == "true" then + return true + elseif var == "false" then + return false + end + + if toint[var] then + return toint[var] + end + + local i = checkint(var) + if i then + return i + end + + local p = checkPercent(var) + if p then + return p + end + + local h = string.match(var, "^#(%x+)$") + if h then + local c = tonumber(h, 16) + if c then + if #h <= 6 then + return c - 0x1000000 + elseif #h <= 8 then + if c > 0x7fffffff then + return c - 0x100000000 + else + return c + end + end + end + end + + local n, ty = checkType(var) + if ty then + return TypedValue.applyDimension(ty, n, dm) + end + end + -- return var +end + +local function checkValue(var) + return tonumber(var) or checkNumber(var) or var +end + +local function checkValues(...) + local vars = { ... } + for n = 1, #vars do + vars[n] = checkValue(vars[n]) + end + return unpack(vars) +end + +local function getattr(s) + return android_R.attr[s] +end + +local function checkattr(s) + local e, s = pcall(getattr, s) + if e then + return s + end + return nil +end + +local function getIdentifier(name) + return context.getResources().getIdentifier(name, null, null) +end + +local function dump2 (t) + local _t = {} + table.insert(_t, tostring(t)) + table.insert(_t, "\t{") + for k, v in pairs(t) do + if type(v) == "table" then + table.insert(_t, "\t\t" .. tostring(k) .. "={" .. tostring(v[1]) .. " ...}") + else + table.insert(_t, "\t\t" .. tostring(k) .. "=" .. tostring(v)) + end + end + table.insert(_t, "\t}") + t = table.concat(_t, "\n") + return t +end + +local ver = luajava.bindClass("android.os.Build").VERSION.SDK_INT; +function setBackground(view, bg) + if ver < 16 then + view.setBackgroundDrawable(bg) + else + view.setBackground(bg) + end +end + +local function setattribute(root, view, params, k, v, ids) + if k == "layout_x" then + params.x = checkValue(v) + elseif k == "layout_y" then + params.y = checkValue(v) + elseif k == "layout_weight" then + params.weight = checkValue(v) + elseif k == "layout_gravity" then + params.gravity = checkValue(v) + elseif k == "layout_marginStart" then + params.setMarginStart(checkValue(v)) + elseif k == "layout_marginEnd" then + params.setMarginEnd(checkValue(v)) + elseif rules[k] and (v == true or v == "true") then + params.addRule(rules[k]) + elseif rules[k] then + params.addRule(rules[k], ids[v]) + elseif k=="items" then --创建列表项目 + if type(v)=="table" then + if view.adapter then + view.adapter.addAll(v) + else + local adapter=ArrayListAdapter(context,android_R.layout.simple_list_item_1, String(v)) + view.setAdapter(adapter) + end + end + elseif k == "pages" and type(v) == "table" then + --创建页项目 + elseif k == "onClick" then + --设置onClick事件接口 + elseif k == "textSize" then + if tonumber(v) then + view.setTextSize(tonumber(v)) + elseif type(v) == "string" then + local n, ty = checkType(v) + if ty then + view.setTextSize(ty, n) + else + view.setTextSize(v) + end + else + view.setTextSize(v) + end + elseif k == "textAppearance" then + view.setTextAppearance(context, checkattr(v)) + elseif k == "ellipsize" then + view.setEllipsize(TruncateAt[string.upper(v)]) + elseif k == "url" then + view.loadUrl(url) + elseif k == "src" then + if v:find("^%?") then + view.setImageResource(getIdentifier(v:sub(2, -1))) + else + if (not v:find("^/")) and luadir then + v = luadir .. v + end + view.setImageBitmap(loadbitmap(v)) + end + elseif k == "scaleType" then + view.setScaleType(scaleTypes[scaleType[v]]) + elseif k == "background" then + if type(v) == "string" then + if v:find("^%?") then + view.setBackgroundResource(getIdentifier(v:sub(2, -1))) + elseif v:find("^#") then + view.setBackgroundColor(checkNumber(v)) + elseif rawget(root, v) or rawget(_G, v) then + v = rawget(root, v) or rawget(_G, v) + if type(v) == "function" then + setBackground(view, LuaDrawable(v)) + elseif type(v) == "userdata" then + setBackground(view, v) + end + else + if (not v:find("^/")) and luadir then + v = luadir .. v + end + if v:find("%.9%.png") then + setBackground(view, NineBitmapDrawable(loadbitmap(v))) + else + setBackground(view, BitmapDrawable(loadbitmap(v))) + end + end + elseif type(v) == "userdata" then + setBackground(view, v) + elseif type(v) == "number" then + view.setBackgroundColor(v) + end + elseif k == "password" and (v == "true" or v == true) then + view.setInputType(0x81) + elseif type(k) == "string" and not (k:find("layout_")) and not (k:find("padding")) and k ~= "style" then + --设置属性 + k = string.gsub(k, "^(%w)", function(s) + return string.upper(s) + end) + if k == "Text" or k == "Title" or k == "Subtitle" then + view["set" .. k](v) + else + view["set" .. k](checkValue(v)) + end + end +end + +local function setMiniSize(view) + view.setMinimumHeight(checkValue("18dp")) + view.setMinimumWidth(checkValue("18dp")) +end + +local function copytable(f, t, b) + for k, v in pairs(f) do + if k == 1 then + elseif b or t[k] == nil then + t[k] = v + end + end +end + +local function setstyle(c, t, root, view, params, ids) + local mt = getmetatable(t) + if not mt or not mt.__index then + return + end + local m = mt.__index + if c[m] then + return + end + c[m] = true + for k, v in pairs(m) do + if not rawget(c, k) then + pcall(setattribute, root, view, params, k, v, ids) + end + c[k] = true + end + setstyle(c, m, root, view, params, ids) +end + +local function loadlayout(t, root, group,p) + if type(t) == "string" then + p = t + t = require(t) + elseif type(t) ~= "table" then + error(string.format("loadlayout error: Fist value Must be a table, checked import layout.", 0)) + end + root = root or _G + local view, style + if t.style then + if t.style:find("^%?") then + style = getIdentifier(t.style:sub(2, -1)) + else + local st, sty = pcall(require, t.style) + if st then + --copytable(sty,t) + setmetatable(t, { __index = sty }) + else + style = checkattr(t.style) + end + end + end + if not t[1] then + error(string.format("loadlayout error: Fist value Must be a Class, checked import package.\n\tat %s", dump2(t)), 0) + end + + if style then + view = t[1](context, nil, style) + else + view = t[1](context) --创建view + end + if p then + view.onTouch = function(v, e) + if e.getAction() == MotionEvent.ACTION_DOWN then + print("import from \"" .. p.."\"") + return true + end + end + else + view.setTag(t) + if group and group == AbsoluteLayout then + view.onTouch = move + else + view.onTouch = onTouch + end + end + local vgw, vgh + pcall(setMiniSize, view) + + + + --MOD BY WSFX + --绘制边框 + if view.getBackground() == nil then + local gd=GradientDrawable() + gd.setColor(0x00ffffff) + gd.setStroke(2,0xFF000000,3,3) + gd.setGradientRadius(700) + gd.setGradientType(1) + setBackground(view, gd) + + end + + + local params = ViewGroup.LayoutParams(checkValue(t.layout_width) or -2, checkValue(t.layout_height) or -2) --设置layout属性 + if group then + params = group.LayoutParams(params) + end + + --设置layout_margin属性 + if t.layout_margin or t.layout_marginStart or t.layout_marginEnd or t.layout_marginLeft or t.layout_marginTop or t.layout_marginRight or t.layout_marginBottom then + params.setMargins(checkValues( t.layout_marginLeft or t.layout_margin or 0, t.layout_marginTop or t.layout_margin or 0, t.layout_marginRight or t.layout_margin or 0, t.layout_marginBottom or t.layout_margin or 0)) + end + + --设置padding属性 + if t.padding or t.paddingLeft or t.paddingTop or t.paddingRight or t.paddingBottom then + view.setPadding(checkValues(t.paddingLeft or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingRight or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + if t.paddingStart or t.paddingEnd then + view.setPaddingRelative(checkValues(t.paddingStart or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingEnd or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + + local c = {} + setmetatable(c, { __index = t }) + setstyle(c, t, root, view, params, ids) + + for k, v in pairs(t) do + if tonumber(k) and (type(v) == "table" or type(v) == "string") then + --创建子view + if luajava.instanceof(view,AdapterView) then + if type(v)=="string" then + v=require(v) + end + view.adapter=LuaAdapter(context,v) + else + view.addView(loadlayout(v,root,t[1])) + end + elseif k == "id" then + --创建view的全局变量 + rawset(root, v, view) + id = id + 1 + view.setId(id) + ids[v] = id + else + local e, s = pcall(setattribute, root, view, params, k, v, ids) + if not e then + local _, i = s:find(":%d+:") + s = s:sub(i or 1, -1) + error(string.format("loadlayout error %s \n\tat %s\n\tat key=%s value=%s\n\tat %s", s, view.toString(), k, v, dump2(t)), 0) + end + end + end + + --if group then + --group.addView(view,params) + --else + view.setLayoutParams(params) + return view + --end +end + +return loadlayout + diff --git a/app/src/main/assets/layouthelper/loadlayout3.lua b/app/src/main/assets/layouthelper/loadlayout3.lua new file mode 100644 index 0000000..107c4a0 --- /dev/null +++ b/app/src/main/assets/layouthelper/loadlayout3.lua @@ -0,0 +1,593 @@ +local require=require +local table=require "table" +local _G=_G +local insert = table.insert +local new = luajava.new +local bindClass = luajava.bindClass +local ids={} +local ltrs={} + +local context=activity or service + +local ViewGroup=bindClass("android.view.ViewGroup") +local String=bindClass("java.lang.String") +local Gravity=bindClass("android.view.Gravity") +local OnClickListener=bindClass("android.view.View$OnClickListener") +local TypedValue=luajava.bindClass("android.util.TypedValue") +local BitmapDrawable=luajava.bindClass("android.graphics.drawable.BitmapDrawable") +local TruncateAt=bindClass("android.text.TextUtils$TruncateAt") +local LuaDrawable=luajava.bindClass "com.androlua.LuaDrawable" +local ArrayAdapter=bindClass("android.widget.ArrayAdapter") +local ScaleType=bindClass("android.widget.ImageView$ScaleType") +local scaleTypes=ScaleType.values() +local android_R=bindClass("android.R") + +local Context=bindClass "android.content.Context" +local DisplayMetrics=bindClass "android.util.DisplayMetrics" + +local wm =context.getSystemService(Context.WINDOW_SERVICE); +local outMetrics = DisplayMetrics(); +wm.getDefaultDisplay().getMetrics(outMetrics); +local W = outMetrics.widthPixels; +local H = outMetrics.heightPixels; + +local dm=context.getResources().getDisplayMetrics() +local id=0x7f000000 +local toint={ + --android:drawingCacheQuality + auto=0, + low=1, + high=2, + + --android:importantForAccessibility + auto=0, + yes=1, + no=2, + + --android:layerType + none=0, + software=1, + hardware=2, + + --android:layoutDirection + ltr=0, + rtl=1, + inherit=2, + locale=3, + + --android:scrollbarStyle + insideOverlay=0x0, + insideInset=0x01000000, + outsideOverlay=0x02000000, + outsideInset=0x03000000, + + --android:visibility + visible=0, + invisible=1, + gone=2, + + wrap_content=-2, + fill_parent=-1, + match_parent=-1, + wrap=-2, + fill=-1, + match=-1, + + --android:autoLink + none=0x00, + web=0x01, + email=0x02, + phon=0x04, + map=0x08, + all=0x0f, + + --android:orientation + vertical=1, + horizontal= 0, + + --android:gravity + axis_clip = 8, + axis_pull_after = 4, + axis_pull_before = 2, + axis_specified = 1, + axis_x_shift = 0, + axis_y_shift = 4, + bottom = 80, + center = 17, + center_horizontal = 1, + center_vertical = 16, + clip_horizontal = 8, + clip_vertical = 128, + display_clip_horizontal = 16777216, + display_clip_vertical = 268435456, + --fill = 119, + fill_horizontal = 7, + fill_vertical = 112, + horizontal_gravity_mask = 7, + left = 3, + no_gravity = 0, + relative_horizontal_gravity_mask = 8388615, + relative_layout_direction = 8388608, + right = 5, + start = 8388611, + top = 48, + vertical_gravity_mask = 112, + ["end"] = 8388613, + + --android:textAlignment + inherit=0, + gravity=1, + textStart=2, + textEnd=3, + textCenter=4, + viewStart=5, + viewEnd=6, + + --android:inputType + none=0x00000000, + text=0x00000001, + textCapCharacters=0x00001001, + textCapWords=0x00002001, + textCapSentences=0x00004001, + textAutoCorrect=0x00008001, + textAutoComplete=0x00010001, + textMultiLine=0x00020001, + textImeMultiLine=0x00040001, + textNoSuggestions=0x00080001, + textUri=0x00000011, + textEmailAddress=0x00000021, + textEmailSubject=0x00000031, + textShortMessage=0x00000041, + textLongMessage=0x00000051, + textPersonName=0x00000061, + textPostalAddress=0x00000071, + textPassword=0x00000081, + textVisiblePassword=0x00000091, + textWebEditText=0x000000a1, + textFilter=0x000000b1, + textPhonetic=0x000000c1, + textWebEmailAddress=0x000000d1, + textWebPassword=0x000000e1, + number=0x00000002, + numberSigned=0x00001002, + numberDecimal=0x00002002, + numberPassword=0x00000012, + phone=0x00000003, + datetime=0x00000004, + date=0x00000014, + time=0x00000024, + + --android:imeOptions + normal=0x00000000, + actionUnspecified=0x00000000, + actionNone=0x00000001, + actionGo=0x00000002, + actionSearch=0x00000003, + actionSend=0x00000004, + actionNext=0x00000005, + actionDone=0x00000006, + actionPrevious=0x00000007, + flagNoFullscreen=0x2000000, + flagNavigatePrevious=0x4000000, + flagNavigateNext=0x8000000, + flagNoExtractUi=0x10000000, + flagNoAccessoryAction=0x20000000, + flagNoEnterAction=0x40000000, + flagForceAscii=0x80000000, + + +} + +local scaleType={ + --android:scaleType + matrix=0, + fitXY=1, + fitStart=2, + fitCenter=3, + fitEnd=4, + center=5, + centerCrop=6, + centerInside=7, +} + + +local rules={ + layout_above=2, + layout_alignBaseline=4, + layout_alignBottom=8, + layout_alignEnd=19, + layout_alignLeft=5, + layout_alignParentBottom=12, + layout_alignParentEnd=21, + layout_alignParentLeft=9, + layout_alignParentRight=11, + layout_alignParentStart=20, + layout_alignParentTop=10, + layout_alignRight=7, + layout_alignStart=18, + layout_alignTop=6, + layout_alignWithParentIfMissing=0, + layout_below=3, + layout_centerHorizontal=14, + layout_centerInParent=13, + layout_centerVertical=15, + layout_toEndOf=17, + layout_toLeftOf=0, + layout_toRightOf=1, + layout_toStartOf=16 +} + + +local types={ + px=0, + dp=1, + sp=2, + pt=3, + ["in"]=4, + mm=5 +} + +local function checkType(v) + local n,ty=string.match(v,"^(%-?%d+)(%a%a)$") + return tonumber(n),types[ty] +end + +local function checkPercent(v) + local n,ty=string.match(v,"^(%-?[%.%d]+)%%([wh])$") + if ty==nil then + return nil + elseif ty=="w" then + return tonumber(n)*W/100 + elseif ty=="h" then + return tonumber(n)*H/100 + end +end + +local function split(s,t) + local idx=1 + local l=#s + return function() + local i=s:find(t,idx) + if idx>=l then + return nil + end + if i==nil then + i=l+1 + end + local sub=s:sub(idx,i-1) + idx=i+1 + return sub + end +end +local function checkint(s) + local ret=0 + for n in split(s,"|") do + if toint[n] then + ret=ret | toint[n] + else + return nil + end + end + return ret +end + + + +local function checkNumber(var) + if type(var) == "string" then + if var=="true" then + return true + elseif var=="false" then + return false + end + + if toint[var] then + return toint[var] + end + local i=checkint(var) + if i then + return i + end + + local p=checkPercent(var) + if p then + return p + end + + local h=string.match(var,"^#(%x+)$") + if h then + local c=tonumber(h,16) + if c then + if #h<=6 then + return c-0x1000000 + elseif #h<=8 then + if c>0x7fffffff then + return c-0x100000000 + else + return c + end + end + end + end + + local n,ty=checkType(var) + if ty then + return TypedValue.applyDimension(ty,n,dm) + end + end + -- return var +end + +local function checkValue(var) + return tonumber(var) or checkNumber(var) or var +end + +local function checkValues(...) + local vars={...} + for n=1,#vars do + vars[n]=checkValue(vars[n]) + end + return unpack(vars) +end + +local function getattr(s) + return android_R.attr[s] +end + +local function checkattr(s) + local e,s=pcall(getattr,s) + if e then + return s + end + return nil +end + +local function getIdentifier(name) + return context.getResources().getIdentifier(name,null,null) +end + +local function dump2 (t) + local _t={} + table.insert(_t,tostring(t)) + table.insert(_t,"\t{") + for k,v in pairs(t) do + if type(v)=="table" then + table.insert(_t,"\t\t"..tostring(k).."={"..tostring(v[1]).." ...}") + else + table.insert(_t,"\t\t"..tostring(k).."="..tostring(v)) + end + end + table.insert(_t,"\t}") + t=table.concat(_t,"\n") + return t +end + +local ver = luajava.bindClass("android.os.Build").VERSION.SDK_INT; +function setBackground(view,bg) + if ver<16 then + view.setBackgroundDrawable(bg) + else + view.setBackground(bg) + end +end + +local function setattribute(root,view,params,k,v,ids) + if k=="layout_x" then + params.x=checkValue(v) + elseif k=="layout_y" then + params.y=checkValue(v) + elseif k=="layout_weight" then + params.weight=checkValue(v) + elseif k=="layout_gravity" then + params.gravity=checkValue(v) + elseif k=="layout_marginStart" then + params.setMarginStart(checkValue(v)) + elseif k=="layout_marginEnd" then + params.setMarginEnd(checkValue(v)) + elseif rules[k] and (v==true or v=="true") then + params.addRule(rules[k]) + elseif rules[k] then + params.addRule(rules[k],ids[v]) + elseif k=="items" then --创建列表项目 + if type(v)=="table" then + if view.adapter then + view.adapter.addAll(v) + else + local adapter=ArrayListAdapter(context,android_R.layout.simple_list_item_1, String(v)) + view.setAdapter(adapter) + end + end + elseif k=="pages" and type(v)=="table" then --创建页项目 + elseif k=="onClick" then --设置onClick事件接口 + elseif k=="textSize" then + if tonumber(v) then + view.setTextSize(tonumber(v)) + elseif type(v)=="string" then + local n,ty=checkType(v) + if ty then + view.setTextSize(ty,n) + else + view.setTextSize(v) + end + else + view.setTextSize(v) + end + elseif k=="textAppearance" then + view.setTextAppearance(context,checkattr(v)) + elseif k=="ellipsize" then + view.setEllipsize(TruncateAt[string.upper(v)]) + elseif k=="url" then + view.loadUrl(url) + elseif k=="src" then + if v:find("^%?") then + view.setImageResource(getIdentifier(v:sub(2,-1))) + else + if (not v:find("^/")) and luadir then + v=luadir..v + end + view.setImageBitmap(loadbitmap(v)) + end + elseif k=="scaleType" then + view.setScaleType(scaleTypes[scaleType[v]]) + elseif k=="background" then + if type(v)=="string" then + if v:find("^%?") then + view.setBackgroundResource(getIdentifier(v:sub(2,-1))) + elseif v:find("^#") then + view.setBackgroundColor(checkNumber(v)) + elseif rawget(root,v) or rawget(_G,v) then + v=rawget(root,v) or rawget(_G,v) + if type(v)=="function" then + setBackground(view,LuaDrawable(v)) + elseif type(v)=="userdata" then + setBackground(view,v) + end + else + if (not v:find("^/")) and luadir then + v=luadir..v + end + if v:find("%.9%.png") then + setBackground(view,NineBitmapDrawable(loadbitmap(v))) + else + setBackground(view,BitmapDrawable(loadbitmap(v))) + end + end + elseif type(v)=="userdata" then + setBackground(view,v) + elseif type(v)=="number" then + view.setBackgroundColor(v) + end + elseif k=="password" and (v=="true" or v==true) then + view.setInputType(0x81) + elseif type(k)=="string" and not(k:find("layout_")) and not(k:find("padding")) and k~="style" then --设置属性 + k=string.gsub(k,"^(%w)",function(s)return string.upper(s)end) + if k=="Text" or k=="Title" or k=="Subtitle" then + view["set"..k](v) + else + view["set"..k](checkValue(v)) + end + end +end + +local function copytable(f,t,b) + for k,v in pairs(f) do + if k==1 then + elseif b or t[k]==nil then + t[k]=v + end + end +end + + +local function setstyle(c,t,root,view,params,ids) + local mt=getmetatable(t) + if not mt or not mt.__index then + return + end + local m=mt.__index + if c[m] then + return + end + c[m]=true + for k,v in pairs(m) do + if not rawget(c,k) then + pcall(setattribute,root,view,params,k,v,ids) + end + c[k]=true + end + setstyle(c,m,root,view,params,ids) +end + + +local function loadlayout(t,root,group) + if type(t)=="string" then + t=require(t) + elseif type(t)~="table" then + error(string.format("loadlayout error: Fist value Must be a table, checked import layout.",0)) + end + root=root or _G + local view,style + if t.style then + if t.style:find("^%?") then + style=getIdentifier(t.style:sub(2,-1)) + else + local st,sty=pcall(require,t.style) + if st then + --copytable(sty,t) + setmetatable(t,{__index=sty}) + else + style=checkattr(t.style) + end + end + end + if not t[1] then + error(string.format("loadlayout error: Fist value Must be a Class, checked import package.\n\tat %s",dump2(t)),0) + end + + if style then + view = t[1](context,nil,style) + else + view = t[1](context) --创建view + end + + + local params=ViewGroup.LayoutParams(checkValue(t.layout_width) or -2,checkValue(t.layout_height) or -2) --设置layout属性 + if group then + params=group.LayoutParams(params) + end + + --设置layout_margin属性 + if t.layout_margin or t.layout_marginStart or t.layout_marginEnd or t.layout_marginLeft or t.layout_marginTop or t.layout_marginRight or t.layout_marginBottom then + params.setMargins(checkValues( t.layout_marginLeft or t.layout_margin or 0,t.layout_marginTop or t.layout_margin or 0,t.layout_marginRight or t.layout_margin or 0,t.layout_marginBottom or t.layout_margin or 0)) + end + + --设置padding属性 + if t.padding or t.paddingLeft or t.paddingTop or t.paddingRight or t.paddingBottom then + view.setPadding(checkValues(t.paddingLeft or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingRight or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + if t.paddingStart or t.paddingEnd then + view.setPaddingRelative(checkValues(t.paddingStart or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingEnd or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + + + local c={} + setmetatable(c,{__index=t}) + setstyle(c,t,root,view,params,ids) + + for k,v in pairs(t) do + if tonumber(k) and (type(v)=="table" or type(v)=="string") then --创建子view + if luajava.instanceof(view,AdapterView) then + if type(v)=="string" then + v=require(v) + end + view.adapter=LuaAdapter(context,v) + else + view.addView(loadlayout(v,root,t[1])) + end + elseif k=="id" then --创建view的全局变量 + rawset(root,v,view) + id=id+1 + view.setId(id) + ids[v]=id + + else + local e,s=pcall(setattribute,root,view,params,k,v,ids) + if not e then + local _,i=s:find(":%d+:") + s=s:sub(i or 1,-1) + error(string.format("loadlayout error %s \n\tat %s\n\tat key=%s value=%s\n\tat %s",s,view.toString(),k,v,dump2(t)),0) + end + end + end + + --if group then + --group.addView(view,params) + --else + view.setLayoutParams(params) + return view + --end +end + + +return loadlayout + diff --git a/app/src/main/assets/layouthelper/main.lua b/app/src/main/assets/layouthelper/main.lua new file mode 100644 index 0000000..4616648 --- /dev/null +++ b/app/src/main/assets/layouthelper/main.lua @@ -0,0 +1,1005 @@ +require "import" +import "android.text.Html" +import "android.graphics.Paint" +import "android.app.*" +import "android.os.*" +import "java.io.*" +import "android.widget.*" +import "android.view.*" +import "android.content.*" +import "com.androlua.*" +import "android.view.WindowManager" +import "android.view.inputmethod.InputMethodManager" +layout={ + main={ + RelativeLayout, + layout_width = "fill"; + layout_height = "fill"; + }, + + ck={ + LinearLayout; + { + RadioGroup; + layout_weight="1"; + id="ck_rg"; + }; + { + Button; + Text="确定"; + layout_gravity="right"; + id="ck_bt"; + }; + orientation="vertical"; + }; +} + +luadir,luapath,content=... +luadir=luadir or luapath:gsub("/[^/]+$","") +package.path=package.path..";"..luadir.."/?.lua;" +imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) +import "loadlayout2" +require "xml2table" +function getFilesDir() + return "/data/user/0/"..activity.getPackageName().."/files/" +end +local a=io.open(getFilesDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色6=0xffffffff + 颜色5=0xff212121 + 颜色7=0xEBFFFFFF + activity.setTheme(android.R.style.Theme_DeviceDefault_Light) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色6=0xff757575 + 颜色5=0x5FFFFFFF + 颜色7=0xff303030 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light) +end +if luapath:find("%.aly$") then + local f=io.open(luapath) + local s=f:read("*a") + f:close() + xpcall(function() + layout.main=assert(loadstring("return "..s))() + end, + function() + Toast.makeText(activity,"不支持编辑该布局",1000).show() + activity.finish() + end) + showsave=true +end + +if luapath:find("%.lua$") and content then + xpcall(function() + layout.main=assert(loadstring("return "..content))() + end, + function() + Toast.makeText(activity,"加载布局失败布局",1000).show() + activity.finish() + end) + showsave=true +end + +--判断是否在点击该控件 +is_clicking = false + +--点击事件信息 + + +function click_info_init() + click_info = { + --起始坐标 + start = { + x = 0;y = 0; + }; + start_time = 0; + now_click = nil; + mode = 1; + now_view = nil; + } +end + +--保持View属性窗口开启 +holding_view = false + +local function clicking_background(c,p) + p.color = + ({0x554A148C,0x55004D40,0x55BF360C,0x55FFFF00}) + [click_info.mode] + + if click_info.now_click then + c.drawRect(0,0,c.width,c.height,p) + if click_info.mode == 1 and (System.currentTimeMillis() - click_info.start_time) < 750 then + p.color = 0x4437474F + c.drawRect(0,0,(c.width/750)*(System.currentTimeMillis() - click_info.start_time),c.height,p) + if click_info.now_view then + click_info.now_view.invalidate() + end + elseif click_info.mode == 1 then + p.color = 0x550288D1 + c.drawRect(0,0,c.width,c.height,p) + end + p.style = Paint.Style.STROKE + p.setStrokeWidth(20) + p.setStrokeJoin(Paint.Join.ROUND) + p.color = + ({0x994A148C,0x99004D40,0x99BF360C,0x99FFFF00}) + [click_info.mode] + c.drawRect(0,0,c.width,c.height,p) + + p.setTextSize(40) + p.color = + ({0xFF4A148C,0xFF004D40,0xFFBF360C,0xFFF57F17}) + [click_info.mode] + p.setStyle(Paint.Style.FILL) + c.drawText(click_info.now_click.class.getSimpleName(),20,50,p) + + p.setTextSize(20) + + c.drawText( + ({(((System.currentTimeMillis() - click_info.start_time) > 750) and "固定属性面板") or "打开属性面板","选择子控件/父控件","添加/ID","删除"}) + [click_info.mode],20,70,p) + end +end + +clicking_background_drawable = LuaDrawable(clicking_background) + +function onTouch(v,e) + if is_clicking and e.getAction() == MotionEvent.ACTION_UP then + getCurr(v) + fd_dlg.hide() + v.foreground = nil + is_clicking = false + if (System.currentTimeMillis() - click_info.start_time) > 750 then + holding_view = true + end + if click_info.mode == 2 then + if luajava.instanceof(v,ViewGroup) then + func["子控件"](v) + else + func["父控件"](v) + end + return + + elseif click_info.mode == 3 then + if luajava.instanceof(v,ViewGroup) then + func["添加"](v) + else + func["id"](v) + end + return + elseif click_info.mode == 4 then + func["删除"](v) + return + end + + getCurr(v) + elseif (not is_clicking) and e.getAction() == MotionEvent.ACTION_DOWN then + holding_view = false + v.foreground = clicking_background_drawable + click_info_init() + click_info.now_view = v + click_info.start = { + x = e.rawX; + y = e.rawY; + } + click_info.start_time = System.currentTimeMillis() + click_info.now_click = v + is_clicking = true + return true + elseif is_clicking and e.getAction() == MotionEvent.ACTION_MOVE then + + local offset = activity.getWidth()/3 + --点击的偏移 + + if + math.abs(e.rawX - click_info.start.x) > offset or + math.abs(e.rawY - click_info.start.y) > offset then + + is_clicking = false + v.foreground = nil + else + if e.rawY - click_info.start.y > offset*0.3 then + click_info.mode = 3 + v.invalidate() + elseif e.rawY - click_info.start.y < -(offset*0.3) then + click_info.mode = 2 + v.invalidate() + elseif e.rawX - click_info.start.x < -(offset*0.3) then + click_info.mode = 4 + v.invalidate() + else + if click_info.mode ~= 1 then + click_info.start_time = System.currentTimeMillis() + end + click_info.mode = 1 + v.invalidate() + end + end + return true + end + +end + +local TypedValue=luajava.bindClass("android.util.TypedValue") +local dm=activity.getResources().getDisplayMetrics() +function dp(n) + return TypedValue.applyDimension(1,n,dm) +end + +function to(n) + return string.format("%ddp",n//dn) +end + +dn=dp(1) +lastX=0 +lastY=0 +vx=0 +vy=0 +vw=0 +vh=0 +zoomX=false +zoomY=false +function move(v,e) + curr=v.Tag + currView=v + ry=e.getRawY()--获取触摸绝对Y位置 + rx=e.getRawX()--获取触摸绝对X位置 + if e.getAction() == MotionEvent.ACTION_DOWN then + lp=v.getLayoutParams() + vy=v.getY()--获取视图的Y位置 + vx=v.getX()--获取视图的X位置 + lastY=ry--记录按下的Y位置 + lastX=rx--记录按下的X位置 + vw=v.getWidth()--记录控件宽度 + vh=v.getHeight()--记录控件高度 + if vw-e.getX()<20 then + zoomX=true--如果触摸右边缘启动缩放宽度模式 + elseif vh-e.getY()<20 then + zoomY=true--如果触摸下边缘启动缩放高度模式 + end + + elseif e.getAction() == MotionEvent.ACTION_MOVE then + --lp.gravity=Gravity.LEFT|Gravity.TOP --调整控件至左上角 + if zoomX then + lp.width=(vw+(rx-lastX))--调整控件宽度 + elseif zoomY then + lp.height=(vh+(ry-lastY))--调整控件高度 + else + lp.x=(vx+(rx-lastX))--移动的相对位置 + lp.y=(vy+(ry-lastY))--移动的相对位置 + end + v.setLayoutParams(lp)--调整控件到指定的位置 + --v.Parent.invalidate() + elseif e.getAction() == MotionEvent.ACTION_UP then + if (rx-lastX)^2<100 and (ry-lastY)^2<100 then + getCurr(v) + else + curr.layout_x=to(v.getX()) + curr.layout_y=to(v.getY()) + if zoomX then + curr.layout_width=to(v.getWidth()) + elseif zoomY then + curr.layout_height=to(v.getHeight()) + end + end + zoomX=false--初始化状态 + zoomY=false--初始化状态 + end + return true +end + +function getCurr(v) + curr=v.Tag + currView=v + fd_dlg.setView(View(activity)) + fd_dlg.Title=tostring(v.Class.getSimpleName()) + if luajava.instanceof(v,GridLayout) then + fd_dlg.setItems(fds_grid) + elseif luajava.instanceof(v,LinearLayout) then + fd_dlg.setItems(fds_linear) + elseif luajava.instanceof(v,CardView) then + fd_dlg.setItems(fds_card) + elseif luajava.instanceof(v,ViewGroup) then + fd_dlg.setItems(fds_group) + elseif luajava.instanceof(v,EditText) then + fd_dlg.setItems(fds_edit) + elseif luajava.instanceof(v,TextView) then + fd_dlg.setItems(fds_text) + elseif luajava.instanceof(v,ImageView) then + fd_dlg.setItems(fds_image) + else + fd_dlg.setItems(fds_view) + end + + + + if luajava.instanceof(v.Parent,LinearLayout) then + fd_list.getAdapter().add("layout_weight") + elseif luajava.instanceof(v.Parent,AbsoluteLayout) then + fd_list.getAdapter().insert(5,"layout_x") + fd_list.getAdapter().insert(6,"layout_y") + elseif luajava.instanceof(v.Parent,RelativeLayout) then + local adp=fd_list.getAdapter() + for k,v in ipairs(relative) do + adp.add(v) + end + end + local adapter = fd_list.adapter + local put_position = 4 + local unknow_fd = table.clone(curr) + + + --移除数字索引 + for k,v in pairs(unknow_fd) do + if tonumber(k) then + unknow_fd[k] = 0 + end + end + + for i = 0,adapter.count-1 do + local key = adapter.getItem(i) + + if key == "id" then + put_position = i + end + + if curr[key] then + adapter.remove(i) + adapter.insert(put_position,Html.fromHtml(""..key..":"..tostring(curr[key]).."")) + + unknow_fd[key] = nil + end + end + + for k,v in pairs(unknow_fd) do + if not tonumber(k) then + adapter.insert(put_position,Html.fromHtml(""..k..":"..tostring(v).."")) + end + end + + fd_dlg.show() +end + +function adapter(t) + local ls=ArrayList() + for k,v in ipairs(t) do + ls.add(v) + end + return ArrayAdapter(activity,android.R.layout.simple_list_item_1, ls) +end + +import "android.graphics.drawable.*" + + +curr=nil +activity.setTitle('布局助手') +function getFilesDir() + return "/data/user/0/"..activity.getPackageName().."/files/" +end +local a=io.open(getFilesDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + activity.setTheme(android.R.style.Theme_DeviceDefault_Light) + else + activity.setTheme(android.R.style.Theme_DeviceDefault_Light) +end +xpcall(function() + activity.setContentView(loadlayout2(layout.main,{})) +end, +function() + Toast.makeText(activity,"不支持编辑该布局\n(请检查布局文件是否出错)",1000).show() + activity.finish() +end) + +relative={ + "layout_above","layout_alignBaseline","layout_alignBottom","layout_alignEnd","layout_alignLeft","layout_alignParentBottom","layout_alignParentEnd","layout_alignParentLeft","layout_alignParentRight","layout_alignParentStart","layout_alignParentTop","layout_alignRight","layout_alignStart","layout_alignTop","layout_alignWithParentIfMissing","layout_below","layout_centerHorizontal","layout_centerInParent","layout_centerVertical","layout_toEndOf","layout_toLeftOf","layout_toRightOf","layout_toStartOf" +} + +--属性列表对话框 +fd_dlg=AlertDialogBuilder(activity) +fd_list=fd_dlg.getListView() +fds_grid={ + "添加","删除","父控件","子控件", + "id","orientation", + "columnCount","rowCount", + "layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_linear={ + "添加","删除","父控件","子控件", + "id","orientation","layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_group={ + "添加","删除","父控件","子控件", + "id","layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_edit={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","text","hint","textColorHint","inputType","digits","maxEms","textColor","textSize","singleLine","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_text={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","text","textColor","textSize","textStyle","singleLine","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_image={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","src","adjustViewBounds","scaleType","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_view={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_card={ + "添加","删除","父控件","子控件", + "id","layout_width","layout_height","layout_gravity", + "background","gravity","radius","elevation","backgroundColor", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +--全部View操作 +local view_actions = { + fds_grid;fds_linear;fds_card;fds_group; + fds_edit;fds_text;fds_image;fds_view; +} + +for k,v in ipairs(view_actions) do + table.insert(v,3,"复制") + table.insert(v,4,"编辑") +end + +--属性选择列表 +checks={} +checks.textStyle = {"normal","bold","italic"} +checks.inputType = {"none","phone","text","datetime","date","textAutoComplete","textAutoCorrect","textCapCharacters","textCapSentences","textCapWords","textEmailAddress","textEmailSubject","textFilter","textImeMultiLine","textLongMessage","textMultiLine","textNoSuggestions","textPassword","textPersonName","textPhonetic","textPostalAddress","textShortMessage","textUri","textVisiblePassword","textWebEditText","textWebEmailAddress","textWebPassword","numberPassword","numberSigned","number","numberDecimal"} +checks.adjustViewBounds={"true","false","none"} +checks.layout_width={"fill","wrap","other"} +checks.layout_height={"fill","wrap","other"} +checks.singleLine={"true","false"} +checks.orientation={"vertical","horizontal"} +checks.gravity={"left","top","right","bottom","start","center","end"} +checks.layout_gravity={"left","top","right","bottom","start","center","end"} +checks.scaleType={ + "matrix", + "fitXY", + "fitStart", + "fitCenter", + "fitEnd", + "center", + "centerCrop", + "centerInside"} + + +function addDir(out,dir,f) + local ls=f.listFiles() + for n=0,#ls-1 do + local name=ls[n].getName() + if ls[n].isDirectory() then + addDir(out,dir..name.."/",ls[n]) + elseif name:find("%.j?pn?g$") then + table.insert(out,dir..name) + end + end +end + +function checkid() + local cs={} + local parent=currView.Parent.Tag + for k,v in ipairs(parent) do + if v==curr then + break + end + if type(v)=="table" and v.id then + table.insert(cs,v.id) + end + end + return cs +end + +rbs={"layout_alignParentBottom","layout_alignParentEnd","layout_alignParentLeft","layout_alignParentRight","layout_alignParentStart","layout_alignParentTop","layout_centerHorizontal","layout_centerInParent","layout_centerVertical"} +ris={"layout_above","layout_alignBaseline","layout_alignBottom","layout_alignEnd","layout_alignLeft","layout_alignRight","layout_alignStart","layout_alignTop","layout_alignWithParentIfMissing","layout_below","layout_toEndOf","layout_toLeftOf","layout_toRightOf","layout_toStartOf"} +for k,v in ipairs(rbs) do + checks[v]={"true","false","none"} +end + +for k,v in ipairs(ris) do + checks[v]=checkid +end + +if luadir then + checks.src=function() + local src={} + addDir(src,"",File(luadir)) + return src + end +end + +fd_list.onItemClick=function(l,v,p,i) + + fd_dlg.hide() + + local fd=tostring(v.Text) + if string.find(fd,":") then + fd = fd:gsub("%:.*","") + end + if checks[fd] then + if type(checks[fd])=="table" then + check_dlg.Title=fd + check_dlg.setItems(checks[fd]) + check_dlg.show() + else + check_dlg.Title=fd + check_dlg.setItems(checks[fd](fd)) + check_dlg.show() + end + else + func[fd]() + end +end + +--子视图列表对话框 +cd_dlg=AlertDialogBuilder(activity) +cd_list=cd_dlg.getListView() +cd_list.onItemClick=function(l,v,p,i) + getCurr(chids[p]) + cd_dlg.hide() +end + +--可选属性对话框 +check_dlg=AlertDialogBuilder(activity) +check_list=check_dlg.getListView() +check_list.onItemClick=function(l,v,p,i) + + local v=tostring(v.Text) + local fld=check_dlg.Title + if v == "other" then + check_dlg.hide() + func[fld]() + return + end + if #v==0 or v=="none" then + v=nil + end + local fld=check_dlg.Title + local old=curr[tostring(fld)] + curr[tostring(fld)]=v + check_dlg.hide() + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(fld)]=old + print(l) + end + + if holding_view then + getCurr(currView) + end +end + +func={} +setmetatable(func,{__index=function(t,k) + return function() + sfd_dlg.Title=k--tostring(currView.Class.getSimpleName()) + --sfd_dlg.Message=k + fld.Text= (curr[k] and tostring(curr[k])) or "" + fld.selectAll() + sfd_dlg.show() + fld.requestFocus() + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,InputMethodManager.HIDE_NOT_ALWAYS); + end + end +}) +func["添加"]=function() + add_dlg.Title=tostring(currView.Class.getSimpleName()) + for n=0,#ns-1 do + if n~=i then + el.collapseGroup(n) + end + end + add_dlg.show() +end + +func["删除"]=function() + local gp=currView.Parent.Tag + if gp==nil then + Toast.makeText(activity,"不可以删除顶部控件",1000).show() + return + end + for k,v in ipairs(gp) do + if v==curr then + table.remove(gp,k) + break + end + end + activity.setContentView(loadlayout2(layout.main,{})) +end + +func["复制"]=function() + local clone = table.clone(curr) + getCurr(currView.Parent) + table.insert(curr,clone) + + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(fld)]=old + print(l) + end + + fd_dlg.hide() +end + +func["编辑"]=function() + local _layout ={ + LinearLayout; + orientation="vertical"; + layout_height="fill"; + layout_width="fill"; + { + LuaEditor; + id="editor"; + layout_weight="1.0"; + layout_height="wrap"; + layout_width="fill"; + }; + { + LinearLayout; + layout_gravity="center"; + layout_width="fill"; + { + Button; + layout_weight="1"; + text="取消"; + id="cancel"; + }; + { + Button; + layout_weight="1"; + text="确定"; + id="ok"; + }; + }; + }; + local _ids = {} + local dialog = Dialog() + dialog.setContentView(loadlayout(_layout,_ids)) + dialog.setTitle("编辑控件布局代码") + dialog.cancelable = true + dialog.show() + local ab=io.open(getFilesDir().."/Verify/set5.XY"):read("*a") +local abc=io.open(getFilesDir().."/Verify/set6.XY"):read("*a") +local abcd=io.open(getFilesDir().."/Verify/set7.XY"):read("*a") +local abcde=io.open(getFilesDir().."/Verify/set8.XY"):read("*a") +local abcdef=io.open(getFilesDir().."/Verify/set9.XY"):read("*a") +local abcdefg=io.open(getFilesDir().."/Verify/set10.XY"):read("*a") +local abcdefgh=io.open(getFilesDir().."/Verify/set11.XY"):read("*a") +local abcdefghi=io.open(getFilesDir().."/Verify/set12.XY"):read("*a") +switch abc + case "颜色1" + abc=颜色1 + default + abc=tonumber(abc) +end +switch abcdef + case "颜色3" + abcdef=颜色3 + default + abcdef=tonumber(abcdef) +end +_ids.editor.setBasewordColor(tonumber(ab))--基词 +_ids.editor.setPanelBackgroundColor(tonumber(abc))--卡片颜色 +_ids.editor.setPanelTextColor(tonumber(abcd))--卡片字体颜色 +_ids.editor.setStringColor(tonumber(abcde))--字符串颜色 +_ids.editor.setTextColor(tonumber(abcdef))--文本颜色 +_ids.editor.setUserwordColor(tonumber(abcdefg))--数字 +_ids.editor.setCommentColor(tonumber(abcdefgh))--注释颜色 +_ids.editor.setKeywordColor(tonumber(abcdefghi))--if then等 + _ids.editor.text = dumplayout2(curr) + Handler().postDelayed(function() + _ids.editor.format() + end,100) + _ids.cancel.onClick = function() + dialog.cancel() + end + + _ids.ok.onClick = function() + local code = _ids.editor.text + e,i = pcall(loadstring("return "..code)) + if e then + for k,v in pairs(i) do + curr[k] = v + end + dialog.cancel() + else + print("代码出错,请检查拼写!\n"..i) + end + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(fld)]=old + print(l) + end + end +end + +func["父控件"]=function() + local p=currView.Parent + if p.Tag==nil then + Toast.makeText(activity,"已是顶部控件",1000).show() + else + getCurr(p) + end +end + +chids={} +func["子控件"]=function() + chids={} + local arr={} + for n=0,currView.ChildCount-1 do + local chid=currView.getChildAt(n) + chids[n]=chid + table.insert(arr,chid.Class.getSimpleName()) + end + cd_dlg.Title=tostring(currView.Class.getSimpleName()) + cd_dlg.setItems(arr) + cd_dlg.show() +end + +--添加视图对话框 +add_dlg=Dialog(activity) +add_dlg.Title="添加" +wdt_list=ListView(activity) + +ns={ + "小部件","检查视图","适配器视图","高级控件","布局","高级布局","附加控件" +} + + +wdt={ + {"Button -按钮控件","EditText -编辑框控件","TextView -文本控件", + "ImageButton -图片按钮控件","ImageView -图片控件","CircleImageView -圆形图片控件","SearchView -搜索框"}, + {"CheckBox -复选框","RadioButton -单选框","ToggleButton -按钮开关控件","Switch -开关控件"}, + {"ListView -列表视图","GridView -网格视图","PageView -滑动视图","ExpandableListView -折叠列表","Spinner -下拉框"}, + {"SeekBar -拖动条","ProgressBar -进度条","RatingBar -评分栏", + "DatePicker -日期选择器","TimePicker -时间选择器","NumberPicker -数字选择器","Chronometer -计时器"}, + {"LinearLayout -线性布局","AbsoluteLayout -绝对布局","FrameLayout -帧布局","RelativeLayout -相对布局","TableLayout -表布局","RippleLayout -水波纹布局"}, + {"CardView -卡片控件","RadioGroup -单选视图","GridLayout -网格布局", + "ScrollView -纵向滚动布局","HorizontalScrollView -横向滚动布局"}, + {"LuaEditor -Lua代码编辑框","LuaWebView -Lua浏览器控件","PullingLayout -下拉刷新"} +} + +wds={ + {"Button","EditText","TextView", + "ImageButton","ImageView","CircleImageView","SearchView"}, + {"CheckBox","RadioButton","ToggleButton","Switch"}, + {"ListView","GridView","PageView","ExpandableListView","Spinner"}, + {"SeekBar","ProgressBar","RatingBar", + "DatePicker","TimePicker","NumberPicker","Chronometer"}, + {"LinearLayout","AbsoluteLayout","FrameLayout","RelativeLayout","TableLayout","RippleLayout"}, + {"CardView","RadioGroup","GridLayout", + "ScrollView","HorizontalScrollView"}, + {"LuaEditor","LuaWebView","PullingLayout"} +} + + +mAdapter=ArrayExpandableListAdapter(activity) +for k,v in ipairs(ns) do + mAdapter.add(v,wdt[k]) +end + +el=ExpandableListView(activity) +el.setAdapter(mAdapter) +add_dlg.setContentView(el) + +el.onChildClick=function(l,v,g,c) + local w={_G[wds[g+1][c+1]]} + table.insert(curr,w) + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + table.remove(curr) + print(l) + end + add_dlg.hide() +end + + + +function ok() + imm.hideSoftInputFromWindow(fld.getWindowToken(), 0) + local v=tostring(fld.Text) + if #v==0 then + v=nil + end + local fld=sfd_dlg.Title + local old=curr[tostring(fld)] + curr[tostring(fld)]=v + --sfd_dlg.hide() + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + + + if holding_view then + getCurr(currView) + end + else + curr[tostring(fld)]=old + print(l) + end + +end + +function none() + local old=curr[tostring(sfd_dlg.Title)] + curr[tostring(sfd_dlg.Title)]=nil + --sfd_dlg.hide() + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(sfd_dlg.Title)]=old + print(l) + end + imm.hideSoftInputFromWindow(fld.getWindowToken(), 0) + + if holding_view then + getCurr(currView) + end +end + + +--输入属性对话框 +sfd_dlg=AlertDialogBuilder(activity) +fld=EditText(activity) +fld.setFocusable(true); +fld.setFocusableInTouchMode(true); +sfd_dlg.setView(fld) +sfd_dlg.setPositiveButton("确定",{onClick=ok}) +sfd_dlg.setNegativeButton("取消",{onClick=function() + --隐藏键盘 + imm.hideSoftInputFromWindow(fld.getWindowToken(), 0) + if holding_view then + getCurr(currView) + end + end}) +sfd_dlg.setNeutralButton("无",{onClick=none}) +function dumparray(arr) + local ret={} + table.insert(ret,"{\n") + for k,v in ipairs(arr) do + table.insert(ret,string.format("\"%s\";\n",v)) + end + table.insert(ret,"};\n") + return table.concat(ret) +end +function dumplayout(t) + table.insert(ret,"{\n") + table.insert(ret,tostring(t[1].getSimpleName()..";\n")) + for k,v in pairs(t) do + if type(k)=="number" then + --do nothing + elseif type(v)=="table" then + table.insert(ret,k.."="..dumparray(v)) + elseif type(v)=="string" then + if v:find("[\"\'\r\n]") then + table.insert(ret,string.format("%s=[==[%s]==];\n",k,v)) + else + table.insert(ret,string.format("%s=\"%s\";\n",k,v)) + end + else + table.insert(ret,string.format("%s=%s;\n",k,tostring(v))) + end + end + for k,v in ipairs(t) do + if type(v)=="table" then + dumplayout(v) + end + end + table.insert(ret,"};\n") +end + +function dumplayout2(t) + ret={} + dumplayout(t) + return table.concat(ret) +end + +function onCreateOptionsMenu(menu) + menu.add("复制") + menu.add("编辑") + menu.add("预览") + if showsave then + menu.add("保存") + end +end + +function save(s) + local f=io.open(luapath,"w") + f:write(s) + f:close() +end + +import "android.content.*" +cm=activity.getSystemService(activity.CLIPBOARD_SERVICE) + +function onMenuItemSelected(id,item) + local t=item.getTitle() + if t=="复制" then + local cd = ClipData.newPlainText("label",dumplayout2(layout.main)) + cm.setPrimaryClip(cd) + Toast.makeText(activity,"已复制到剪切板",1000).show() + elseif t=="编辑" then + editlayout(dumplayout2(layout.main)) + elseif t=="预览" then + show(dumplayout2(layout.main)) + elseif t=="保存" then + if luapath:find("%.lua$") then + activity.result({dumplayout2(layout.main)}) + return + end + save(dumplayout2(layout.main)) + Toast.makeText(activity,"已保存",1000).show() + activity.setResult(10000,Intent()); + activity.finish() + end +end + +function onStart() + activity.setContentView(loadlayout2(layout.main,{})) +end + +lastclick=os.time()-2 +function onKeyDown(e) + local now=os.time() + if e==4 then + if now-lastclick>2 then + Toast.makeText(activity, "再按一次返回.", Toast.LENGTH_SHORT ).show() + lastclick=now + return true + end + end +end + + diff --git a/app/src/main/assets/layouthelper/xml2table.lua b/app/src/main/assets/layouthelper/xml2table.lua new file mode 100644 index 0000000..99ad44e --- /dev/null +++ b/app/src/main/assets/layouthelper/xml2table.lua @@ -0,0 +1,197 @@ +require "import" +import "console" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "android.content.*" +import "com.androlua.*" +import "loadlayout3" +function getFilesDir() + return "/data/user/0/"..activity.getPackageName().."/files/" +end +function autotheme() +local a=io.open(getFilesDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + return (android.R.style.Theme_DeviceDefault) + else + return (android.R.style.Theme_DeviceDefault_Light) +end +end +local a=io.open(getFilesDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色6=0xffffffff + 颜色5=0xff212121 + 颜色7=0xEBFFFFFF + activity.setTheme(android.R.style.Theme_DeviceDefault) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色6=0xff757575 + 颜色5=0x5FFFFFFF + 颜色7=0xff303030 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light) +end +--activity.setTitle('XML转换器') +--activity.setTheme(android.R.style.Theme_Holo_Light) +cm=activity.getSystemService(Context.CLIPBOARD_SERVICE) +t={ + LinearLayout, + id="l", + orientation="vertical" , + --backgroundColor="#eeeeff", + { + LuaEditor, + id="edit", + --hint= "XML布局代码转换AndroLua布局表", + layout_width="fill", + layout_height="fill", + layout_weight=1, + --gravity="top" + }, + { + LinearLayout, + layout_width="fill", + backgroundColor=颜色1, + { + Button, + id="open", + text="转换", + layout_width="fill", + layout_weight=1, + onClick ="click", + } , + { + Button, + id="open", + text="预览", + layout_width="fill", + layout_weight=1, + onClick ="click2", + } , + { + Button, + id="open", + text="复制", + layout_width="fill", + layout_weight=1, + onClick ="click3", + } , + { + Button, + id="open", + text="确定", + layout_width="fill", + layout_weight=1, + onClick ="click4", + } , + } +} + +function xml2table(xml) + local xml,s=xml:gsub("","}") + if s==0 then + return xml + end + xml=xml:gsub("<%?[^<>]+%?>","") + xml=xml:gsub("xmlns:android=%b\"\"","") + xml=xml:gsub("%w+:","") + xml=xml:gsub("\"([^\"]+)\"",function(s)return (string.format("\"%s\"",s:match("([^/]+)$")))end) + xml=xml:gsub("[\t ]+","") + xml=xml:gsub("\n+","\n") + xml=xml:gsub("^\n",""):gsub("\n$","") + xml=xml:gsub("<","{"):gsub("/>","}"):gsub(">",""):gsub("\n",",\n") + return (xml) +end + +dlg=Dialog(activity,autotheme()) +dlg.setTitle("布局表预览") +function show(s) + dlg.setContentView(loadlayout3(loadstring("return "..s)(),{})) + dlg.show() +end + +function click() + local str=edit.getText().toString() + str=xml2table(str) + str=console.format(str) + edit.setText(str) +end + +function click2() + local str=edit.getText().toString() + show(str) +end + + +function click3(s) + local cd = ClipData.newPlainText("label", edit.getText().toString()) + cm.setPrimaryClip(cd) + Toast.makeText(activity,"已复制的剪切板",1000).show() +end + +function click4() + local str=edit.getText().toString() + layout.main=loadstring("return "..str)() + activity.setContentView(loadlayout2(layout.main,{})) + dlg2.hide() + +end + + +loadlayout(t) +dlg2=Dialog(activity,autotheme()) +dlg2.setTitle("编辑代码") +dlg2.getWindow().setSoftInputMode(0x10) + +dlg2.setContentView(l) + + + +function editlayout(txt) + edit.Text=txt + edit.format() + dlg2.show() + local ab=io.open(getFilesDir().."/Verify/set5.XY"):read("*a") +local abc=io.open(getFilesDir().."/Verify/set6.XY"):read("*a") +local abcd=io.open(getFilesDir().."/Verify/set7.XY"):read("*a") +local abcde=io.open(getFilesDir().."/Verify/set8.XY"):read("*a") +local abcdef=io.open(getFilesDir().."/Verify/set9.XY"):read("*a") +local abcdefg=io.open(getFilesDir().."/Verify/set10.XY"):read("*a") +local abcdefgh=io.open(getFilesDir().."/Verify/set11.XY"):read("*a") +local abcdefghi=io.open(getFilesDir().."/Verify/set12.XY"):read("*a") +switch abc + case "颜色1" + abc=颜色1 + default + abc=tonumber(abc) +end +switch abcdef + case "颜色3" + abcdef=颜色3 + default + abcdef=tonumber(abcdef) +end +edit.setBasewordColor(tonumber(ab))--基词 +edit.setPanelBackgroundColor(tonumber(abc))--卡片颜色 +edit.setPanelTextColor(tonumber(abcd))--卡片字体颜色 +edit.setStringColor(tonumber(abcde))--字符串颜色 +edit.setTextColor(tonumber(abcdef))--文本颜色 +edit.setUserwordColor(tonumber(abcdefg))--数字 +edit.setCommentColor(tonumber(abcdefgh))--注释颜色 +edit.setKeywordColor(tonumber(abcdefghi))--if then等 +end + +function onResume2() + local cd=cm.getPrimaryClip(); + local msg=cd.getItemAt(0).getText()--.toString(); + edit.setText(msg) +end diff --git a/app/src/main/assets/libs/mao.odex b/app/src/main/assets/libs/mao.odex new file mode 100644 index 0000000..08e7c7f Binary files /dev/null and b/app/src/main/assets/libs/mao.odex differ diff --git a/app/src/main/assets/libs/mao.vdex b/app/src/main/assets/libs/mao.vdex new file mode 100644 index 0000000..9381eb0 Binary files /dev/null and b/app/src/main/assets/libs/mao.vdex differ diff --git a/app/src/main/assets/libs/oat/arm/android-support-v4.odex b/app/src/main/assets/libs/oat/arm/android-support-v4.odex new file mode 100644 index 0000000..9ebf7f2 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm/android-support-v4.odex differ diff --git a/app/src/main/assets/libs/oat/arm/android-support-v4.vdex b/app/src/main/assets/libs/oat/arm/android-support-v4.vdex new file mode 100644 index 0000000..4675d23 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm/android-support-v4.vdex differ diff --git a/app/src/main/assets/libs/oat/arm/classes.odex b/app/src/main/assets/libs/oat/arm/classes.odex new file mode 100644 index 0000000..faac479 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm/classes.odex differ diff --git a/app/src/main/assets/libs/oat/arm/classes.vdex b/app/src/main/assets/libs/oat/arm/classes.vdex new file mode 100644 index 0000000..2f80929 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm/classes.vdex differ diff --git a/app/src/main/assets/libs/oat/arm/okh.odex b/app/src/main/assets/libs/oat/arm/okh.odex new file mode 100644 index 0000000..da4dcdd Binary files /dev/null and b/app/src/main/assets/libs/oat/arm/okh.odex differ diff --git a/app/src/main/assets/libs/oat/arm/okh.vdex b/app/src/main/assets/libs/oat/arm/okh.vdex new file mode 100644 index 0000000..f237d00 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm/okh.vdex differ diff --git a/app/src/main/assets/libs/oat/arm64/android-support-v4.odex b/app/src/main/assets/libs/oat/arm64/android-support-v4.odex new file mode 100644 index 0000000..08f8a8e Binary files /dev/null and b/app/src/main/assets/libs/oat/arm64/android-support-v4.odex differ diff --git a/app/src/main/assets/libs/oat/arm64/android-support-v4.vdex b/app/src/main/assets/libs/oat/arm64/android-support-v4.vdex new file mode 100644 index 0000000..9281de4 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm64/android-support-v4.vdex differ diff --git a/app/src/main/assets/libs/oat/arm64/classes.odex b/app/src/main/assets/libs/oat/arm64/classes.odex new file mode 100644 index 0000000..18406f6 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm64/classes.odex differ diff --git a/app/src/main/assets/libs/oat/arm64/classes.vdex b/app/src/main/assets/libs/oat/arm64/classes.vdex new file mode 100644 index 0000000..3bbbbad Binary files /dev/null and b/app/src/main/assets/libs/oat/arm64/classes.vdex differ diff --git a/app/src/main/assets/libs/oat/arm64/okh.odex b/app/src/main/assets/libs/oat/arm64/okh.odex new file mode 100644 index 0000000..14559b4 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm64/okh.odex differ diff --git a/app/src/main/assets/libs/oat/arm64/okh.vdex b/app/src/main/assets/libs/oat/arm64/okh.vdex new file mode 100644 index 0000000..759d4d3 Binary files /dev/null and b/app/src/main/assets/libs/oat/arm64/okh.vdex differ diff --git a/app/src/main/assets/libs/oat1/arm/classes.odex b/app/src/main/assets/libs/oat1/arm/classes.odex new file mode 100644 index 0000000..63bbd5b Binary files /dev/null and b/app/src/main/assets/libs/oat1/arm/classes.odex differ diff --git a/app/src/main/assets/libs/oat1/arm/classes.vdex b/app/src/main/assets/libs/oat1/arm/classes.vdex new file mode 100644 index 0000000..bda9a52 Binary files /dev/null and b/app/src/main/assets/libs/oat1/arm/classes.vdex differ diff --git a/app/src/main/assets/libs/sign.odex b/app/src/main/assets/libs/sign.odex new file mode 100644 index 0000000..6cd6dbf Binary files /dev/null and b/app/src/main/assets/libs/sign.odex differ diff --git a/app/src/main/assets/libs/sign.vdex b/app/src/main/assets/libs/sign.vdex new file mode 100644 index 0000000..7be1474 Binary files /dev/null and b/app/src/main/assets/libs/sign.vdex differ diff --git a/app/src/main/assets/loadlayout2.lua b/app/src/main/assets/loadlayout2.lua new file mode 100644 index 0000000..0fc2a2d --- /dev/null +++ b/app/src/main/assets/loadlayout2.lua @@ -0,0 +1,628 @@ +local require = require +local table = require "table" +local _G = _G +local insert = table.insert +local new = luajava.new +local bindClass = luajava.bindClass +local ids = {} +local ltrs = {} +local id = 0x7f000000 + +local context = activity or service + +local ViewGroup = bindClass("android.view.ViewGroup") +local String = bindClass("java.lang.String") +local Gravity = bindClass("android.view.Gravity") +local OnClickListener = bindClass("android.view.View$OnClickListener") +local TypedValue = luajava.bindClass("android.util.TypedValue") +local BitmapDrawable = luajava.bindClass("android.graphics.drawable.BitmapDrawable") +local LuaDrawable = luajava.bindClass "com.androlua.LuaDrawable" +local TruncateAt = bindClass("android.text.TextUtils$TruncateAt") +local ArrayAdapter = bindClass("android.widget.ArrayAdapter") +local ScaleType = bindClass("android.widget.ImageView$ScaleType") +local scaleTypes = ScaleType.values() +local android_R = bindClass("android.R") + +local Context = bindClass "android.content.Context" +local DisplayMetrics = bindClass "android.util.DisplayMetrics" + +local wm = context.getSystemService(Context.WINDOW_SERVICE); +local outMetrics = DisplayMetrics(); +wm.getDefaultDisplay().getMetrics(outMetrics); +local W = outMetrics.widthPixels; +local H = outMetrics.heightPixels; + +local dm = context.getResources().getDisplayMetrics() +local toint = { +--android:drawingCacheQuality + auto = 0, + low = 1, + high = 2, + +--android:importantForAccessibility + auto = 0, + yes = 1, + no = 2, + +--android:layerType + none = 0, + software = 1, + hardware = 2, + +--android:layoutDirection + ltr = 0, + rtl = 1, + inherit = 2, + locale = 3, + +--android:scrollbarStyle + insideOverlay = 0x0, + insideInset = 0x01000000, + outsideOverlay = 0x02000000, + outsideInset = 0x03000000, + +--android:visibility + visible = 0, + invisible = 1, + gone = 2, + + wrap_content = -2, + fill_parent = -1, + match_parent = -1, + wrap = -2, + fill = -1, + match = -1, + +--android:autoLink + none = 0x00, + web = 0x01, + email = 0x02, + phon = 0x04, + map = 0x08, + all = 0x0f, + +--android:orientation + vertical = 1, + horizontal = 0, + +--android:gravity + axis_clip = 8, + axis_pull_after = 4, + axis_pull_before = 2, + axis_specified = 1, + axis_x_shift = 0, + axis_y_shift = 4, + bottom = 80, + center = 17, + center_horizontal = 1, + center_vertical = 16, + clip_horizontal = 8, + clip_vertical = 128, + display_clip_horizontal = 16777216, + display_clip_vertical = 268435456, +--fill = 119, + fill_horizontal = 7, + fill_vertical = 112, + horizontal_gravity_mask = 7, + left = 3, + no_gravity = 0, + relative_horizontal_gravity_mask = 8388615, + relative_layout_direction = 8388608, + right = 5, + start = 8388611, + top = 48, + vertical_gravity_mask = 112, + ["end"] = 8388613, + +--android:textAlignment + inherit = 0, + gravity = 1, + textStart = 2, + textEnd = 3, + textCenter = 4, + viewStart = 5, + viewEnd = 6, + +--android:inputType + none = 0x00000000, + text = 0x00000001, + textCapCharacters = 0x00001001, + textCapWords = 0x00002001, + textCapSentences = 0x00004001, + textAutoCorrect = 0x00008001, + textAutoComplete = 0x00010001, + textMultiLine = 0x00020001, + textImeMultiLine = 0x00040001, + textNoSuggestions = 0x00080001, + textUri = 0x00000011, + textEmailAddress = 0x00000021, + textEmailSubject = 0x00000031, + textShortMessage = 0x00000041, + textLongMessage = 0x00000051, + textPersonName = 0x00000061, + textPostalAddress = 0x00000071, + textPassword = 0x00000081, + textVisiblePassword = 0x00000091, + textWebEditText = 0x000000a1, + textFilter = 0x000000b1, + textPhonetic = 0x000000c1, + textWebEmailAddress = 0x000000d1, + textWebPassword = 0x000000e1, + number = 0x00000002, + numberSigned = 0x00001002, + numberDecimal = 0x00002002, + numberPassword = 0x00000012, + phone = 0x00000003, + datetime = 0x00000004, + date = 0x00000014, + time = 0x00000024, + +--android:imeOptions + normal = 0x00000000, + actionUnspecified = 0x00000000, + actionNone = 0x00000001, + actionGo = 0x00000002, + actionSearch = 0x00000003, + actionSend = 0x00000004, + actionNext = 0x00000005, + actionDone = 0x00000006, + actionPrevious = 0x00000007, + flagNoFullscreen = 0x2000000, + flagNavigatePrevious = 0x4000000, + flagNavigateNext = 0x8000000, + flagNoExtractUi = 0x10000000, + flagNoAccessoryAction = 0x20000000, + flagNoEnterAction = 0x40000000, + flagForceAscii = 0x80000000, + +} + +local scaleType = { +--android:scaleType + matrix = 0, + fitXY = 1, + fitStart = 2, + fitCenter = 3, + fitEnd = 4, + center = 5, + centerCrop = 6, + centerInside = 7, +} + +local rules = { + layout_above = 2, + layout_alignBaseline = 4, + layout_alignBottom = 8, + layout_alignEnd = 19, + layout_alignLeft = 5, + layout_alignParentBottom = 12, + layout_alignParentEnd = 21, + layout_alignParentLeft = 9, + layout_alignParentRight = 11, + layout_alignParentStart = 20, + layout_alignParentTop = 10, + layout_alignRight = 7, + layout_alignStart = 18, + layout_alignTop = 6, + layout_alignWithParentIfMissing = 0, + layout_below = 3, + layout_centerHorizontal = 14, + layout_centerInParent = 13, + layout_centerVertical = 15, + layout_toEndOf = 17, + layout_toLeftOf = 0, + layout_toRightOf = 1, + layout_toStartOf = 16 +} + +local types = { + px = 0, + dp = 1, + sp = 2, + pt = 3, + ["in"] = 4, + mm = 5 +} + +local function checkType(v) + local n, ty = string.match(v, "^(%-?%d+)(%a%a)$") + return tonumber(n), types[ty] +end + +local function checkPercent(v) + local n, ty = string.match(v, "^(%-?[%.%d]+)%%([wh])$") + if ty == nil then + return nil + elseif ty == "w" then + return tonumber(n) * W / 100 + elseif ty == "h" then + return tonumber(n) * H / 100 + end +end + +local function split(s, t) + local idx = 1 + local l = #s + return function() + local i = s:find(t, idx) + if idx >= l then + return nil + end + if i == nil then + i = l + 1 + end + local sub = s:sub(idx, i - 1) + idx = i + 1 + return sub + end +end +local function checkint(s) + local ret = 0 + for n in split(s, "|") do + if toint[n] then + ret = ret | toint[n] + else + return nil + end + end + return ret +end + +local function checkNumber(var) + if type(var) == "string" then + if var == "true" then + return true + elseif var == "false" then + return false + end + + if toint[var] then + return toint[var] + end + + local i = checkint(var) + if i then + return i + end + + local p = checkPercent(var) + if p then + return p + end + + local h = string.match(var, "^#(%x+)$") + if h then + local c = tonumber(h, 16) + if c then + if #h <= 6 then + return c - 0x1000000 + elseif #h <= 8 then + if c > 0x7fffffff then + return c - 0x100000000 + else + return c + end + end + end + end + + local n, ty = checkType(var) + if ty then + return TypedValue.applyDimension(ty, n, dm) + end + end + -- return var +end + +local function checkValue(var) + return tonumber(var) or checkNumber(var) or var +end + +local function checkValues(...) + local vars = { ... } + for n = 1, #vars do + vars[n] = checkValue(vars[n]) + end + return unpack(vars) +end + +local function getattr(s) + return android_R.attr[s] +end + +local function checkattr(s) + local e, s = pcall(getattr, s) + if e then + return s + end + return nil +end + +local function getIdentifier(name) + return context.getResources().getIdentifier(name, null, null) +end + +local function dump2 (t) + local _t = {} + table.insert(_t, tostring(t)) + table.insert(_t, "\t{") + for k, v in pairs(t) do + if type(v) == "table" then + table.insert(_t, "\t\t" .. tostring(k) .. "={" .. tostring(v[1]) .. " ...}") + else + table.insert(_t, "\t\t" .. tostring(k) .. "=" .. tostring(v)) + end + end + table.insert(_t, "\t}") + t = table.concat(_t, "\n") + return t +end + +local ver = luajava.bindClass("android.os.Build").VERSION.SDK_INT; +function setBackground(view, bg) + if ver < 16 then + view.setBackgroundDrawable(bg) + else + view.setBackground(bg) + end +end + +local function setattribute(root, view, params, k, v, ids) + if k == "layout_x" then + params.x = checkValue(v) + elseif k == "layout_y" then + params.y = checkValue(v) + elseif k == "layout_weight" then + params.weight = checkValue(v) + elseif k == "layout_gravity" then + params.gravity = checkValue(v) + elseif k == "layout_marginStart" then + params.setMarginStart(checkValue(v)) + elseif k == "layout_marginEnd" then + params.setMarginEnd(checkValue(v)) + elseif rules[k] and (v == true or v == "true") then + params.addRule(rules[k]) + elseif rules[k] then + params.addRule(rules[k], ids[v]) + elseif k=="items" then --创建列表项目 + if type(v)=="table" then + if view.adapter then + view.adapter.addAll(v) + else + local adapter=ArrayListAdapter(context,android_R.layout.simple_list_item_1, String(v)) + view.setAdapter(adapter) + end + end + elseif k == "pages" and type(v) == "table" then + --创建页项目 + elseif k == "onClick" then + --设置onClick事件接口 + elseif k == "textSize" then + if tonumber(v) then + view.setTextSize(tonumber(v)) + elseif type(v) == "string" then + local n, ty = checkType(v) + if ty then + view.setTextSize(ty, n) + else + view.setTextSize(v) + end + else + view.setTextSize(v) + end + elseif k == "textAppearance" then + view.setTextAppearance(context, checkattr(v)) + elseif k == "ellipsize" then + view.setEllipsize(TruncateAt[string.upper(v)]) + elseif k == "url" then + view.loadUrl(url) + elseif k == "src" then + if v:find("^%?") then + view.setImageResource(getIdentifier(v:sub(2, -1))) + else + if (not v:find("^/")) and luadir then + v = luadir .. v + end + view.setImageBitmap(loadbitmap(v)) + end + elseif k == "scaleType" then + view.setScaleType(scaleTypes[scaleType[v]]) + elseif k == "background" then + if type(v) == "string" then + if v:find("^%?") then + view.setBackgroundResource(getIdentifier(v:sub(2, -1))) + elseif v:find("^#") then + view.setBackgroundColor(checkNumber(v)) + elseif rawget(root, v) or rawget(_G, v) then + v = rawget(root, v) or rawget(_G, v) + if type(v) == "function" then + setBackground(view, LuaDrawable(v)) + elseif type(v) == "userdata" then + setBackground(view, v) + end + else + if (not v:find("^/")) and luadir then + v = luadir .. v + end + if v:find("%.9%.png") then + setBackground(view, NineBitmapDrawable(loadbitmap(v))) + else + setBackground(view, BitmapDrawable(loadbitmap(v))) + end + end + elseif type(v) == "userdata" then + setBackground(view, v) + elseif type(v) == "number" then + view.setBackgroundColor(v) + end + elseif k == "password" and (v == "true" or v == true) then + view.setInputType(0x81) + elseif type(k) == "string" and not (k:find("layout_")) and not (k:find("padding")) and k ~= "style" then + --设置属性 + k = string.gsub(k, "^(%w)", function(s) + return string.upper(s) + end) + if k == "Text" or k == "Title" or k == "Subtitle" then + view["set" .. k](v) + else + view["set" .. k](checkValue(v)) + end + end +end + +local function setMiniSize(view) + view.setMinimumHeight(checkValue("18dp")) + view.setMinimumWidth(checkValue("18dp")) +end + +local function copytable(f, t, b) + for k, v in pairs(f) do + if k == 1 then + elseif b or t[k] == nil then + t[k] = v + end + end +end + +local function setstyle(c, t, root, view, params, ids) + local mt = getmetatable(t) + if not mt or not mt.__index then + return + end + local m = mt.__index + if c[m] then + return + end + c[m] = true + for k, v in pairs(m) do + if not rawget(c, k) then + pcall(setattribute, root, view, params, k, v, ids) + end + c[k] = true + end + setstyle(c, m, root, view, params, ids) +end + +local function loadlayout(t, root, group,p) + if type(t) == "string" then + p = t + t = require(t) + elseif type(t) ~= "table" then + error(string.format("loadlayout error: Fist value Must be a table, checked import layout.", 0)) + end + root = root or _G + local view, style + if t.style then + if t.style:find("^%?") then + style = getIdentifier(t.style:sub(2, -1)) + else + local st, sty = pcall(require, t.style) + if st then + --copytable(sty,t) + setmetatable(t, { __index = sty }) + else + style = checkattr(t.style) + end + end + end + if not t[1] then + error(string.format("loadlayout error: Fist value Must be a Class, checked import package.\n\tat %s", dump2(t)), 0) + end + + if style then + view = t[1](context, nil, style) + else + view = t[1](context) --创建view + end + if p then + view.onTouch = function(v, e) + if e.getAction() == MotionEvent.ACTION_DOWN then + print("import from \"" .. p.."\"") + return true + end + end + else + view.setTag(t) + if group and group == AbsoluteLayout then + view.onTouch = move + else + view.onTouch = onTouch + end + end + local vgw, vgh + pcall(setMiniSize, view) + + + + --MOD BY WSFX + --绘制边框 + if view.getBackground() == nil then + local gd=GradientDrawable() + gd.setColor(0x00ffffff) + gd.setStroke(2,0xFF000000,3,3) + gd.setGradientRadius(700) + gd.setGradientType(1) + setBackground(view, gd) + + end + + + local params = ViewGroup.LayoutParams(checkValue(t.layout_width) or -2, checkValue(t.layout_height) or -2) --设置layout属性 + if group then + params = group.LayoutParams(params) + end + + --设置layout_margin属性 + if t.layout_margin or t.layout_marginStart or t.layout_marginEnd or t.layout_marginLeft or t.layout_marginTop or t.layout_marginRight or t.layout_marginBottom then + params.setMargins(checkValues( t.layout_marginLeft or t.layout_margin or 0, t.layout_marginTop or t.layout_margin or 0, t.layout_marginRight or t.layout_margin or 0, t.layout_marginBottom or t.layout_margin or 0)) + end + + --设置padding属性 + if t.padding or t.paddingLeft or t.paddingTop or t.paddingRight or t.paddingBottom then + view.setPadding(checkValues(t.paddingLeft or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingRight or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + if t.paddingStart or t.paddingEnd then + view.setPaddingRelative(checkValues(t.paddingStart or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingEnd or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + + local c = {} + setmetatable(c, { __index = t }) + setstyle(c, t, root, view, params, ids) + + for k, v in pairs(t) do + if tonumber(k) and (type(v) == "table" or type(v) == "string") then + --创建子view + if luajava.instanceof(view,AdapterView) then + if type(v)=="string" then + v=require(v) + end + view.adapter=LuaAdapter(context,v) + else + view.addView(loadlayout(v,root,t[1])) + end + elseif k == "id" then + --创建view的全局变量 + rawset(root, v, view) + id = id + 1 + view.setId(id) + ids[v] = id + else + local e, s = pcall(setattribute, root, view, params, k, v, ids) + if not e then + local _, i = s:find(":%d+:") + s = s:sub(i or 1, -1) + error(string.format("loadlayout error %s \n\tat %s\n\tat key=%s value=%s\n\tat %s", s, view.toString(), k, v, dump2(t)), 0) + end + end + end + + --if group then + --group.addView(view,params) + --else + view.setLayoutParams(params) + return view + --end +end + +return loadlayout + diff --git a/app/src/main/assets/loadlayout3.lua b/app/src/main/assets/loadlayout3.lua new file mode 100644 index 0000000..107c4a0 --- /dev/null +++ b/app/src/main/assets/loadlayout3.lua @@ -0,0 +1,593 @@ +local require=require +local table=require "table" +local _G=_G +local insert = table.insert +local new = luajava.new +local bindClass = luajava.bindClass +local ids={} +local ltrs={} + +local context=activity or service + +local ViewGroup=bindClass("android.view.ViewGroup") +local String=bindClass("java.lang.String") +local Gravity=bindClass("android.view.Gravity") +local OnClickListener=bindClass("android.view.View$OnClickListener") +local TypedValue=luajava.bindClass("android.util.TypedValue") +local BitmapDrawable=luajava.bindClass("android.graphics.drawable.BitmapDrawable") +local TruncateAt=bindClass("android.text.TextUtils$TruncateAt") +local LuaDrawable=luajava.bindClass "com.androlua.LuaDrawable" +local ArrayAdapter=bindClass("android.widget.ArrayAdapter") +local ScaleType=bindClass("android.widget.ImageView$ScaleType") +local scaleTypes=ScaleType.values() +local android_R=bindClass("android.R") + +local Context=bindClass "android.content.Context" +local DisplayMetrics=bindClass "android.util.DisplayMetrics" + +local wm =context.getSystemService(Context.WINDOW_SERVICE); +local outMetrics = DisplayMetrics(); +wm.getDefaultDisplay().getMetrics(outMetrics); +local W = outMetrics.widthPixels; +local H = outMetrics.heightPixels; + +local dm=context.getResources().getDisplayMetrics() +local id=0x7f000000 +local toint={ + --android:drawingCacheQuality + auto=0, + low=1, + high=2, + + --android:importantForAccessibility + auto=0, + yes=1, + no=2, + + --android:layerType + none=0, + software=1, + hardware=2, + + --android:layoutDirection + ltr=0, + rtl=1, + inherit=2, + locale=3, + + --android:scrollbarStyle + insideOverlay=0x0, + insideInset=0x01000000, + outsideOverlay=0x02000000, + outsideInset=0x03000000, + + --android:visibility + visible=0, + invisible=1, + gone=2, + + wrap_content=-2, + fill_parent=-1, + match_parent=-1, + wrap=-2, + fill=-1, + match=-1, + + --android:autoLink + none=0x00, + web=0x01, + email=0x02, + phon=0x04, + map=0x08, + all=0x0f, + + --android:orientation + vertical=1, + horizontal= 0, + + --android:gravity + axis_clip = 8, + axis_pull_after = 4, + axis_pull_before = 2, + axis_specified = 1, + axis_x_shift = 0, + axis_y_shift = 4, + bottom = 80, + center = 17, + center_horizontal = 1, + center_vertical = 16, + clip_horizontal = 8, + clip_vertical = 128, + display_clip_horizontal = 16777216, + display_clip_vertical = 268435456, + --fill = 119, + fill_horizontal = 7, + fill_vertical = 112, + horizontal_gravity_mask = 7, + left = 3, + no_gravity = 0, + relative_horizontal_gravity_mask = 8388615, + relative_layout_direction = 8388608, + right = 5, + start = 8388611, + top = 48, + vertical_gravity_mask = 112, + ["end"] = 8388613, + + --android:textAlignment + inherit=0, + gravity=1, + textStart=2, + textEnd=3, + textCenter=4, + viewStart=5, + viewEnd=6, + + --android:inputType + none=0x00000000, + text=0x00000001, + textCapCharacters=0x00001001, + textCapWords=0x00002001, + textCapSentences=0x00004001, + textAutoCorrect=0x00008001, + textAutoComplete=0x00010001, + textMultiLine=0x00020001, + textImeMultiLine=0x00040001, + textNoSuggestions=0x00080001, + textUri=0x00000011, + textEmailAddress=0x00000021, + textEmailSubject=0x00000031, + textShortMessage=0x00000041, + textLongMessage=0x00000051, + textPersonName=0x00000061, + textPostalAddress=0x00000071, + textPassword=0x00000081, + textVisiblePassword=0x00000091, + textWebEditText=0x000000a1, + textFilter=0x000000b1, + textPhonetic=0x000000c1, + textWebEmailAddress=0x000000d1, + textWebPassword=0x000000e1, + number=0x00000002, + numberSigned=0x00001002, + numberDecimal=0x00002002, + numberPassword=0x00000012, + phone=0x00000003, + datetime=0x00000004, + date=0x00000014, + time=0x00000024, + + --android:imeOptions + normal=0x00000000, + actionUnspecified=0x00000000, + actionNone=0x00000001, + actionGo=0x00000002, + actionSearch=0x00000003, + actionSend=0x00000004, + actionNext=0x00000005, + actionDone=0x00000006, + actionPrevious=0x00000007, + flagNoFullscreen=0x2000000, + flagNavigatePrevious=0x4000000, + flagNavigateNext=0x8000000, + flagNoExtractUi=0x10000000, + flagNoAccessoryAction=0x20000000, + flagNoEnterAction=0x40000000, + flagForceAscii=0x80000000, + + +} + +local scaleType={ + --android:scaleType + matrix=0, + fitXY=1, + fitStart=2, + fitCenter=3, + fitEnd=4, + center=5, + centerCrop=6, + centerInside=7, +} + + +local rules={ + layout_above=2, + layout_alignBaseline=4, + layout_alignBottom=8, + layout_alignEnd=19, + layout_alignLeft=5, + layout_alignParentBottom=12, + layout_alignParentEnd=21, + layout_alignParentLeft=9, + layout_alignParentRight=11, + layout_alignParentStart=20, + layout_alignParentTop=10, + layout_alignRight=7, + layout_alignStart=18, + layout_alignTop=6, + layout_alignWithParentIfMissing=0, + layout_below=3, + layout_centerHorizontal=14, + layout_centerInParent=13, + layout_centerVertical=15, + layout_toEndOf=17, + layout_toLeftOf=0, + layout_toRightOf=1, + layout_toStartOf=16 +} + + +local types={ + px=0, + dp=1, + sp=2, + pt=3, + ["in"]=4, + mm=5 +} + +local function checkType(v) + local n,ty=string.match(v,"^(%-?%d+)(%a%a)$") + return tonumber(n),types[ty] +end + +local function checkPercent(v) + local n,ty=string.match(v,"^(%-?[%.%d]+)%%([wh])$") + if ty==nil then + return nil + elseif ty=="w" then + return tonumber(n)*W/100 + elseif ty=="h" then + return tonumber(n)*H/100 + end +end + +local function split(s,t) + local idx=1 + local l=#s + return function() + local i=s:find(t,idx) + if idx>=l then + return nil + end + if i==nil then + i=l+1 + end + local sub=s:sub(idx,i-1) + idx=i+1 + return sub + end +end +local function checkint(s) + local ret=0 + for n in split(s,"|") do + if toint[n] then + ret=ret | toint[n] + else + return nil + end + end + return ret +end + + + +local function checkNumber(var) + if type(var) == "string" then + if var=="true" then + return true + elseif var=="false" then + return false + end + + if toint[var] then + return toint[var] + end + local i=checkint(var) + if i then + return i + end + + local p=checkPercent(var) + if p then + return p + end + + local h=string.match(var,"^#(%x+)$") + if h then + local c=tonumber(h,16) + if c then + if #h<=6 then + return c-0x1000000 + elseif #h<=8 then + if c>0x7fffffff then + return c-0x100000000 + else + return c + end + end + end + end + + local n,ty=checkType(var) + if ty then + return TypedValue.applyDimension(ty,n,dm) + end + end + -- return var +end + +local function checkValue(var) + return tonumber(var) or checkNumber(var) or var +end + +local function checkValues(...) + local vars={...} + for n=1,#vars do + vars[n]=checkValue(vars[n]) + end + return unpack(vars) +end + +local function getattr(s) + return android_R.attr[s] +end + +local function checkattr(s) + local e,s=pcall(getattr,s) + if e then + return s + end + return nil +end + +local function getIdentifier(name) + return context.getResources().getIdentifier(name,null,null) +end + +local function dump2 (t) + local _t={} + table.insert(_t,tostring(t)) + table.insert(_t,"\t{") + for k,v in pairs(t) do + if type(v)=="table" then + table.insert(_t,"\t\t"..tostring(k).."={"..tostring(v[1]).." ...}") + else + table.insert(_t,"\t\t"..tostring(k).."="..tostring(v)) + end + end + table.insert(_t,"\t}") + t=table.concat(_t,"\n") + return t +end + +local ver = luajava.bindClass("android.os.Build").VERSION.SDK_INT; +function setBackground(view,bg) + if ver<16 then + view.setBackgroundDrawable(bg) + else + view.setBackground(bg) + end +end + +local function setattribute(root,view,params,k,v,ids) + if k=="layout_x" then + params.x=checkValue(v) + elseif k=="layout_y" then + params.y=checkValue(v) + elseif k=="layout_weight" then + params.weight=checkValue(v) + elseif k=="layout_gravity" then + params.gravity=checkValue(v) + elseif k=="layout_marginStart" then + params.setMarginStart(checkValue(v)) + elseif k=="layout_marginEnd" then + params.setMarginEnd(checkValue(v)) + elseif rules[k] and (v==true or v=="true") then + params.addRule(rules[k]) + elseif rules[k] then + params.addRule(rules[k],ids[v]) + elseif k=="items" then --创建列表项目 + if type(v)=="table" then + if view.adapter then + view.adapter.addAll(v) + else + local adapter=ArrayListAdapter(context,android_R.layout.simple_list_item_1, String(v)) + view.setAdapter(adapter) + end + end + elseif k=="pages" and type(v)=="table" then --创建页项目 + elseif k=="onClick" then --设置onClick事件接口 + elseif k=="textSize" then + if tonumber(v) then + view.setTextSize(tonumber(v)) + elseif type(v)=="string" then + local n,ty=checkType(v) + if ty then + view.setTextSize(ty,n) + else + view.setTextSize(v) + end + else + view.setTextSize(v) + end + elseif k=="textAppearance" then + view.setTextAppearance(context,checkattr(v)) + elseif k=="ellipsize" then + view.setEllipsize(TruncateAt[string.upper(v)]) + elseif k=="url" then + view.loadUrl(url) + elseif k=="src" then + if v:find("^%?") then + view.setImageResource(getIdentifier(v:sub(2,-1))) + else + if (not v:find("^/")) and luadir then + v=luadir..v + end + view.setImageBitmap(loadbitmap(v)) + end + elseif k=="scaleType" then + view.setScaleType(scaleTypes[scaleType[v]]) + elseif k=="background" then + if type(v)=="string" then + if v:find("^%?") then + view.setBackgroundResource(getIdentifier(v:sub(2,-1))) + elseif v:find("^#") then + view.setBackgroundColor(checkNumber(v)) + elseif rawget(root,v) or rawget(_G,v) then + v=rawget(root,v) or rawget(_G,v) + if type(v)=="function" then + setBackground(view,LuaDrawable(v)) + elseif type(v)=="userdata" then + setBackground(view,v) + end + else + if (not v:find("^/")) and luadir then + v=luadir..v + end + if v:find("%.9%.png") then + setBackground(view,NineBitmapDrawable(loadbitmap(v))) + else + setBackground(view,BitmapDrawable(loadbitmap(v))) + end + end + elseif type(v)=="userdata" then + setBackground(view,v) + elseif type(v)=="number" then + view.setBackgroundColor(v) + end + elseif k=="password" and (v=="true" or v==true) then + view.setInputType(0x81) + elseif type(k)=="string" and not(k:find("layout_")) and not(k:find("padding")) and k~="style" then --设置属性 + k=string.gsub(k,"^(%w)",function(s)return string.upper(s)end) + if k=="Text" or k=="Title" or k=="Subtitle" then + view["set"..k](v) + else + view["set"..k](checkValue(v)) + end + end +end + +local function copytable(f,t,b) + for k,v in pairs(f) do + if k==1 then + elseif b or t[k]==nil then + t[k]=v + end + end +end + + +local function setstyle(c,t,root,view,params,ids) + local mt=getmetatable(t) + if not mt or not mt.__index then + return + end + local m=mt.__index + if c[m] then + return + end + c[m]=true + for k,v in pairs(m) do + if not rawget(c,k) then + pcall(setattribute,root,view,params,k,v,ids) + end + c[k]=true + end + setstyle(c,m,root,view,params,ids) +end + + +local function loadlayout(t,root,group) + if type(t)=="string" then + t=require(t) + elseif type(t)~="table" then + error(string.format("loadlayout error: Fist value Must be a table, checked import layout.",0)) + end + root=root or _G + local view,style + if t.style then + if t.style:find("^%?") then + style=getIdentifier(t.style:sub(2,-1)) + else + local st,sty=pcall(require,t.style) + if st then + --copytable(sty,t) + setmetatable(t,{__index=sty}) + else + style=checkattr(t.style) + end + end + end + if not t[1] then + error(string.format("loadlayout error: Fist value Must be a Class, checked import package.\n\tat %s",dump2(t)),0) + end + + if style then + view = t[1](context,nil,style) + else + view = t[1](context) --创建view + end + + + local params=ViewGroup.LayoutParams(checkValue(t.layout_width) or -2,checkValue(t.layout_height) or -2) --设置layout属性 + if group then + params=group.LayoutParams(params) + end + + --设置layout_margin属性 + if t.layout_margin or t.layout_marginStart or t.layout_marginEnd or t.layout_marginLeft or t.layout_marginTop or t.layout_marginRight or t.layout_marginBottom then + params.setMargins(checkValues( t.layout_marginLeft or t.layout_margin or 0,t.layout_marginTop or t.layout_margin or 0,t.layout_marginRight or t.layout_margin or 0,t.layout_marginBottom or t.layout_margin or 0)) + end + + --设置padding属性 + if t.padding or t.paddingLeft or t.paddingTop or t.paddingRight or t.paddingBottom then + view.setPadding(checkValues(t.paddingLeft or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingRight or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + if t.paddingStart or t.paddingEnd then + view.setPaddingRelative(checkValues(t.paddingStart or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingEnd or t.padding or 0, t.paddingBottom or t.padding or 0)) + end + + + local c={} + setmetatable(c,{__index=t}) + setstyle(c,t,root,view,params,ids) + + for k,v in pairs(t) do + if tonumber(k) and (type(v)=="table" or type(v)=="string") then --创建子view + if luajava.instanceof(view,AdapterView) then + if type(v)=="string" then + v=require(v) + end + view.adapter=LuaAdapter(context,v) + else + view.addView(loadlayout(v,root,t[1])) + end + elseif k=="id" then --创建view的全局变量 + rawset(root,v,view) + id=id+1 + view.setId(id) + ids[v]=id + + else + local e,s=pcall(setattribute,root,view,params,k,v,ids) + if not e then + local _,i=s:find(":%d+:") + s=s:sub(i or 1,-1) + error(string.format("loadlayout error %s \n\tat %s\n\tat key=%s value=%s\n\tat %s",s,view.toString(),k,v,dump2(t)),0) + end + end + end + + --if group then + --group.addView(view,params) + --else + view.setLayoutParams(params) + return view + --end +end + + +return loadlayout + diff --git a/app/src/main/assets/main.lua b/app/src/main/assets/main.lua new file mode 100644 index 0000000..3aeb6d3 --- /dev/null +++ b/app/src/main/assets/main.lua @@ -0,0 +1,2084 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +--import "AndLua" +import "other" +import "java.io.File" +import "com.androlua.LuaUtil" +compile "libs/android-support-v4" +import "android.support.v4.widget.*" +import "bmob" +import "android.graphics.drawable.ColorDrawable" +import "android.graphics.drawable.StateListDrawable" +import "android.graphics.PorterDuffColorFilter" +import "android.graphics.PorterDuff" +import "Dialog" +import "java.io.File" +import "android.graphics.Color" +import "android.graphics.drawable.GradientDrawable" +import "android.graphics.drawable.RippleDrawable" +import "android.content.res.ColorStateList" +import "android.graphics.drawable.ShapeDrawable" +import "android.graphics.drawable.shapes.RectShape" +import "android.graphics.Path" +import "android.graphics.Canvas" +import "com.baoyz.widget.PullRefreshLayout" +--activity.setTheme(R.AndLua5) +activity.setTitle("ThomeLua") +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xCFFFFFFF + 颜色5=0xff303030 + 颜色7=0xEBFFFFFF + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色5=0x5FFFFFFF + 颜色7=0xff303030 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end + + +import "android.graphics.Typeface" +import "java.io.File" + +import "project" + + + + + + + +import "Community" +import "com.applua.RippleView" + +--import "My" + + + + + + +import "layout" + + + +activity.setContentView(loadlayout(layout)) +--隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end + +import "android.graphics.Typeface" +local Text_Type=Typeface.defaultFromStyle(Typeface.BOLD) +local sd = StateListDrawable() +import "android.graphics.Color" +import "android.content.res.ColorStateList" +import "android.graphics.drawable.RippleDrawable" +import "android.content.Context" +appt={C_Bacgg=function(mBinding,radiu,InsideColor,S,S2,T1) + local drawable = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{}); + drawable.setCornerRadius(radiu); + drawable.setColor(颜色5) + drawable.setStroke(3, 0xCFB0B0B0) + drawable.setGradientType(GradientDrawable.RECTANGLE); + mBinding.setTextColor(T1) + mBinding.setTypeface(Text_Type) + return drawable + end} +美化按钮1=function(mBinding,radiu,InsideColor,T1) + stateList = { + {android.R.attr.state_pressed}, + {android.R.attr.state_focused}, + {android.R.attr.state_activated}, + {android.R.attr.selectableItemBackground}, + }; + sd.addState({ android.R.attr.state_enabled}, appt.C_Bacgg(mBinding,radiu,InsideColor,S,S2,T1)) + pressedColor =InsideColor --Color.parseColor("#7ab946ff"); + stateColorList ={ + pressedColor, + pressedColor, + pressedColor, + normalColor + }; + colorStateList = ColorStateList(stateList, stateColorList); + rippleDrawable = RippleDrawable(colorStateList,sd,nil); + mBinding.setBackground(rippleDrawable); +end + +波纹(其他,0xFFD9D9D9) +local wl=activity.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE).getActiveNetworkInfo(); + +import "projectitem" + +local plugindir=("/sdcard/ThomeLua/project/") + +local function getinfo(dir) + local app={} + loadfile(plugindir.."/"..dir.."/init.lua","bt",app)() + return app +end + + + +local function sort(a,b) + return string.lower(a.appname) < string.lower(b.appname) +end + +local pds=File(plugindir).list() +local pls={} +for n=0,#pds-1 do + local s,i=pcall(getinfo,pds[n]) + switch s + case true + i.path="/"..pds[n] + table.insert(pls,i) + end +end +table.sort(pls,sort) + +local function checkicon(i) + --i=plugindir.."/"..pps[i].."/icon.png" + local f=io.open(i) + if f then + f:close() + return i + else + return R.drawable.icon + end +end + + +function 刷新项目() + local adp=LuaAdapter(activity,projectitem) + adp.clear() + local pds=File(plugindir).list() + local pls={} + for n=0,#pds-1 do + local s,i=pcall(getinfo,pds[n]) + switch s + case true + i.path="/"..pds[n] + table.insert(pls,i) + end + end + table.sort(pls,sort) + for k,v in ipairs(pls) do + local i=plugindir..v.path.."/icon.png" + switch v.appname + case nil + appname="nil" + default + appname=v.appname + end + switch v.packagename + case nil + packagename="nil" + default + packagename=v.packagename + end + switch v.appcode + case nil + appcode="nil" + default + appcode=v.appcode + end + switch v.path + case nil + pat="nil" + default + pat=v.path + end + adp.add{图标=checkicon(i),软件名=appname,包名="包名:"..packagename,版本="版本:"..appcode,文件夹名称=pat} + end + 项目列表.Adapter=adp +end +项目列表.onItemClick=function(l,v,p,i) + --activity.overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); + activity.newActivity("main2",android.R.anim.fade_in,android.R.anim.fade_out,{项目文件夹..v.tag.文件夹名称.text,true,v.tag.文件夹名称.text,"/storage/emulated/0/ThomeLua+/project/"..v.tag.软件名.text}) + return true +end +--[[function 刷新项目(pls) + local adp=LuaAdapter(activity,projectitem) + for k,v in ipairs(pls) do + local i=plugindir..v.path.."/icon.png" + adp.add{图标=checkicon(i),软件名=appname,包名="包名:"..packagename,版本="版本:"..appcode} + end + 项目列表.Adapter=adp +end]] +项目列表.onItemLongClick=function(l,v,p,i) + 标题=v.tag.文件夹名称.text + local ca={ + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="match_parent"; + layout_width="match_parent"; + backgroundColor=颜色1, + radius=20; + { + TextView; + text="项目操作"; + layout_marginTop="10dp"; + textSize="20sp"; + layout_marginLeft="25dp"; + textColor="0xFF03A9F4"; + }; + + { + ListView; + id="项目操作"; + items={ + ""; + " 删除"; + " 打包"; + " 属性"; + " 分享"; + -- " 详情"; + }; + layout_height="fill"; + backgroundColor="0xffffff"; + DividerHeight=0; + layout_width="fill"; + }; + }; + }; + + + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(ca)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + 项目操作.onItemClick=function(l,v,p,i) + if p==1 then + a=LuaUtil.rmDir(File(项目文件夹.."/"..标题)) + if a==true then + print"删除成功" + 刷新项目() + else + print"删除失败" + 刷新项目() + end + dialog1.dismiss() + elseif p==2 then + import "java.util.zip.ZipOutputStream" + import "android.net.Uri" + import "java.io.File" + import "android.widget.Toast" + import "java.util.zip.CheckedInputStream" + import "java.io.FileInputStream" + import "android.content.Intent" + import "com.androlua.LuaUtil" + import "java.security.Signer" + import "java.util.ArrayList" + import "java.io.FileOutputStream" + import "java.io.BufferedOutputStream" + import "java.util.zip.ZipInputStream" + import "java.io.BufferedInputStream" + import "java.util.zip.ZipEntry" + import "android.app.ProgressDialog" + import "java.util.zip.CheckedOutputStream" + import "java.util.zip.Adler32" + import "android.graphics.drawable.ColorDrawable" + local bin_dlg, error_dlg + local function update(s) + bin_dlg.setMessage(s) + end + + local function callback(s) + LuaUtil.rmDir(File(activity.getLuaExtDir("bin/.temp"))) + bin_dlg.dismiss() + bin_dlg.Message = "" + if not s:find("成功") then + error_dlg.Message = s + error_dlg.show() + end + end + + local function create_bin_dlg() + if bin_dlg then + return + end + bin_dlg = ProgressDialog(activity); + bin_dlg.setTitle("正在打包"); + bin_dlg.setMax(100); + end + + local function create_error_dlg2() + if error_dlg then + return + end + error_dlg = AlertDialogBuilder(activity) + error_dlg.Title = "出错" + error_dlg.setPositiveButton("确定", nil) + end + local function binapk(luapath, apkpath) + require "import" + -- module(...,package.seeall) + --by nirenr + + local function ps(str) + str = str:gsub("%b\"\"",""):gsub("%b\'\'","") + local _,f= str:gsub ('%f[%w]function%f[%W]',"") + local _,t= str:gsub ('%f[%w]then%f[%W]',"") + local _,i= str:gsub ('%f[%w]elseif%f[%W]',"") + local _,d= str:gsub ('%f[%w]do%f[%W]',"") + local _,e= str:gsub ('%f[%w]end%f[%W]',"") + local _,r= str:gsub ('%f[%w]repeat%f[%W]',"") + local _,u= str:gsub ('%f[%w]until%f[%W]',"") + local _,a= str:gsub ("{","") + local _,b= str:gsub ("}","") + return (f+t+d+r+a)*4-(i+e+u+b)*4 + end + + + local function _format() + local p=0 + return function(str) + str=str:gsub("[ \t]+$","") + str=string.format('%s%s',string.rep(' ',p),str) + p=p+ps(str) + return str + end + end + + + function format(Text) + local t=os.clock() + local Format=_format() + Text=Text:gsub('[ \t]*([^\r\n]+)',function(str)return Format(str)end) + print('操作完成,耗时:'..os.clock()-t) + return Text + end + + + function build(path) + if path then + local str,st=loadfile(path) + if st then + return nil,st + end + local path=path..'c' + + local st,str=pcall(string.dumpThomeLua,str,true) + if st then + f=io.open(path,'wb') + f:write(str) + f:close() + return path + else + os.remove(path) + return nil,str + end + end + end + + function build_aly(path2) + if path2 then + local f,st=io.open(path2) + if st then + return nil,st + end + local str=f:read("*a") + f:close() + str=string.format("local layout=%s\nreturn layout",str) + local path=path2..'c' + str,st=loadstring(str,path2:match("[^/]+/[^/]+$"),"bt") + if st then + return nil,st:gsub("%b[]",path2,1) + end + + local st,str=pcall(string.dumpThomeLua,str,true) + if st then + f=io.open(path,'wb') + f:write(str) + f:close() + return path + else + os.remove(path) + return nil,str + end + end + end + + + compile "mao" + compile "sign" + import "java.util.zip.*" + import "java.io.*" + import "mao.res.*" + import "apksigner.*" + local b = byte[2 ^ 16] + local function copy(input, output) + LuaUtil.copyFile(input, output) + input.close() + --[[local l=input.read(b) + while l>1 do + output.write(b,0,l) + l=input.read(b) + end]] + end + local function copy2(input, output) + LuaUtil.copyFile(input, output) + end + local temp = File(apkpath).getParentFile(); + if (not temp.exists()) then + + if (not temp.mkdirs()) then + + error("create file " .. temp.getName() .. " fail"); + end + end + + local tmp = luajava.luadir.. "/tmp.apk" + local info = activity.getApplicationInfo() + local ver = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionName + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + + --local zip=ZipFile(info.publicSourceDir) + local zipFile = File(info.publicSourceDir) + local fis = FileInputStream(zipFile); + --local checksum = CheckedInputStream(fis, Adler32()); + local zis = ZipInputStream(BufferedInputStream(fis)); + + local fot = FileOutputStream(tmp) + --local checksum2 = CheckedOutputStream(fot, Adler32()); + local out = ZipOutputStream(BufferedOutputStream(fot)) + local f = File(luapath) + local errbuffer = {} + local replace = {} + local checked = {} + local lualib = {} + local md5s = {} + local libs = File(activity.ApplicationInfo.nativeLibraryDir).list() + libs = luajava.astable(libs) + for k, v in ipairs(libs) do + --libs[k]="lib/armeabi/"..libs[k] + replace[v] = true + end + + local mdp = activity.Application.MdDir + local function getmodule(dir) + local mds = File(activity.Application.MdDir .. dir).listFiles() + mds = luajava.astable(mds) + for k, v in ipairs(mds) do + if mds[k].isDirectory() then + getmodule(dir .. mds[k].Name .. "/") + else + mds[k] = "lua" .. dir .. mds[k].Name + replace[mds[k]] = true + end + end + end + + getmodule("/") + + local function checklib(path) + if checked[path] then + return + end + local cp, lp + checked[path] = true + local f = io.open(path) + local s = f:read("*a") + f:close() + for m, n in s:gmatch("require *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + for m, n in s:gmatch("import *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + end + + replace["libluajava.so"] = false + function isintable(value,tb) + for k,v in pairs(tb) do + switch v + case value + return true + end + end + return false + end + + function strippath(filename) + return string.match(filename, ".+/([^/]*%.%w+)$") + end + function stripextension(filename) + local idx = filename:match(".+()%.%w+$") + if(idx) then + return filename:sub(1, idx-1) + else + return filename + end + end + function getExtension(str) + return str:match(".+%.(%w+)$") + end + local function addDir(out, dir, f) + local entry = ZipEntry("assets/" .. dir) + out.putNextEntry(entry) + local ls = f.listFiles() + for n = 0, #ls - 1 do + local name = ls[n].getName() + if name==(".using") then + checklib(luapath .. dir .. name) + elseif name:find("%.apk$") or name:find("%.luac$") or name:find("^%.") then + elseif name:find("%.lua$") then + checklib(luapath .. dir .. name) + switch skip_compilation + case nil + path=build(luapath..dir..name) + default + switch isintable(dir..name,skip_compilation) + case true + local readlua=io.open(luapath..dir..name):read("*a") + io.open(luapath..dir..name.."c","w"):write(readlua):close() + path=luapath..dir..name.."c" + default + path=build(luapath..dir..name) + end + end + if path then + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif name:find("%.aly$") then + switch skip_compilation + case nil + path=build_aly(luapath..dir..name) + default + switch isintable(dir..name,skip_compilation) + case true + local readlua=io.open(luapath..dir..name):read("*a") + io.open(luapath..dir..name.."c","w"):write(stripextension(strippath(luapath..dir..name)).."="..readlua):close() + path=luapath..dir..name.."c" + default + path=build_aly(luapath..dir..name) + end + end + if path then + name = name:gsub("aly$", "lua") + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif ls[n].isDirectory() then + addDir(out, dir .. name .. "/", ls[n]) + else + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + replace["assets/" .. dir .. name] = true + copy(FileInputStream(ls[n]), out) + table.insert(md5s, LuaUtil.getFileMD5(ls[n])) + end + end + end + + + this.update("正在编译..."); + if f.isDirectory() then + require "permission" + dofile(luapath .. "init.lua") + if user_permission then + for k, v in ipairs(user_permission) do + user_permission[v] = true + end + end + + + local ss, ee = pcall(addDir, out, "", f) + if not ss then + table.insert(errbuffer, ee) + end + --print(ee,dump(errbuffer),dump(replace)) + + + local wel = File(luapath .. "icon.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/icon.png") + out.putNextEntry(entry) + replace["res/drawable/icon.png"] = true + copy(FileInputStream(wel), out) + end + local wel = File(luapath .. "welcome.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/welcome.png") + out.putNextEntry(entry) + replace["res/drawable/welcome.png"] = true + + copy(FileInputStream(wel), out) + end + else + return "error" + end + + --print(dump(lualib)) + for name, v in pairs(lualib) do + local path, err = build(v) + if path then + local entry = ZipEntry(name) + out.putNextEntry(entry) + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + end + + apkpath="/storage/emulated/0/ThomeLua/bin/"..appname.."_"..appver..".apk" + function touint32(i) + local code = string.format("%08x", i) + local uint = {} + for n in code:gmatch("..") do + table.insert(uint, 1, string.char(tonumber(n, 16))) + end + return table.concat(uint) + end + + this.update("正在打包..."); + local entry = zis.getNextEntry(); + while entry do + local name = entry.getName() + local lib = name:match("([^/]+%.so)$") + if replace[name] then + elseif lib and replace[lib] then + elseif name:find("^assets/") then + elseif name:find("^lua/") then + elseif name:find("META%-INF") then + else + local entry = ZipEntry(name) + out.putNextEntry(entry) + if entry.getName() == "AndroidManifest.xml" then + if path_pattern and #path_pattern > 1 then + path_pattern = ".*\\\\." .. path_pattern:match("%w+$") + end + local list = ArrayList() + local xml = AXmlDecoder.read(list, zis) + local req = { + [activity.getPackageName()] = packagename, + [info.nonLocalizedLabel] = appname, + [ver] = appver, + [".*\\\\.alp"] = path_pattern or "", + [".*\\\\.lua"] = "", + [".*\\\\.luac"] = "", + } + for n = 0, list.size() - 1 do + local v = list.get(n) + if req[v] then + list.set(n, req[v]) + elseif user_permission then + local p = v:match("%.permission%.([%w_]+)$") + if p and (not user_permission[p]) then + list.set(n, "android.permission.UNKNOWN") + end + end + end + local pt = activity.getLuaPath(".tmp") + local fo = FileOutputStream(pt) + xml.write(list, fo) + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + fo.close() + local f = io.open(pt) + local s = f:read("a") + f:close() + s = string.gsub(s, touint32(code), touint32(tointeger(appcode) or 1),1) + s = string.gsub(s, touint32(18), touint32(tointeger(appsdk) or 18),1) + + local f = io.open(pt, "w") + f:write(s) + f:close() + local fi = FileInputStream(pt) + copy(fi, out) + os.remove(pt) + elseif not entry.isDirectory() then + copy2(zis, out) + end + end + entry = zis.getNextEntry() + end + out.setComment(table.concat(md5s)) + --print(table.concat(md5s,"/n")) + zis.close(); + out.closeEntry() + out.close() + + if #errbuffer == 0 then + this.update("正在签名..."); + os.remove(apkpath) + Signer.sign(tmp, apkpath) + os.remove(tmp) + activity.installApk(apkpath) + --[[import "android.net.*" + import "android.content.*" + i = Intent(Intent.ACTION_VIEW); + i.setDataAndType(activity.getUriForFile(File(apkpath)), "application/vnd.android.package-archive"); + i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + this.update("正在打开..."); + activity.startActivityForResult(i, 0);]] + return "打包成功:" .. apkpath + else + os.remove(tmp) + this.update("打包出错:\n " .. table.concat(errbuffer, "\n")); + return "打包出错:\n " .. table.concat(errbuffer, "\n") + end + end + luabindir=activity.getLuaExtDir("bin") + local function bin(path) + local p = {} + local e, s = pcall(function()dofile(path .. "init.lua")end) + if e then + create_error_dlg2() + create_bin_dlg() + bin_dlg.show() + activity.newTask(binapk, update, callback).execute { path, activity.getLuaExtPath("bin", appname .. "_" .. appver .. ".apk") } + else + Toast.makeText(activity, "工程配置文件错误." .. s, Toast.LENGTH_SHORT).show() + end + end + bin(项目文件夹.."/"..标题.."/") + dialog1.dismiss() + elseif p==4 then + function Sharing(path) + import "android.webkit.MimeTypeMap" + import "android.content.Intent" + import "android.net.Uri" + import "java.io.File" + import "android.content.FileProvider" + intent = Intent() + intent.setAction(Intent.ACTION_SEND) + intent.setType("*/*") + uri=FileProvider.getUriForFile(activity,activity.getPackageName(),File(path)); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.putExtra(Intent.EXTRA_STREAM,uri) + activity.startActivity(Intent.createChooser(intent, "分享到:")) + end + LuaUtil.zip(项目文件夹.."/"..标题,"/sdcard/ThomeLua/backup/") + os.execute("mv ".."/sdcard/ThomeLua/backup/"..标题..".zip".." ".."/sdcard/ThomeLua/backup/"..标题..".alp") + Sharing("/sdcard/ThomeLua/backup/"..标题..".alp") + --os.remove("/sdcard/ThomeLua/"..标题..".alp") + elseif p==1 then + import "java.util.zip.ZipOutputStream" + import "android.net.Uri" + import "java.io.File" + import "android.widget.Toast" + import "java.util.zip.CheckedInputStream" + import "java.io.FileInputStream" + import "android.content.Intent" + import "com.androlua.LuaUtil" + import "java.security.Signer" + import "java.util.ArrayList" + import "java.io.FileOutputStream" + import "java.io.BufferedOutputStream" + import "java.util.zip.ZipInputStream" + import "java.io.BufferedInputStream" + import "java.util.zip.ZipEntry" + import "android.app.ProgressDialog" + import "java.util.zip.CheckedOutputStream" + import "java.util.zip.Adler32" + import "android.graphics.drawable.ColorDrawable" + local bin_dlg, error_dlg + local function update(s) + bin_dlg.setMessage(s) + end + + local function callback(s) + LuaUtil.rmDir(File(activity.getLuaExtDir("bin/.temp"))) + bin_dlg.dismiss() + bin_dlg.Message = "" + if not s:find("成功") then + error_dlg.Message = s + error_dlg.show() + end + end + + local function create_bin_dlg() + if bin_dlg then + return + end + bin_dlg = ProgressDialog(activity); + bin_dlg.setTitle("正在打包"); + bin_dlg.setMax(100); + end + + local function create_error_dlg2() + if error_dlg then + return + end + error_dlg = AlertDialogBuilder(activity) + error_dlg.Title = "出错" + error_dlg.setPositiveButton("确定", nil) + end + local function binapk(luapath, apkpath) + require "import" + -- module(...,package.seeall) + --by nirenr + + local function ps(str) + str = str:gsub("%b\"\"",""):gsub("%b\'\'","") + local _,f= str:gsub ('%f[%w]function%f[%W]',"") + local _,t= str:gsub ('%f[%w]then%f[%W]',"") + local _,i= str:gsub ('%f[%w]elseif%f[%W]',"") + local _,d= str:gsub ('%f[%w]do%f[%W]',"") + local _,e= str:gsub ('%f[%w]end%f[%W]',"") + local _,r= str:gsub ('%f[%w]repeat%f[%W]',"") + local _,u= str:gsub ('%f[%w]until%f[%W]',"") + local _,a= str:gsub ("{","") + local _,b= str:gsub ("}","") + return (f+t+d+r+a)*4-(i+e+u+b)*4 + end + + + local function _format() + local p=0 + return function(str) + str=str:gsub("[ \t]+$","") + str=string.format('%s%s',string.rep(' ',p),str) + p=p+ps(str) + return str + end + end + + + function format(Text) + local t=os.clock() + local Format=_format() + Text=Text:gsub('[ \t]*([^\r\n]+)',function(str)return Format(str)end) + print('操作完成,耗时:'..os.clock()-t) + return Text + end + + + function build(path) + if path then + local str,st=loadfile(path) + if st then + return nil,st + end + local path=path..'c' + + local st,str=pcall(string.dumpThomeLua,str,true) + if st then + f=io.open(path,'wb') + f:write(str) + f:close() + return path + else + os.remove(path) + return nil,str + end + end + end + + function build_aly(path2) + if path2 then + local f,st=io.open(path2) + if st then + return nil,st + end + local str=f:read("*a") + f:close() + str=string.format("local layout=%s\nreturn layout",str) + local path=path2..'c' + str,st=loadstring(str,path2:match("[^/]+/[^/]+$"),"bt") + if st then + return nil,st:gsub("%b[]",path2,1) + end + + local st,str=pcall(string.dumpThomeLua,str,true) + if st then + f=io.open(path,'wb') + f:write(str) + f:close() + return path + else + os.remove(path) + return nil,str + end + end + end + + + compile "mao" + compile "sign" + import "java.util.zip.*" + import "java.io.*" + import "mao.res.*" + import "apksigner.*" + local b = byte[2 ^ 16] + local function copy(input, output) + LuaUtil.copyFile(input, output) + input.close() + --[[local l=input.read(b) + while l>1 do + output.write(b,0,l) + l=input.read(b) + end]] + end + local function copy2(input, output) + LuaUtil.copyFile(input, output) + end + local temp = File(apkpath).getParentFile(); + if (not temp.exists()) then + + if (not temp.mkdirs()) then + + error("create file " .. temp.getName() .. " fail"); + end + end + + local tmp = luajava.luadir.. "/tmp.apk" + local info = activity.getApplicationInfo() + local ver = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionName + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + + --local zip=ZipFile(info.publicSourceDir) + local zipFile = File(info.publicSourceDir) + local fis = FileInputStream(zipFile); + --local checksum = CheckedInputStream(fis, Adler32()); + local zis = ZipInputStream(BufferedInputStream(fis)); + + local fot = FileOutputStream(tmp) + --local checksum2 = CheckedOutputStream(fot, Adler32()); + local out = ZipOutputStream(BufferedOutputStream(fot)) + local f = File(luapath) + local errbuffer = {} + local replace = {} + local checked = {} + local lualib = {} + local md5s = {} + local libs = File(activity.ApplicationInfo.nativeLibraryDir).list() + libs = luajava.astable(libs) + for k, v in ipairs(libs) do + --libs[k]="lib/armeabi/"..libs[k] + replace[v] = true + end + + local mdp = activity.Application.MdDir + local function getmodule(dir) + local mds = File(activity.Application.MdDir .. dir).listFiles() + mds = luajava.astable(mds) + for k, v in ipairs(mds) do + if mds[k].isDirectory() then + getmodule(dir .. mds[k].Name .. "/") + else + mds[k] = "lua" .. dir .. mds[k].Name + replace[mds[k]] = true + end + end + end + + getmodule("/") + + local function checklib(path) + if checked[path] then + return + end + local cp, lp + checked[path] = true + local f = io.open(path) + local s = f:read("*a") + f:close() + for m, n in s:gmatch("require *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + for m, n in s:gmatch("import *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + end + + replace["libluajava.so"] = false + + local function addDir(out, dir, f) + local entry = ZipEntry("assets/" .. dir) + out.putNextEntry(entry) + local ls = f.listFiles() + for n = 0, #ls - 1 do + local name = ls[n].getName() + if name==(".using") then + checklib(luapath .. dir .. name) + elseif name:find("%.apk$") or name:find("%.luac$") or name:find("^%.") then + elseif name:find("%.lua$") then + checklib(luapath .. dir .. name) + local path, err = build(luapath .. dir .. name) + if path then + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif name:find("%.aly$") then + local path, err = build_aly(luapath .. dir .. name) + if path then + name = name:gsub("aly$", "lua") + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif ls[n].isDirectory() then + addDir(out, dir .. name .. "/", ls[n]) + else + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + replace["assets/" .. dir .. name] = true + copy(FileInputStream(ls[n]), out) + table.insert(md5s, LuaUtil.getFileMD5(ls[n])) + end + end + end + + + this.update("正在编译..."); + if f.isDirectory() then + require "permission" + dofile(luapath .. "init.lua") + if user_permission then + for k, v in ipairs(user_permission) do + user_permission[v] = true + end + end + + + local ss, ee = pcall(addDir, out, "", f) + if not ss then + table.insert(errbuffer, ee) + end + --print(ee,dump(errbuffer),dump(replace)) + + + local wel = File(luapath .. "icon.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/icon.png") + out.putNextEntry(entry) + replace["res/drawable/icon.png"] = true + copy(FileInputStream(wel), out) + end + local wel = File(luapath .. "welcome.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/welcome.png") + out.putNextEntry(entry) + replace["res/drawable/welcome.png"] = true + + copy(FileInputStream(wel), out) + end + else + return "error" + end + + --print(dump(lualib)) + for name, v in pairs(lualib) do + local path, err = build(v) + if path then + local entry = ZipEntry(name) + out.putNextEntry(entry) + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + end + + apkpath="/storage/emulated/0/ThomeLua/bin/"..appname.."_"..appver..".apk" + function touint32(i) + local code = string.format("%08x", i) + local uint = {} + for n in code:gmatch("..") do + table.insert(uint, 1, string.char(tonumber(n, 16))) + end + return table.concat(uint) + end + + this.update("正在打包..."); + local entry = zis.getNextEntry(); + while entry do + local name = entry.getName() + local lib = name:match("([^/]+%.so)$") + if replace[name] then + elseif lib and replace[lib] then + elseif name:find("^assets/") then + elseif name:find("^lua/") then + elseif name:find("META%-INF") then + else + local entry = ZipEntry(name) + out.putNextEntry(entry) + if entry.getName() == "AndroidManifest.xml" then + if path_pattern and #path_pattern > 1 then + path_pattern = ".*\\\\." .. path_pattern:match("%w+$") + end + local list = ArrayList() + local xml = AXmlDecoder.read(list, zis) + local req = { + [activity.getPackageName()] = packagename, + [info.nonLocalizedLabel] = appname, + [ver] = appver, + [".*\\\\.alp"] = path_pattern or "", + [".*\\\\.lua"] = "", + [".*\\\\.luac"] = "", + } + for n = 0, list.size() - 1 do + local v = list.get(n) + if req[v] then + list.set(n, req[v]) + elseif user_permission then + local p = v:match("%.permission%.([%w_]+)$") + if p and (not user_permission[p]) then + list.set(n, "android.permission.UNKNOWN") + end + end + end + local pt = activity.getLuaPath(".tmp") + local fo = FileOutputStream(pt) + xml.write(list, fo) + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + fo.close() + local f = io.open(pt) + local s = f:read("a") + f:close() + s = string.gsub(s, touint32(code), touint32(tointeger(appcode) or 1),1) + s = string.gsub(s, touint32(18), touint32(tointeger(appsdk) or 18),1) + + local f = io.open(pt, "w") + f:write(s) + f:close() + local fi = FileInputStream(pt) + copy(fi, out) + os.remove(pt) + elseif not entry.isDirectory() then + copy2(zis, out) + end + end + entry = zis.getNextEntry() + end + out.setComment(table.concat(md5s)) + --print(table.concat(md5s,"/n")) + zis.close(); + out.closeEntry() + out.close() + + if #errbuffer == 0 then + this.update("正在签名..."); + os.remove(apkpath) + Signer.sign(tmp, apkpath) + os.remove(tmp) + activity.installApk(apkpath) + --[[import "android.net.*" + import "android.content.*" + i = Intent(Intent.ACTION_VIEW); + i.setDataAndType(activity.getUriForFile(File(apkpath)), "application/vnd.android.package-archive"); + i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + this.update("正在打开..."); + activity.startActivityForResult(i, 0);]] + return "打包成功:" .. apkpath + else + os.remove(tmp) + this.update("打包出错:\n " .. table.concat(errbuffer, "\n")); + return "打包出错:\n " .. table.concat(errbuffer, "\n") + end + end + luabindir=activity.getLuaExtDir("bin") + local function bin(path) + local p = {} + local e, s = pcall(function()dofile(path .. "init.lua")end) + if e then + create_error_dlg2() + create_bin_dlg() + bin_dlg.show() + activity.newTask(binapk, update, callback).execute { path, activity.getLuaExtPath("bin", appname .. "_" .. appver .. ".apk") } + else + Toast.makeText(activity, "工程配置文件错误." .. s, Toast.LENGTH_SHORT).show() + end + end + bin("/storage/emulated/0/ThomeLua/project/"..标题.."/") + dialog1.dismiss() + elseif p==3 then + dialog1.dismiss() + b=io.open(项目文件夹.."/"..标题.."/init.lua"):read("*a") + if b:find("appcode") then + 版本=b:match('appcode="(.-)"') + else + 版本="nil" + end + if b:find("packagename") then + 包名=b:match('packagename="(.-)"') + else + 包名="nil" + end + if b:find("appver") then + 版本号=b:match('appver="(.-)"') + else + 版本号="nil" + end + if b:find("appsdk") then + SDK=b:match('appsdk="(.-)"') + else + SDK="nil" + end + local xq={ + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="match_parent"; + layout_width="match_parent"; + backgroundColor=颜色1, + radius=20; + { + TextView; + text="文件详情"; + layout_marginTop="10dp"; + textSize="20sp"; + layout_marginLeft="25dp"; + textColor="0xFF03A9F4"; + }; + { + ListView; + id="文件详情"; + items={ + ""; + "名称:"..标题; + "包名:"..包名; + "版本:"..版本; + "版本号:"..版本号; + "SDK:"..SDK; + }; + layout_height="fill"; + backgroundColor="0xffffff"; + DividerHeight=0; + layout_width="fill"; + }; + }; + }; + + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(xq)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + 文件详情.onItemClick=function(l,v,p,i) + if p==1 then + 写入剪切板(标题) + print"已复制到剪切板" + elseif p==2 then + 写入剪切板(包名) + print"已复制到剪切板" + elseif p==3 then + 写入剪切板(版本) + print"已复制到剪切板" + elseif p==4 then + 写入剪切板(版本号) + print"已复制到剪切板" + elseif p==5 then + 写入剪切板(SDK) + print"已复制到剪切板" + end + + return true + end + end + return true + end + return true + + +end + +local function shortcut(path) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(); + intent.setClass(activity, activity.getClass()); + intent.setData(Uri.parse("file://"..path)) + addShortcut = Intent("com.android.launcher.action.INSTALL_SHORTCUT"); + icon = Intent.ShortcutIconResource.fromContext(activity, + R.drawable.icon); + addShortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, "工程列表"); + addShortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); + addShortcut.putExtra("duplicate", 0); + addShortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon); + activity.sendBroadcast(addShortcut); +end +--shortcut(activity.getLuaPath()) +local ppls={} +for n=0,#pds-1 do + local s,i=pcall(getinfo,pds[n]) + switch s + case true + i.path="/"..pds[n] + table.insert(ppls,i) + end +end +table.sort(ppls,sort) +function update(ppls) + local adp=LuaAdapter(activity,projectitem) + for k,v in ipairs(ppls) do + local i=plugindir..v.path.."/icon.png" + switch v.appname + case nil + appname="nil" + default + appname=v.appname + end + switch v.packagename + case nil + packagename="nil" + default + packagename=v.packagename + end + switch v.appcode + case nil + appcode="nil" + default + appcode=v.appcode + end + switch v.path + case nil + pat="nil" + default + pat=v.path + end + adp.add{图标=checkicon(i),软件名=appname,包名="包名:"..packagename,版本="版本:"..appcode,文件夹名称=pat} + end + 项目列表.Adapter=adp +end + + +--[[function onCreateOptionsMenu(menu) + local item=menu.add("搜索") + item.setShowAsAction(1) + item.setActionView(edit) +end + +edit=EditText() +edit.Hint="输入关键字" +edit.Width=activity.Width/2 +edit.SingleLine=true]] + +actionbar.setVisibility(0) +--标题栏.setVisibility(8) +actp = actionbar.getLayoutParams() + +alphain=AlphaAnimation(0,1) +alphain.setDuration(100) +alphaout=AlphaAnimation(1,0) +alphaout.setDuration(100) +local function dp2px(dpValue) + local scale = activity.getResources().getDisplayMetrics().scaledDensity + return dpValue * scale + 0.5 +end + +actheight=dp2px(90) +local function scaleup(dur) + + finding=true + + if actp.heightactheight + stop=true + + --scale.stop() + else + actp.height =actp.height+(actheight-dp2px(56))/dur + actionbar.setLayoutParams(actp) + + end + + + --end + --启动Ticker定时器 + --scale.start() +end + +findbar.onClick=function() + scaleup(100) + task(50,function() + edit.setVisibility(0) + inbar.startAnimation(alphain) + findbar.startAnimation(alphaout) + findbar.setVisibility(8) + inbar.setVisibility(0) + dism.startAnimation(alphain) + dism.setVisibility(0) + end) + edit.addTextChangedListener{ + onTextChanged=function(c) + local s=tostring(c) + if #s==0 then + 项目列表.Adapter=adp + return + end + local t={} + s=s:lower() + for k,v in ipairs(ppls) do + if v.appname:lower():find(s,1,true) then + table.insert(t,v) + end + end + update(t) + end + } +end + +dism.onClick=function() + scaledown(100) + task(50,function() + inbar.startAnimation(alphaout) + findbar.startAnimation(alphain) + findbar.setVisibility(0) + inbar.setVisibility(8) + dism.startAnimation(alphaout) + dism.setVisibility(8) + + + end) +end + + + + +--[[function jrlt.onClick() + activity.newActivity("forum/main39") +end]] +sx.setDurations(2000,200) +sx.onRefresh=function(a) + 刷新项目() + task(1150,function() + sx.setRefreshing(false); + end) +end +sx.setColor(0xFF03A9F4) +sx.setRefreshStyle(PullRefreshLayout.STYLE_MATERIAL); +sx.setRefreshing(true); +task(1000,function() + sx.setRefreshing(false); + task(155,function() + 刷新项目() + end) +end) +--刷新项目() +--[[pagev.onPageChange=function(v,i) + switch i + case 0 + 写入文件(activity.getLuaDir().."/Verify/set1.XY","0") + --[[社区图片.setColorFilter(0xFF383A3D) + p_c1.setColorFilter(0xFF383A3D) + 我的图片.setColorFilter(0xFF383A3D) + 项目图片.setColorFilter(0xFF2196F3) + case 1 + 写入文件(activity.getLuaDir().."/Verify/set1.XY","1") + 社区图片.setColorFilter(0xFF2196F3) + p_c1.setColorFilter(0xFF383A3D) + 项目图片.setColorFilter(0xFF2196F3) + 我的图片.setColorFilter(0xFF383A3D) + +case 2 + 写入文件(activity.getLuaDir().."/Verify/set1.XY","2") + 社区图片.setColorFilter(0xFF383A3D) + p_c1.setColorFilter(0xFF2196F3) + 项目图片.setColorFilter(0xFF383A3D) + 我的图片.setColorFilter(0xFF383A3D) +case 3 + 写入文件(activity.getLuaDir().."/Verify/set1.XY","3") + 社区图片.setColorFilter(0xFF383A3D) + p_c1.setColorFilter(0xFF383A3D) + 项目图片.setColorFilter(0xFF383A3D) + 我的图片.setColorFilter(0xFF2196F3) + end + +end]] +--[[function 项目.onClick() + pagev.showPage(0) +end +function 社区.onClick() + pagev.showPage(1) +end +function p_c1.onClick() + pagev.showPage(2) +end +function 我的.onClick() + pagev.showPage(3) +end]] + +local function 创建工程() + local xz={ + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="match_parent"; + layout_width="match_parent"; + backgroundColor=颜色1, + radius=20; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + orientation="vertical"; + { + TextView; + text="新建工程"; + textColor="0xFF03A9F4"; + textSize="19sp"; + layout_marginLeft="20dp"; + layout_marginTop="15dp"; + }; + { + FrameLayout; + layout_marginTop="5dp", + layout_width="match_parent"; + layout_height="fill"; + { + ListView; + id="创建选择", + items={ + " 参考模板"; + " 默认工程"; + }; + layout_height="match_parent"; + DividerHeight=0; + layout_width="match_parent"; + }; + }; + }; + }; + }; + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(xz)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + 创建选择.onItemClick=function(l,v,p,i) + if i==1 then + dialog1.dismiss() + mb={ + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="match_parent"; + layout_width="match_parent"; + backgroundColor=颜色1, + radius=20; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + orientation="vertical"; + { + TextView; + text="参考模板"; + textColor=0xFF03A9F4; + textSize="18sp"; + layout_marginLeft="20dp"; + layout_marginTop="15dp"; + }; + { + FrameLayout; + layout_width="match_parent"; + layout_height="fill"; + { + ListView; + id="模板", + items= + { + " 密码进入软件"; + " 美化路径模块"; + " DrawerLayout"; + " TabBar"; + " TitleBar", + }; + + layout_height="match_parent"; + DividerHeight=0; + layout_width="match_parent"; + }; + }; + }; + }; + }; + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(mb)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + --模板.TextColor=颜色3 + 模板.onItemClick=function(l,v,p,i); + if i==1 then + mc="密码进入软件" + lj="xy1" + elseif i==2 then + mc="美化路径模块" + lj="xy2" + elseif i==3 then + mc="DrawerLayout" + lj="xy3" + elseif i==4 then + mc="TabBar" + lj="xy4" + elseif i==5 then + mc="TitleBar" + lj="xy5" + end + ZipUtil.unzip(activity.getLuaDir().."/project/"..lj..".zip",项目文件夹.."/"..mc) + 刷新项目() + dialog1.dismiss() + activity.newActivity("main2",android.R.anim.fade_in,android.R.anim.fade_out,{项目文件夹.."/"..mc,true,mc}) + end + else + dialog1.dismiss() + tj= + + + { + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + backgroundColor=颜色2, + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="300dp"; + layout_width="match_parent"; + backgroundColor=颜色2, + radius=20; + { + TextView; + layout_marginTop="15dp"; + layout_marginLeft="20dp"; + textSize="20sp"; + textColor="0xFF03A9F4"; + text="新建工程"; + }; + { + LinearLayout; + orientation="horizontal"; + layout_width="match_parent"; + layout_height="150dp"; + gravity="center"; + { + EditText; + layout_marginTop="10dp", + layout_width="320dp"; + gravity="center"; + textSize="15sp"; + hint="请输入工程的名称"; + text="Myapp"; + id="输入名称", + textColor=颜色4, + --HintTextColor=颜色4, + }; + }; + { + + LinearLayout; + orientation="horizontal"; + layout_width="match_parent"; + layout_height="match_parent"; + gravity="center"; + { + EditText; + --layout_marginTop="10dp", + layout_width="320dp"; + gravity="center"; + textSize="15sp"; + id="输入包名", + --hintTextColor=颜色4, + textColor=颜色4, + hint="请输入工程的包名"; + text="com.Myapp.demo"; + }; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + { + Button; + id="取消创建工程", + layout_gravity="center"; + layout_marginLeft="20dp"; + textColor="0x7E000000"; + text="取消"; + layout_marginTop="50dp", + layout_height="40dp"; + }; + { + LinearLayout; + gravity="right"; + layout_width="match_parent"; + layout_height="match_parent"; + { + Button; + layout_height="40dp"; + id="确定创建工程", + layout_marginTop="50dp", + layout_gravity="center"; + layout_marginRight="20dp"; + textColor="0xFF03A9F4"; + text="创建"; + }; + }; + }; + }; + }; + + + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(tj)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + 美化按钮1(取消创建工程,10,0x7E000000,颜色7) + 美化按钮1(确定创建工程,10,0x7a00bfff,0xFF03A9F4) + 控件圆角(输入名称,颜色5,30) + 控件圆角(输入包名,颜色5,30) + function 确定创建工程.onClick() + if #输入名称.text~=0 then + if #输入包名.text~=0 then + if File(项目文件夹.."/"..输入名称.text).isDirectory() then + print"工程已存在" + else + main=[[ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "layout" +activity.setTitle("Myapp") +activity.setTheme(android.R.style.Theme_DeviceDefault_Light) +activity.setContentView(loadlayout(layout)) +]] + init=[[ +appname="Myapp" +packagename="com.Myapp.demo" +appcode="1" +appver="1.0" +appsdk="15" +debugmode=true +user_permission={ + "INTERNET", + "WRITE_EXTERNAL_STORAGE", +} +skip_compilation={ +} +]] + layout1=[[ +{ +LinearLayout; +layout_width="fill"; +orientation="vertical"; +layout_height="fill"; +}; +]] + 创建文件夹(项目文件夹.."/"..输入名称.text) + main1=string.gsub(main,"Myapp",输入名称.text) + 写入文件(项目文件夹.."/"..输入名称.text.."/main.lua",main1) + init1=string.gsub(init,'appname="Myapp"','appname="'..输入名称.text..'"') + init2=string.gsub(init1,"com.Myapp.demo",输入包名.text) + 写入文件(项目文件夹.."/"..输入名称.text.."/init.lua",init2) + 写入文件(项目文件夹.."/"..输入名称.text.."/layout.aly",layout1) + sx.setRefreshing(true); + task(10,function() + sx.setRefreshing(false); + 刷新项目() + if File(项目文件夹.."/"..输入名称.text).isDirectory() then + print"创建成功" + activity.newActivity("main2",android.R.anim.fade_in,android.R.anim.fade_out,{项目文件夹.."/"..输入名称.text,true,输入名称.text}) + dialog1.dismiss() + else print"创建失败" + end + end) + end + else + print"请输入工程包名" + end + else + print"请输入工程名称" + end + end + function 取消创建工程.onClick() + dialog1.dismiss() + end + end + end +end +--[[function 添加.onClick() + a=io.open(activity.getLuaDir().."/Verify/set1.XY"):read("*a") + if a=="0" then + 创建工程() + else + if a=="1" then + + end + end +end]] +lastclick = os.time() - 2 +function onKeyDown(e) + local now = os.time() + if e == 4 then + if now - lastclick > 2 then + --print("再按一次退出程序") + Toast.makeText(activity, "再按一次退出程序.", Toast.LENGTH_SHORT ).show() + lastclick = now + return true + end + end +end +function 其他.onClick() + pop=PopupMenu(activity,其他) + menu=pop.Menu + menu.add("创建工程").onMenuItemClick=function(a) + 创建工程() + end + menu.add("导入工程").onMenuItemClick=function(a) + activity.newActivity("file",android.R.anim.fade_in,android.R.anim.fade_out,{"选择源码(*.alp)",Environment.getExternalStorageDirectory().toString(),{".alp"}}) + function onResult(name,arg) + if name=="file" then + sx.setRefreshing(true); + task(10,function() + sx.setRefreshing(false); + 刷新项目() + print("导入成功") + end) + else + + end + + end + end + menu.add("中文手册").onMenuItemClick=function(a) + activity.newActivity("main3",android.R.anim.fade_in,android.R.anim.fade_out) + end + menu.add("编辑器设置").onMenuItemClick=function(a) + activity.newActivity("main13",android.R.anim.fade_in,android.R.anim.fade_out) + end + pop.show() +end +--[[项目列表.onItemClick=function(l,v,p,i) + activity.newActivity("main2",android.R.anim.fade_in,android.R.anim.fade_out,{项目文件夹.."/"..v.tag.软件名.text,true,v.tag.软件名.text,"/storage/emulated/0/ThomeLua+/project/"..v.tag.软件名.text}) + return true +end]] + +import "android.view.animation.Animation$AnimationListener" +import "android.view.animation.ScaleAnimation" +import "android.view.animation.ScaleAnimation" +function CircleButton (InsideColor,radiu,...) + import "android.graphics.drawable.GradientDrawable" + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(InsideColor) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + for k,v in ipairs({...}) do + v.setBackgroundDrawable(drawable) + end +end +CircleButton(0xff20d0d0,100,bt,bt1,bt2) +bt.onClick=function(v) + if bt1.getVisibility()==0 then + bt2.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(100)) + bt2.setVisibility(View.INVISIBLE) + bt1.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(200)) + bt1.setVisibility(View.INVISIBLE) + bt.text="+" + + else + bt1.setVisibility(View.VISIBLE) + bt2.setVisibility(View.VISIBLE) + bt1.startAnimation(ScaleAnimation(0.0, 1.0, 0.0, 1.0,1, 0.5, 1, 0.5).setDuration(100)) + bt2.startAnimation(ScaleAnimation(0.0, 1.0, 0.0, 1.0,1, 0.5, 1, 0.5).setDuration(200)) + bt.text="-" + bt1.Text="导入" + bt2.Text="新建" + end +end +bt1.onClick=function(v) + bt1.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(100)) + bt1.setVisibility(View.INVISIBLE) + bt2.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(200)) + bt2.setVisibility(View.INVISIBLE) + bt.text="+" + activity.newActivity("file",android.R.anim.fade_in,android.R.anim.fade_out,{"选择源码(*.alp)",Environment.getExternalStorageDirectory().toString(),{".alp"}}) + function onResult(name,arg) + if name=="file" then + sx.setRefreshing(true); + task(10,function() + sx.setRefreshing(false); + 刷新项目() + print("导入成功") + end) + else + end + end +end +bt2.onClick=function(v) + bt1.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(100)) + bt1.setVisibility(View.INVISIBLE) + bt2.startAnimation(ScaleAnimation(1.0, 0.0, 1.0, 0.0,1, 0.5, 1, 0.5).setDuration(200)) + bt2.setVisibility(View.INVISIBLE) + bt.text="+" + 创建工程() +end + + diff --git a/app/src/main/assets/main10.lua b/app/src/main/assets/main10.lua new file mode 100644 index 0000000..14f18fd --- /dev/null +++ b/app/src/main/assets/main10.lua @@ -0,0 +1,137 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "AndLua" +import "toast" +import "android" +--activity.setTheme(R.AndLua5) +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色2=0xFFF2F1F6 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end +layout10={ + LinearLayout; + layout_width="fill"; + layout_height="fill"; + backgroundColor=颜色2, + orientation="vertical"; + { + LinearLayout; + orientation="vertical"; + layout_height="fill"; + layout_width="fill"; + { + LinearLayout; + backgroundColor=颜色1; + layout_height="56dp"; + layout_width="fill"; + { + ImageView; + onClick=function() + activity.finish() + end; + src="res/ThomeLua8.png"; + layout_marginLeft="20dp"; + ColorFilter="0xFF03A9F4"; + layout_width="25dp"; + layout_gravity="center"; + }; + { + TextView; + textSize="18sp"; + textColor="0xFF03A9F4"; + layout_marginLeft="30dp"; + text="Java Api"; + layout_gravity="center"; + }; + }; + { + EditText; + hint="搜索", + layout_marginTop="10dp", + id="搜索api"; + --hintTextColor=颜色3, + textColor=颜色3, + layout_width="320dp"; + layout_gravity="center"; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + { + ListView; + fastScrollEnabled=true, + layout_marginTop="10dp", + DividerHeight=0; + id="api"; + layout_height="fill"; + layout_width="fill"; + }; + }; + }; +}; + + +activity.setContentView(loadlayout(layout10)) +--隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +控件圆角(搜索api,颜色2,25) +apiitem={ + LinearLayout; + layout_height="fill"; + layout_width="fill"; + gravity="center"; + backgroundColor=颜色2, + { + LinearLayout; + layout_width="match_parent"; + { + TextView; + textSize="17sp"; + id="nrapi"; + textColor=颜色3; + layout_marginLeft="25dp"; + layout_marginTop="10dp"; + layout_marginBottom="10dp"; + text="com.androlua.Http"; + }; + }; +}; +data={} +local adp=LuaAdapter(activity,data,apiitem) +api.setAdapter(adp) +function 加载(内容) + adp.clear() + for k in apinr:gmatch("【(.-)】") + if k:match(tostring(内容)) then + adp.add{nrapi=k} + else + adp.clear() + end + end +end +加载("") + +搜索api.addTextChangedListener({ + onTextChanged=function(a) + 加载(a) + end}) +function api.onItemClick(l,v,p,i) + 写入剪切板(v.tag.nrapi.text) + print"复制成功" +end \ No newline at end of file diff --git a/app/src/main/assets/main11.lua b/app/src/main/assets/main11.lua new file mode 100644 index 0000000..55b4ec8 --- /dev/null +++ b/app/src/main/assets/main11.lua @@ -0,0 +1,257 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "AndLua" +import "other" +import "Dialog" +import "toast" +import "main6" +compile "libs/android-support-v4" +import "android.support.v4.widget.*" +--activity.setTheme(R.AndLua5) + +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色2=0xFFF2F1F6 +end + +layout11={ + LinearLayout; + layout_height="fill"; + backgroundColor=颜色2, + layout_width="fill"; + orientation="vertical"; + { + SwipeRefreshLayout; + id="sxbf", + { + RelativeLayout; + layout_height="fill"; + layout_width="fill"; + { + LinearLayout; + layout_height="56dp"; + backgroundColor=颜色1; + layout_width="fill"; + { + ImageView; + layout_gravity="center"; + src="res/ThomeLua8.png"; + ColorFilter="0xFF03A9F4"; + layout_width="25dp"; + id="备份q"; + layout_marginLeft="20dp"; + }; + { + TextView; + layout_gravity="center"; + text="备份管理"; + textSize="18sp"; + layout_marginLeft="30dp"; + textColor="0xFF03A9F4"; + }; + }; + { + + LinearLayout; + gravity="center"; + layout_height="88.3%h"; + orientation="vertical"; + layout_alignParentBottom="true"; + layout_width="fill"; + { + ListView; + layout_gravity="end"; + layout_width="fill"; + layout_height="fill"; + id="备份列表"; + DividerHeight=0; + layout_marginTop="5dp"; + }; + }; + }; + }, +} +activity.setContentView(loadlayout(layout11)) +--隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end + +local item11={ + LinearLayout; + gravity="center"; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + orientation="vertical"; + gravity="center"; + layout_width="fill"; + layout_height="70dp"; + { + CardView; + radius=20; + backgroundColor=颜色1; + CardElevation=0; + layout_width="340dp"; + layout_height="60dp"; + { + LinearLayout; + layout_width="match_parent"; + layout_height="match_parent"; + { + LinearLayout; + gravity="center"; + layout_width="8%h"; + layout_height="match_parent"; + { + ImageView; + src="res/bft.png"; + layout_width="35dp"; + layout_height="35dp"; + }; + }; + { + LinearLayout; + orientation="vertical"; + layout_width="match_parent"; + layout_height="match_parent"; + { + TextView; + textColor=颜色3; + layout_marginTop="10dp"; + id="备份文件名"; + text="文件名"; + }; + { + TextView; + textColor=颜色3, + text="时间"; + id="备份时间"; + layout_marginTop="5dp"; + }; + }; + }; + }; + }; +}; +function GetFilelastTime(path) + f = File(path); + cal = Calendar.getInstance(); + time = f.lastModified() + cal.setTimeInMillis(time); + return cal.getTime().toLocaleString() +end +local function 刷新备份() + sdata={} + asdp=LuaAdapter(activity,sdata,item11) + 备份列表.Adapter=asdp + local a=luajava.astable(File(备份文件夹).listFiles()) + if a[1]==nil then + else + for i=1,#a do + if File(备份文件夹.."/"..a[i].name).isFile() then + asdp.add{备份文件名=a[i].name,备份时间=GetFilelastTime(备份文件夹.."/"..a[i].name)} + end + end + end +end +刷新备份() +sxbf.setColorSchemeColors({0xFF03A9F4}); +sxbf.setProgressBackgroundColorSchemeColor(颜色1); +sxbf.setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener{onRefresh=function() + 刷新备份() + sxbf.setRefreshing(false); + end}) +波纹(备份q,0xFFD9D9D9) +function 备份列表.onItemLongClick(l,v,p,i) + local bt=v.tag.备份文件名.text + local sc={ + LinearLayout; + layout_width="fill"; + gravity="center"; + layout_height="fill"; + { + LinearLayout; + backgroundColor=颜色1, + orientation="vertical"; + layout_width="match_parent"; + layout_height="160dp"; + { + TextView; + layout_marginLeft="25dp"; + layout_marginTop="10dp"; + textSize="20sp"; + textColor="0xFF03A9F4"; + text="提示"; + }; + { + TextView; + textColor=颜色3, + textSize="15sp"; + layout_marginLeft="25dp"; + text="您确定要删除此文件吗?删除后将无法恢复!"; + layout_marginTop="10dp"; + }; + { + LinearLayout; + layout_marginBottom="50dp"; + layout_gravity="bottom"; + layout_marginTop="20dp"; + layout_width="match_parent"; + layout_height="50dp"; + { + Button; + text="取消"; + layout_gravity="center"; + layout_marginLeft="20dp"; + id="取消删除备份"; + layout_height="40dp"; + }; + { + LinearLayout; + layout_width="match_parent"; + gravity="right"; + layout_height="match_parent"; + { + Button; + layout_marginRight="20dp"; + layout_gravity="center"; + text="删除"; + layout_height="40dp"; + id="确定删除备份"; + }; + }; + }; + }; + }; + + Dialog1=MyBottomSheetDialog() + .设置布局(sc) + .设置弹窗背景("#ffffffff") + .设置弹窗圆角("10dp") + .显示() + 美化按钮(取消删除备份,10,0x7E000000,0x7E000000) + 美化按钮(确定删除备份,10,0x7a00bfff,0x7a00bfff) + function 确定删除备份.onClick() + dialog1.dismiss() + os.remove(备份文件夹.."/"..bt) + 刷新备份() + print"删除成功" + end + function 取消删除备份.onClick() + dialog1.dismiss() + end + return true +end \ No newline at end of file diff --git a/app/src/main/assets/main12.lua b/app/src/main/assets/main12.lua new file mode 100644 index 0000000..aed31ae --- /dev/null +++ b/app/src/main/assets/main12.lua @@ -0,0 +1,264 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "AndLua" +import "other" +import "Dialog" +import "toast" +import "main6" +compile "libs/android-support-v4" +import "android.support.v4.widget.*" +--activity.setTheme(R.AndLua5) + +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色2=0xFFF2F1F6 +end + + +layout12={ + LinearLayout; + layout_height="fill"; + layout_width="fill"; + backgroundColor=颜色2, + orientation="vertical"; + { + SwipeRefreshLayout; + id="sxdb", + { + RelativeLayout; + layout_height="fill"; + layout_width="fill"; + { + LinearLayout; + layout_height="56dp"; + backgroundColor=颜色1; + layout_width="fill"; + { + ImageView; + onClick=function() + activity.finish() + end; + layout_gravity="center"; + src="res/ThomeLua8.png"; + ColorFilter="0xFF03A9F4"; + layout_width="25dp"; + id="dbq"; + layout_marginLeft="20dp"; + }; + { + TextView; + layout_gravity="center"; + text="打包管理"; + textSize="18sp"; + layout_marginLeft="30dp"; + textColor="0xFF03A9F4"; + }; + }; + { + + LinearLayout; + gravity="center"; + layout_height="88.2%h"; + orientation="vertical"; + layout_alignParentBottom="true"; + layout_width="fill"; + { + ListView; + layout_gravity="end"; + layout_width="fill"; + layout_height="fill"; + id="打包列表"; + DividerHeight=0; + layout_marginTop="5dp"; + }; + }; + }; + }, +} +activity.setContentView(loadlayout(layout12)) +--隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end + +local item12={ + LinearLayout; + gravity="center"; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + orientation="vertical"; + gravity="center"; + layout_width="fill"; + layout_height="70dp"; + { + CardView; + radius=20; + backgroundColor=颜色1; + CardElevation=0; + layout_width="340dp"; + layout_height="60dp"; + { + LinearLayout; + layout_width="match_parent"; + layout_height="match_parent"; + { + LinearLayout; + gravity="center"; + layout_width="8%h"; + layout_height="match_parent"; + { + ImageView; + src="res/bft.png"; + layout_width="35dp"; + layout_height="35dp"; + }; + }; + { + LinearLayout; + orientation="vertical"; + layout_width="match_parent"; + layout_height="match_parent"; + { + TextView; + textColor=颜色3; + layout_marginTop="10dp"; + id="打包文件名"; + text="文件名"; + }; + { + TextView; + textColor=颜色3, + text="时间"; + id="打包时间"; + layout_marginTop="5dp"; + }; + }; + }; + }; + }; +}; +function GetFilelastTime(path) + f = File(path); + cal = Calendar.getInstance(); + time = f.lastModified() + cal.setTimeInMillis(time); + return cal.getTime().toLocaleString() +end +local function 刷新打包() + sdata={} + asdp=LuaAdapter(activity,sdata,item12) + 打包列表.Adapter=asdp + local a=luajava.astable(File(打包文件夹).listFiles()) + if a[1]==nil then + else + for i=1,#a do + if File(打包文件夹.."/"..a[i].name).isFile() then + asdp.add{打包文件名=a[i].name,打包时间=GetFilelastTime(打包文件夹.."/"..a[i].name)} + end + end + end +end +刷新打包() +sxdb.setColorSchemeColors({0xFF03A9F4}); +sxdb.setProgressBackgroundColorSchemeColor(颜色1); +sxdb.setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener{onRefresh=function() + 刷新打包() + sxdb.setRefreshing(false); + end}) +波纹(dbq,0xFFD9D9D9) +function 打包列表.onItemClick(l,v,p,i) + activity.installApk(打包文件夹.."/"..v.tag.打包文件名.text) +end +function 打包列表.onItemLongClick(l,v,p,i) + local bt=v.tag.打包文件名.text + local sc={ + LinearLayout; + layout_width="fill"; + gravity="center"; + layout_height="fill"; + { + LinearLayout; + backgroundColor=颜色1, + orientation="vertical"; + layout_width="match_parent"; + layout_height="160dp"; + { + TextView; + layout_marginLeft="25dp"; + layout_marginTop="10dp"; + textSize="20sp"; + textColor="0xFF03A9F4"; + text="提示"; + }; + { + TextView; + textSize="15sp"; + textColor=颜色3, + layout_marginLeft="25dp"; + text="您确定要删除此文件吗?删除后将无法恢复!"; + layout_marginTop="10dp"; + }; + { + LinearLayout; + layout_marginBottom="50dp"; + layout_gravity="bottom"; + layout_marginTop="20dp"; + layout_width="match_parent"; + layout_height="50dp"; + { + Button; + text="取消"; + layout_gravity="center"; + layout_marginLeft="20dp"; + id="取消删除打包"; + layout_height="40dp"; + }; + { + LinearLayout; + layout_width="match_parent"; + gravity="right"; + layout_height="match_parent"; + { + Button; + layout_marginRight="20dp"; + layout_gravity="center"; + text="删除"; + layout_height="40dp"; + id="确定删除打包"; + }; + }; + }; + }; + }; + + Dialog1=MyBottomSheetDialog() + .设置布局(sc) + .设置弹窗背景(颜色4) + .设置弹窗圆角("10dp") + .显示() + 美化按钮(取消删除打包,10,0x7E000000,0x7E000000) + 美化按钮(确定删除打包,10,0x7a00bfff,0x7a00bfff) + function 确定删除打包.onClick() + dialog1.dismiss() + os.remove(打包文件夹.."/"..bt) + 刷新打包() + print"删除成功" + end + function 取消删除打包.onClick() + dialog1.dismiss() + end + return true +end \ No newline at end of file diff --git a/app/src/main/assets/main13.lua b/app/src/main/assets/main13.lua new file mode 100644 index 0000000..2f5a5c3 --- /dev/null +++ b/app/src/main/assets/main13.lua @@ -0,0 +1,1362 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "toast" +import "AndLua" +import "android.net.Uri" +import "android.content.Intent" +import "android.graphics.PorterDuffColorFilter" +import "android.graphics.PorterDuff" +--activity.setTheme(R.AndLua5) + +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色a=0xff303030 + 颜色b=0xff212121 + 颜色c=0xFFFFFFFF + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色6=0xffffffff + 颜色5=0xff212121 + 颜色7=0xEBFFFFFF + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色a=0xffffffff + 颜色b=0xFFF2F1F6 + 颜色c=0xff303030 + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色6=0xff757575 + 颜色5=0x5FFFFFFF + 颜色7=0xff303030 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end +local ab=io.open(activity.getLuaDir().."/Verify/set5.XY"):read("*a") +local abc=io.open(activity.getLuaDir().."/Verify/set6.XY"):read("*a") +local abcd=io.open(activity.getLuaDir().."/Verify/set7.XY"):read("*a") +local bj=io.open(activity.getLuaDir().."/Verify/setb.XY"):read("*a") +local bbl=io.open(activity.getLuaDir().."/Verify/setbb.XY"):read("*a") +local abcde=io.open(activity.getLuaDir().."/Verify/set8.XY"):read("*a") +local abcdef=io.open(activity.getLuaDir().."/Verify/set9.XY"):read("*a") +local abcdefg=io.open(activity.getLuaDir().."/Verify/set10.XY"):read("*a") +local abcdefgh=io.open(activity.getLuaDir().."/Verify/set11.XY"):read("*a") +local abcdefghi=io.open(activity.getLuaDir().."/Verify/set12.XY"):read("*a") +switch abc + case "颜色1" + abc=颜色1 +end +switch abcdef + case "颜色3" + abcdef=颜色3 +end +switch bj + case "颜色5" + bj=颜色5 +end +switch bbl + case "颜色1" + bbl=颜色1 +end +layout13={ + ScrollView; + { + LinearLayout; + layout_width="fill"; + orientation="vertical"; + backgroundColor=颜色b; + layout_height="fill"; + { + LinearLayout; + orientation="vertical"; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + layout_width="fill"; + backgroundColor=颜色a; + layout_height="8.2%h"; + { + ImageView; + layout_gravity="center"; + onClick=function() + activity.finish() + end; + layout_width="6.9%w"; + src="res/ThomeLua8.png"; + ColorFilter="0xFF03A9F4"; + layout_marginLeft="5.5%w"; + }; + { + TextView; + layout_gravity="center"; + text="软件设置"; + textColor="0xFF03A9F4"; + layout_marginLeft="8.3%w"; + textSize="18sp"; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="5.5%w"; + gravity="right"; + { + ImageView; + layout_gravity="center"; + id="保存设置", + layout_width="6.9%w"; + src="res/ThomeLua9.png"; + ColorFilter="0xFF03A9F4"; + }; + }; + }; + { + LinearLayout; + orientation="vertical"; + layout_width="match_parent"; + layout_height="match_parent"; + { + CardView; + backgroundColor=颜色a, + layout_gravity="center"; + layout_width="94.4%w"; + layout_height="19%h"; + radius=25; + layout_marginTop="3%h"; + CardElevation="0dp"; + { + LinearLayout; + orientation="vertical"; + layout_width="match_parent"; + layout_height="match_parent"; + { + TextView; + text="通用"; + textColor="0xFF03A9F4"; + layout_marginTop="1%h"; + layout_marginLeft="3%w"; + textSize="16sp"; + }; + { + LinearLayout; + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="检测更新"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right"; + { + Switch; + id="检测更新", + layout_gravity="center"; + }; + }; + }; + { + LinearLayout; + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="深色模式"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + Switch; + id="夜间模式", + layout_gravity="center"; + }; + }; + }; + }; + }; + { + CardView; + layout_gravity="center"; + layout_width="94.4%w"; + layout_height="111%h"; + radius=25; + backgroundColor=颜色a, + layout_marginTop="3%h"; + CardElevation="0dp"; + { + LinearLayout; + orientation="vertical"; + layout_width="match_parent"; + layout_height="match_parent"; + + { + TextView; + text="编辑器设置"; + textColor="0xFF03A9F4"; + layout_marginTop="1%h"; + layout_marginLeft="3%w"; + textSize="16sp"; + }; + { + LinearLayout; + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="自动换行"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + Switch; + id="自动换行", + layout_gravity="center"; + }; + }; + }; + { + LinearLayout; + id="自定义符号栏", + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="自定义符号栏"; + textColor=颜色c; + }; + }; + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(ab),"确定",1) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="基词颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=ab; + id="q"; + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="42.8%w"; + }; + }, + }; + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(abc),"确定",2) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="卡片背景颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=abc; + id="qq", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="35%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(abcd),"确定",3) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="卡片字体颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=abcd; + id="qqq", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="35%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + switch bj + case 颜色5 + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + yss1("调色板","0xFF212121","确定",33) + else + yss1("调色板","0x5FFFFFFF","确定",33) + end + default + yss1("调色板",tostring(bj),"确定",33) + end + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="编辑器背景颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=bj; + id="b", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="30.8%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + switch bbl + case 颜色1 + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + yss1("调色板","0xFF303030","确定",333) + else + yss1("调色板","0xFFFFFFFF","确定",333) + end + default + yss1("调色板",tostring(bbl),"确定",333) + end + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="工具栏颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=bbl; + id="bb", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="38.8%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(abcde),"确定",4) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="字符串颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=abcde; + id="qqqq", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="38.8%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(abcdef),"确定",5) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="文本颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=abcdef; + id="qqqqq", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="42.8%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(abcdefg),"确定",6) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="数字颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=abcdefg; + id="qqqqqq", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="42.8%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(abcdefgh),"确定",7) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="注释颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=abcdefgh; + id="qqqqqqq", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="42.8%w"; + }; + }; + + }, + { + LinearLayout; + onClick=function() + yss1("调色板",tostring(abcdefghi),"确定",8) + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="关键字颜色"; + textColor=颜色c; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="10%w"; + gravity="right";{ + CardView; + layout_gravity="center"; + layout_width="3%h"; + backgroundColor=abcdefghi; + id="qqqqqqqq", + layout_height="3%h"; + radius="10dp"; + layout_marginLeft="38.8%w"; + }; + }, + }; + { + LinearLayout; + onClick=function() + io.open(activity.getLuaDir().."/Verify/set5.XY","w"):write("0xff8dbdc9"):close() + io.open(activity.getLuaDir().."/Verify/set6.XY","w"):write("颜色1"):close() + io.open(activity.getLuaDir().."/Verify/set7.XY","w"):write("0xFF03A9F4"):close() + io.open(activity.getLuaDir().."/Verify/set8.XY","w"):write("0xFF03A9F4"):close() + io.open(activity.getLuaDir().."/Verify/set9.XY","w"):write("颜色3"):close() + io.open(activity.getLuaDir().."/Verify/set10.XY","w"):write("0xFF03A9F4"):close() + io.open(activity.getLuaDir().."/Verify/set11.XY","w"):write("0xffa0a0a0"):close() + io.open(activity.getLuaDir().."/Verify/set12.XY","w"):write("0xFF03A9F4"):close() + io.open(activity.getLuaDir().."/Verify/setb.XY","w"):write("颜色5"):close() + io.open(activity.getLuaDir().."/Verify/setbb.XY","w"):write("颜色1"):close() + q.backgroundColor=0xff8dbdc9 + qq.backgroundColor=颜色1 + qqq.backgroundColor=0xFF03A9F4 + qqqq.backgroundColor=0xFF03A9F4 + qqqqq.backgroundColor=颜色3 + qqqqqq.backgroundColor=0xFF03A9F4 + qqqqqqq.backgroundColor=0xffa0a0a0 + qqqqqqqq.backgroundColor=0xFF03A9F4 + b.backgroundColor=颜色5 + bb.backgroundColor=颜色1 + print("已恢复颜色") + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="恢复颜色"; + textColor=颜色c; + }; + + + + }, + { + LinearLayout; + onClick=function() + LuaUtil.copyDir(activity.getLuaDir().."/Verify","/sdcard/ThomeLua/backup/Verify") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/Verify/set1.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/Verify/set2.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/Verify/set3.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/Verify/set4.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/Verify/set13.XY") + local date=os.date("%Y%m%d%H%M%S") + LuaUtil.zip("/sdcard/ThomeLua/backup/Verify","/sdcard/ThomeLua/backup/XColor/","XColor_"..date..".XColor") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/Verify") + local jm=require "crypt" + local jmh=jm.desencode(io.open("/sdcard/ThomeLua/backup/XColor/XColor_"..date..".XColor"):read("*a")) + io.open("/sdcard/ThomeLua/backup/XColor/XColor_"..date..".XColor","w"):write(jmh):close() + print("已导出颜色") + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="导出颜色"; + textColor=颜色c; + }; + + + + }, + { + LinearLayout; + onClick=function() + import "android.graphics.Typeface" + local Text_Type=Typeface.defaultFromStyle(Typeface.BOLD) + local sd = StateListDrawable() + import "android.graphics.Color" + import "android.content.res.ColorStateList" + import "android.graphics.drawable.RippleDrawable" + import "android.content.Context" + appt={C_Bacgg=function(mBinding,radiu,InsideColor,S,S2,T1) + local drawable = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{}); + drawable.setCornerRadius(radiu); + drawable.setColor(颜色5) + drawable.setStroke(3, 0xCFB0B0B0) + drawable.setGradientType(GradientDrawable.RECTANGLE); + mBinding.setTextColor(T1) + mBinding.setTypeface(Text_Type) + return drawable + end} + 美化按钮1=function(mBinding,radiu,InsideColor,T1) + stateList = { + {android.R.attr.state_pressed}, + {android.R.attr.state_focused}, + {android.R.attr.state_activated}, + {android.R.attr.selectableItemBackground}, + }; + sd.addState({ android.R.attr.state_enabled}, appt.C_Bacgg(mBinding,radiu,InsideColor,S,S2,T1)) + pressedColor =InsideColor --Color.parseColor("#7ab946ff"); + stateColorList ={ + pressedColor, + pressedColor, + pressedColor, + normalColor + }; + colorStateList = ColorStateList(stateList, stateColorList); + rippleDrawable = RippleDrawable(colorStateList,sd,nil); + mBinding.setBackground(rippleDrawable); + end + cm=activity.getSystemService(Context.CLIPBOARD_SERVICE) + function 控件圆角(view,InsideColor,radiu) + import "android.graphics.drawable.GradientDrawable" + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(InsideColor) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + view.setBackgroundDrawable(drawable) + end + tj= + { + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="300dp"; + layout_width="match_parent"; + backgroundColor=颜色1, + radius=20; + { + TextView; + layout_marginTop="15dp"; + layout_marginLeft="20dp"; + textSize="20sp"; + textColor="0xFF03A9F4"; + text="导入颜色(*.XColor)"; + }; + { + LinearLayout; + orientation="horizontal"; + layout_width="match_parent"; + layout_height="150dp"; + gravity="center"; + { + EditText; + layout_marginTop="10dp", + layout_width="320dp"; + gravity="center"; + textSize="15sp"; + hint="请输入XColor路径"; + id="路径", + textColor=颜色4, + --HintTextColor=颜色4, + }; + }; + + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + { + Button; + id="取消创建工程", + layout_gravity="center"; + layout_marginLeft="20dp"; + textColor="0x7E000000"; + text="取消"; + layout_marginTop="50dp", + layout_height="40dp"; + }; + { + LinearLayout; + gravity="right"; + layout_width="match_parent"; + layout_height="match_parent"; + { + Button; + layout_height="40dp"; + id="确定创建工程", + layout_marginTop="50dp", + layout_gravity="center"; + layout_marginRight="20dp"; + textColor="0xFF03A9F4"; + text="导入"; + }; + }; + }; + }; + }; + + + + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(tj)); + import "android.content.res.ColorStateList" + import "android.graphics.drawable.ColorDrawable" + import "android.graphics.drawable.GradientDrawable" + import "android.graphics.drawable.RippleDrawable" + import "android.content.res.ColorStateList" + import "android.graphics.drawable.ColorDrawable" + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + 美化按钮1(取消创建工程,10,0x7E000000,颜色7) + 美化按钮1(确定创建工程,10,0x7a00bfff,0xFF03A9F4) + 控件圆角(路径,颜色2,30) + function file_exists(path) + local f=io.open(path,'r') + if f~=nil then io.close(f) return true else return false end + end + function 取消创建工程.onClick() + dialog1.dismiss() + end + function 确定创建工程.onClick() + local jm=require "crypt" + local emh=jm.desdecode(io.open(路径.Text):read("*a")) + io.open(路径.Text.."J","w"):write(emh):close() + LuaUtil.unZip(路径.Text.."J","/sdcard/ThomeLua/backup/XColor/") + os.execute("rm -r "..路径.Text.."J") + local ab=io.open("/sdcard/ThomeLua/backup/XColor/set5.XY"):read("*a") + local abc=io.open("/sdcard/ThomeLua/backup/XColor/set6.XY"):read("*a") + local abcd=io.open("/sdcard/ThomeLua/backup/XColor/set7.XY"):read("*a") + local abcde=io.open("/sdcard/ThomeLua/backup/XColor/set8.XY"):read("*a") + local abcdef=io.open("/sdcard/ThomeLua/backup/XColor/set9.XY"):read("*a") + local abcdefg=io.open("/sdcard/ThomeLua/backup/XColor/set10.XY"):read("*a") + local abcdefgh=io.open("/sdcard/ThomeLua/backup/XColor/set11.XY"):read("*a") + local abcdefghi=io.open("/sdcard/ThomeLua/backup/XColor/set12.XY"):read("*a") + switch file_exists("/sdcard/ThomeLua/backup/XColor/setb.XY") + case true + local bj=io.open("/sdcard/ThomeLua/backup/XColor/setb.XY"):read("*a") + io.open(activity.getLuaDir().."/Verify/setb.XY","w"):write(bj):close() + default io.open(activity.getLuaDir().."/Verify/setb.XY","w"):write("颜色5"):close() + end + switch file_exists("/sdcard/ThomeLua/backup/XColor/setbb.XY") + case true + local bbl=io.open("/sdcard/ThomeLua/backup/XColor/setbb.XY"):read("*a") + io.open(activity.getLuaDir().."/Verify/setbb.XY","w"):write(bbl):close() + default + io.open(activity.getLuaDir().."/Verify/setbb.XY","w"):write("颜色1"):close() + end + + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set5.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set6.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set7.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set8.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set9.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set10.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set11.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/set12.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/setb.XY") + os.execute("rm -r ".."/sdcard/ThomeLua/backup/XColor/setbb.XY") + io.open(activity.getLuaDir().."/Verify/set5.XY","w"):write(ab):close() + io.open(activity.getLuaDir().."/Verify/set6.XY","w"):write(abc):close() + io.open(activity.getLuaDir().."/Verify/set7.XY","w"):write(abcd):close() + io.open(activity.getLuaDir().."/Verify/set8.XY","w"):write(abcde):close() + io.open(activity.getLuaDir().."/Verify/set9.XY","w"):write(abcdef):close() + io.open(activity.getLuaDir().."/Verify/set10.XY","w"):write(abcdefg):close() + io.open(activity.getLuaDir().."/Verify/set11.XY","w"):write(abcdefgh):close() + io.open(activity.getLuaDir().."/Verify/set12.XY","w"):write(abcdefghi):close() + switch type(ab) + case "number" + ab=ab + case "string" + ab=tonumber(ab) + end + switch type(abc) + case "number" + abc=abc + case "string" + abc=tonumber(abc) + end + switch type(abcd) + case "number" + abcd=abcd + case "string" + abcd=tonumber(abcd) + end + switch type(abcde) + case "number" + abcde=abcde + case "string" + abcde=tonumber(abcde) + end + switch type(abcdef) + case "number" + abcdef=abcdef + case "string" + abcdef=tonumber(abcdef) + end + switch type(abcdefg) + case "number" + abcdefg=abcdefg + case "string" + abcdefg=tonumber(abcdefg) + end + switch type(abcdefgh) + case "number" + abcdefgh=abcdefgh + case "string" + abcdefgh=tonumber(abcdefgh) + end + switch type(abcdefghi) + case "number" + abcdefghi=abcdefghi + case "string" + abcdefghi=tonumber(abcdefghi) + end + switch abc + case "颜色1" + abc=颜色1 + case nil + abc=颜色1 + case "" + abc=颜色1 + end + switch abcdef + case "颜色3" + abcdef=颜色3 + case nil + abcdef=颜色3 + case "" + abcdef=颜色3 + end + switch bj + case "颜色5" + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + b.backgroundColor="0xFF212121" + else + b.backgroundColor="0x5FFFFFFF" + end + case nil + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + b.backgroundColor="0xFF212121" + else + b.backgroundColor="0x5FFFFFFF" + end + case "" + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + b.backgroundColor="0xFF212121" + else + b.backgroundColor="0x5FFFFFFF" + end + default + b.backgroundColor=tonumber(bj) + end + switch bbl + case "颜色1" + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + bb.backgroundColor="0xFF303030" + else + bb.backgroundColor="0xFFFFFFFF" + end + case nil + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + bb.backgroundColor="0xFF303030" + else + bb.backgroundColor="0xFFFFFFFF" + end + case "" + local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local ip=a:match("2(.-)"..'"') + if ip=="开" then + bb.backgroundColor="0xFF303030" + else + bb.backgroundColor="0xFFFFFFFF" + end + default + bb.backgroundColor=tonumber(bbl) + end + q.backgroundColor=ab + qq.backgroundColor=abc + qqq.backgroundColor=abcd + qqqq.backgroundColor=abcde + qqqqq.backgroundColor=abcdef + qqqqqq.backgroundColor=abcdefg + qqqqqqq.backgroundColor=abcdefgh + qqqqqqqq.backgroundColor=abcdefghi + + + print("已导入颜色") + dialog1.dismiss() + end + end, + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="导入颜色"; + textColor=颜色c; + }; + + + + }, + }, + }; + { + CardView; + backgroundColor=颜色a, + layout_gravity="center"; + layout_width="94.4%w"; + layout_height="wrap_content"; + radius=25; + layout_marginTop="3%h"; + layout_marginBottom="3%h"; + CardElevation="0dp"; + { + LinearLayout; + orientation="vertical"; + layout_width="match_parent"; + layout_height="match_parent"; + { + TextView; + text="其他"; + textColor="0xFF03A9F4"; + layout_marginTop="1%h"; + layout_marginLeft="3%w"; + textSize="16sp"; + }; + { + LinearLayout; + id="加群", + layout_width="match_parent"; + layout_marginTop="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="加入官方群聊:748285868"; + textColor=颜色c; + }; + }; + { + LinearLayout; + id="联系作者", + layout_width="match_parent"; + layout_marginTop="1%h"; + layout_marginBottom="1%h"; + orientation="horizontal"; + layout_height="6%h"; + { + ImageView; + layout_gravity="center"; + layout_width="4%h"; + src="res/ThomeLua11.png"; + layout_height="4%h"; + ColorFilter=颜色c; + layout_marginLeft="3%w"; + }; + { + TextView; + layout_gravity="center"; + layout_marginLeft="5%w"; + text="作者QQ:176971467"; + textColor=颜色c; + }; + }; + }; + }; + }; + }; + }; +}; + +activity.setContentView(loadlayout(layout13)) + +--隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色a); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +import "color1" +检测更新.ThumbDrawable.setColorFilter(PorterDuffColorFilter(0xFF03A9F4,PorterDuff.Mode.SRC_ATOP)); +夜间模式.ThumbDrawable.setColorFilter(PorterDuffColorFilter(0xFF03A9F4,PorterDuff.Mode.SRC_ATOP)); +自动换行.ThumbDrawable.setColorFilter(PorterDuffColorFilter(0xFF03A9F4,PorterDuff.Mode.SRC_ATOP)); +检测更新.TrackDrawable.setColorFilter(PorterDuffColorFilter(0xFF03A9F4,PorterDuff.Mode.SRC_ATOP)) +夜间模式.TrackDrawable.setColorFilter(PorterDuffColorFilter(0xFF03A9F4,PorterDuff.Mode.SRC_ATOP)) +自动换行.TrackDrawable.setColorFilter(PorterDuffColorFilter(0xFF03A9F4,PorterDuff.Mode.SRC_ATOP)) +function 联系作者.onClick() + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin=176971467"))) +end +function 加群.onClick() + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqapi://card/show_pslcard?src_type=internal&version=1&uin=748285868&card_type=group&source=qrcode"))) +end +local c=a:match("2(.-)"..'"') +local b=a:match("1(.-)"..'"') +local d=io.open(activity.getLuaDir().."/Verify/set13.XY"):read("*a") + +if b=="开" then 检测更新.Checked=true else 检测更新.Checked=false end +if c=="开" then 夜间模式.Checked=true else 夜间模式.Checked=false end +if d=="true" then 自动换行.Checked=true elseif d==true then 自动换行.Checked=true else 自动换行.Checked=false end +function 保存设置.onClick() + local c=[["1%s" +"2%s" +"3%s"]] + if 检测更新.Checked==true then e="开" else e="关" end + if 夜间模式.Checked==true then f="开" else f="关" end + if 自动换行.Checked==true then + io.open(activity.getLuaDir().."/Verify/set13.XY","w"):write("true"):close() + else + io.open(activity.getLuaDir().."/Verify/set13.XY","w"):write(""):close() + end + local d=c:format(e,f,g) + 写入文件(activity.getLuaDir().."/Verify/set4.XY",d) + activity.finish() + print"保存成功" +end +function 自定义符号栏.onClick() + InputLayout={ + LinearLayout; + orientation="vertical"; + Focusable=true, + FocusableInTouchMode=true, + { + TextView; + textSize="15sp", + layout_marginTop="1%h"; + layout_marginLeft="3.5%w", + layout_marginRight="10dp", + layout_width="match_parent"; + layout_gravity="center", + text="请输入自定义符号,用换行符隔开"; + textColor="0xFF03A9F4", + }; + { + EditText; + layout_marginTop="5dp"; + layout_marginLeft="10dp", + layout_marginRight="10dp", + layout_width="match_parent"; + layout_gravity="center", + id="edit"; + }; + }; + + AlertDialog.Builder(this) + .setTitle("自定义符号栏") + .setView(loadlayout(InputLayout)) + .setPositiveButton("保存",{onClick=function() + 写入文件(activity.getLuaDir().."/Verify/set2.XY",edit.text.." @XY") + print"已保存" + end}) + .setNegativeButton("取消",nil) + .show() + local a=io.open(activity.getLuaDir().."/Verify/set2.XY"):read("*a") + local b=a:find("@") + local c=a:sub(0,b-2) + edit.text=c + +end diff --git a/app/src/main/assets/main14.lua b/app/src/main/assets/main14.lua new file mode 100644 index 0000000..2da6e12 --- /dev/null +++ b/app/src/main/assets/main14.lua @@ -0,0 +1,320 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "toast" +import "bmob" +import "AndLua" +activity.setTheme(R.AndLua5) +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 +end +layout14={ + LinearLayout; + orientation="vertical"; + backgroundColor=颜色2; + layout_height="fill"; + layout_width="fill"; + { + LinearLayout; + backgroundColor=颜色1; + layout_height="56dp"; + layout_width="fill"; + { + ImageView; + layout_gravity="center"; + layout_width="25dp"; + layout_marginLeft="20dp"; + id="tclts", + src="res/ThomeLua8.png"; + ColorFilter="0xFF03A9F4"; + }; + { + TextView; + layout_gravity="center"; + textColor="0xFF03A9F4"; + layout_marginLeft="30dp"; + textSize="18sp"; + text="聊天大厅"; + }; + { + ImageView; + layout_gravity="center"; + layout_width="30dp"; + layout_marginLeft="25%h"; + id="ltsqt"; + src="imgs/Other.png"; + ColorFilter="0xFF03A9F4"; + }; + }; + { + RelativeLayout; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + layout_centerVertical="true"; + layout_width="match_parent"; + orientation="vertical"; + layout_alignParentBottom="true"; + layout_height="89%h"; + layout_centerHorizontal="true"; + { + RelativeLayout; + layout_width="match_parent"; + layout_height="match_parent"; + { + ListView; + id="聊天室", + layout_width="fill"; + layout_height="80%h"; + DividerHeight=0; + layout_marginTop="1%h", + }; + { + LinearLayout; + backgroundColor=颜色1; + layout_alignParentBottom="true"; + layout_width="match_parent"; + gravity="center"; + layout_height="7%h"; + { + EditText; + layout_marginRight="3%w"; + hint="说点什么吧..."; + textSize="11sp"; + layout_height="5%h", + textColor=颜色3, + hintTextColor=颜色3, + id="lxx", + layout_width="75%w"; + }; + { + Button; + style="?android:attr/buttonBarButtonStyle"; + layout_width="9%h"; + textSize="10sp"; + id="l发送", + layout_height="5%h"; + text="发送"; + }; + }; + }; + }; + }; +}; + + +activity.setContentView(loadlayout(layout14)) +隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +xp,xq=... +id="f4583c64387a36e08a2d7f2181f4ca76" +key="e3b5994c466cb86b0450011c57bdf152" +local bmob=bmob(id,key) +lt={ + { + LinearLayout; + layout_width="fill"; + layout_height="fill"; + orientation="vertical"; + { + LinearLayout; + layout_marginLeft="1%h", + layout_width="40%h"; + { + CircleImageView; + layout_width="7%h"; + layout_height="7%h"; + id="l用户图", + src="imgs/User.png"; + }; + { + LinearLayout; + layout_width="match_parent"; + orientation="vertical"; + { + TextView; + id="l用户名", + textColor=颜色4, + layout_marginLeft="1%h"; + text="用户名"; + layout_marginTop="1%w"; + }; + { + CardView; + radius=15; + CardElevation=0; + backgroundColor=颜色1, + layout_marginLeft="1%h"; + layout_marginBottom="10dp"; + layout_marginTop="1%h"; + { + TextView; + id="l信息", + textColor=颜色3; + layout_marginRight="1.3%h"; + layout_marginTop="1%h"; + layout_marginBottom="1%h"; + layout_marginLeft="1.3%h"; + layout_gravity="center"; + text="消息"; + }; + }; + }; + }; + }; + { + LinearLayout; + layout_width="fill"; + layout_height="fill"; + orientation="vertical"; + { + LinearLayout; + layout_gravity="right", + layout_marginRight="1%h", + layout_width="40%h"; + { + LinearLayout; + layout_width="33%h"; + gravity="right"; + orientation="vertical"; + { + TextView; + id="l用户名", + textColor=颜色4, + layout_marginTop="1%w"; + text="用户名"; + layout_marginRight="1%h"; + }; + { + CardView; + CardElevation=0; + backgroundColor=颜色1, + radius=15; + layout_marginBottom="10dp"; + layout_marginRight="1%h"; + layout_marginTop="1%h"; + layout_marginLeft="1%h"; + { + TextView; + id="l信息", + layout_marginTop="1%h"; + layout_marginBottom="1%h"; + layout_marginRight="1.3%h"; + layout_gravity="center"; + textColor=颜色3; + text="消息"; + layout_marginLeft="1.3%h"; + }; + }; + }; + { + CircleImageView; + id="l用户图", + layout_width="7%h"; + layout_height="7%h"; + src="imgs/User.png"; + }; + }; + }; +} +local lgs=nil +控件圆角(lxx,颜色2,25) +控件圆角(l发送,颜色2,25) +local adp=LuaMultiAdapter(activity,lt) +function sxlt() + if xp==true then + adp.clear() + bmob:query("lts",nil,function(a,b) + if #b.results~=0 then + for i=1,#b.results do + local c=b.results[i].zh + local d=b.results[i].xx + local e=b.results[i].mc + if e:find(xq) then + adp.add{__type=2,l用户名=e,l用户图="http://q1.qlogo.cn/g?b=qq&nk="..c.."&s=640",l信息=d} + else + adp.add{__type=1,l用户名=e,l用户图="http://q1.qlogo.cn/g?b=qq&nk="..c.."&s=640",l信息=d} + end + local s=聊天室.getCount() + 聊天室.setSelection(s) + lgs=s + end + end + end) + end +end +sxlt() +聊天室.Adapter=adp +if not File("/sdcard/.cookie.dat").isFile() then + 创建文件("/sdcard/.cookie.dat") + else + local lzh=io.open("/sdcard/.cookie.dat"):read("*a") +end +function l发送.onClick() + if #lxx.text~=0 then + local d={} + d.mc=xq + d.zh=lzh + d.xx=lxx.text + bmob:insert("lts",d,function(a,b) + if a==-1 then + print"发送失败" + else + sxlt() + end + end) + lxx.setText("") + else + print"请输入内容" + end +end +ti2=Ticker() +ti2.Period=42000 +ti2.onTick=function() + bmob:query("lts",nil,function(a,b) + if #b.results~=0 then + local llgs=#b.results + if llgs>lgs then + sxlt() + end + end + end) +end +if xp==true then + ti2.start() +end +function tclts.onClick() + activity.finish() + ti2.stop() +end +function ltsqt.onClick() + pop=PopupMenu(activity,ltsqt) + menu=pop.Menu + menu.add("聊天公告").onMenuItemClick=function() + print"禁止讨论与外挂相关的话题,政治敏感的话题" + end + pop.show() +end +波纹(tclts,0xFFD9D9D9) +波纹(ltsqt,0xFFD9D9D9) +function onKeyDown(a,b) + if a==4 then + ti2.stop() + end +end \ No newline at end of file diff --git a/app/src/main/assets/main2.lua b/app/src/main/assets/main2.lua new file mode 100644 index 0000000..36d8574 --- /dev/null +++ b/app/src/main/assets/main2.lua @@ -0,0 +1,2983 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "ThomeLua" +import "java.io.File" +import "other" +--import "console" +import "color" +import "color1" +import "main10" +import "android.graphics.drawable.ColorDrawable" +import "android.graphics.drawable.StateListDrawable" +import "android.graphics.PorterDuffColorFilter" +import "android.graphics.PorterDuff" +import "Dialog" +import "toast" +--activity.setTheme(R.AndLua5) +local open=io.open +local ts=tostring +local a=open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色6=0xffffffff + 颜色5=0xff212121 + 颜色7=0xEBFFFFFF + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色6=0xff757575 + 颜色5=0x5FFFFFFF + 颜色7=0xff303030 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end + + + +layout2={ + LinearLayout; + orientation="vertical"; + id="c"; + backgroundColor=颜色1; + layout_width="fill"; + layout_height="fill"; + { + RelativeLayout; + layout_height="match_parent"; + layout_width="match_parent"; + id="cc"; + backgroundColor=颜色1; + { + LinearLayout; + gravity="left"; + layout_height="60dp"; + orientation="horizontal"; + layout_width="fill"; + id="ccc"; + backgroundColor=颜色1; + { + LinearLayout; + paddingRight="3%w"; + gravity="center"; + layout_height="fill"; + paddingLeft="4%w"; + orientation="horizontal"; + layout_width="15%w"; + { + ImageView; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_height="30dp"; + src="res/ThomeLua1.png"; + layout_width="25dp"; + id="其他1x"; + }; + }; + { + LinearLayout; + gravity="center"; + layout_height="fill"; + paddingLeft="2%w"; + orientation="vertical"; + layout_width="20%w"; + { + TextView; + textSize="18sp"; + singleLine=true; + focusableInTouchMode=true; + text="编辑器"; + textColor="0xFF03A9F4"; + focusable=true; + id="xy22"; + layout_width="fill"; + ellipsize="marquee"; + }; + { + TextView; + layout_marginTop="2dp"; + singleLine="true"; + focusableInTouchMode=true; + text="main.lua"; + textColor="0xFF03A9F4"; + focusable=true; + id="xy33"; + layout_width="fill"; + ellipsize="end"; + }; + }; + { + LinearLayout; + layout_width="65%w"; + layout_height="match_parent"; + { + LinearLayout; + gravity="center"; + layout_width="13%w"; + layout_height="fill"; + { + ImageView; + ColorFilter="0xFF03A9F4"; + layout_height="30dp"; + src="res/ThomeLua2.png"; + layout_width="25dp"; + id="布局助手"; + }; + }; + { + LinearLayout; + gravity="center"; + layout_width="13%w"; + layout_height="fill"; + { + ImageView; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_height="30dp"; + src="res/ThomeLua3.png"; + layout_width="25dp"; + id="运行"; + }; + }; + { + LinearLayout; + gravity="center"; + layout_width="13%w"; + layout_height="fill"; + { + ImageView; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_height="30dp"; + src="res/ThomeLua4.png"; + layout_width="25dp"; + id="撤销"; + }; + }; + { + LinearLayout; + gravity="center"; + layout_width="13%w"; + layout_height="fill"; + { + ImageView; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_height="30dp"; + src="res/ThomeLua5.png"; + layout_width="25dp"; + id="恢复"; + }; + }; + { + LinearLayout; + gravity="center"; + layout_width="13%w"; + layout_height="fill"; + { + ImageView; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_height="30dp"; + src="res/ThomeLua6.png"; + layout_width="25dp"; + id="其他2x"; + }; + }; + }; + }; + { + LinearLayout; + layout_width="fill"; + id="选择代码1"; + visibility=8; + backgroundColor=颜色1; + layout_height="60dp"; + { + ImageView; + src="res3/1.png"; + id="XY01"; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_width="30dp"; + layout_marginLeft="10dp"; + layout_height="30dp"; + }; + { + TextView; + textSize="18sp"; + layout_gravity="center"; + textColor="0xFF03A9F4"; + layout_marginLeft="15dp"; + text="选择代码"; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + paddingRight="15dp", + gravity="right"; + { + ImageView; + src="res3/2.png"; + id="XY11"; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_width="29dp"; + layout_marginLeft="30dp"; + layout_height="29dp"; + }; + { + ImageView; + src="res3/3.png"; + id="XY21"; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_width="25dp"; + layout_marginLeft="25dp"; + layout_height="25dp"; + }; + { + ImageView; + src="res3/4.png"; + id="XY31"; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_width="25dp"; + layout_marginLeft="25dp"; + layout_height="25dp"; + }; + { + ImageView; + src="res3/5.png"; + id="XY41"; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_width="25dp"; + layout_marginLeft="25dp"; + layout_height="25dp"; + }; + }; + }; + { + LinearLayout; + layout_width="fill"; + id="转到"; + visibility=8; + backgroundColor=颜色1; + layout_height="60dp"; + { + ImageView; + src="res3/1.png"; + id="关闭转到"; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_width="30dp"; + layout_marginLeft="10dp"; + layout_height="30dp"; + }; + { + TextView; + textSize="16sp"; + layout_gravity="center"; + textColor="0xFF03A9F4"; + layout_marginLeft="15dp"; + text="转到"; + }; + { + LinearLayout; + layout_width="match_parent"; + gravity="right"; + layout_gravity="center"; + layout_height="match_parent"; + { + EditText; + textSize="15sp"; + id="转到行数"; + textColor=颜色4, + singleLine="true"; + layout_gravity="center"; + layout_width="140dp"; + gravity="center"; + }; + { + Button; + layout_width="70dp"; + textSize="12sp"; + id="确定转到"; + layout_height="match_parent"; + backgroundColor="0"; + textColor="0xFF03A9F4"; + layout_gravity="center"; + text="确定"; + }; + }; + }; + { + LinearLayout; + layout_width="fill"; + id="搜索"; + visibility=8; + backgroundColor=颜色1; + layout_height="60dp"; + { + ImageView; + src="res3/1.png"; + id="关闭搜索"; + ColorFilter="0xFF03A9F4"; + layout_gravity="center"; + layout_width="30dp"; + layout_marginLeft="10dp"; + layout_height="30dp"; + }; + { + TextView; + textSize="16sp"; + layout_gravity="center"; + textColor="0xFF03A9F4"; + layout_marginLeft="15dp"; + text="搜索"; + }; + { + LinearLayout; + layout_width="match_parent"; + gravity="right"; + layout_gravity="center"; + layout_height="match_parent"; + { + EditText; + textSize="15sp"; + id="搜索字符"; + textColor=颜色4, + singleLine="true"; + layout_gravity="center"; + layout_width="140dp"; + gravity="center"; + }; + { + Button; + layout_width="70dp"; + textSize="12sp"; + id="确定搜索"; + layout_height="match_parent"; + backgroundColor="0"; + textColor="0xFF03A9F4"; + layout_gravity="center"; + text="搜索"; + }; + }; + }; + { + LinearLayout; + layout_width="match_parent"; + layout_height="match_parent"; + layout_marginTop="60dp"; + { + DrawerLayout; + id="左侧滑"; + layout_width="fill"; + layout_height="fill"; + { + RelativeLayout; + id="cf", + { + LinearLayout; + orientation="vertical"; + layout_width="match_parent"; + + { + RelativeLayout; + layout_width="fill"; + backgroundColor=颜色1; + layout_height="4%h"; + + { + HorizontalScrollView; + horizontalScrollBarEnabled=false; + backgroundColor=颜色1; + id="cccc"; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + layout_width="fill"; + id="bar2"; + layout_height="fill"; + }; + + }; + { + LinearLayout; + layout_width="match_parent"; + id="错误提示"; + Visibility=8, + backgroundColor="0xFFFF0000"; + layout_height="4%h"; + { + TextView; + id="错误文字"; + layout_gravity="center"; + textColor="0xffffffff"; + layout_marginLeft="10dp"; + text="错误提示"; + }; + }; + }; + { + RelativeLayout; + layout_width="fill"; + backgroundColor=颜色1; + id="ccccc"; + layout_height="5%h"; + { + HorizontalScrollView; + horizontalScrollBarEnabled=false; + backgroundColor=颜色1; + id="cccccc"; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + layout_width="fill"; + id="bar3"; + layout_height="fill"; + + }; + }; + }; + { + LuaEditor; + TextSize="12sp"; + layout_width="fill"; + id="editor"; + backgroundColor=颜色5, + layout_height="fill"; + }; + }; + { + LinearLayout; + layout_width="fill"; + layout_height="6%h"; + layout_alignParentBottom="true"; + { + HorizontalScrollView; horizontalScrollBarEnabled=false; + backgroundColor=颜色1; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + layout_width="fill"; + id="bar"; + layout_height="fill"; + } + }; + }; + }; + { + LinearLayout; + layout_gravity="left", + layout_width="match_parent"; + background="0"; + layout_height="match_parent"; + { + LinearLayout; + layout_width="match_parent"; + layout_height="match_parent"; + { + LinearLayout; + layout_width="280dp"; + backgroundColor=颜色2; + orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_marginTop="10dp"; + layout_gravity="center"; + layout_height="50dp"; + layout_width="260dp"; + CardElevation=0; + radius=25; + backgroundColor=颜色1; + + { + LinearLayout; + layout_width="match_parent"; + gravity="center"; + orientation="vertical"; + layout_height="match_parent"; + id="ch", + { + TextView; + textColor=颜色4, + textSize="16sp"; + text="文件资源列表"; + }; + { + TextView; + textColor=颜色4, + ellipsize="marquee"; + focusableInTouchMode=true; + focusable=true; + singleLine=true; + layout_width="240dp", + layout_height="15dp"; + textSize="10sp"; + text="路径"; + layout_marginTop="5dp"; + id="cp"; + }; + }; + }; + { + ListView; + layout_height="fill"; + layout_width="fill"; + DividerHeight=0; + id="lv"; + layout_marginTop="5dp"; + }; + }; + }, + }; + }; + }; + }; +}; + +activity.setContentView(loadlayout(layout2)) +--隐藏标题栏() + +import "android.graphics.Typeface" +local Text_Type=Typeface.defaultFromStyle(Typeface.BOLD) +local sd = StateListDrawable() +import "android.graphics.Color" +import "android.content.res.ColorStateList" +import "android.graphics.drawable.RippleDrawable" +import "android.content.Context" +appt={C_Bacgg=function(mBinding,radiu,InsideColor,S,S2,T1) + local drawable = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{}); + drawable.setCornerRadius(radiu); + drawable.setColor(颜色5) + drawable.setStroke(3,0xCFB0B0B0) + drawable.setGradientType(GradientDrawable.RECTANGLE); + mBinding.setTextColor(T1) + mBinding.setTypeface(Text_Type) + return drawable + end} +美化按钮2=function(mBinding,radiu,InsideColor,T1) + stateList = { + {android.R.attr.state_pressed}, + {android.R.attr.state_focused}, + {android.R.attr.state_activated}, + {android.R.attr.selectableItemBackground}, + }; + sd.addState({ android.R.attr.state_enabled}, appt.C_Bacgg(mBinding,radiu,InsideColor,S,S2,T1)) + pressedColor =InsideColor --Color.parseColor("#7ab946ff"); + stateColorList ={ + pressedColor, + pressedColor, + pressedColor, + normalColor + }; + colorStateList = ColorStateList(stateList, stateColorList); + rippleDrawable = RippleDrawable(colorStateList,sd,nil); + mBinding.setBackground(rippleDrawable); +end + +local function ToStringEx(value) + switch type(value) + case 'table' + return TableToStr(value) + case 'string' + return "\'"..value.."\'" + default + return loadstring("return "..ts(value))() + end +end + +local function TableToStr(t) + switch t + case nil + return "" + end + local retstr= "{" + + local i = 1 + for key,value in pairs(t) do + local signal = "," + if i==1 then + signal = "" + end + + switch key + case i + retstr = retstr..signal..ToStringEx(value) + default + if type(key)=='number' or type(key) == 'string' then + retstr = retstr..signal..'['..ToStringEx(key).."]="..ToStringEx(value) + else + if type(key)=='userdata' then + retstr = retstr..signal.."*s"..TableToStr(getmetatable(key)).."*e".."="..ToStringEx(value) + else + retstr = retstr..signal..key.."="..ToStringEx(value) + end + end + end + + i = i+1 + end + retstr = retstr.."}" + local ret={} + table.insert(ret,retstr) + return ret[1] +end + +local function StrToTable(str) + if str == nil or type(str) ~= "string" then + return + end + return loadstring("return " .. str)() +end + +kj={} +kjk={} +kjkj={} +local close=io.close +项目名称,状态,项目名,多了个=... +local function file_exists(path) + local f=open(path,'r') + switch f + case nil + return false + default + close(f) + return true + end +end +local pn=activity.getPackageName +local tq={true} +local tq={pn()} +local function getCacheDir() + return ("/data/user/0/"..tq[1].."/cache/") +end +function checkBug(s) + switch 错误提示.visibility + case 0 + 错误提示.visibility=8 + end + local s = s or editor.getText().toString() + local _,data = load(s) + local alypath=项目名称.."/"..xy33.text + if alypath:find("%.aly$") then + s="return "..s + end + local _,data=load(s) + if data then + local _, _, line, data = data:find(".(%d+).(.+)") + 错误文字.text = "第" .. line .. "行:" .. data + 错误提示.visibility=0 + 错误提示.onClick=function() + editor.gotoLine(tointeger(line)) + end + return true + end +end +local edd=import "com.b.a.a.c"; +local onchange=import "com.b.a.a.f"; +local field=edd.getDeclaredField("K") +field.setAccessible(true) +local oldOnchange=field.get(editor) +field.set(editor,onchange{ + b=function(c,i,j) + oldOnchange.b(c,i,j) + checkBug() + return true + end, + a=function(c,i,j) + oldOnchange.a(c,i,j) + task(10,checkBug) + end +}) + +checkBug() + +switch file_exists(getCacheDir().."/"..项目名.."-X") + case false + local luaconf = getCacheDir().."/"..项目名.."-X" open(luaconf,"w"):write([[luaname="]]..xy33.text..[["]]..'\nluapath="'..项目名称.."/"..xy33.text..[["]]..'\nlast='..editor.getSelectionEnd()):close() + pcall(dofile,luaconf) + editor.text=open(luapath):read("*a") + xy33.text=luaname + checkBug() + + default + switch open(getCacheDir().."/"..项目名.."-X"):read("*a") + case "" + local luaconf = getCacheDir().."/"..项目名.."-X" + open(luaconf,"w"):write([[luaname="]]..xy33.text..[["]]..'\nluapath="'..项目名称.."/"..xy33.text..[["]]..'\nlast='..editor.getSelectionEnd()):close() + + pcall(dofile,luaconf) + editor.text=open(luapath):read("*a") + xy33.text=luaname + checkBug() + + default + local luaconf = getCacheDir().."/"..项目名.."-X" + pcall(dofile,luaconf) + editor.text=open(luapath):read("*a") + xy33.text=luaname + checkBug() + + end +end +switch file_exists(getCacheDir().."/"..项目名.."-X") + case true + local luaconf = getCacheDir().."/"..项目名.."-X" + pcall(dofile,luaconf) + switch luapath + case 项目名称.."/"..xy33.text + editor.setSelection(last) + default + local luaconf = getCacheDir().."/"..项目名.."-X" + open(luaconf,"w"):write([[luaname="]]..xy33.text..[["]]..'\nluapath="'..项目名称.."/"..xy33.text..[["]]..'\nlast='..editor.getSelectionEnd()):close() + end + default + local luaconf = getCacheDir().."/"..项目名.."-X" + open(luaconf,"w"):write([[luaname="]]..xy33.text..[["]]..'\nluapath="'..项目名称.."/"..xy33.text..[["]]..'\nlast='..editor.getSelectionEnd()):close() +end +local 快捷文件列表 = {} +是否在项目目录 = true +function 返回当前路径() + for i=1,#快捷文件列表 do + if ts(File(快捷文件列表[i]).Name) == xy33.text then + if ts(File(快捷文件列表[i]).getParentFile()) == 项目名称 then + if 是否在项目目录 == true then + return ts(快捷文件列表[i]) + end + else + if 是否在项目目录 == false then + return ts(快捷文件列表[i]) + end + end + end + end + return 项目名称.."/"..xy33.text +end +switch file_exists("/sdcard/ThomeLua/cache/") + case true + default + os.execute("mkdir /sdcard/ThomeLua/cache") +end +function 保存() + local json = require "cjson" + --写入文件(返回当前路径(),editor.text) + open(返回当前路径(),"w"):write(editor.text):close() + local test = open(getCacheDir().."/"..项目名..".ini","w") + result = json.encode(kjkj) + test:write(项目名.."!!"..result.."!!".."\n") + test:close() + 写入文件("/sdcard/ThomeLua/cache/"..File(项目名称).Name..".lua",TableToStr(快捷文件列表)) +end +function save() + open(项目名称.."/"..xy33.text,"w"):write(editor.text):close() + +end + + +function 初始化快捷栏() + local 缓存路径 = "/storage/emulated/0/ThomeLua/cache/"..File(项目名称).Name..".lua" + switch file_exists(缓存路径) + case false + table.insert(快捷文件列表,项目名称.."/main.lua") + table.insert(快捷文件列表,项目名称.."/init.lua") + default + local 内容 = open(缓存路径):read("*a") + switch 内容 + case "" + table.insert(快捷文件列表,项目名称.."/main.lua") + table.insert(快捷文件列表,项目名称.."/init.lua") + default + switch 内容 + case nil + table.insert(快捷文件列表,项目名称.."/main.lua") + table.insert(快捷文件列表,项目名称.."/init.lua") + default + 快捷文件列表 = StrToTable(内容) + end + end + end + 加载快捷栏() +end + +function 加载快捷栏() + bar3.removeAllViews() + for i数量 = 1,#快捷文件列表 do + local 快捷文件布局字体颜色 = 颜色4 + local 表文件 = File(快捷文件列表[i数量]) + if ts(表文件.Name) == xy33.text then + if (ts(表文件.getParentFile()) != ts(项目名称)) then + switch 是否在项目目录 + case false + 快捷文件布局字体颜色 = 0xFF03A9F4 + end + else + switch 是否在项目目录 + case true + 快捷文件布局字体颜色 = 0xFF03A9F4 + end + end + end + local 快捷文件布局文字 = 表文件.Name + if (ts(表文件.getParentFile()) != ts(项目名称)) then + 快捷文件布局文字 = ts(表文件.getParentFile().Name).."/"..表文件.Name + end + 是否隐藏 = 8 + if 快捷文件布局字体颜色 == 0xFF03A9F4 then + 是否隐藏 = 0 + else + 是否隐藏 = 8 + end + button3={ + LinearLayout; + layout_height="5%h"; + orientation="vertical"; + paddingLeft="3%w"; + id="sssssw", + layout_width="wrap_content"; + paddingRight="3%w"; + gravity="center"; + { + TextView; + text=快捷文件布局文字; + gravity="center"; + textColor=快捷文件布局字体颜色, + layout_width="match_parent"; + }; + { + TextView; + layout_height="2dp"; + id="scrollbar"; + Visibility=是否隐藏, + text=快捷文件布局文字.."@"; + layout_marginTop="2dp"; + layout_width="wrap_content"; + backgroundColor=快捷文件布局字体颜色; + }; + }; + m3=loadlayout(button3) + bar3.addView(m3) + 波纹(sssssw,0xE7EAEEEE) + m3.onClick=function(v) + 保存() + if (ts(表文件.getParentFile()) != ts(项目名称)) then + 是否在项目目录 = false + else + 是否在项目目录 = true + end editor.text=open(ts(快捷文件列表[i数量])):read("*a") + xy33.text=ts(表文件.Name) + 加载快捷栏() + end + m3.onLongClick=function(v) + 保存() + local cj={ + CardView; + radius=30; + layout_width="match_parent"; + + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="350dp"; + layout_width="match_parent"; + --backgroundColor=颜色1, + --radius=20; + { + TextView; + layout_marginTop="15dp"; + text="标签操作"; + layout_marginLeft="20dp"; + textColor="0xFF03A9F4"; + textSize="20sp"; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + { + Button; + textColor="0x7E000000"; + layout_gravity="center"; + text="关闭标签"; + layout_height="40dp"; + layout_marginBottom="5dp"; + id="关闭标签"; + layout_marginLeft="10dp"; + }; + + { + Button; + layout_marginLeft="20dp"; + textColor="0xFF03A9F4"; + text="重命名文件"; + layout_height="40dp"; + layout_marginBottom="5dp"; + id="重命名文件"; + layout_gravity="center"; + }; + + + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + gravity="right"; + { + Button; + layout_marginRight="10dp"; + textColor="0xFF03A9F4"; + text="删除文件"; + layout_height="40dp"; + layout_marginBottom="5dp"; + id="删除文件"; + layout_gravity="center"; + + }; + }; + }; + }; + }; + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(cj)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + local x=nil + 美化按钮2(关闭标签,10,0x7E000000,颜色7) + 美化按钮2(重命名文件,10,0x7E000000,颜色7) + 美化按钮2(删除文件,10,0x7E000000,颜色7) + function 关闭标签.onClick() + if ts(表文件.getParentFile()) == 项目名称 then + switch 表文件.Name + case "main.lua" + print("请勿关闭main.lua") + dialog1.dismiss() + case "init.lua" + print("请勿关闭init.lua") + dialog1.dismiss() + case xy33.text + print("请勿关闭正在编辑的文件") + dialog1.dismiss() + default + table.remove(快捷文件列表,i数量) + 加载快捷栏() + print("关闭成功") + dialog1.dismiss() + end + else + table.remove(快捷文件列表,i数量) + 加载快捷栏() + print("关闭成功") + dialog1.dismiss() + end + end + function 删除文件.onClick() + if ts(表文件.getParentFile()) == 项目名称 then + switch 表文件.Name + case "main.lua" + print("请勿删除main.lua") + dialog1.dismiss() + case "init.lua" + print("请勿删除init.lua") + dialog1.dismiss() + case xy33.text + print("请勿删除正在编辑的文件") + dialog1.dismiss() + default + local luaconf = luajava.luadir.."/"..项目名.."-X" + pcall(dofile,luaconf) + os.execute("rm -r "..快捷文件列表[i数量]) + table.remove(快捷文件列表,i数量) + 加载快捷栏() + print("删除成功") + dialog1.dismiss() + end + else + local luaconf = luajava.luadir.."/"..项目名.."-X" + pcall(dofile,luaconf) + os.execute("rm -r "..快捷文件列表[i数量]) + table.remove(快捷文件列表,i数量) + 加载快捷栏() + print("删除成功") + dialog1.dismiss() + end + end + function 重命名文件.onClick() + dialog1.dismiss() + local cmm={ + CardView; + radius=30; + layout_width="match_parent"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="350dp"; + layout_width="match_parent"; + backgroundColor=颜色1, + radius=20; + { + TextView; + layout_marginTop="15dp"; + text="重命名"; + layout_marginLeft="20dp"; + textColor="0xFF03A9F4"; + textSize="20sp"; + }; + { + LinearLayout; + layout_height="180dp"; + layout_width="match_parent"; + orientation="horizontal"; + gravity="center"; + { + EditText; + layout_width="150dp"; + hint="请输入文件名称"; + textSize="15sp"; + --hintTextColor=颜色3, + textColor=颜色3, + id="输入文件名称"; + gravity="center"; + }; + { + Spinner; + layout_marginLeft="10dp"; + items={ + ".lua"; + ".aly"; + ".txt"; + }; + id="类型"; + layout_gravity="center"; + }; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + { + Button; + textColor="0x7E000000"; + layout_gravity="center"; + text="取消"; + layout_height="40dp"; + layout_marginBottom="5dp"; + id="取消"; + layout_marginLeft="10dp"; + }; + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + gravity="right"; + { + Button; + layout_marginRight="10dp"; + textColor="0xFF03A9F4"; + text="重命名"; + layout_height="40dp"; + layout_marginBottom="5dp"; + id="重命名"; + layout_gravity="center"; + }; + }; + }; + }; + }; + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(cmm)); + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + local x=nil + 美化按钮2(取消,10,0x7E000000,颜色7) + 美化按钮2(重命名,10,0x7E000000,颜色7) + 控件圆角(输入文件名称,颜色2,30) + 类型.onItemSelected=function(l,v,p,i) + x=v.text + end + function 取消.onClick() + dialog1.dismiss() + end + function 重命名.onClick() + if ts(表文件.getParentFile()) == 项目名称 then + switch 表文件.Name + case "main.lua" + print("请勿重命名main.lua") + dialog1.dismiss() + case "init.lua" + print("请勿重命名init.lua") + dialog1.dismiss() + case xy33.text + print("请勿重命名正在编辑的文件") + dialog1.dismiss() + default + os.execute("mv "..快捷文件列表[i数量].." "..ts(表文件.getParentFile()).."/"..输入文件名称.Text..x) + 快捷文件列表[i数量] = ts(表文件.getParentFile()).."/"..输入文件名称.Text..x + 加载快捷栏() + 刷新路径(项目名称) + print("重命名成功") + dialog1.dismiss() + end + else + os.execute("mv "..快捷文件列表[i数量].." "..ts(表文件.getParentFile()).."/"..输入文件名称.Text..x) + 快捷文件列表[i数量] = ts(表文件.getParentFile()).."/"..输入文件名称.Text..x + 加载快捷栏() + 刷新路径(项目名称) + print("重命名成功") + dialog1.dismiss() + end + end + end + end + end +end +初始化快捷栏() + +--[[ti=Ticker() +ti.Period=480000 +ti.onTick=function() + 保存() + local a=File(项目名称).getName() + LuaUtil.copyDir(项目名称,备份文件夹.."/"..a) + ZipUtil.zip(备份文件夹.."/"..a,备份文件夹) + LuaUtil.rmDir(File(备份文件夹.."/"..a)) + File(备份文件夹.."/"..a..".zip").renameTo(File(备份文件夹.."/"..a.."_"..os.date("%Y%m%d%H%M%S")..".alp")) + print("备份成功"..备份文件夹.."/"..a.."_"..os.date("%Y%m%d%H%M%S")..".alp") + +end]] +--[[function 是否备份() + local a=open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") + local b=a:match("3(.-)"..'"') + if b=="开" then + ti.start() + else + ti.stop() + end +end]] +local itemq={ + LinearLayout; + background="0"; + layout_width="match_parent"; + layout_height="match_parent"; + { + LinearLayout; + layout_width="match_parent"; + gravity="center"; + layout_height="match_parent"; + { + LinearLayout; + layout_width="280dp"; + gravity="center"; + orientation="vertical"; + layout_height="60dp"; + { + CardView; + backgroundColor=颜色1; + CardElevation="0dp"; + radius=25; + layout_width="260dp"; + layout_height="50dp"; + { + LinearLayout; + layout_width="fill"; + gravity="center"; + layout_height="match_parent"; + { + LinearLayout; + layout_width="50dp"; + gravity="center"; + layout_height="match_parent"; + { + ImageView; + layout_width="35dp"; + src="res2/file.png"; + id="wjlx"; + ColorFilter=颜色6, + layout_height="35dp"; + }; + }; + { + LinearLayout; + layout_width="match_parent"; + layout_height="match_parent"; + { + TextView; + textColor=颜色4, + id="wjm", + layout_gravity="center"; + text="main.lua"; + textSize="15sp"; + }; + { + TextView; + --textColor=颜色4, + id="sb", + --layout_gravity="center"; + --text=""; + textSize="0sp"; + }; + + }; + }; + }; + }; + }; +}; + + + + +function indexOf(list, target, from, useMaxN) + local len = (useMaxN and #list) or table.maxn(list) + if from == nil then + from = 1 + end + for i = from, len do + if list[i] == target then + return i + end + end + return -1 +end + + + + + + + + +function strippath(filename) + return string.match(filename, ".+/([^/]*%.%w+)$") +end +function isintable(value,tb) + for k,v in pairs(tb) do + switch v + case value + return true + end + end + return false +end + +function 是否有此文件(hh路径) + for i = 1,#快捷文件列表 do + local kjkjkj= ts(快捷文件列表[i]) + local jkjkjk=ts(hh路径) + switch kjkjkj + case jkjkjk + return true + end + end + return false +end + +function 刷新路径(StartPath) + --创建项目数组 + data={} + adpq=LuaAdapter(activity,data,itemq) + lv.setAdapter(adpq) + function SetItem(path) + path=ts(path) + adpq.clear()--清空适配器 + cp.Text=ts(path)--设置当前路径 + if path~=ts(项目名称) then--不是根目录则加上../ + adpq.add{wjm="返回上级目录",wjlx="res2/folder.png",sb="返回"} + end + ls=File(path).listFiles() + if ls~=nil then + ls=luajava.astable(File(path).listFiles()) --全局文件列表变量 + table.sort(ls,function(a,b) + return (a.isDirectory()~=b.isDirectory() and a.isDirectory()) or ((a.isDirectory()==b.isDirectory()) and a.Name1 do + output.write(b,0,l) + l=input.read(b) + end]] + end + local function copy2(input, output) + LuaUtil.copyFile(input, output) + end + local temp = File(apkpath).getParentFile(); + if (not temp.exists()) then + + if (not temp.mkdirs()) then + + error("create file " .. temp.getName() .. " fail"); + end + end + + local tmp = luajava.luadir.. "/tmp.apk" + local info = activity.getApplicationInfo() + local ver = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionName + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + + --local zip=ZipFile(info.publicSourceDir) + local zipFile = File(info.publicSourceDir) + local fis = FileInputStream(zipFile); + --local checksum = CheckedInputStream(fis, Adler32()); + local zis = ZipInputStream(BufferedInputStream(fis)); + + local fot = FileOutputStream(tmp) + --local checksum2 = CheckedOutputStream(fot, Adler32()); + local out = ZipOutputStream(BufferedOutputStream(fot)) + local f = File(luapath) + local errbuffer = {} + local replace = {} + local checked = {} + local lualib = {} + local md5s = {} + local libs = File(activity.ApplicationInfo.nativeLibraryDir).list() + libs = luajava.astable(libs) + for k, v in ipairs(libs) do + --libs[k]="lib/armeabi/"..libs[k] + replace[v] = true + end + + local mdp = activity.Application.MdDir + local function getmodule(dir) + local mds = File(activity.Application.MdDir .. dir).listFiles() + mds = luajava.astable(mds) + for k, v in ipairs(mds) do + if mds[k].isDirectory() then + getmodule(dir .. mds[k].Name .. "/") + else + mds[k] = "lua" .. dir .. mds[k].Name + replace[mds[k]] = true + end + end + end + + getmodule("/") + + local function checklib(path) + if checked[path] then + return + end + local cp, lp + checked[path] = true + local f = open(path) + local s = f:read("*a") + f:close() + for m, n in s:gmatch("require *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + for m, n in s:gmatch("import *%(? *\"([%w_]+)%.?([%w_]*)") do + cp = string.format("lib%s.so", m) + if n ~= "" then + lp = string.format("lua/%s/%s.lua", m, n) + m = m .. '/' .. n + else + lp = string.format("lua/%s.lua", m) + end + if replace[cp] then + replace[cp] = false + end + if replace[lp] then + checklib(mdp .. "/" .. m .. ".lua") + replace[lp] = false + lualib[lp] = mdp .. "/" .. m .. ".lua" + end + end + end + + replace["libluajava.so"] = false + function isintable(value,tb) + for k,v in pairs(tb) do + switch v + case value + return true + end + end + return false + end + + function strippath(filename) + return string.match(filename, ".+/([^/]*%.%w+)$") + end + function stripextension(filename) + local idx = filename:match(".+()%.%w+$") + if(idx) then + return filename:sub(1, idx-1) + else + return filename + end + end + function getExtension(str) + return str:match(".+%.(%w+)$") + end + local function addDir(out, dir, f) + local entry = ZipEntry("assets/" .. dir) + out.putNextEntry(entry) + local ls = f.listFiles() + for n = 0, #ls - 1 do + local name = ls[n].getName() + if name==(".using") then + checklib(luapath .. dir .. name) + elseif name:find("%.apk$") or name:find("%.luac$") or name:find("^%.") then + elseif name:find("%.lua$") then + checklib(luapath .. dir .. name) + switch skip_compilation + case nil + path=build(luapath..dir..name) + default + switch isintable(dir..name,skip_compilation) + case true + local readlua=open(luapath..dir..name):read("*a") + open(luapath..dir..name.."c","w"):write(readlua):close() + path=luapath..dir..name.."c" + default + path=build(luapath..dir..name) + end + end + if path then + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif name:find("%.aly$") then + switch skip_compilation + case nil + path=build_aly(luapath..dir..name) + default + switch isintable(dir..name,skip_compilation) + case true + local readlua=open(luapath..dir..name):read("*a") + open(luapath..dir..name.."c","w"):write(stripextension(strippath(luapath..dir..name)).."="..readlua):close() + path=luapath..dir..name.."c" + default + path=build_aly(luapath..dir..name) + end + end + if path then + name = name:gsub("aly$", "lua") + if replace["assets/" .. dir .. name] then + table.insert(errbuffer, dir .. name .. "/.aly") + end + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + + replace["assets/" .. dir .. name] = true + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + elseif ls[n].isDirectory() then + addDir(out, dir .. name .. "/", ls[n]) + else + local entry = ZipEntry("assets/" .. dir .. name) + out.putNextEntry(entry) + replace["assets/" .. dir .. name] = true + copy(FileInputStream(ls[n]), out) + table.insert(md5s, LuaUtil.getFileMD5(ls[n])) + end + end + end + + + this.update("正在编译..."); + if f.isDirectory() then + require "permission" + dofile(luapath .. "init.lua") + if user_permission then + for k, v in ipairs(user_permission) do + user_permission[v] = true + end + end + + + local ss, ee = pcall(addDir, out, "", f) + if not ss then + table.insert(errbuffer, ee) + end + --print(ee,dump(errbuffer),dump(replace)) + + + local wel = File(luapath .. "icon.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/icon.png") + out.putNextEntry(entry) + replace["res/drawable/icon.png"] = true + copy(FileInputStream(wel), out) + end + local wel = File(luapath .. "welcome.png") + if wel.exists() then + local entry = ZipEntry("res/drawable/welcome.png") + out.putNextEntry(entry) + replace["res/drawable/welcome.png"] = true + + copy(FileInputStream(wel), out) + end + else + return "error" + end + + --print(dump(lualib)) + for name, v in pairs(lualib) do + local path, err = build(v) + if path then + local entry = ZipEntry(name) + out.putNextEntry(entry) + copy(FileInputStream(File(path)), out) + table.insert(md5s, LuaUtil.getFileMD5(path)) + os.remove(path) + else + table.insert(errbuffer, err) + end + end + + apkpath="/storage/emulated/0/ThomeLua/bin/"..appname.."_"..appver..".apk" + function touint32(i) + local code = string.format("%08x", i) + local uint = {} + for n in code:gmatch("..") do + table.insert(uint, 1, string.char(tonumber(n, 16))) + end + return table.concat(uint) + end + + this.update("正在打包..."); + local entry = zis.getNextEntry(); + while entry do + local name = entry.getName() + local lib = name:match("([^/]+%.so)$") + if replace[name] then + elseif lib and replace[lib] then + elseif name:find("^assets/") then + elseif name:find("^lua/") then + elseif name:find("META%-INF") then + else + local entry = ZipEntry(name) + out.putNextEntry(entry) + if entry.getName() == "AndroidManifest.xml" then + if path_pattern and #path_pattern > 1 then + path_pattern = ".*\\\\." .. path_pattern:match("%w+$") + end + local list = ArrayList() + local xml = AXmlDecoder.read(list, zis) + local req = { + [activity.getPackageName()] = packagename, + [info.nonLocalizedLabel] = appname, + [ver] = appver, + [".*\\\\.alp"] = path_pattern or "", + [".*\\\\.lua"] = "", + [".*\\\\.luac"] = "", + } + for n = 0, list.size() - 1 do + local v = list.get(n) + if req[v] then + list.set(n, req[v]) + elseif user_permission then + local p = v:match("%.permission%.([%w_]+)$") + if p and (not user_permission[p]) then + list.set(n, "android.permission.UNKNOWN") + end + end + end + local pt = activity.getLuaPath(".tmp") + local fo = FileOutputStream(pt) + xml.write(list, fo) + local code = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode + fo.close() + local f = open(pt) + local s = f:read("a") + f:close() + s = string.gsub(s, touint32(code), touint32(tointeger(appcode) or 1),1) + s = string.gsub(s, touint32(18), touint32(tointeger(appsdk) or 18),1) + + local f = open(pt, "w") + f:write(s) + f:close() + local fi = FileInputStream(pt) + copy(fi, out) + os.remove(pt) + elseif not entry.isDirectory() then + copy2(zis, out) + end + end + entry = zis.getNextEntry() + end + out.setComment(table.concat(md5s)) + --print(table.concat(md5s,"/n")) + zis.close(); + out.closeEntry() + out.close() + + if #errbuffer == 0 then + this.update("正在签名..."); + os.remove(apkpath) + Signer.sign(tmp, apkpath) + os.remove(tmp) + activity.installApk(apkpath) + --[[import "android.net.*" + import "android.content.*" + i = Intent(Intent.ACTION_VIEW); + i.setDataAndType(activity.getUriForFile(File(apkpath)), "application/vnd.android.package-archive"); + i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + this.update("正在打开..."); + activity.startActivityForResult(i, 0);]] + return "打包成功:" .. apkpath + else + os.remove(tmp) + this.update("打包出错:\n " .. table.concat(errbuffer, "\n")); + return "打包出错:\n " .. table.concat(errbuffer, "\n") + end + end + luabindir=activity.getLuaExtDir("bin") + local function bin(path) + local p = {} + local e, s = pcall(function()dofile(path .. "init.lua")end) + if e then + create_error_dlg2() + create_bin_dlg() + bin_dlg.show() + activity.newTask(binapk, update, callback).execute { path, activity.getLuaExtPath("bin", appname .. "_" .. appver .. ".apk") } + else + Toast.makeText(activity, "工程配置文件错误." .. s, Toast.LENGTH_SHORT).show() + end + end + + + bin(项目名称.."/") + end + if i=="属性" then + 保存() + x90=open(项目名称.."/init.lua"):read("*a") + if x90:find("appname") then + x91=x90:match('appname="(.-)"') + end + if x90:find("appcode") then + x92=x90:match('appcode="(.-)"') + end + if x90:find("appver") then + x93=x90:match('appver="(.-)"') + end + if x90:find("appsdk") then + x94=x90:match('appsdk="(.-)"') + end + if x90:find("packagename") then + x95=x90:match('packagename="(.-)"') + end + if x90:find("rue") or x90:find("tru") then + x96="开" + end + if x90:find("user_permission") then + x97=x90:match('user_permission={(.-)}') + end + if x90:find("skip_compilation") then + x99=x90:match('skip_compilation={(.-)}') + end + x98=项目名称.."/init.lua" + x0=open(项目名称.."/init.lua"):read("*a") + activity.newActivity("main5",android.R.anim.fade_in,android.R.anim.fade_out,{ + true, + x0, + x91, + x92, + x93, + x94, + x95, + x96, + x97, + x98, + 项目名, + x99, + }) + end + if i=="分析" then + + --print(项目名称.."/"..xy33.text) + activity.newActivity("javaapi/fiximport",{项目名称.."/",项目名称.."/"..xy33.text}) + end + if i=="搜索" then + 保存() + editor.search() + --搜索.setVisibility(0) + end + if i=="插件" then + 保存() + import "java.io.*" + if File("/sdcard/ThomeLua/plugin/").isDirectory()then + activity.newActivity("plugin/main", {项目名称.."/",项目名称.."/"..xy33.text}) + else + os.execute("mkdir /sdcard/ThomeLua/plugin/") + activity.newActivity("plugin/main", {项目名称.."/",项目名称.."/"..xy33.text}) + end + end + + if i=="跳转" then + 保存() + if 转到.Visibility==8 then + 转到.setVisibility(0) + else + 转到.setVisibility(8) + end + end + if i=="布局" then + 保存() + if xy33.text:find("%.aly$") then + activity.newActivity("main9",android.R.anim.fade_in,android.R.anim.fade_out,{项目名称.."/"..xy33.text,项目名称}) + function onResult(a,b) + if a=="main9" then + editor.text=open(项目名称.."/"..xy33.text):read("*a") + end + end + else + print("请选择aly文件") + end + end + if i=="格式" then + editor.format() + 保存() + end + if i=="编译" then + 保存() + -- module(...,package.seeall) + --by nirenr + + local function ps(str) + str = str:gsub("%b\"\"",""):gsub("%b\'\'","") + local _,f= str:gsub ('%f[%w]function%f[%W]',"") + local _,t= str:gsub ('%f[%w]then%f[%W]',"") + local _,i= str:gsub ('%f[%w]elseif%f[%W]',"") + local _,d= str:gsub ('%f[%w]do%f[%W]',"") + local _,e= str:gsub ('%f[%w]end%f[%W]',"") + local _,r= str:gsub ('%f[%w]repeat%f[%W]',"") + local _,u= str:gsub ('%f[%w]until%f[%W]',"") + local _,a= str:gsub ("{","") + local _,b= str:gsub ("}","") + return (f+t+d+r+a)*4-(i+e+u+b)*4 + end + + + local function _format() + local p=0 + return function(str) + str=str:gsub("[ \t]+$","") + str=string.format('%s%s',string.rep(' ',p),str) + p=p+ps(str) + return str + end + end + + + function format(Text) + local t=os.clock() + local Format=_format() + Text=Text:gsub('[ \t]*([^\r\n]+)',function(str)return Format(str)end) + print('操作完成,耗时:'..os.clock()-t) + return Text + end + + + function build(path) + if path then + local str,st=loadfile(path) + if st then + return nil,st + end + local path=path..'c' + + local st,str=pcall(string.dumpThomeLua,str,true) + if st then + f=open(path,'wb') + f:write(str) + f:close() + return path + else + os.remove(path) + return nil,str + end + end + end + + function build_aly(path2) + if path2 then + local f,st=open(path2) + if st then + return nil,st + end + local str=f:read("*a") + f:close() + str=string.format("local layout=%s\nreturn layout",str) + local path=path2..'c' + str,st=loadstring(str,path2:match("[^/]+/[^/]+$"),"bt") + if st then + return nil,st:gsub("%b[]",path2,1) + end + + local st,str=pcall(string.dumpThomeLua,str,true) + if st then + f=open(path,'wb') + f:write(str) + f:close() + return path + else + os.remove(path) + return nil,str + end + end + end + local 路径,错误=build(项目名称.."/"..xy33.text) + if 路径 then + print("编译成功"..路径) + else + print("编译失败"..错误) + end + + + end + end +end + +if 状态==true then + 刷新路径(项目名称) + --是否备份() + --print(项目名称) + editor.text=open(项目名称.."/main.lua"):read("*a") +end +activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) +local ab=open(activity.getLuaDir().."/Verify/set5.XY"):read("*a") +local abc=open(activity.getLuaDir().."/Verify/set6.XY"):read("*a") +local abcd=open(activity.getLuaDir().."/Verify/set7.XY"):read("*a") +local abcde=open(activity.getLuaDir().."/Verify/set8.XY"):read("*a") +local abcdef=open(activity.getLuaDir().."/Verify/set9.XY"):read("*a") +local abcdefg=open(activity.getLuaDir().."/Verify/set10.XY"):read("*a") +local abcdefgh=open(activity.getLuaDir().."/Verify/set11.XY"):read("*a") +local abcdefghi=open(activity.getLuaDir().."/Verify/set12.XY"):read("*a") +local abcdefghij=open(activity.getLuaDir().."/Verify/set13.XY"):read("*a") +local bj=open(activity.getLuaDir().."/Verify/setb.XY"):read("*a") +local bbl=open(activity.getLuaDir().."/Verify/setbb.XY"):read("*a") +switch abc + case "颜色1" + abc=颜色1 + default + abc=tonumber(abc) +end +switch abcdef + case "颜色3" + abcdef=颜色3 + default + abcdef=tonumber(abcdef) +end +switch bj + case "颜色5" + bj=颜色5 + default + bj=tonumber(bj) +end +switch bbl + case "颜色1" + bbl=颜色1 + default + bbl=tonumber(bbl) +end +editor.backgroundColor=bj +--c.backgroundColor=bbl +cc.backgroundColor=bbl +ccc.backgroundColor=bbl +cccc.backgroundColor=bbl +ccccc.backgroundColor=bbl +cccccc.backgroundColor=bbl +选择代码1.backgroundColor=bbl +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(bbl); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +editor.setBasewordColor(tonumber(ab))--基词 +editor.setPanelBackgroundColor(tonumber(abc))--卡片颜色 +editor.setPanelTextColor(tonumber(abcd))--卡片字体颜色 +editor.setStringColor(tonumber(abcde))--字符串颜色 +editor.setTextColor(tonumber(abcdef))--文本颜色 +editor.setUserwordColor(tonumber(abcdefg))--数字 +editor.setCommentColor(tonumber(abcdefgh))--注释颜色 +editor.setKeywordColor(tonumber(abcdefghi))--if then等 +switch abcdefghij + case "true" + editor.setWordWrap(true) + case true + editor.setWordWrap(true) +end +hs={"删除文件()"} +editor.addNames(hs) +fh=open(activity.getLuaDir().."/Verify/set2.XY"):read("*a") +for t,c in fh:gmatch("(.-) ") do + button={ + Button; + text=ts(t); + layout_width="45dp"; + layout_height="fill"; + background="#ffffff"; + textColor=0xFF03A9F4; + padding="5dp", + id="sssss", + }; + m=loadlayout(button) + bar.addView(m) + 波纹(sssss,0xE7EAEEEE) + m.onClick=function(v) + if v.text=="Fun" or v.text=="fun" or v.text=="function" or v.text=="Function" then + editor.paste("function") + checkBug() + else + if v.text=="End" or v.text=="end" then + editor.paste("end") + checkBug() + else + editor.paste(v.Text) + checkBug() + end + end + end + m.onLongClick=function(v) + if v.text=="Fun" or v.text=="fun" or v.text=="function" or v.text=="Function" then + editor.paste("function") + checkBug() + else + if v.text=="End" or v.text=="end" then + editor.paste("end") + checkBug() + else + editor.paste(v.Text..v.text) + checkBug() + end + end + return true + end +end +editor.OnSelectionChangedListener=function(a,b,c) + if a==true then + 其他2x.setVisibility(View.GONE) + 恢复.setVisibility(View.GONE) + 撤销.setVisibility(View.GONE) + 运行.setVisibility(View.GONE) + 布局助手.setVisibility(View.GONE) + 其他1x.setVisibility(View.GONE) + 选择代码1.setVisibility(0) + else + 其他2x.setVisibility(View.VISIBLE) + 恢复.setVisibility(View.VISIBLE) + 撤销.setVisibility(View.VISIBLE) + 运行.setVisibility(View.VISIBLE) + 布局助手.setVisibility(View.VISIBLE) + 其他1x.setVisibility(View.VISIBLE) + 选择代码1.setVisibility(8) + end +end +function XY01.onClick() + 其他2x.setVisibility(View.VISIBLE) + 恢复.setVisibility(View.VISIBLE) + 撤销.setVisibility(View.VISIBLE) + 运行.setVisibility(View.VISIBLE) + 布局助手.setVisibility(View.VISIBLE) + 其他1x.setVisibility(View.VISIBLE) + 选择代码1.setVisibility(8) +end +function XY11.onClick() + editor.selectAll() + 保存() +end +function XY21.onClick() + editor.cut() + 保存() +end +function XY31.onClick() + editor.copy() + 保存() +end +function XY41.onClick() + editor.paste() + 保存() +end +波纹(XY11,0xFFD9D9D9) +波纹(XY21,0xFFD9D9D9) +波纹(XY31,0xFFD9D9D9) +波纹(XY41,0xFFD9D9D9) +波纹(撤销,0xFFD9D9D9) +波纹(恢复,0xFFD9D9D9) +波纹(布局助手,0xFFD9D9D9) +波纹(其他1x,0xFFD9D9D9) +波纹(其他2x,0xFFD9D9D9) +波纹(运行,0xFFD9D9D9) +波纹(确定转到,0xFFD9D9D9) + +function 确定转到.onClick() + 保存() + if #转到行数.text~=0 then + editor.gotoLine(tointeger(转到行数.text)) + end +end +function 关闭转到.onClick() + 保存() + 转到.setVisibility(8) +end + +--[[function 确定搜索.onClick() + 保存() + if #转到行数.text~=0 then + editor.gotoLine(tointeger(转到行数.text)) + end +end +function 关闭搜索.onClick() + 保存() + 搜索.setVisibility(8) +end]] + +--[[ti1=Ticker() +ti1.Period=100 +ti1.onTick=function() + 保存()]] +--[[错误提示.setVisibility(View.GONE) + local cc=editor.getText() + luapath=项目名称.."/"..xy33.text + cc=cc.toString() + if luapath:find("%.aly$") then + cc="return "..cc + end + local _,data=loadstring(cc) + if data then + 错误提示.setVisibility(View.VISIBLE) + local _,_,line,data=data:find(".(%d+).(.+)") + 错误文字.text="第"..line.."行 "..data + return true + elseif b then + else + 错误提示.setVisibility(View.GONE) + end]] +--end + +function reopen(path) + local f = open(path, "r") + if f then + local str = f:read("*all") + if ts(editor.getText()) ~= str then + editor.setText(str, true) + checkBug() + end + f:close() + end +end +function onStart() + reopen(项目名称.."/"..xy33.text) + checkBug() + local luaconf = getCacheDir().."/"..项目名.."-X" + pcall(dofile,luaconf) + switch luapath + case 项目名称.."/"..xy33.text + editor.setSelection(last) + end + if isupdate then + editor.format() + checkBug() + local luaconf = getCacheDir().."/"..项目名.."-X" + pcall(dofile,luaconf) + switch luapath + case 项目名称.."/"..xy33.text + editor.setSelection(last) + end + end + isupdate = false +end +function onStop() + 保存() + local luaconf = getCacheDir().."/"..项目名.."-X" open(luaconf,"w"):write([[luaname="]]..xy33.text..[["]]..'\nluapath="'..项目名称.."/"..xy33.text..[["]]..'\nlast='..editor.getSelectionEnd()):close() + --print(true) +end + + + + + +local function adds() + require "import" + local classes = require "javaapi.android" + local ms = { "onCreate", + "onStart", + "onResume", + "onPause", + "onStop", + "onDestroy", + "onActivityResult", + "onResult", + "onCreateOptionsMenu", + "onOptionsItemSelected", + "onClick", + "onTouch", + "onLongClick", + "onItemClick", + "onItemLongClick", + "圆角提示()", + "字符转ASCII码()", + "ASCII码转字符()", + "ASCII码判断字符()", + "提示()", + "MD提示()", + "窗口标题()", + "载入界面()", + "隐藏标题栏()", + "设置主题()", + "打印()", + "截取文本()", + "替换文本()", + "字符串长度()", + "状态栏颜色()", + "沉浸状态栏()", + "设置文本()", + "跳转界面()", + "关闭界面()", + "获取文本()", + "结束程序()", + "控件圆角()", + "获取设备标识码()", + "获取IMEI()", + "控件背景渐变动画()", + "获取屏幕尺寸()", + "是否安装APP()", + "设置中划线()", + "设置下划线()", + "设置字体加粗()", + "设置斜体()", + "分享内容()", + "跳转QQ群()", + "跳转QQ聊天()", + "发送短信()", + "获取剪切板()", + "写入剪切板()", + "开启WIFI()", + "关闭WIFI()", + "断开网络()", + "创建文件()", + "创建文件夹()", + "创建多级文件夹()", + "移动文件()", + "写入文件()", + "设置按钮颜色()", + "设置编辑框颜色()", + "设置进度条颜色()", + "设置控件颜色()", + "获取手机存储路径()", + "获取屏幕宽()", + "获取屏幕高()", + "文件是否存在()", + "关闭侧滑()", + "打开侧滑()", + "显示控件()", + "隐藏控件()", + "播放本地音乐()", + "在线播放音乐()", + "播放本地视频()", + "在线本地视频()", + "打开APP()", + "卸载APP()", + "安装APP()", + "调用系统下载文件()", + "确定弹窗()", + "添加波纹效果()", + "随机数()", + "删除控件()", + "状态栏亮色()", + "ThomeLua", + "thomelua", + "andluax", + "AndLua1", + "AndLua2", + "AndLua3", + "AndLua4", + "AndLua5", + "AndLua6", + "AndLua7", + "AndLua8", + "AndLua9", + "AndLua10", + "AndLua11", + "AndLua12", + "AndLua13", + "AndLua14", + "AndLua15", + "AndLua16", + "AndLua17", + "AndLua18", + "this", + "onItemLongClick", + "api", + "MarText", + "sid()", + "key()", + "窗口全屏()", + "取消全屏()", + "返回桌面()", + "重构页面()", + "YLListView", + "PhotoView", + "SwipeMenuListView", + "gif", + "loadGif", + "void", + "static", + "class", + "public", + "new", + "boolean", + "char", + "int", + "private", + "trim", + "toString", + "length", + "IOException", + "FileNotFoundException", + "out", + "println", + "util", + "append", + "Theme_Pink", + "Theme_Yellow", + "Theme_Black", + "Theme_Green", + "Theme_Cyan", + "Theme_Purple", + "Theme_Teal", + "Theme_Blue", + "Theme_Dark_Blue", + "Theme_Brown", + "Theme_Dark_Brown", + "Theme_Gray", + "Theme_Dark_Gray", + "Theme_Light_Gray", + "Theme_Red" + } + local buf = String[#ms + #classes] + for k, v in ipairs(ms) do + buf[k - 1] = v + end + local l = #ms + for k, v in ipairs(classes) do + buf[l + k - 1] = string.match(v, "%w+$") + end + return buf +end +task(adds, function(buf) + editor.addNames(buf) +end) +function onKeyShortcut(keyCode, event) + local filteredMetaState = event.getMetaState() & ~KeyEvent.META_CTRL_MASK; + if (KeyEvent.metaStateHasNoModifiers(filteredMetaState)) then + switch(keyCode) + case + KeyEvent.KEYCODE_S + 保存(); + return true; + case + KeyEvent.KEYCODE_I + fix(editor.getSelectedText()); + return true; + end + end + return false; +end + +import "android.content.*" +cm = activity.getSystemService(activity.CLIPBOARD_SERVICE) + +function copyClip(str) + local cd = ClipData.newPlainText("label", str) + cm.setPrimaryClip(cd) + Toast.makeText(activity, "已复制到剪切板", 1000).show() +end + +function create_import_dlg() + if import_dlg then + return + end + import_dlg = AlertDialogBuilder(activity) + import_dlg.Title = "可能需要导入的类" + import_dlg.setPositiveButton("确定", nil) + + import_dlg.ListView.onItemClick = function(l, v) + copyClip(v.Text) + import_dlg.hide() + return true + end +end + +function create_error_dlg() + if error_dlg then + return + end + error_dlg = AlertDialogBuilder(activity) + error_dlg.Title = "出错" + error_dlg.setPositiveButton("确定", nil) +end + +function onActivityResult(req, res, intent) + if res == 10000 then + editor.format() + return + end + if res ~= 0 then + local data = intent.getStringExtra("data") + local _, _, path, line = data:find("\n[ ]*([^\n]-):(%d+):") + if path == luapath then + editor.gotoLine(tonumber(line)) + end + local classes = require "javaapi.android" + local c = data:match("a nil value %(global '(%w+)'%)") + if c then + local cls = {} + c = "%." .. c .. "$" + for k, v in ipairs(classes) do + if v:find(c) then + table.insert(cls, string.format("import %q", v)) + end + end + if #cls > 0 then + create_import_dlg() + import_dlg.setItems(cls) + import_dlg.show() + end + end + + end +end + + + + +--create_import_dlg() +--[[if 状态==true then + ti1.start() +end]] +function 其他1x.onClick() + 保存() + if 左侧滑.isDrawerOpen(3) then + 左侧滑.closeDrawer(3) + else + 左侧滑.openDrawer(3) + end +end +delay_handler = Handler() +function 布局助手.onClick() + 保存() + if xy33.text:find("%.aly$") then + isupdate = true + activity.newActivity("layouthelper/main",{项目名称.."/",项目名称.."/"..xy33.text}) + function onResult(a,b) + if a=="layouthelper/main" then + delay_handler.postDelayed( + function() + editor.paste(path) + end,200) + delay_handler.postDelayed( + function() + editor.format() + end,400) + --editor.text=open(项目名称.."/"..xy33.text):read("*a") + end + end + else + print("请选择aly文件") + end +end +function 运行.onClick() + 保存() + activity.newActivity(项目名称.."/main.lua") +end +function 撤销.onClick() + editor.undo() + checkBug() + 保存() +end +function 恢复.onClick() + editor.redo() + checkBug() + 保存() +end +function 其他2x.onClick() + pop=PopupMenu(activity,其他2x) + menu=pop.Menu + --menu.add("手册").onMenuItemClick=function() + --end + menu.add("Java Api").onMenuItemClick=function() + 保存() + activity.newActivity("main10",android.R.anim.fade_in,android.R.anim.fade_out) + end + menu.add("中文手册").onMenuItemClick=function(a) + activity.newActivity("main3",android.R.anim.fade_in,android.R.anim.fade_out) + end + menu.add("编辑器设置").onMenuItemClick=function(a) + activity.newActivity("main13",android.R.anim.fade_in,android.R.anim.fade_out) + end + menu.add("保存并退出").onMenuItemClick=function() + 保存() + activity.finish() + end + pop.show() +end + +--[[[function onKeyDown(e) + if e == 4 then + q.format() + 保存() + --ti1.stop() + ti.stop() + end +end]] + +lastclick = os.time() - 2 +function onKeyDown(e) + local now = os.time() + if e == 4 then + if now - lastclick > 2 then + --print("再按一次退出程序") + Toast.makeText(activity, "再按一次退出编辑器.", Toast.LENGTH_SHORT ).show() + lastclick = now + return true + else + editor.format() + 保存() + --ti1.stop() + --ti.stop() + end + end +end diff --git a/app/src/main/assets/main3.lua b/app/src/main/assets/main3.lua new file mode 100644 index 0000000..c27385f --- /dev/null +++ b/app/src/main/assets/main3.lua @@ -0,0 +1,151 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "ThomeLua" +import "main4" +import "toast" +import "android.graphics.drawable.ColorDrawable" +activity.setTheme(R.AndLua5) +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 +end +layout3={ + LinearLayout; + layout_height="fill"; + layout_width="fill"; + backgroundColor=颜色2, + orientation="vertical"; + { + RelativeLayout; + layout_height="fill"; + layout_width="fill"; + { + LinearLayout; + layout_height="56dp"; + backgroundColor=颜色1; + layout_width="fill"; + { + ImageView; + layout_gravity="center"; + src="res/ThomeLua8.png"; + ColorFilter="0xFF03A9F4"; + layout_width="25dp"; + id="mImageView2"; + layout_marginLeft="20dp"; + }; + { + TextView; + layout_gravity="center"; + text="中文手册"; + textSize="18sp"; + layout_marginLeft="30dp"; + textColor="0xFF03A9F4"; + }; + }; + { + + LinearLayout; + gravity="center"; + layout_height="90%h"; + orientation="vertical"; + layout_alignParentBottom="true"; + layout_width="fill"; + { + ListView; + layout_gravity="end"; + layout_width="fill"; + layout_height="fill"; + id="中文列表"; + DividerHeight=0; + layout_marginTop="5dp"; + }; + }; + }; +} + +activity.setContentView(loadlayout(layout3)) + +隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) + +item5={ + LinearLayout; + gravity="center"; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + gravity="center"; + orientation="vertical"; + layout_height="19.1%h"; + layout_width="fill"; + { + CardView; + radius=20; + CardElevation=0; + backgroundColor=颜色1; + layout_height="120dp"; + layout_width="340dp"; + { + LinearLayout; + orientation="vertical"; + layout_height="fill"; + layout_width="fill"; + { + TextView; + id="标题1"; + layout_marginTop="5dp"; + layout_marginLeft="10dp"; + text="中文函数"; + textColor=颜色3; + textSize="18sp"; + }; + { + TextView; + id="内容1"; + layout_marginLeft="10dp"; + textSize="14sp"; + textColor=颜色4, + layout_marginTop="5dp"; + text=[==[需导入中文函数包 +import "ThomeLua"]==]; + }; + }; + }; + }; +}; + + +内容="【中文函数使用说明】使用中文函数库需要导入包\nimport \"ThomeLua\"【MD提示】--MD提示(\"内容\",\"背景颜色\",\"字体颜色\",\"阴影\",\"圆角\")\nMD提示(\"ThomeLua\",0xFF2196F3,\"#ffffffff\",\"4\",\"10\")【圆角提示】--圆角提示(\"内容\")\n圆角提示(\"ThomeLua\")【窗口标题】窗口标题(\"ThomeLua\")【载入页面】载入页面(\"layout\")【隐藏标题栏】隐藏标题栏()【打印】a=\"ThomeLua\"\n打印(a)【提示】a=\"ThomeLua\"\n提示(a)【截取字符串】--截取(字符串,前字符,后字符)\na=\"123456\"\nb=截取(a,\"3\",\"6\")\n提示(b)\n--结果45【替换字符串】--替换(字符串,要替换的字符,替换成的字符)\na=\"123456789\"\nb=替换(a,\"123\",\"321\")\n提示(b)\n--结果321456789【字符串长度】--字符串长度(\"字符串\")\na=\"ThomeLua\"\nb=字符串长度(a)\n打印(b)\n结果4【字符转ASCII码】--字符转ASCII码(\"内容\",\"要转换的位数\")\n字符转ASCII码(\"abc\",2)\n--将abc中的b转换为ASCII码【ASCII码转字符】--ASCII码转字符(ASCII码)\n字符转ASCII码(98)\n--将98转换字符后为b【ASCII码判断字符】--ASCII码判断字符(\"内容\",要判断的位数,ASCII码)\nASCII码判断字符(\"abc\",2,98)\n--判断abc中的第2位转换为ASCII码是否为98【状态栏颜色】状态栏颜色(\"0xff4285f4\")【沉浸状态栏】沉浸状态栏()【设置文本】设置文本(id,\"内容\")【跳转页面】跳转页面(\"main\")【关闭页面】关闭页面()【获取文本】--获取文本(id)\na=获取文本(id)\n提示(a)【结束程序】结束程序()【控件圆角】控件圆角(id,0xb0000000,20)\n--id是控件id,0xb0000000是颜色,20是角度\n可以使用字符串型的\"0xb0000000\"颜色\n可以使用字符串型的\"#b0000000\"颜色代码【获取设备标识码】--获取设备标识码()\na=获取设备标识码()\n打印(a)【获取IMEI】--获取IMEI()\na=获取IMEI()\n打印(a)【控件背景渐变动画】--控件背景渐变动画(控件ID,颜色1,颜色2,颜色3,颜色4)\n控件背景渐变动画(a,\"0xffFF8080\",\"0xff8080FF\",\"0xff80ff80\",\"0xff80ffff\")【获取屏幕尺寸】--获取屏幕尺寸()\na=获取屏幕尺寸\n打印(a)【判断是否安装指定软件】--安装判断(包名)\na=安装判断(\"com.ThomeLua.IDE\")\n打印(a)【设置文本中划线风格】设置中划线(ID)【设置文本下划线风格】设置下划线(ID)【设置字体加粗】设置字体加粗(ID)【设置字体斜体】设置字体斜体(ID)【分享内容】分享(\"内容\")【跳转到QQ群】加群(\"群号码\")【跳转到QQ聊天】QQ聊天(\"QQ号\")【发送短信】发送短信(号码,内容)【获取剪切板】--获取剪切板()\na=获取剪切板()\n打印(a)【写入剪切板】写入剪切板(\"内容\")【开启wifi】开启WIFI()【关闭wifi】关闭WIFI()【断开网络】断开网络()【创建文件】创建文件(\"路径\")\n--创建文件(\"/sdcard/ThomeLua.txt\")【创建文件夹】创建文件夹(\"路径\")\n--创建文件夹(\"/sdcard/ThomeLua/\")【创建多级文件夹】创建多级文件夹(\"路径\")\n--创建多级文件夹(\"/sdcard/a/b/c/\")【移动文件】移动文件(\"旧文件路径\",\"新文件路径\")【写入文件】写入文件(\"路径\",\"内容\")【删除文件】删除文件(\"路径\")【按钮颜色】按钮颜色(id,0xb00000000)【编辑框颜色】编辑框颜色(id,0xb00000000)【进度条颜色】进度条颜色(id,0xb00000000)【控件颜色】控件颜色(id,0xb00000000)【获取手机存储路径】a=获取手机存储路径()\n打印(a)【获取屏幕高】a=获取屏幕高()\n打印(a)\n--获取之后赋值到a【获取屏幕宽】a=获取屏幕宽()\n打印(a)\n--获取之后赋值到a【文件是否存在】a=\"文件是否存在(\"路径\")\na=true则为存在\nfalse为不存在\"【打开侧滑】打开侧滑()【关闭侧滑】关闭侧滑()【显示控件】显示(id)\n--显示控件【隐藏控件】隐藏(id)\n--隐藏控件【播放本地音乐】播放本地音乐(\"/sdcard/1.mp3\")【在线播放音乐】在线播放音乐(\"http://adc.cn/1.mp3\")【播放本地视频】播放本地视频(\"/sdcard/1.mp4\")【在线播放视频】在线播放视频(\"http://adc.cn/1.mp4\")【打开APP】打开app(\"包名\")【卸载APP】卸载app(\"包名\")【安装APP】安装app(\"/sdcard/1.apk\")【调用系统下载文件】系统下载文件(\"文件直链\",\"文件下载目录\",\"文件名\")【设置波纹效果】波纹(id,颜色)【删除控件】删除控件(父控件id,控件id)【状态栏高色】状态栏亮色()【重构页面】重构页面()【窗口全屏】窗口全屏()【取消全屏】取消全屏()【返回桌面】返回桌面()【获取悬浮窗权限】获取悬浮窗权限()【" +data={} +adp=LuaAdapter(activity,data,item5) +中文列表.Adapter=adp +标题=内容:gmatch("】(.-)【") +for i in 内容:gmatch("【(.-)】") do + sss=标题() + adp.add{标题1=i,内容1=sss} +end +中文列表.onItemClick=function(l,v,p,i) + activity.newActivity("main4",android.R.anim.fade_in,android.R.anim.fade_out,{v.tag.标题1.text,v.tag.内容1.text}) + return true +end +波纹(mImageView2,0xFFD9D9D9) +function mImageView2.onClick() + activity.finish() +end \ No newline at end of file diff --git a/app/src/main/assets/main4.lua b/app/src/main/assets/main4.lua new file mode 100644 index 0000000..6ac8c1f --- /dev/null +++ b/app/src/main/assets/main4.lua @@ -0,0 +1,248 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "AndLua" +import "toast" +activity.setTheme(R.AndLua5) +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色2=0xFFF2F1F6 +end + +layout4={ + LinearLayout; + orientation="vertical"; + layout_width="fill"; + layout_height="fill"; + { + RelativeLayout; + layout_height="fill"; + layout_width="fill"; + { + LinearLayout; + layout_width="fill"; + layout_height="50dp"; + backgroundColor=颜色1; + { + ImageView; + layout_width="25dp"; + onClick=function() + activity.finish() + end; + layout_gravity="center"; + ColorFilter="0xFF03A9F4"; + src="res/ThomeLua8.png"; + id="mImageView1"; + layout_marginLeft="20dp"; + }; + { + TextView; + textColor="0xFF03A9F4"; + layout_gravity="center"; + textSize="18sp"; + text="中文手册"; + id="oi"; + layout_marginLeft="30dp"; + }; + }; + { + LinearLayout; + layout_width="fill"; + visibility=8; + layout_height="50dp"; + id="选择代码"; + backgroundColor=颜色1; + { + ImageView; + layout_width="30dp"; + layout_marginLeft="10dp"; + layout_gravity="center"; + ColorFilter="0xFF03A9F4"; + layout_height="30dp"; + id="XY0"; + src="res3/1.png"; + }; + { + TextView; + layout_gravity="center"; + textSize="18sp"; + textColor="0xFF03A9F4"; + text="选择代码"; + layout_marginLeft="15dp"; + }; + { + ImageView; + layout_width="29dp"; + layout_marginLeft="30dp"; + layout_gravity="center"; + ColorFilter="0xFF03A9F4"; + layout_height="29dp"; + id="XY1"; + src="res3/2.png"; + }; + { + ImageView; + layout_width="25dp"; + layout_marginLeft="25dp"; + layout_gravity="center"; + ColorFilter="0xFF03A9F4"; + layout_height="25dp"; + id="XY2"; + src="res3/3.png"; + }; + { + ImageView; + layout_width="25dp"; + layout_marginLeft="25dp"; + layout_gravity="center"; + ColorFilter="0xFF03A9F4"; + layout_height="25dp"; + id="XY3"; + src="res3/4.png"; + }; + { + ImageView; + layout_width="25dp"; + layout_marginLeft="25dp"; + layout_gravity="center"; + ColorFilter="0xFF03A9F4"; + layout_height="25dp"; + id="XY4"; + src="res3/5.png"; + }; + }; + { + LinearLayout; + layout_width="fill"; + layout_height="88.2%h"; + layout_marginTop="50dp"; + { + LuaEditor; + TextSize="12sp"; + id="r"; + backgroundColor=颜色2, + }; + }; + { + LinearLayout; + layout_alignParentBottom="true"; + layout_height="6%h"; + layout_width="fill"; + { + HorizontalScrollView; + horizontalScrollBarEnabled=false; + layout_width="fill"; + layout_height="fill"; + backgroundColor=颜色1; + { + LinearLayout; + id="bar1"; + layout_width="fill"; + layout_height="fill"; + }; + }; + }; + }; +}; + +activity.setContentView(loadlayout(layout4)) +隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +参数,参数1=... +oi.text=参数 +r.text=参数1 +波纹(mImageView1,0xFFD9D9D9) +activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) +r.OnSelectionChangedListener=function(a,b,c,d) + if a==true then + 选择代码.setVisibility(0) + else + 选择代码.setVisibility(8) + end +end +function XY1.onClick() + r.selectAll() +end +function XY2.onClick() + r.cut() +end +function XY3.onClick() + r.copy() +end +function XY4.onClick() + r.paste() +end +r.setBasewordColor(0xff8dbdc9)--基词 +r.setPanelBackgroundColor(颜色1)--卡片颜色 +r.setPanelTextColor(0xFF03A9F4)--卡片字体颜色 +r.setStringColor(0xFF03A9F4)--字符串颜色 +r.setTextColor(颜色3)--文本颜色 +r.setUserwordColor(0xFF03A9F4)--数字 +r.setCommentColor(0xffa0a0a0)--注释颜色 +r.setKeywordColor(0xFF03A9F4)--if then等 +a={"删除文件()","获取悬浮窗权限()"} +r.addNames(a) +p={ + LinearLayout; + layout_width="40dp"; + gravity="center"; + layout_height="fill"; + { + TextView; + id="符号文本1"; + text="Fun"; + textSize="15sp"; + textColor="0xFF03A9F4"; + }; +}; +fh=io.open(activity.getLuaDir().."/Verify/set2.XY"):read("*a") +for t,c in fh:gmatch("(.-) ") do + button={ + Button; + text=tostring(t); + layout_width="45dp"; + layout_height="fill"; + background="#ffffff"; + textColor=0xFF03A9F4; + padding="5dp", + id="sssss1", + }; + m1=loadlayout(button) + bar1.addView(m1) + 波纹(sssss1,0xE7EAEEEE) + m1.onClick=function(v) + if v.text=="Fun" or v.text=="fun" or v.text=="function" or v.text=="Function" then + r.paste("function") + else + if v.text=="End" or v.text=="end" then + r.paste("end") + else + r.paste(v.Text) + end + end + end + m1.onLongClick=function(v) + if v.text=="Fun" or v.text=="fun" or v.text=="function" or v.text=="Function" then + r.paste("function") + else + if v.text=="End" or v.text=="end" then + r.paste("end") + else + r.paste(v.Text..v.text) + end + end + return true + end +end \ No newline at end of file diff --git a/app/src/main/assets/main5.lua b/app/src/main/assets/main5.lua new file mode 100644 index 0000000..2d04e8f --- /dev/null +++ b/app/src/main/assets/main5.lua @@ -0,0 +1,556 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "ThomeLua" +import "toast" +import "other" +--activity.setTheme(R.AndLua5) + +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + activity.setTheme(android.R.style.Theme_DeviceDefault_NoActionBar) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar) +end + +layout5={ + LinearLayout; + layout_height="fill"; + backgroundColor=颜色2; + orientation="vertical"; + layout_width="fill"; + { + LinearLayout; + layout_height="56dp"; + backgroundColor=颜色1; + layout_width="fill"; + layout_marginBottom="10dp"; + { + ImageView; + layout_marginLeft="20dp"; + layout_gravity="center"; + ColorFilter="0xFF03A9F4"; + src="res/ThomeLua8.png"; + onClick=function() + activity.finish() + end; + layout_width="25dp"; + }; + { + TextView; + text="工程属性"; + layout_marginLeft="30dp"; + layout_gravity="center"; + textColor="0xFF03A9F4"; + textSize="18sp"; + }; + { + ImageView; + layout_marginLeft="170dp"; + id="保存属性"; + ColorFilter="0xFF03A9F4"; + src="res/ThomeLua9.png"; + layout_width="25dp"; + layout_gravity="center"; + }; + }; + { + LinearLayout; + layout_height="120dp"; + layout_width="fill"; + orientation="horizontal"; + { + LinearLayout; + layout_height="fill"; + gravity="center"; + orientation="vertical"; + layout_width="100dp"; + { + CardView; + layout_marginLeft="5dp"; + layout_height="65dp"; + radius=25; + backgroundColor=颜色1, + layout_width="65dp"; + CardElevation=0; + { + ImageView; + id="项目图片"; + layout_height="45dp"; + src="icon.png"; + layout_width="45dp"; + layout_gravity="center"; + }; + }; + }; + { + LinearLayout; + layout_height="fill"; + gravity="center"; + orientation="vertical"; + layout_width="fill"; + { + LinearLayout; + layout_height="fill"; + gravity="center"; + orientation="vertical"; + layout_width="fill"; + { + LinearLayout; + layout_height="60dp"; + layout_width="fill"; + gravity="center"; + { + CardView; + layout_height="50dp"; + radius=25; + backgroundColor=颜色1, + layout_width="200dp"; + CardElevation=0; + { + EditText; + text="ThomeLua"; + layout_marginLeft="5dp"; + id="软件名称q"; + background="0"; + textColor=颜色3; + hintTextColor=颜色3, + layout_gravity="center"; + layout_height="50dp"; + layout_width="fill"; + singleLine="true"; + hint="请输入软件名称"; + }; + }; + }; + { + LinearLayout; + layout_height="fill"; + gravity="center"; + orientation="horizontal"; + layout_width="fill"; + { + CardView; + radius=25; + backgroundColor=颜色1, + layout_marginRight="20dp"; + layout_height="50dp"; + layout_width="100dp"; + CardElevation=0; + { + TextView; + textColor=颜色4, + text="版本:"; + layout_marginLeft="4dp"; + layout_marginTop="3dp"; + textSize="10sp"; + }; + { + EditText; + text="1.0"; + id="软件版本w"; + background="0"; + textColor=颜色3; + singleLine="true"; + hintTextColor=颜色3, + textSize="12sp"; + layout_gravity="center"; + layout_height="40dp"; + layout_width="80dp"; + layout_marginTop="5dp"; + hint="请输入版本"; + }; + }; + { + CardView; + layout_height="50dp"; + radius=25; + backgroundColor=颜色1, + layout_width="100dp"; + CardElevation=0; + { + TextView; + textColor=颜色4, + text="版本号:"; + layout_marginLeft="4dp"; + layout_marginTop="3dp"; + textSize="10sp"; + }; + { + EditText; + text="1.0"; + id="版本号e"; + background="0"; + textColor=颜色3; + singleLine="true"; + textSize="12sp"; + layout_gravity="center"; + layout_height="40dp"; + layout_width="80dp"; + hintTextColor=颜色3, + layout_marginTop="5dp"; + hint="请输入版本号"; + }; + }; + }; + }; + }; + }; + { + LinearLayout; + layout_height="60dp"; + gravity="center"; + orientation="horizontal"; + layout_width="fill"; + { + CardView; + backgroundColor=颜色1, + layout_height="50dp"; + radius=25; + layout_width="320dp"; + CardElevation=0; + { + TextView; + text="包名:"; + textColor=颜色4, + layout_marginLeft="4dp"; + layout_marginTop="3dp"; + textSize="10sp"; + }; + { + EditText; + hintTextColor=颜色3, + text="1.0"; + id="软件包名r"; + background="0"; + textColor=颜色3; + singleLine="true"; + textSize="12sp"; + layout_gravity="center"; + layout_height="40dp"; + layout_width="290dp"; + layout_marginTop="5dp"; + hint="请输入包名"; + }; + }; + }; + { + LinearLayout; + gravity="center"; + layout_height="70dp"; + orientation="horizontal"; + layout_width="fill"; + layout_marginBottom="20dp"; + { + CardView; + radius=25; + backgroundColor=颜色1, + layout_marginRight="20dp"; + layout_height="50dp"; + layout_width="150dp"; + CardElevation=0; + { + TextView; + textColor=颜色4, + text="SDK:"; + layout_marginLeft="4dp"; + layout_marginTop="3dp"; + textSize="10sp"; + }; + { + EditText; + text="1.0"; + id="SDKt"; + hintTextColor=颜色3, + background="0"; + textColor=颜色3; + singleLine="true"; + textSize="12sp"; + layout_gravity="center"; + layout_height="40dp"; + layout_width="120dp"; + layout_marginTop="5dp"; + hint="请输入SDK"; + }; + }; + { + CardView; + radius=25; + id="开关2"; + layout_height="50dp"; + backgroundColor="0xFF03A9F4"; + layout_width="150dp"; + CardElevation=0; + { + LinearLayout; + layout_height="fill"; + gravity="center"; + layout_width="fill"; + orientation="horizontal"; + { + LinearLayout; + layout_height="fill"; + layout_width="90dp"; + gravity="center"; + { + TextView; + id="调试模式"; + text="调试模式[开]"; + textColor="0xffffffff"; + }; + }; + { + Switch; + focusable=false; + clickable=false; + id="开关1"; + }; + }; + }; + }; + { + CardView; + layout_marginLeft="20dp"; + radius=25; + layout_height="44.1%h"; + layout_marginBottom="30dp"; + layout_width="87%w"; + CardElevation=0; + { + ListView; + layout_height="fill"; + layout_width="fill"; + DividerHeight=0; + id="list1"; + }; + }; +}; + + +activity.setContentView(loadlayout(layout5)) +--隐藏标题栏() +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色1); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +XY_1,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10=... +items={ + LinearLayout; + layout_height="fill"; + layout_width="fill"; + backgroundColor=颜色1; + orientation="vertical"; + { + LinearLayout; + layout_height="35dp"; + layout_width="88.8%w"; + { + LinearLayout; + layout_height="fill"; + layout_width="75.7%w"; + { + TextView; + id="权限"; + textColor=颜色4, + layout_marginLeft="10dp"; + layout_gravity="center"; + text="工程权限"; + textSize="15sp"; + }; + }; + { + CheckBox; + id="开关"; + focusable=false; + clickable=false; + layout_gravity="center"; + }; + }; +}; + +权限1={"访问大致位置信息(以网络为依据)","访问确切位置信息(以GPS和网络为依据)","查看网络连接","查看WiFI连接","ANSWER_PHONE_CALLS","android.permission.BATTERY_STATS","辅助功能","与蓝牙设备配对","访问蓝牙设置","直接拨打电话号码","拍摄照片和视频","更改网络连接性","连接WIFI网络和断开连接","android.permissions.CLEAR_APP_CACHE","直接下载文件而不显示通知","FOREGROUND_SERVICE","计算应用储存空间","检索正在运行的应用","安装快捷方式","拥有完全的网络访问权限","关闭其他应用","读取通话记录","读取您的通讯录","读取您的SD卡中的内容","android.permissions.READ_FRAME_BUFFER","android.permissions.READ_LOGS","读取手机状态和身份","读取您的讯息(短信或短信)" + ,"录音","请求安装文件包","发送短信","设置壁纸","出现在其他应用","控制振动","防止手机休眠","写入/删除通话记录","写入/删除通讯录","修改或删除您SD卡中的内容","修改系统设置","android.permission.WRITE.SMS"} +对应权限={"ACCESS_COARSE_LOCATION", + "ACCESS_FINE_LOCATION", + "ACCESS_NETWORK_STATE", + "ACCESS_WIFI_STATE", + "ANSWER_PHONE_CALLS", + "BATTERY_STATS", + "BIND_ACCESSIBILITY_SERVICE", + "BLUETOOTH", + "BLUETOOTH_ADMIN", + "CALL_PHONE", + "CAMERA", + "CHANGE_NETWORK_STATE", + "CHANGE_WIFI_STATE", + "CLEAR_APP_CACHE", + "DOWNLOAD_WITHOUT_NOTIFICATION", + "FOREGROUND_SERVICE", + "GET_PACKAGE_SIZE", + "GET_TASKS", + "INSTALL_SHORTCUT", + "INTERNET", + "KILL_BACKGROUND_PROCESSES", + "READ_CALL_LOG", + "READ_CONTACTS", + "READ_EXTERNAL_STORAGE", + "READ_FRAME_BUFFER", + "READ_LOGS", + "READ_PHONE_STATE", + "READ_SMS", + "RECORD_AUDIO", + "REQUEST_INSTALL_PACKAGES", + "SEND_SMS", + "SET_WALLPAPER", + "SYSTEM_ALERT_WINDOW", + "VIBRATE", + "WAKE_LOCK", + "WRITE_CALL_LOG", + "WRITE_CONTACTS", + "WRITE_EXTERNAL_STORAGE", + "WRITE_SETTINGS", + "WRITE_SMS",} +data={} +adp=LuaAdapter(activity,data,items) +list1.Adapter=adp +for i=1,#权限1 do + table.insert(data,{权限={Text=权限1[i]},开关={Checked=false},}) + if XY_1==true then + if x0:find('"'..对应权限[i]..'"') then + data[i].开关["Checked"]=true end + end +end +if XY_1==true then + if File(项目文件夹.."/"..x9.."/icon.png").isFile() then + 项目图片.setImageBitmap(loadbitmap(项目文件夹.."/"..x9.."/icon.png")) + end + 软件名称q.text=x1 + 软件版本w.text=x2 + 版本号e.text=x3 + SDKt.text=x4 + 软件包名r.text=x5 + if x6=="开" then + 开关1.Checked=true + 调试模式.text="调试模式[开]" + else + 开关1.Checked=false + 调试模式.text="调试模式[关]" + end +end +tpzt=false +tplj=nil +function 项目图片.onClick() + import "android.content.Intent" + local intent= Intent(Intent.ACTION_PICK) + intent.setType("image/*") + this.startActivityForResult(intent, 1) + ------- + + --回调 + function onActivityResult(requestCode,resultCode,intent) + if intent then + local cursor =this.getContentResolver ().query(intent.getData(), nil, nil, nil, nil) + cursor.moveToFirst() + import "android.provider.MediaStore" + local idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA) + fileSrc = cursor.getString(idx) + bit=nil + --fileSrc回调路径路径 + import "android.graphics.BitmapFactory" + bit =BitmapFactory.decodeFile(fileSrc) + if fileSrc:find("%.png$") then + tpzt=true + tplj=fileSrc + 项目图片.setImageBitmap(loadbitmap(fileSrc)) + else + print"请选择png文件" + end + end + end +end +开关1.ThumbDrawable.setColorFilter(PorterDuffColorFilter(0x3CECEFF0,PorterDuff.Mode.SRC_ATOP)); +function 开关2.onClick() + if 开关1.Checked then + 开关1.Checked=false + 调试模式.text="调试模式[关]" + else + 开关1.Checked=true + 调试模式.text="调试模式[开]" + end +end +--权限 +list1.onItemClick=function(l,v,p,i) + if data[i].开关["Checked"] then + data[i].开关={Checked=false} + else + data[i].开关={Checked=true} + end + adp.notifyDataSetChanged() +end +--权限 +function 转换(t) + for k,v in ipairs(t) do + t[k]=string.format("%q",v) + end + return table.concat(t,",\n ") +end +function 保存属性.onClick() + sss=[[ +--名称 +appname="%s" +--包名 +packagename="%s" +--版本 +appcode="%s" +--版本号 +appver="%s" +--SDK +appsdk="%s" +--调试模式 +debugmode=%s +--应用权限 +user_permission={ +%s +} +--跳过编译 +skip_compilation={]] + ..x10..[[ +}]] + + ssr={} + for i=1,#data do + if data[i].开关["Checked"] then + table.insert(ssr,对应权限[i]) + end + end + sst=转换(ssr) + q0=sss:format(软件名称q.text,软件包名r.text,软件版本w.text,版本号e.text,SDKt.text,开关1.Checked,sst) + if tpzt==true then + if File(项目文件夹.."/"..x9.."/"..a).isFile() then + --os.remove(项目文件夹.."/"..x9.."/"..a) + local a=File(tplj).getName() + LuaUtil.copyDir(tplj,项目文件夹.."/"..x9.."/"..a) + --os.rename(项目文件夹.."/"..x9.."/"..a,项目文件夹.."/"..x9.."/icon.png") + else + local a=File(tplj).getName() + LuaUtil.copyDir(tplj,项目文件夹.."/"..x9.."/"..a) + --os.rename(项目文件夹.."/"..x9.."/"..a,项目文件夹.."/"..x9.."/icon.png") + end + else + 写入文件(x8,q0) + --os.rename(项目文件夹.."/"..x9,项目文件夹.."/"..软件名称q.text) + end + print"保存成功" + activity.result{true} +end \ No newline at end of file diff --git a/app/src/main/assets/main6.lua b/app/src/main/assets/main6.lua new file mode 100644 index 0000000..235ef99 --- /dev/null +++ b/app/src/main/assets/main6.lua @@ -0,0 +1,53 @@ +import "AndLua" +import "android.graphics.drawable.ColorDrawable" +import "android.graphics.drawable.StateListDrawable" +import "android.graphics.PorterDuffColorFilter" +import "android.graphics.PorterDuff" +import "android.graphics.drawable.GradientDrawable" +import "toast" +import "android.graphics.Typeface" +local Text_Type=Typeface.defaultFromStyle(Typeface.BOLD) +local sd = StateListDrawable() +import "android.graphics.Color" +import "android.content.res.ColorStateList" +import "android.graphics.drawable.RippleDrawable" +import "android.content.Context" + +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + else + 颜色1=0x5FFFFFFF +end + +appt={C_Bacgg=function(mBinding,radiu,InsideColor,S,S2,T1) + local drawable = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{}); + drawable.setCornerRadius(radiu); + drawable.setColor(颜色1) + drawable.setStroke(3, 0xCFB0B0B0) + drawable.setGradientType(GradientDrawable.RECTANGLE); + mBinding.setTextColor(T1) + mBinding.setTypeface(Text_Type) + return drawable + end} +美化按钮=function(mBinding,radiu,InsideColor,T1) + stateList = { + {android.R.attr.state_pressed}, + {android.R.attr.state_focused}, + {android.R.attr.state_activated}, + {android.R.attr.selectableItemBackground}, + }; + sd.addState({ android.R.attr.state_enabled}, appt.C_Bacgg(mBinding,radiu,InsideColor,S,S2,T1)) + pressedColor =InsideColor --Color.parseColor("#7ab946ff"); + stateColorList ={ + pressedColor, + pressedColor, + pressedColor, + normalColor + }; + colorStateList = ColorStateList(stateList, stateColorList); + rippleDrawable = RippleDrawable(colorStateList,sd,nil); + mBinding.setBackground(rippleDrawable); +end + diff --git a/app/src/main/assets/main7.lua b/app/src/main/assets/main7.lua new file mode 100644 index 0000000..cc50bf5 --- /dev/null +++ b/app/src/main/assets/main7.lua @@ -0,0 +1,180 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "AndLua" +import "main6" +import "toast" +activity.setTheme(R.AndLua5) + +local a=io.open(activity.getLuaDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色2=0xFFF2F1F6 +end +layout7={ + LinearLayout; + layout_width="fill"; + layout_height="fill"; + orientation="vertical"; + backgroundColor=颜色2; + { + LinearLayout; + orientation="vertical"; + layout_height="-1"; + layout_width="match_parent"; + { + CardView; + layout_width="-1"; + layout_marginTop="10dp"; + layout_marginRight="10dp"; + layout_height="-2"; + radius=25; + layout_marginLeft="10dp"; + cardElevation=0; + { + LinearLayout; + layout_width="-1"; + layout_height="-1"; + { + CardView; + layout_width="-1"; + backgroundColor=颜色1; + radius=0; + layout_height="70dp"; + cardElevation=0; + { + TextView; + text="标题"; + layout_marginTop="5dp"; + layout_marginLeft="10dp"; + textColor="0xFF03A9F4"; + }; + { + EditText; + id="tzbt", + textColor=颜色3, + layout_width="320dp"; + layout_marginTop="10dp"; + singleLine="true"; + background="0"; + textSize="15sp"; + layout_gravity="center"; + }; + { + TextView; + id="tzbq"; + text="#其他内容#"; + layout_marginTop="5dp"; + layout_marginLeft="250dp"; + textColor="0xFF03A9F4"; + }; + }; + }; + }; + { + CardView; + layout_width="-1"; + layout_marginTop="10dp"; + layout_marginBottom="10dp"; + layout_marginRight="10dp"; + cardElevation=0; + radius=25; + backgroundColor=颜色1; + layout_marginLeft="10dp"; + layout_height="100dp"; + { + TextView; + text="内容"; + layout_marginTop="5dp"; + layout_marginLeft="10dp"; + textColor="0xFF03A9F4"; + }; + { + EditText; + id="tznr"; + layout_width="320dp"; + layout_marginTop="20dp"; + layout_gravity="left"; + textSize="15sp"; + textColor=颜色3, + layout_marginBottom="20dp"; + layout_marginLeft="10dp"; + background="0"; + }; + }; + { + LinearLayout; + orientation="horizontal"; + gravity="center"; + layout_height="450dp"; + layout_width="match_parent"; + { + Button; + id="取消发布"; + layout_marginBottom="200dp"; + text="取消"; + layout_width="150dp"; + }; + { + Button; + layout_width="150dp"; + layout_marginBottom="200dp"; + id="发布帖子"; + layout_marginLeft="20dp"; + text="发布"; + }; + }; + }; +}; + +import "bmob" +id="1f6759cbbac7c4ef109e1c51ce9f7072" +key="7313b823d9b466408e11932c8060f7d2" +bm=bmob(id,key) +activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(颜色2); +if tonumber(Build.VERSION.SDK) >= 23 then + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +end +activity.setContentView(loadlayout(layout7)) +隐藏标题栏() +美化按钮(取消发布,100,0x7a00bfff,0x7a00bfff) +美化按钮(发布帖子,100,0x7a00bfff,0x7a00bfff) +function 取消发布.onClick() + activity.finish() +end +function tzbq.onClick() + pop=PopupMenu(activity,tzbq) + menu=pop.Menu + menu.add("其他内容").onMenuItemClick=function() + tzbq.text="#其他内容#" + end + menu.add("BUG反馈").onMenuItemClick=function() + tzbq.text="#BUG反馈#" + end + menu.add("大佬求教").onMenuItemClick=function() + tzbq.text="#大佬求教#" + end + menu.add("开发教程").onMenuItemClick=function() + tzbq.text="#开发教程#" + end + pop.show() +end +function 发布帖子.onClick() + if #tzbt.text~=0 then + if #tznr.text~=0 then + activity.result{true,tzbt.text,tzbq.text,tznr.text} + else + print"请输入帖子内容" + end + else + print"请输入帖子标题" + end +end \ No newline at end of file diff --git a/app/src/main/assets/main9.lua b/app/src/main/assets/main9.lua new file mode 100644 index 0000000..686b637 --- /dev/null +++ b/app/src/main/assets/main9.lua @@ -0,0 +1,950 @@ +require "import" +import "android.text.Html" +import "android.graphics.Paint" +import "android.app.*" +import "android.os.*" +import "java.io.*" +import "android.widget.*" +import "android.view.*" +import "android.content.*" +import "com.androlua.*" + +import "android.view.WindowManager" +import "android.view.inputmethod.InputMethodManager" +layout={ + main={ + RelativeLayout, + layout_width = "fill"; + layout_height = "fill"; + }, + + ck={ + LinearLayout; + { + RadioGroup; + layout_weight="1"; + id="ck_rg"; + }; + { + Button; + Text="确定"; + layout_gravity="right"; + id="ck_bt"; + }; + orientation="vertical"; + }; +} + +luapath,luadir=... +luadir=luadir or luapath:gsub("/[^/]+$","") +package.path=package.path..";"..luadir.."/?.lua;" + +imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) + +import "loadlayout2" +require "xml2table" +import "autotheme" +activity.setTheme(autotheme()) +if luapath:find("%.aly$") then + local f=io.open(luapath) + local s=f:read("*a") + f:close() + xpcall(function() + layout.main=assert(loadstring("return "..s))() + end, + function() + Toast.makeText(activity,"不支持编辑该布局",1000).show() + activity.finish() + end) + showsave=true +end + +if luapath:find("%.lua$") and content then + xpcall(function() + layout.main=assert(loadstring("return "..content))() + end, + function() + Toast.makeText(activity,"加载布局失败布局",1000).show() + activity.finish() + end) + showsave=true +end + +--判断是否在点击该控件 +is_clicking = false + +--点击事件信息 + + +function click_info_init() + click_info = { + --起始坐标 + start = { + x = 0;y = 0; + }; + start_time = 0; + now_click = nil; + mode = 1; + now_view = nil; + } +end + +--保持View属性窗口开启 +holding_view = false + +local function clicking_background(c,p) + p.color = + ({0x554A148C,0x55004D40,0x55BF360C,0x55FFFF00}) + [click_info.mode] + + if click_info.now_click then + c.drawRect(0,0,c.width,c.height,p) + if click_info.mode == 1 and (System.currentTimeMillis() - click_info.start_time) < 750 then + p.color = 0x4437474F + c.drawRect(0,0,(c.width/750)*(System.currentTimeMillis() - click_info.start_time),c.height,p) + if click_info.now_view then + click_info.now_view.invalidate() + end + elseif click_info.mode == 1 then + p.color = 0x550288D1 + c.drawRect(0,0,c.width,c.height,p) + end + p.style = Paint.Style.STROKE + p.setStrokeWidth(20) + p.setStrokeJoin(Paint.Join.ROUND) + p.color = + ({0x994A148C,0x99004D40,0x99BF360C,0x99FFFF00}) + [click_info.mode] + c.drawRect(0,0,c.width,c.height,p) + + p.setTextSize(40) + p.color = + ({0xFF4A148C,0xFF004D40,0xFFBF360C,0xFFF57F17}) + [click_info.mode] + p.setStyle(Paint.Style.FILL) + c.drawText(click_info.now_click.class.getSimpleName(),20,50,p) + + p.setTextSize(20) + + c.drawText( + ({(((System.currentTimeMillis() - click_info.start_time) > 750) and "固定属性面板") or "打开属性面板","选择子控件/父控件","添加/ID","删除"}) + [click_info.mode],20,70,p) + end +end + +clicking_background_drawable = LuaDrawable(clicking_background) + +function onTouch(v,e) + if is_clicking and e.getAction() == MotionEvent.ACTION_UP then + getCurr(v) + fd_dlg.hide() + v.foreground = nil + is_clicking = false + if (System.currentTimeMillis() - click_info.start_time) > 750 then + holding_view = true + end + if click_info.mode == 2 then + if luajava.instanceof(v,ViewGroup) then + func["子控件"](v) + else + func["父控件"](v) + end + return + + elseif click_info.mode == 3 then + if luajava.instanceof(v,ViewGroup) then + func["添加"](v) + else + func["id"](v) + end + return + elseif click_info.mode == 4 then + func["删除"](v) + return + end + + getCurr(v) + elseif (not is_clicking) and e.getAction() == MotionEvent.ACTION_DOWN then + holding_view = false + v.foreground = clicking_background_drawable + click_info_init() + click_info.now_view = v + click_info.start = { + x = e.rawX; + y = e.rawY; + } + click_info.start_time = System.currentTimeMillis() + click_info.now_click = v + is_clicking = true + return true + elseif is_clicking and e.getAction() == MotionEvent.ACTION_MOVE then + + local offset = activity.getWidth()/3 + --点击的偏移 + + if + math.abs(e.rawX - click_info.start.x) > offset or + math.abs(e.rawY - click_info.start.y) > offset then + + is_clicking = false + v.foreground = nil + else + if e.rawY - click_info.start.y > offset*0.3 then + click_info.mode = 3 + v.invalidate() + elseif e.rawY - click_info.start.y < -(offset*0.3) then + click_info.mode = 2 + v.invalidate() + elseif e.rawX - click_info.start.x < -(offset*0.3) then + click_info.mode = 4 + v.invalidate() + else + if click_info.mode ~= 1 then + click_info.start_time = System.currentTimeMillis() + end + click_info.mode = 1 + v.invalidate() + end + end + return true + end + +end + +local TypedValue=luajava.bindClass("android.util.TypedValue") +local dm=activity.getResources().getDisplayMetrics() +function dp(n) + return TypedValue.applyDimension(1,n,dm) +end + +function to(n) + return string.format("%ddp",n//dn) +end + +dn=dp(1) +lastX=0 +lastY=0 +vx=0 +vy=0 +vw=0 +vh=0 +zoomX=false +zoomY=false +function move(v,e) + curr=v.Tag + currView=v + ry=e.getRawY()--获取触摸绝对Y位置 + rx=e.getRawX()--获取触摸绝对X位置 + if e.getAction() == MotionEvent.ACTION_DOWN then + lp=v.getLayoutParams() + vy=v.getY()--获取视图的Y位置 + vx=v.getX()--获取视图的X位置 + lastY=ry--记录按下的Y位置 + lastX=rx--记录按下的X位置 + vw=v.getWidth()--记录控件宽度 + vh=v.getHeight()--记录控件高度 + if vw-e.getX()<20 then + zoomX=true--如果触摸右边缘启动缩放宽度模式 + elseif vh-e.getY()<20 then + zoomY=true--如果触摸下边缘启动缩放高度模式 + end + + elseif e.getAction() == MotionEvent.ACTION_MOVE then + --lp.gravity=Gravity.LEFT|Gravity.TOP --调整控件至左上角 + if zoomX then + lp.width=(vw+(rx-lastX))--调整控件宽度 + elseif zoomY then + lp.height=(vh+(ry-lastY))--调整控件高度 + else + lp.x=(vx+(rx-lastX))--移动的相对位置 + lp.y=(vy+(ry-lastY))--移动的相对位置 + end + v.setLayoutParams(lp)--调整控件到指定的位置 + --v.Parent.invalidate() + elseif e.getAction() == MotionEvent.ACTION_UP then + if (rx-lastX)^2<100 and (ry-lastY)^2<100 then + getCurr(v) + else + curr.layout_x=to(v.getX()) + curr.layout_y=to(v.getY()) + if zoomX then + curr.layout_width=to(v.getWidth()) + elseif zoomY then + curr.layout_height=to(v.getHeight()) + end + end + zoomX=false--初始化状态 + zoomY=false--初始化状态 + end + return true +end + +function getCurr(v) + curr=v.Tag + currView=v + fd_dlg.setView(View(activity)) + fd_dlg.Title=tostring(v.Class.getSimpleName()) + if luajava.instanceof(v,GridLayout) then + fd_dlg.setItems(fds_grid) + elseif luajava.instanceof(v,LinearLayout) then + fd_dlg.setItems(fds_linear) + elseif luajava.instanceof(v,CardView) then + fd_dlg.setItems(fds_card) + elseif luajava.instanceof(v,ViewGroup) then + fd_dlg.setItems(fds_group) + elseif luajava.instanceof(v,EditText) then + fd_dlg.setItems(fds_edit) + elseif luajava.instanceof(v,TextView) then + fd_dlg.setItems(fds_text) + elseif luajava.instanceof(v,ImageView) then + fd_dlg.setItems(fds_image) + else + fd_dlg.setItems(fds_view) + end + + + + if luajava.instanceof(v.Parent,LinearLayout) then + fd_list.getAdapter().add("layout_weight") + elseif luajava.instanceof(v.Parent,AbsoluteLayout) then + fd_list.getAdapter().insert(5,"layout_x") + fd_list.getAdapter().insert(6,"layout_y") + elseif luajava.instanceof(v.Parent,RelativeLayout) then + local adp=fd_list.getAdapter() + for k,v in ipairs(relative) do + adp.add(v) + end + end + local adapter = fd_list.adapter + local put_position = 4 + local unknow_fd = table.clone(curr) + + + --移除数字索引 + for k,v in pairs(unknow_fd) do + if tonumber(k) then + unknow_fd[k] = 0 + end + end + + for i = 0,adapter.count-1 do + local key = adapter.getItem(i) + + if key == "id" then + put_position = i + end + + if curr[key] then + adapter.remove(i) + adapter.insert(put_position,Html.fromHtml(""..key..":"..tostring(curr[key]).."")) + + unknow_fd[key] = nil + end + end + + for k,v in pairs(unknow_fd) do + if not tonumber(k) then + adapter.insert(put_position,Html.fromHtml(""..k..":"..tostring(v).."")) + end + end + + fd_dlg.show() +end + +function adapter(t) + local ls=ArrayList() + for k,v in ipairs(t) do + ls.add(v) + end + return ArrayAdapter(activity,android.R.layout.simple_list_item_1, ls) +end + +import "android.graphics.drawable.*" + + +curr=nil +activity.setTitle('布局助手') +activity.setTheme(autotheme()) +--activity.Theme=android.R.style.Theme_Material_Light +xpcall(function() + activity.setContentView(loadlayout2(layout.main,{})) +end, +function() + Toast.makeText(activity,"不支持编辑该布局\n(请检查布局文件是否出错)",1000).show() + activity.finish() +end) + +relative={ + "layout_above","layout_alignBaseline","layout_alignBottom","layout_alignEnd","layout_alignLeft","layout_alignParentBottom","layout_alignParentEnd","layout_alignParentLeft","layout_alignParentRight","layout_alignParentStart","layout_alignParentTop","layout_alignRight","layout_alignStart","layout_alignTop","layout_alignWithParentIfMissing","layout_below","layout_centerHorizontal","layout_centerInParent","layout_centerVertical","layout_toEndOf","layout_toLeftOf","layout_toRightOf","layout_toStartOf" +} + +--属性列表对话框 +fd_dlg=AlertDialogBuilder(activity) +fd_list=fd_dlg.getListView() +fds_grid={ + "添加","删除","父控件","子控件", + "id","orientation", + "columnCount","rowCount", + "layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_linear={ + "添加","删除","父控件","子控件", + "id","orientation","layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_group={ + "添加","删除","父控件","子控件", + "id","layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_edit={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","text","hint","textColorHint","inputType","digits","maxEms","textColor","textSize","singleLine","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_text={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","text","textColor","textSize","textStyle","singleLine","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_image={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","src","adjustViewBounds","scaleType","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_view={ + "删除","父控件", + "id","layout_width","layout_height","layout_gravity", + "background","gravity", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +fds_card={ + "添加","删除","父控件","子控件", + "id","layout_width","layout_height","layout_gravity", + "background","gravity","radius","elevation","backgroundColor", + "layout_margin","layout_marginLeft","layout_marginTop","layout_marginRight","layout_marginBottom", + "padding","paddingLeft","paddingTop","paddingRight","paddingBottom", +} + +--全部View操作 +local view_actions = { + fds_grid;fds_linear;fds_card;fds_group; + fds_edit;fds_text;fds_image;fds_view; +} + +for k,v in ipairs(view_actions) do + table.insert(v,3,"复制") + table.insert(v,4,"编辑") +end + +--属性选择列表 +checks={} +checks.textStyle = {"normal","bold","italic"} +checks.inputType = {"none","phone","text","datetime","date","textAutoComplete","textAutoCorrect","textCapCharacters","textCapSentences","textCapWords","textEmailAddress","textEmailSubject","textFilter","textImeMultiLine","textLongMessage","textMultiLine","textNoSuggestions","textPassword","textPersonName","textPhonetic","textPostalAddress","textShortMessage","textUri","textVisiblePassword","textWebEditText","textWebEmailAddress","textWebPassword","numberPassword","numberSigned","number","numberDecimal"} +checks.adjustViewBounds={"true","false","none"} +checks.layout_width={"fill","wrap","other"} +checks.layout_height={"fill","wrap","other"} +checks.singleLine={"true","false"} +checks.orientation={"vertical","horizontal"} +checks.gravity={"left","top","right","bottom","start","center","end"} +checks.layout_gravity={"left","top","right","bottom","start","center","end"} +checks.scaleType={ + "matrix", + "fitXY", + "fitStart", + "fitCenter", + "fitEnd", + "center", + "centerCrop", + "centerInside"} + + +function addDir(out,dir,f) + local ls=f.listFiles() + for n=0,#ls-1 do + local name=ls[n].getName() + if ls[n].isDirectory() then + addDir(out,dir..name.."/",ls[n]) + elseif name:find("%.j?pn?g$") then + table.insert(out,dir..name) + end + end +end + +function checkid() + local cs={} + local parent=currView.Parent.Tag + for k,v in ipairs(parent) do + if v==curr then + break + end + if type(v)=="table" and v.id then + table.insert(cs,v.id) + end + end + return cs +end + +rbs={"layout_alignParentBottom","layout_alignParentEnd","layout_alignParentLeft","layout_alignParentRight","layout_alignParentStart","layout_alignParentTop","layout_centerHorizontal","layout_centerInParent","layout_centerVertical"} +ris={"layout_above","layout_alignBaseline","layout_alignBottom","layout_alignEnd","layout_alignLeft","layout_alignRight","layout_alignStart","layout_alignTop","layout_alignWithParentIfMissing","layout_below","layout_toEndOf","layout_toLeftOf","layout_toRightOf","layout_toStartOf"} +for k,v in ipairs(rbs) do + checks[v]={"true","false","none"} +end + +for k,v in ipairs(ris) do + checks[v]=checkid +end + +if luadir then + checks.src=function() + local src={} + addDir(src,"",File(luadir)) + return src + end +end + +fd_list.onItemClick=function(l,v,p,i) + + fd_dlg.hide() + + local fd=tostring(v.Text) + if string.find(fd,":") then + fd = fd:gsub("%:.*","") + end + if checks[fd] then + if type(checks[fd])=="table" then + check_dlg.Title=fd + check_dlg.setItems(checks[fd]) + check_dlg.show() + else + check_dlg.Title=fd + check_dlg.setItems(checks[fd](fd)) + check_dlg.show() + end + else + func[fd]() + end +end + +--子视图列表对话框 +cd_dlg=AlertDialogBuilder(activity) +cd_list=cd_dlg.getListView() +cd_list.onItemClick=function(l,v,p,i) + getCurr(chids[p]) + cd_dlg.hide() +end + +--可选属性对话框 +check_dlg=AlertDialogBuilder(activity) +check_list=check_dlg.getListView() +check_list.onItemClick=function(l,v,p,i) + + local v=tostring(v.Text) + local fld=check_dlg.Title + if v == "other" then + check_dlg.hide() + func[fld]() + return + end + if #v==0 or v=="none" then + v=nil + end + local fld=check_dlg.Title + local old=curr[tostring(fld)] + curr[tostring(fld)]=v + check_dlg.hide() + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(fld)]=old + print(l) + end + + if holding_view then + getCurr(currView) + end +end + +func={} +setmetatable(func,{__index=function(t,k) + return function() + sfd_dlg.Title=k--tostring(currView.Class.getSimpleName()) + --sfd_dlg.Message=k + fld.Text= (curr[k] and tostring(curr[k])) or "" + fld.selectAll() + sfd_dlg.show() + fld.requestFocus() + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,InputMethodManager.HIDE_NOT_ALWAYS); + end + end +}) +func["添加"]=function() + add_dlg.Title=tostring(currView.Class.getSimpleName()) + for n=0,#ns-1 do + if n~=i then + el.collapseGroup(n) + end + end + add_dlg.show() +end + +func["删除"]=function() + local gp=currView.Parent.Tag + if gp==nil then + Toast.makeText(activity,"不可以删除顶部控件",1000).show() + return + end + for k,v in ipairs(gp) do + if v==curr then + table.remove(gp,k) + break + end + end + activity.setContentView(loadlayout2(layout.main,{})) +end + +func["复制"]=function() + local clone = table.clone(curr) + getCurr(currView.Parent) + table.insert(curr,clone) + + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(fld)]=old + print(l) + end + + fd_dlg.hide() +end + +func["编辑"]=function() + local _layout ={ + LinearLayout; + orientation="vertical"; + layout_height="fill"; + layout_width="fill"; + { + LuaEditor; + id="editor"; + layout_weight="1.0"; + layout_height="wrap"; + layout_width="fill"; + }; + { + LinearLayout; + layout_gravity="center"; + layout_width="fill"; + { + Button; + layout_weight="1"; + text="取消"; + id="cancel"; + }; + { + Button; + layout_weight="1"; + text="确定"; + id="ok"; + }; + }; + }; + local _ids = {} + local dialog = Dialog() + dialog.setContentView(loadlayout(_layout,_ids)) + dialog.setTitle("编辑控件布局代码") + dialog.cancelable = true + dialog.show() + _ids.editor.text = dumplayout2(curr) + Handler().postDelayed(function() + _ids.editor.format() + end,100) + _ids.cancel.onClick = function() + dialog.cancel() + end + + _ids.ok.onClick = function() + local code = _ids.editor.text + e,i = pcall(loadstring("return "..code)) + if e then + for k,v in pairs(i) do + curr[k] = v + end + dialog.cancel() + else + print("代码出错,请检查拼写!\n"..i) + end + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(fld)]=old + print(l) + end + end +end + +func["父控件"]=function() + local p=currView.Parent + if p.Tag==nil then + Toast.makeText(activity,"已是顶部控件",1000).show() + else + getCurr(p) + end +end + +chids={} +func["子控件"]=function() + chids={} + local arr={} + for n=0,currView.ChildCount-1 do + local chid=currView.getChildAt(n) + chids[n]=chid + table.insert(arr,chid.Class.getSimpleName()) + end + cd_dlg.Title=tostring(currView.Class.getSimpleName()) + cd_dlg.setItems(arr) + cd_dlg.show() +end + +--添加视图对话框 +add_dlg=Dialog(activity) +add_dlg.Title="添加" +wdt_list=ListView(activity) + +ns={ + "小部件","检查视图","适配器视图","高级控件","布局","高级布局","附加控件" +} + + +wdt={ + {"Button -按钮控件","EditText -编辑框控件","TextView -文本控件", + "ImageButton -图片按钮控件","ImageView -图片控件","CircleImageView -圆形图片控件","SearchView -搜索框"}, + {"CheckBox -复选框","RadioButton -单选框","ToggleButton -按钮开关控件","Switch -开关控件"}, + {"ListView -列表视图","GridView -网格视图","PageView -滑动视图","ExpandableListView -折叠列表","Spinner -下拉框"}, + {"SeekBar -拖动条","ProgressBar -进度条","RatingBar -评分栏", + "DatePicker -日期选择器","TimePicker -时间选择器","NumberPicker -数字选择器","Chronometer -计时器"}, + {"LinearLayout -线性布局","AbsoluteLayout -绝对布局","FrameLayout -帧布局","RelativeLayout -相对布局","TableLayout -表布局","RippleLayout -水波纹布局"}, + {"CardView -卡片控件","RadioGroup -单选视图","GridLayout -网格布局", + "ScrollView -纵向滚动布局","HorizontalScrollView -横向滚动布局"}, + {"LuaEditor -Lua代码编辑框","LuaWebView -Lua浏览器控件","PullingLayout -下拉刷新"} +} + +wds={ + {"Button","EditText","TextView", + "ImageButton","ImageView","CircleImageView","SearchView"}, + {"CheckBox","RadioButton","ToggleButton","Switch"}, + {"ListView","GridView","PageView","ExpandableListView","Spinner"}, + {"SeekBar","ProgressBar","RatingBar", + "DatePicker","TimePicker","NumberPicker","Chronometer"}, + {"LinearLayout","AbsoluteLayout","FrameLayout","RelativeLayout","TableLayout","RippleLayout"}, + {"CardView","RadioGroup","GridLayout", + "ScrollView","HorizontalScrollView"}, + {"LuaEditor","LuaWebView","PullingLayout"} +} + + +mAdapter=ArrayExpandableListAdapter(activity) +for k,v in ipairs(ns) do + mAdapter.add(v,wdt[k]) +end + +el=ExpandableListView(activity) +el.setAdapter(mAdapter) +add_dlg.setContentView(el) + +el.onChildClick=function(l,v,g,c) + local w={_G[wds[g+1][c+1]]} + table.insert(curr,w) + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + table.remove(curr) + print(l) + end + add_dlg.hide() +end + + + +function ok() + imm.hideSoftInputFromWindow(fld.getWindowToken(), 0) + local v=tostring(fld.Text) + if #v==0 then + v=nil + end + local fld=sfd_dlg.Title + local old=curr[tostring(fld)] + curr[tostring(fld)]=v + --sfd_dlg.hide() + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + + + if holding_view then + getCurr(currView) + end + else + curr[tostring(fld)]=old + print(l) + end + +end + +function none() + local old=curr[tostring(sfd_dlg.Title)] + curr[tostring(sfd_dlg.Title)]=nil + --sfd_dlg.hide() + local s,l=pcall(loadlayout2,layout.main,{}) + if s then + activity.setContentView(l) + else + curr[tostring(sfd_dlg.Title)]=old + print(l) + end + imm.hideSoftInputFromWindow(fld.getWindowToken(), 0) + + if holding_view then + getCurr(currView) + end +end + + +--输入属性对话框 +sfd_dlg=AlertDialogBuilder(activity) +fld=EditText(activity) +fld.setFocusable(true); +fld.setFocusableInTouchMode(true); +sfd_dlg.setView(fld) +sfd_dlg.setPositiveButton("确定",{onClick=ok}) +sfd_dlg.setNegativeButton("取消",{onClick=function() + --隐藏键盘 + imm.hideSoftInputFromWindow(fld.getWindowToken(), 0) + if holding_view then + getCurr(currView) + end +end}) +sfd_dlg.setNeutralButton("无",{onClick=none}) +function dumparray(arr) + local ret={} + table.insert(ret,"{\n") + for k,v in ipairs(arr) do + table.insert(ret,string.format("\"%s\";\n",v)) + end + table.insert(ret,"};\n") + return table.concat(ret) +end +function dumplayout(t) + table.insert(ret,"{\n") + table.insert(ret,tostring(t[1].getSimpleName()..";\n")) + for k,v in pairs(t) do + if type(k)=="number" then + --do nothing + elseif type(v)=="table" then + table.insert(ret,k.."="..dumparray(v)) + elseif type(v)=="string" then + if v:find("[\"\'\r\n]") then + table.insert(ret,string.format("%s=[==[%s]==];\n",k,v)) + else + table.insert(ret,string.format("%s=\"%s\";\n",k,v)) + end + else + table.insert(ret,string.format("%s=%s;\n",k,tostring(v))) + end + end + for k,v in ipairs(t) do + if type(v)=="table" then + dumplayout(v) + end + end + table.insert(ret,"};\n") +end + +function dumplayout2(t) + ret={} + dumplayout(t) + return table.concat(ret) +end + +function onCreateOptionsMenu(menu) + menu.add("复制") + menu.add("编辑") + menu.add("预览") + if showsave then + menu.add("保存") + end +end + +function save(s) + local f=io.open(luapath,"w") + f:write(s) + f:close() +end + +import "android.content.*" +cm=activity.getSystemService(activity.CLIPBOARD_SERVICE) + +function onMenuItemSelected(id,item) + local t=item.getTitle() + if t=="复制" then + local cd = ClipData.newPlainText("label",dumplayout2(layout.main)) + cm.setPrimaryClip(cd) + Toast.makeText(activity,"已复制到剪切板",1000).show() + elseif t=="编辑" then + editlayout(dumplayout2(layout.main)) + elseif t=="预览" then + show(dumplayout2(layout.main)) + elseif t=="保存" then + if luapath:find("%.lua$") then + activity.result({dumplayout2(layout.main)}) + return + end + save(dumplayout2(layout.main)) + Toast.makeText(activity,"已保存",1000).show() + activity.setResult(10000,Intent()); + activity.finish() + end +end + +function onStart() + activity.setContentView(loadlayout2(layout.main,{})) +end + +lastclick=os.time()-2 +function onKeyDown(e) + local now=os.time() + if e==4 then + if now-lastclick>2 then + Toast.makeText(activity, "再按一次返回.", Toast.LENGTH_SHORT ).show() + lastclick=now + return true + end + end +end + + diff --git a/app/src/main/assets/oat/arm/mao.odex b/app/src/main/assets/oat/arm/mao.odex new file mode 100644 index 0000000..8688fdf Binary files /dev/null and b/app/src/main/assets/oat/arm/mao.odex differ diff --git a/app/src/main/assets/oat/arm/mao.vdex b/app/src/main/assets/oat/arm/mao.vdex new file mode 100644 index 0000000..9381eb0 Binary files /dev/null and b/app/src/main/assets/oat/arm/mao.vdex differ diff --git a/app/src/main/assets/oat/arm/sign.odex b/app/src/main/assets/oat/arm/sign.odex new file mode 100644 index 0000000..25dc845 Binary files /dev/null and b/app/src/main/assets/oat/arm/sign.odex differ diff --git a/app/src/main/assets/oat/arm/sign.vdex b/app/src/main/assets/oat/arm/sign.vdex new file mode 100644 index 0000000..7be1474 Binary files /dev/null and b/app/src/main/assets/oat/arm/sign.vdex differ diff --git a/app/src/main/assets/oat/arm64/mao.odex b/app/src/main/assets/oat/arm64/mao.odex new file mode 100644 index 0000000..6f790d1 Binary files /dev/null and b/app/src/main/assets/oat/arm64/mao.odex differ diff --git a/app/src/main/assets/oat/arm64/mao.vdex b/app/src/main/assets/oat/arm64/mao.vdex new file mode 100644 index 0000000..9381eb0 Binary files /dev/null and b/app/src/main/assets/oat/arm64/mao.vdex differ diff --git a/app/src/main/assets/oat/arm64/sign.odex b/app/src/main/assets/oat/arm64/sign.odex new file mode 100644 index 0000000..9da665b Binary files /dev/null and b/app/src/main/assets/oat/arm64/sign.odex differ diff --git a/app/src/main/assets/oat/arm64/sign.vdex b/app/src/main/assets/oat/arm64/sign.vdex new file mode 100644 index 0000000..7be1474 Binary files /dev/null and b/app/src/main/assets/oat/arm64/sign.vdex differ diff --git a/app/src/main/assets/other.lua b/app/src/main/assets/other.lua new file mode 100644 index 0000000..c540408 --- /dev/null +++ b/app/src/main/assets/other.lua @@ -0,0 +1,31 @@ +import "java.io.File" +import "AndLua" +软件文件夹="/sdcard/ThomeLua" +项目文件夹=软件文件夹.."/project" +备份文件夹=软件文件夹.."/backup" +打包文件夹=软件文件夹.."/bin" +解压文件夹=软件文件夹.."/Decompression" +a=File(软件文件夹).isDirectory() +if a==false then + 创建文件夹(软件文件夹) +end +a=File(项目文件夹).isDirectory() +if a==false then + 创建文件夹(项目文件夹) +end +a=File(备份文件夹).isDirectory() +if a==false then + 创建文件夹(备份文件夹) +end +a=File(打包文件夹).isDirectory() +if a==false then + 创建文件夹(打包文件夹) +end +a=File(解压文件夹).isDirectory() +if a==false then + 创建文件夹(解压文件夹) +end +a=File("/sdcard/.cookie.dat").isFile() +if a==false then + 创建文件("/sdcard/.cookie.dat") +end diff --git a/app/src/main/assets/picture/1642739853191.png b/app/src/main/assets/picture/1642739853191.png new file mode 100644 index 0000000..40a29cb Binary files /dev/null and b/app/src/main/assets/picture/1642739853191.png differ diff --git a/app/src/main/assets/picture/a1.png b/app/src/main/assets/picture/a1.png new file mode 100644 index 0000000..7c01e5d Binary files /dev/null and b/app/src/main/assets/picture/a1.png differ diff --git a/app/src/main/assets/picture/a2.png b/app/src/main/assets/picture/a2.png new file mode 100644 index 0000000..62ee2a5 Binary files /dev/null and b/app/src/main/assets/picture/a2.png differ diff --git a/app/src/main/assets/picture/a3.png b/app/src/main/assets/picture/a3.png new file mode 100644 index 0000000..7e7af64 Binary files /dev/null and b/app/src/main/assets/picture/a3.png differ diff --git a/app/src/main/assets/picture/a4.png b/app/src/main/assets/picture/a4.png new file mode 100644 index 0000000..b5d5323 Binary files /dev/null and b/app/src/main/assets/picture/a4.png differ diff --git a/app/src/main/assets/picture/a5.png b/app/src/main/assets/picture/a5.png new file mode 100644 index 0000000..b4452be Binary files /dev/null and b/app/src/main/assets/picture/a5.png differ diff --git a/app/src/main/assets/picture/b1.png b/app/src/main/assets/picture/b1.png new file mode 100644 index 0000000..9ddbba9 Binary files /dev/null and b/app/src/main/assets/picture/b1.png differ diff --git a/app/src/main/assets/picture/b2.png b/app/src/main/assets/picture/b2.png new file mode 100644 index 0000000..7059834 Binary files /dev/null and b/app/src/main/assets/picture/b2.png differ diff --git a/app/src/main/assets/picture/b3.png b/app/src/main/assets/picture/b3.png new file mode 100644 index 0000000..40e4760 Binary files /dev/null and b/app/src/main/assets/picture/b3.png differ diff --git a/app/src/main/assets/picture/b4.png b/app/src/main/assets/picture/b4.png new file mode 100644 index 0000000..34a6d04 Binary files /dev/null and b/app/src/main/assets/picture/b4.png differ diff --git a/app/src/main/assets/picture/privatemsg_chat_my_bg.9.png b/app/src/main/assets/picture/privatemsg_chat_my_bg.9.png new file mode 100644 index 0000000..1bfd33b Binary files /dev/null and b/app/src/main/assets/picture/privatemsg_chat_my_bg.9.png differ diff --git a/app/src/main/assets/picture/privatemsg_chat_other_bg.9.png b/app/src/main/assets/picture/privatemsg_chat_other_bg.9.png new file mode 100644 index 0000000..78d4209 Binary files /dev/null and b/app/src/main/assets/picture/privatemsg_chat_other_bg.9.png differ diff --git a/app/src/main/assets/plugin/init.lua b/app/src/main/assets/plugin/init.lua new file mode 100644 index 0000000..a0c49d0 --- /dev/null +++ b/app/src/main/assets/plugin/init.lua @@ -0,0 +1,10 @@ +appname="插件" +appver="1.1" +packagename="com.androlua.plugin" +developer="nirenr" +description="插件管理" +debugmode=true +user_permission={ + "INTERNET", + "WRITE_EXTERNAL_STORAGE" +} diff --git a/app/src/main/assets/plugin/item.aly b/app/src/main/assets/plugin/item.aly new file mode 100644 index 0000000..b8d6382 --- /dev/null +++ b/app/src/main/assets/plugin/item.aly @@ -0,0 +1,32 @@ +{ + LinearLayout; + layout_width="fill"; + { + ImageView; + id="icon"; + padding="2dp"; + layout_width="64dp"; + layout_height="64dp"; + }; + { + FrameLayout; + padding="2dp"; + layout_width="fill"; + layout_height="64dp"; + { + TextView; + id="title"; + layout_width="fill"; + singleLine="true"; + textSize="20sp"; + }; + { + TextView; + textSize="14sp"; + id="description"; + layout_width="fill"; + singleLine="true"; + layout_gravity="bottom"; + }; + }; +}; diff --git a/app/src/main/assets/plugin/layout.aly b/app/src/main/assets/plugin/layout.aly new file mode 100644 index 0000000..d668f3d --- /dev/null +++ b/app/src/main/assets/plugin/layout.aly @@ -0,0 +1,10 @@ +{ + LinearLayout, + layout_width="fill", + orientation="vertical", + { + ListView, + id="plist", + layout_width="fill" + }, +} diff --git a/app/src/main/assets/plugin/main.lua b/app/src/main/assets/plugin/main.lua new file mode 100644 index 0000000..a5b18cb --- /dev/null +++ b/app/src/main/assets/plugin/main.lua @@ -0,0 +1,256 @@ +require "import" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "java.io.File" +import "layout" +import "item" +import "autotheme" + +activity.setTitle('插件') +function getFilesDir() + return "/data/user/0/"..activity.getPackageName().."/files/" +end +local a=io.open(getFilesDir().."/Verify/set4.XY"):read("*a") +local ip=a:match("2(.-)"..'"') +if ip=="开" then + 颜色1=0xff303030 + 颜色2=0xff212121 + 颜色3=0xffffffff + 颜色4=0xffffffff + 颜色6=0xffffffff + 颜色5=0xff212121 + 颜色7=0xEBFFFFFF + activity.setTheme(android.R.style.Theme_DeviceDefault) + else + 颜色1=0xffffffff + 颜色3=0xff303030 + 颜色4=0xff757575 + 颜色2=0xFFF2F1F6 + 颜色6=0xff757575 + 颜色5=0x5FFFFFFF + 颜色7=0xff303030 + activity.setTheme(android.R.style.Theme_DeviceDefault_Light) +end +activity.setContentView(loadlayout(layout)) + +local luadir,luapath=... +local plugindir=activity.getLuaExtDir("plugin") + +local function getinfo(dir) + local app={} + loadfile(plugindir.."/"..dir.."/init.lua","bt",app)() + return app +end + +local pds=File(plugindir).list() +Arrays.sort(pds) +local pls={} +local pps={} +for n=0,#pds-1 do + local s,i=pcall(getinfo,pds[n]) + if s then + table.insert(pls,i) + table.insert(pps,pds[n]) + end +end + +function checkicon(i) + i=plugindir.."/"..pps[i].."/icon.png" + local f=io.open(i) + if f then + f:close() + return i + else + return R.drawable.icon + end +end + +adp=LuaAdapter(activity,item) +for k,v in ipairs(pls) do + adp.add{icon=checkicon(k),title=v.appname.." "..v.appver,description=v.description or ""} +end +plist.Adapter=adp +plist.onItemClick=function(l,v,p,i) + activity.newActivity(plugindir.."/"..pps[p+1].."/main.lua",{luadir,luapath}) +end +import "android.content.*" +import "android.graphics.drawable.StateListDrawable" +function onCreateOptionsMenu(menu) + menu.add("导入插件").setShowAsAction(1) +end +import "android.graphics.Typeface" +local Text_Type=Typeface.defaultFromStyle(Typeface.BOLD) +local sd = StateListDrawable() +import "android.graphics.Color" +import "android.content.res.ColorStateList" +import "android.graphics.drawable.RippleDrawable" +import "android.content.Context" +appt={C_Bacgg=function(mBinding,radiu,InsideColor,S,S2,T1) + local drawable = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{}); + drawable.setCornerRadius(radiu); + drawable.setColor(颜色5) + drawable.setStroke(3, 0xCFB0B0B0) + drawable.setGradientType(GradientDrawable.RECTANGLE); + mBinding.setTextColor(T1) + mBinding.setTypeface(Text_Type) + return drawable + end} +美化按钮1=function(mBinding,radiu,InsideColor,T1) + stateList = { + {android.R.attr.state_pressed}, + {android.R.attr.state_focused}, + {android.R.attr.state_activated}, + {android.R.attr.selectableItemBackground}, + }; + sd.addState({ android.R.attr.state_enabled}, appt.C_Bacgg(mBinding,radiu,InsideColor,S,S2,T1)) + pressedColor =InsideColor --Color.parseColor("#7ab946ff"); + stateColorList ={ + pressedColor, + pressedColor, + pressedColor, + normalColor + }; + colorStateList = ColorStateList(stateList, stateColorList); + rippleDrawable = RippleDrawable(colorStateList,sd,nil); + mBinding.setBackground(rippleDrawable); +end +cm=activity.getSystemService(Context.CLIPBOARD_SERVICE) +function 控件圆角(view,InsideColor,radiu) + import "android.graphics.drawable.GradientDrawable" + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(InsideColor) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + view.setBackgroundDrawable(drawable) +end +function onOptionsItemSelected(item) + if item.Title=="导入插件" then + tj= + { + CardView; + radius=30; + layout_width="match_parent"; + --orientation="vertical"; + layout_height="match_parent"; + { + CardView; + layout_gravity="center"; + layout_height="300dp"; + layout_width="match_parent"; + backgroundColor=颜色1, + radius=20; + { + TextView; + layout_marginTop="15dp"; + layout_marginLeft="20dp"; + textSize="20sp"; + textColor="0xFF03A9F4"; + text="导入插件(*.XX)"; + }; + { + LinearLayout; + orientation="horizontal"; + layout_width="match_parent"; + layout_height="150dp"; + gravity="center"; + { + EditText; + layout_marginTop="10dp", + layout_width="320dp"; + gravity="center"; + textSize="15sp"; + hint="请输入插件路径"; + id="输入插件", + textColor=颜色4, + --HintTextColor=颜色4, + }; + }; + + { + LinearLayout; + layout_height="match_parent"; + layout_width="match_parent"; + { + Button; + id="取消创建工程", + layout_gravity="center"; + layout_marginLeft="20dp"; + textColor="0x7E000000"; + text="取消"; + layout_marginTop="50dp", + layout_height="40dp"; + }; + { + LinearLayout; + gravity="right"; + layout_width="match_parent"; + layout_height="match_parent"; + { + Button; + layout_height="40dp"; + id="确定创建工程", + layout_marginTop="50dp", + layout_gravity="center"; + layout_marginRight="20dp"; + textColor="0xFF03A9F4"; + text="导入"; + }; + }; + }; + }; + }; + + + + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + dialog1.getWindow().setContentView(loadlayout(tj)); + import "android.content.res.ColorStateList" + import "android.graphics.drawable.ColorDrawable" + import "android.graphics.drawable.GradientDrawable" + import "android.graphics.drawable.RippleDrawable" + import "android.content.res.ColorStateList" + import "android.graphics.drawable.ColorDrawable" + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + local dialogWindow = dialog1.getWindow(); + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + 美化按钮1(取消创建工程,10,0x7E000000,颜色7) + 美化按钮1(确定创建工程,10,0x7a00bfff,0xFF03A9F4) + 控件圆角(输入插件,颜色2,30) + function 取消创建工程.onClick() + dialog1.dismiss() + end + function exec(cmd,sh,su) + cmd=tostring(cmd) + if sh==true then + cmd=io.open(cmd):read("*a") + end + if su==0 then + p=io.popen(string.format('%s',cmd)) + else + p=io.popen(string.format('%s',"su -c "..cmd)) + end + local s=p:read("*a") + p:close() + return s + end + + + function 确定创建工程.onClick() + 插件路径="/storage/emulated/0/ThomeLua/plugin/" + 插件名称=File(输入插件.Text).getName():match("(.-).XX") + exec("cp -r "..输入插件.Text.." "..插件路径) + os.execute('mkdir '..插件路径..插件名称) + os.execute("mv "..插件路径..插件名称..".XX".." "..插件路径..插件名称..".zip") + ZipUtil.unzip(插件路径..插件名称..".zip",插件路径..插件名称) + os.execute("rm -r "..插件路径..插件名称..".zip") + print("导入成功") + dialog1.dismiss() + end + end +end + diff --git a/app/src/main/assets/project.aly b/app/src/main/assets/project.aly new file mode 100644 index 0000000..e37a325 --- /dev/null +++ b/app/src/main/assets/project.aly @@ -0,0 +1,74 @@ +{ + RelativeLayout; + layout_width="fill"; + layout_height="fill"; + background="#000000"; + { + LinearLayout; + layout_height="-1"; + layout_width="-1"; + }; + { + Button; + layout_height="56dp"; + layout_marginRight="32dp"; + background="#ff50f8f8"; + id="bt"; + layout_alignParentRight="true"; + layout_width="56dp"; + layout_alignParentBottom="true"; + text="+"; + textSize="25sp", + textColor="#ffffffff", + layout_marginBottom="62dp"; + }; + { + Button; + layout_alignLeft="bt"; + layout_height="56dp"; + id="bt1"; + layout_above="bt"; + background="#ff50f8f8"; + layout_width="56dp"; + Visibility="invisible"; + textColor="#ffffffff", + layout_marginBottom="16dp"; + }; + { + Button; + layout_alignLeft="bt"; + layout_height="56dp"; + id="bt2"; + layout_above="bt1"; + background="#ff50f8f8"; + layout_width="56dp"; + textColor="#ffffffff", + Visibility="invisible"; + layout_marginBottom="16dp"; + }; + { + DrawerLayout; + --gravity="center"; + layout_height="fill"; + layout_width="fill"; + id="优化", + + { + PullRefreshLayout; + backgroundColor=颜色2; + layout_height="fill"; + layout_width="fill"; + id="sx"; + + { + ListView; + id="项目列表"; + DividerHeight=0; + verticalScrollBarEnabled=false; + -- layout_gravity="end"; + layout_width="fill"; + + }; + }; + }; +}; \ No newline at end of file diff --git a/app/src/main/assets/projectitem.aly b/app/src/main/assets/projectitem.aly new file mode 100644 index 0000000..04da43c --- /dev/null +++ b/app/src/main/assets/projectitem.aly @@ -0,0 +1,99 @@ +{ + LinearLayout; + layout_height="fill"; + layout_width="fill"; + gravity="center"; + { + LinearLayout; + layout_height="10.2%h"; + layout_width="fill"; + gravity="center"; + { + CardView; + layout_height="8.8%h"; + backgroundColor=颜色1; + layout_width="97.2%w"; + CardElevation=0; + layout_gravity="center"; + radius=20; + { + LinearLayout; + layout_height="fill"; + layout_width="fill"; + orientation="horizontal"; + { + ImageView; + layout_height="6.6%h"; + id="图标"; + layout_width="12.5%w"; + layout_marginLeft="10dp"; + layout_gravity="center"; + src="icon.png"; + }; + { + LinearLayout; + layout_height="fill"; + layout_width="fill"; + orientation="vertical"; + { + LinearLayout; + layout_width="fill"; + layout_height="4.4%h"; + { + TextView; + id="软件名"; + layout_width="fill"; + layout_gravity="center"; + layout_marginTop="4dp"; + layout_marginLeft="10dp"; + text="软件名"; + textSize="16sp"; + textColor=颜色4, + layout_height="3.6%h"; + }; + }; + { + LinearLayout; + layout_width="fill"; + layout_height="fill"; + { + LinearLayout; + layout_height="fill"; + layout_gravity="center"; + { + TextView; + id="版本"; + textColor=颜色4, + layout_marginBottom="2dp"; + layout_marginLeft="2.7%w"; + text="版本:"; + textSize="13sp"; + layout_gravity="center"; + }; + }; + { + LinearLayout; + layout_height="fill"; + layout_marginLeft="2.7%w"; + { + TextView; + id="包名"; + textColor=颜色4, + layout_marginBottom="2dp"; + layout_marginLeft="3.4%w"; + text="包名:"; + textSize="13sp"; + layout_gravity="center"; + }; + { + TextView; + id="文件夹名称"; + textSize="0sp"; + }; + }; + }; + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/app/src/main/assets/res/ThomeLua1.png b/app/src/main/assets/res/ThomeLua1.png new file mode 100644 index 0000000..0349dec Binary files /dev/null and b/app/src/main/assets/res/ThomeLua1.png differ diff --git a/app/src/main/assets/res/ThomeLua10.png b/app/src/main/assets/res/ThomeLua10.png new file mode 100644 index 0000000..d9121b9 Binary files /dev/null and b/app/src/main/assets/res/ThomeLua10.png differ diff --git a/app/src/main/assets/res/ThomeLua11.png b/app/src/main/assets/res/ThomeLua11.png new file mode 100644 index 0000000..7b845df Binary files /dev/null and b/app/src/main/assets/res/ThomeLua11.png differ diff --git a/app/src/main/assets/res/ThomeLua2.png b/app/src/main/assets/res/ThomeLua2.png new file mode 100644 index 0000000..ee04de4 Binary files /dev/null and b/app/src/main/assets/res/ThomeLua2.png differ diff --git a/app/src/main/assets/res/ThomeLua3.png b/app/src/main/assets/res/ThomeLua3.png new file mode 100644 index 0000000..7171cd9 Binary files /dev/null and b/app/src/main/assets/res/ThomeLua3.png differ diff --git a/app/src/main/assets/res/ThomeLua4.png b/app/src/main/assets/res/ThomeLua4.png new file mode 100644 index 0000000..3e30756 Binary files /dev/null and b/app/src/main/assets/res/ThomeLua4.png differ diff --git a/app/src/main/assets/res/ThomeLua5.png b/app/src/main/assets/res/ThomeLua5.png new file mode 100644 index 0000000..b89ffc9 Binary files /dev/null and b/app/src/main/assets/res/ThomeLua5.png differ diff --git a/app/src/main/assets/res/ThomeLua6.png b/app/src/main/assets/res/ThomeLua6.png new file mode 100644 index 0000000..ee617e6 Binary files /dev/null and b/app/src/main/assets/res/ThomeLua6.png differ diff --git a/app/src/main/assets/res/ThomeLua7.png b/app/src/main/assets/res/ThomeLua7.png new file mode 100644 index 0000000..d055cce Binary files /dev/null and b/app/src/main/assets/res/ThomeLua7.png differ diff --git a/app/src/main/assets/res/ThomeLua8.png b/app/src/main/assets/res/ThomeLua8.png new file mode 100644 index 0000000..4d2196b Binary files /dev/null and b/app/src/main/assets/res/ThomeLua8.png differ diff --git a/app/src/main/assets/res/ThomeLua9.png b/app/src/main/assets/res/ThomeLua9.png new file mode 100644 index 0000000..48bee49 Binary files /dev/null and b/app/src/main/assets/res/ThomeLua9.png differ diff --git a/app/src/main/assets/res/a.png b/app/src/main/assets/res/a.png new file mode 100644 index 0000000..d6199e5 Binary files /dev/null and b/app/src/main/assets/res/a.png differ diff --git a/app/src/main/assets/res/a1.png b/app/src/main/assets/res/a1.png new file mode 100644 index 0000000..7d54abf Binary files /dev/null and b/app/src/main/assets/res/a1.png differ diff --git a/app/src/main/assets/res/a2.png b/app/src/main/assets/res/a2.png new file mode 100644 index 0000000..d5ff7dd Binary files /dev/null and b/app/src/main/assets/res/a2.png differ diff --git a/app/src/main/assets/res/a3.png b/app/src/main/assets/res/a3.png new file mode 100644 index 0000000..31837b2 Binary files /dev/null and b/app/src/main/assets/res/a3.png differ diff --git a/app/src/main/assets/res/b.png b/app/src/main/assets/res/b.png new file mode 100644 index 0000000..32d2c63 Binary files /dev/null and b/app/src/main/assets/res/b.png differ diff --git a/app/src/main/assets/res/b1.png b/app/src/main/assets/res/b1.png new file mode 100644 index 0000000..74d975a Binary files /dev/null and b/app/src/main/assets/res/b1.png differ diff --git a/app/src/main/assets/res/b2.png b/app/src/main/assets/res/b2.png new file mode 100644 index 0000000..c7d7d26 Binary files /dev/null and b/app/src/main/assets/res/b2.png differ diff --git a/app/src/main/assets/res/b3.png b/app/src/main/assets/res/b3.png new file mode 100644 index 0000000..ae88da0 Binary files /dev/null and b/app/src/main/assets/res/b3.png differ diff --git a/app/src/main/assets/res/bft.png b/app/src/main/assets/res/bft.png new file mode 100644 index 0000000..54a5405 Binary files /dev/null and b/app/src/main/assets/res/bft.png differ diff --git a/app/src/main/assets/res/c.png b/app/src/main/assets/res/c.png new file mode 100644 index 0000000..17c53cf Binary files /dev/null and b/app/src/main/assets/res/c.png differ diff --git a/app/src/main/assets/res/d1.png b/app/src/main/assets/res/d1.png new file mode 100644 index 0000000..4516768 Binary files /dev/null and b/app/src/main/assets/res/d1.png differ diff --git a/app/src/main/assets/res/d2.png b/app/src/main/assets/res/d2.png new file mode 100644 index 0000000..c4b6703 Binary files /dev/null and b/app/src/main/assets/res/d2.png differ diff --git a/app/src/main/assets/res/d3.png b/app/src/main/assets/res/d3.png new file mode 100644 index 0000000..ca72c25 Binary files /dev/null and b/app/src/main/assets/res/d3.png differ diff --git a/app/src/main/assets/res/d4.png b/app/src/main/assets/res/d4.png new file mode 100644 index 0000000..14773be Binary files /dev/null and b/app/src/main/assets/res/d4.png differ diff --git a/app/src/main/assets/res/end1.png b/app/src/main/assets/res/end1.png new file mode 100644 index 0000000..cd071ab Binary files /dev/null and b/app/src/main/assets/res/end1.png differ diff --git a/app/src/main/assets/res/end2.png b/app/src/main/assets/res/end2.png new file mode 100644 index 0000000..b8a940e Binary files /dev/null and b/app/src/main/assets/res/end2.png differ diff --git a/app/src/main/assets/res/end3.png b/app/src/main/assets/res/end3.png new file mode 100644 index 0000000..1675b2b Binary files /dev/null and b/app/src/main/assets/res/end3.png differ diff --git a/app/src/main/assets/res/end4.png b/app/src/main/assets/res/end4.png new file mode 100644 index 0000000..692117b Binary files /dev/null and b/app/src/main/assets/res/end4.png differ diff --git a/app/src/main/assets/res/end5.png b/app/src/main/assets/res/end5.png new file mode 100644 index 0000000..7dc9748 Binary files /dev/null and b/app/src/main/assets/res/end5.png differ diff --git a/app/src/main/assets/res/search.png b/app/src/main/assets/res/search.png new file mode 100644 index 0000000..21318f4 Binary files /dev/null and b/app/src/main/assets/res/search.png differ diff --git a/app/src/main/assets/res/set.png b/app/src/main/assets/res/set.png new file mode 100644 index 0000000..d7ee59c Binary files /dev/null and b/app/src/main/assets/res/set.png differ diff --git a/app/src/main/assets/res2/apk.png b/app/src/main/assets/res2/apk.png new file mode 100644 index 0000000..39c7e92 Binary files /dev/null and b/app/src/main/assets/res2/apk.png differ diff --git a/app/src/main/assets/res2/compression.png b/app/src/main/assets/res2/compression.png new file mode 100644 index 0000000..4a6f3a4 Binary files /dev/null and b/app/src/main/assets/res2/compression.png differ diff --git a/app/src/main/assets/res2/file.png b/app/src/main/assets/res2/file.png new file mode 100644 index 0000000..5c5a117 Binary files /dev/null and b/app/src/main/assets/res2/file.png differ diff --git a/app/src/main/assets/res2/folder.png b/app/src/main/assets/res2/folder.png new file mode 100644 index 0000000..d52509b Binary files /dev/null and b/app/src/main/assets/res2/folder.png differ diff --git a/app/src/main/assets/res2/image.png b/app/src/main/assets/res2/image.png new file mode 100644 index 0000000..823d419 Binary files /dev/null and b/app/src/main/assets/res2/image.png differ diff --git a/app/src/main/assets/res2/music.png b/app/src/main/assets/res2/music.png new file mode 100644 index 0000000..bfa41f7 Binary files /dev/null and b/app/src/main/assets/res2/music.png differ diff --git a/app/src/main/assets/res2/pdf.png b/app/src/main/assets/res2/pdf.png new file mode 100644 index 0000000..1fd10c1 Binary files /dev/null and b/app/src/main/assets/res2/pdf.png differ diff --git a/app/src/main/assets/res2/text.png b/app/src/main/assets/res2/text.png new file mode 100644 index 0000000..4c2ee50 Binary files /dev/null and b/app/src/main/assets/res2/text.png differ diff --git a/app/src/main/assets/res2/video.png b/app/src/main/assets/res2/video.png new file mode 100644 index 0000000..7148db4 Binary files /dev/null and b/app/src/main/assets/res2/video.png differ diff --git a/app/src/main/assets/res2/xml.png b/app/src/main/assets/res2/xml.png new file mode 100644 index 0000000..aa0690f Binary files /dev/null and b/app/src/main/assets/res2/xml.png differ diff --git a/app/src/main/assets/res3/1.png b/app/src/main/assets/res3/1.png new file mode 100644 index 0000000..5b2be87 Binary files /dev/null and b/app/src/main/assets/res3/1.png differ diff --git a/app/src/main/assets/res3/2.png b/app/src/main/assets/res3/2.png new file mode 100644 index 0000000..cceb4a6 Binary files /dev/null and b/app/src/main/assets/res3/2.png differ diff --git a/app/src/main/assets/res3/3.png b/app/src/main/assets/res3/3.png new file mode 100644 index 0000000..4539bee Binary files /dev/null and b/app/src/main/assets/res3/3.png differ diff --git a/app/src/main/assets/res3/4.png b/app/src/main/assets/res3/4.png new file mode 100644 index 0000000..578ffc7 Binary files /dev/null and b/app/src/main/assets/res3/4.png differ diff --git a/app/src/main/assets/res3/5.png b/app/src/main/assets/res3/5.png new file mode 100644 index 0000000..522b655 Binary files /dev/null and b/app/src/main/assets/res3/5.png differ diff --git a/app/src/main/assets/toast.lua b/app/src/main/assets/toast.lua new file mode 100644 index 0000000..90c4de0 --- /dev/null +++ b/app/src/main/assets/toast.lua @@ -0,0 +1,30 @@ +function print(内容) + tsbj={ + LinearLayout; + layout_width="fill"; + layout_height="fill"; + gravity="center"; + orientation="vertical"; + { + CardView; + radius=15, + CardElevation="0dp"; + backgroundColor="0xff6f6f6f"; + { + TextView; + layout_marginRight="35dp"; + text="提示"; + id="提示内容", + textColor="0xffffffff"; + layout_marginLeft="35dp"; + layout_marginTop="10dp"; + layout_gravity="center"; + layout_marginBottom="10dp"; + }; + }; + }; + local toast=Toast.makeText(activity,"内容",Toast.LENGTH_SHORT).setView(loadlayout(tsbj)) + toast.setGravity(Gravity.BOTTOM,0,100) + 提示内容.Text=tostring(内容) + toast.show() +end \ No newline at end of file diff --git a/app/src/main/assets/xml2table.lua b/app/src/main/assets/xml2table.lua new file mode 100644 index 0000000..8ace383 --- /dev/null +++ b/app/src/main/assets/xml2table.lua @@ -0,0 +1,137 @@ +require "import" +import "console" +import "android.app.*" +import "android.os.*" +import "android.widget.*" +import "android.view.*" +import "android.content.*" +import "com.androlua.*" +import "loadlayout3" +import "autotheme" +activity.setTheme(autotheme()) +--activity.setTitle('XML转换器') +--activity.setTheme(android.R.style.Theme_Holo_Light) +cm=activity.getSystemService(Context.CLIPBOARD_SERVICE) +t={ + LinearLayout, + id="l", + orientation="vertical" , + --backgroundColor="#eeeeff", + { + LuaEditor, + id="edit", + --hint= "XML布局代码转换AndroLua布局表", + layout_width="fill", + layout_height="fill", + layout_weight=1, + --gravity="top" + }, + { + LinearLayout, + layout_width="fill", + backgroundColor="#eeeeff", + { + Button, + id="open", + text="转换", + layout_width="fill", + layout_weight=1, + onClick ="click", + } , + { + Button, + id="open", + text="预览", + layout_width="fill", + layout_weight=1, + onClick ="click2", + } , + { + Button, + id="open", + text="复制", + layout_width="fill", + layout_weight=1, + onClick ="click3", + } , + { + Button, + id="open", + text="确定", + layout_width="fill", + layout_weight=1, + onClick ="click4", + } , + } +} + +function xml2table(xml) + local xml,s=xml:gsub("","}") + if s==0 then + return xml + end + xml=xml:gsub("<%?[^<>]+%?>","") + xml=xml:gsub("xmlns:android=%b\"\"","") + xml=xml:gsub("%w+:","") + xml=xml:gsub("\"([^\"]+)\"",function(s)return (string.format("\"%s\"",s:match("([^/]+)$")))end) + xml=xml:gsub("[\t ]+","") + xml=xml:gsub("\n+","\n") + xml=xml:gsub("^\n",""):gsub("\n$","") + xml=xml:gsub("<","{"):gsub("/>","}"):gsub(">",""):gsub("\n",",\n") + return (xml) +end + +dlg=Dialog(activity,autotheme()) +dlg.setTitle("布局表预览") +function show(s) + dlg.setContentView(loadlayout3(loadstring("return "..s)(),{})) + dlg.show() +end + +function click() + local str=edit.getText().toString() + str=xml2table(str) + str=console.format(str) + edit.setText(str) +end + +function click2() + local str=edit.getText().toString() + show(str) +end + + +function click3(s) + local cd = ClipData.newPlainText("label", edit.getText().toString()) + cm.setPrimaryClip(cd) + Toast.makeText(activity,"已复制的剪切板",1000).show() +end + +function click4() + local str=edit.getText().toString() + layout.main=loadstring("return "..str)() + activity.setContentView(loadlayout2(layout.main,{})) + dlg2.hide() + +end + + +loadlayout(t) +dlg2=Dialog(activity,autotheme()) +dlg2.setTitle("编辑代码") +dlg2.getWindow().setSoftInputMode(0x10) + +dlg2.setContentView(l) + + +function editlayout(txt) + edit.Text=txt + edit.format() + dlg2.show() +end + +function onResume2() + local cd=cm.getPrimaryClip(); + local msg=cd.getItemAt(0).getText()--.toString(); + edit.setText(msg) +end diff --git a/app/src/main/assets/yidian.lua b/app/src/main/assets/yidian.lua new file mode 100644 index 0000000..696aad2 --- /dev/null +++ b/app/src/main/assets/yidian.lua @@ -0,0 +1,923 @@ +import "android.net.Uri" +import "android.content.Intent" +import "com.kn.okhtttp.*" +import "okhttp3.*" +import "java.io.*" +import "cjson" +import "android.support.v4.widget.*" +import "com.bm.library.PhotoView" +function print(内容) toasts={ CardView; CardElevation="0"; radius=10; backgroundColor="0xff575757"; { TextView; layout_marginLeft="5%w", layout_marginRight="5%w", textSize="17sp"; layout_marginTop="1.5%h", layout_marginBottom="1.5%h", TextColor="0xffffffff", text=内容; layout_gravity="center"; }; }; local toast=Toast.makeText(activity,nil,Toast.LENGTH_SHORT).setGravity(Gravity.CENTER, 0, 0).show() toast.setView(loadlayout(toasts)) toast.show() end +function 边(id,Size,Color,Color1,radiu) + local drawable = GradientDrawable() + drawable.setStroke(Size,Color) + drawable.setColor(Color1) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + id.setBackgroundDrawable(drawable) +end +function 圆(Color,radius) + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(Color) + drawable.setCornerRadii({radius,radius,0,0,0,0,0,0}); + return drawable +end +function 边1(Size,Color,Color1,radiu) + local drawable = GradientDrawable() + drawable.setStroke(Size,Color) + drawable.setColor(Color1) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + return drawable +end +function 水珠动画(view,time) + import "android.animation.ObjectAnimator" + ObjectAnimator().ofFloat(view,"scaleX",{1.2,.8,1.1,.9,1}).setDuration(time).start() + ObjectAnimator().ofFloat(view,"scaleY",{1.2,.8,1.1,.9,1}).setDuration(time).start() +end +function 上移动画(id) + translate=TranslateAnimation(0,0, 500, 0) + translate.setDuration(300); + translate.setRepeatCount(0); + translate.setFillAfter(true) + id.startAnimation(translate) + 水珠动画(id,1000) +end +function 下移动画(id) + translate=TranslateAnimation(0,0, 0, 500) + translate.setDuration(300); + translate.setRepeatCount(0); + translate.setFillAfter(true) + id.startAnimation(translate) +end +import "android.graphics.PorterDuffColorFilter" +import "android.graphics.PorterDuff" +import "java.io.File" +import "android.graphics.Typeface" +function MD提示(str,color,color2,ele,rad) + if time then toasttime=Toast.LENGTH_SHORT else toasttime= Toast.LENGTH_SHORT end + toasts={ + CardView; + id="toastb", + CardElevation=ele; + radius=rad; + backgroundColor=color; + { + TextView; + layout_margin="7dp"; + textSize="13sp"; + TextColor=color2, + text=str; + layout_gravity="center"; + id="mess", + }; + }; + local toast=Toast.makeText(activity,nil,toasttime); + toast.setView(loadlayout(toasts)) + toast.show() +end +import "android.graphics.drawable.GradientDrawable" +import "android.graphics.drawable.ColorDrawable" +import "AndLua" +if not File("/sdcard/Android/data/com.yidian.forum").isDirectory() then + 创建文件夹("/sdcard/Android/data/com.yidian.forum") +end +if not File("/sdcard/Android/data/com.yidian.forum/files").isDirectory() then + 创建文件夹("/sdcard/Android/data/com.yidian.forum/files") +end +if not File("/sdcard/Android/data/com.yidian.forum/cache").isDirectory() then + 创建文件夹("/sdcard/Android/data/com.yidian.forum/cache") +end + +import "bmob" +id="720a1216bfaae6b6b37fe4da44a06749" +key="f7b61518946e572eddced0049e70c5c0" +bmoba=bmob(id,key) + +id1="2e26b6c1ff69fe889959119acdedacbf" +key1="d487cbdcde77b01df4e6483348097c28" +bmobb=bmob(id1,key1) + +id2="36c6e9d6e893664935234d9f267d6327" +key2="ccc183d1afe07286253ed084cda368c8" +bmobc=bmob(id2,key2) + +key3="09fc1f888ccd457c013aba36391c992d" +id3="06334ff176ae71bc7cfff9586453f86e" +bmobc=bmob(id3,key3) + +function 窗口标题(text) + activity.setTitle(text) +end +function 普通弹窗(a,b,c,d,e,f) + local tc={ + LinearLayout; + layout_height="fill"; + layout_width="fill"; + orientation="vertical"; + gravity="center"; + { + CardView; + CardElevation="0dp"; + layout_width="85%w"; + radius="10dp"; + backgroundColor="0xffffffff"; + { + LinearLayout; + layout_width="match_parent"; + orientation="vertical"; + layout_height="match_parent"; + { + LinearLayout; + layout_width="match_parent"; + gravity="center"; + layout_height="9%h"; + { + TextView; + textSize="17sp"; + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/a.ttf")); + textColor="0xff3333333"; + text=a; + }; + }; + { + LinearLayout; + layout_marginBottom="3%h"; + layout_width="match_parent"; + gravity="center"; + { + TextView; + layout_height="match_parent"; + layout_width="75%w"; + textColor="0xff363636"; + text=b; + textSize="15sp"; + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/b.ttf")); + }; + }; + { + LinearLayout; + backgroundColor="0xfff7f7f7"; + layout_width="match_parent"; + orientation="horizontal"; + layout_height="7%h"; + { + LinearLayout; + id="t_a"; + onClick=e; + layout_width="38%w"; + gravity="center"; + layout_height="match_parent"; + { + TextView; + textSize="16sp"; + textColor="0xff49dadb"; + text=c; + }; + }; + { + TextView; + backgroundColor="0xffadadad"; + layout_gravity="center"; + layout_marginRight="1%w"; + layout_marginLeft="1%w"; + layout_width="0.1%w"; + layout_height="4%h"; + }; + { + LinearLayout; + onClick=f; + id="t_b"; + layout_width="match_parent"; + gravity="center"; + layout_height="match_parent"; + { + TextView; + textSize="15sp"; + textColor="0xff49dadb"; + text=d; + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/a.ttf")); + }; + }; + }; + }; + }; + }; + dialog=AlertDialog.Builder(activity) + .setView(loadlayout(tc)) + dialog1=dialog.show() + dialog1.setCancelable(false) + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + 波纹(t_b,0xffd1d1d1) + 波纹(t_a,0xffd1d1d1) +end +function 控件旋转(id,时长) + import "android.view.animation.LinearInterpolator" + import "android.animation.ValueAnimator" + import "android.animation.ObjectAnimator" + 动画 = ObjectAnimator() + 动画.setTarget(id); + 动画.setDuration(时长); + 动画.setRepeatCount(ValueAnimator.INFINITE) + 动画.setPropertyName("rotation"); + 动画.setFloatValues({0,720}); + 动画.setRepeatMode(ValueAnimator.INFINITE) + 动画.setInterpolator(LinearInterpolator() ) + 动画.start(); +end +function 光标颜色(id,颜色) + local v = Build.VERSION.RELEASE + local v1=utf8.sub(v,1,1) + if tonumber(v1) > 8 then + else + import "android.graphics.drawable.Drawable" + import "android.graphics.PorterDuff" + local fCursorDrawableRes=TextView.getDeclaredField("mCursorDrawableRes").setAccessible(true); + local mCursorDrawableRes=fCursorDrawableRes.getInt(id); + local editor=TextView.getDeclaredField("mEditor").setAccessible(true).get(id); + local fCursorDrawable=editor.getClass().getDeclaredField("mCursorDrawable").setAccessible(true); + local drawables=Drawable[1]; + drawables[0]=id.getContext().getResources().getDrawable(mCursorDrawableRes); + drawables[0].setColorFilter(颜色, PorterDuff.Mode.SRC_IN); + fCursorDrawable.set(editor,drawables); + end +end +function 渐变色背景(id,color1,color2) + import "android.view.Window" + import "android.view.WindowManager" + import "android.graphics.Color" + import "android.graphics.drawable.GradientDrawable" + local color = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,{color1,color2}); + id.setBackground(color) +end +function Http_upload(ur,name,f,zhacai) + client = OkTest.newok() + f=File(f) + requestBody = MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart(name,tostring(f.Name),RequestBody.create(MediaType.parse("multipart/form-data"), f)) + .build() + + request = Request.Builder() + .header("User-Agent","Dalvik/2.1.0 (Linux; U; Android 5.1.1; Nexus 4 Build/LMY48T)") + .url(ur) + .post(requestBody) + .build(); + + client.newCall(request).enqueue(Callback{ + onFailure=function( call, e) + zhacai(String(e.body().bytes()).toString()) + end, + onResponse=function(call, response) + code=response.code() + header=response.headers() + data=String(response.body().bytes()).toString() + zhacai(code,data,header) + end + }); +end + +function 加载弹窗(text) + local jz={ + LinearLayout; + layout_height="fill"; + gravity="center"; + layout_width="fill"; + orientation="vertical"; + { + CardView; + layout_height="25%w"; + layout_width="25%w"; + backgroundColor="0xffffffff"; + CardElevation="0dp"; + radius="15dp"; + { + LinearLayout; + layout_height="match_parent"; + orientation="vertical"; + layout_width="match_parent"; + gravity="center"; + { + ProgressBar; + id="jz_tp"; + layout_height="8%w"; + layout_width="10%w"; + }; + { + TextView; + textSize="14sp"; + text=text, + Typeface=Typeface.createFromFile(File(activity.getLuaDir().."/font/a.ttf")); + layout_marginTop="2%w"; + }; + }; + }; + }; + dialog=AlertDialog.Builder(activity) + .setView(loadlayout(jz)) + dialog1=dialog.show() + dialog1.setCancelable(false) + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + jz_tp.IndeterminateDrawable.setColorFilter(PorterDuffColorFilter(0xff49dadb,PorterDuff.Mode.SRC_ATOP)) +end + +function 载入界面(id) + activity.setContentView(loadlayout(id)) +end + +function 隐藏标题栏() + activity.ActionBar.hide() +end + +function 设置主题(id) + activity.setTheme(id) +end + +function 打印(text) + print(text) +end + +function 窗口全屏() + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN) +end + +function 取消全屏() + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) +end + +function 返回桌面() + activity.moveTaskToBack(true) +end + +function 提示(text) + Toast.makeText(activity,text,Toast.LENGTH_SHORT).show() +end + +function 截取文本(str,str1,str2) + str1=str1:gsub("%p",function(s) return("%"..s) end) + return str:match(str1 .. "(.-)"..str2) +end + +function 替换文本(str,str1,str2) + str1=str1:gsub("%p",function(s) return("%"..s) end) + str2=str2:gsub("%%","%%%%") + return str:gsub(str1,str2) +end + +function 字符串长度(str) + return utf8.len(str) +end + +function 状态栏颜色(color) + if Build.VERSION.SDK_INT >= 21 then + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS).setStatusBarColor(color); + end +end + +function 沉浸状态栏() + if Build.VERSION.SDK_INT >= 19 then + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + end +end + +function 设置文本(id,text) + id.Text=text +end + +function 跳转页面(name) + activity.newActivity(name) +end + +function 跳转界面(name) + activity.newActivity(name) +end + +function 关闭页面() + activity.finish() +end + +function 关闭界面() + activity.finish() +end + +function 获取文本(id) + return id.Text +end + +function 结束程序() + activity.finish() +end + +function 重构页面() + activity.recreate() +end + +function 重构界面() + activity.recreate() +end + +function 控件圆角(view,InsideColor,radiu) + import "android.graphics.drawable.GradientDrawable" + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(InsideColor) + drawable.setCornerRadii({radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu}); + view.setBackgroundDrawable(drawable) +end + +function 获取设备标识码() + import "android.provider.Settings$Secure" + return Secure.getString(activity.getContentResolver(), Secure.ANDROID_ID) +end + +function 获取IMEI() + import "android.content.Context" + return activity.getSystemService(Context.TELEPHONY_SERVICE).getDeviceId() +end + +function 控件背景渐变动画(view,color1,color2,color3,color4) + import "android.animation.ObjectAnimator" + import "android.animation.ArgbEvaluator" + import "android.animation.ValueAnimator" + import "android.graphics.Color" + colorAnim = ObjectAnimator.ofInt(view,"backgroundColor",{color1, color2, color3,color4}) + colorAnim.setDuration(3000) + colorAnim.setEvaluator(ArgbEvaluator()) + colorAnim.setRepeatCount(ValueAnimator.INFINITE) + colorAnim.setRepeatMode(ValueAnimator.REVERSE) + colorAnim.start() +end + +function 获取屏幕尺寸(ctx) + import "android.util.DisplayMetrics" + dm = DisplayMetrics(); + ctx.getWindowManager().getDefaultDisplay().getMetrics(dm); + diagonalPixels = Math.sqrt(Math.pow(dm.widthPixels, 2) + Math.pow(dm.heightPixels, 2)); + return diagonalPixels / (160 * dm.density); +end + +function 是否安装APP(packageName) + if pcall(function() activity.getPackageManager().getPackageInfo(packageName,0) end) then + return true + else + return false + end +end + +function 设置中划线(id) + import "android.graphics.Paint" + id.getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG) +end + +function 设置下划线(id) + import "android.graphics.Paint" + id.getPaint().setFlags(Paint. UNDERLINE_TEXT_FLAG) +end + +function 设置字体加粗(id) + import "android.graphics.Paint" + id.getPaint().setFakeBoldText(true) +end + +function 设置斜体(id) + import "android.graphics.Paint" + id.getPaint().setTextSkewX(0.2) +end + +function 分享内容(text) + intent=Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, "分享"); + intent.putExtra(Intent.EXTRA_TEXT, text); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(Intent.createChooser(intent,"分享到:")); +end + +function 加QQ群(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqapi://card/show_pslcard?src_type=internal&version=1&uin="..qq.."&card_type=group&source=qrcode"))) +end + +function 跳转QQ群(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqapi://card/show_pslcard?src_type=internal&version=1&uin="..qq.."&card_type=group&source=qrcode"))) +end + +function QQ聊天(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin="..qq))) +end + +function 跳转QQ聊天(qq) + import "android.net.Uri" + import "android.content.Intent" + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin="..qq))) +end + +function 发送短信(phone,text) + require "import" + import "android.telephony.*" + SmsManager.getDefault().sendTextMessage(tostring(phone), nil, tostring(text), nil, nil) +end + +function 获取剪切板() + import "android.content.Context" + return activity.getSystemService(Context.CLIPBOARD_SERVICE).getText() +end + +function 写入剪切板(text) + import "android.content.Context" + activity.getSystemService(Context.CLIPBOARD_SERVICE).setText(text) +end + +function 开启WIFI() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.setWifiEnabled(true) +end + +function 关闭WIFI() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.setWifiEnabled(false) +end + +function 断开网络() + import "android.content.Context" + wifi = activity.Context.getSystemService(Context.WIFI_SERVICE) + wifi.disconnect() +end + +function 创建文件(file) + import "java.io.File" + return File(file).createNewFile() +end + +function 创建文件夹(file) + import "java.io.File" + return File(file).mkdir() +end + +function 创建多级文件夹(file) + import "java.io.File" + return File(file).mkdirs() +end + +function 移动文件(file,file2) + import "java.io.File" + return File(file).renameTo(File(file2)) +end + +function 写入文件(file,text) + return io.open(file,"w"):write(text):close() +end + +function 设置按钮颜色(id,color) + id.getBackground().setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)) +end + +function 设置编辑框颜色(id,color) + id.getBackground().setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)); +end + +function 设置进度条颜色(id,color) + id.IndeterminateDrawable.setColorFilter(PorterDuffColorFilter(color,PorterDuff.Mode.SRC_ATOP)) +end + +function 设置控件颜色(id,color) + id.setBackgroundColor(color) +end + +function 获取手机存储路径() + return Environment.getExternalStorageDirectory().toString() +end + +function 获取屏幕宽() + return activity.getWidth() +end + +function 获取屏幕高() + return activity.getHeight() +end + +function 文件是否存在(file) + return File(file).exists() +end + +function 关闭左侧滑(id) + id.closeDrawer(3) +end + +function 打开左侧滑() + id.openDrawer(3) +end + +function 显示控件(id) + id.setVisibility(0) +end + +function 隐藏控件(id) + id.setVisibility(8) +end + +function 打开APP(packageName) + import "android.content.Intent" + import "android.content.pm.PackageManager" + manager = activity.getPackageManager() + open = manager.getLaunchIntentForPackage(packageName) + this.startActivity(open) +end + +function 卸载APP(file) + import "android.net.Uri" + import "android.content.Intent" + uri = Uri.parse("package:"..file) + intent = Intent(Intent.ACTION_DELETE,uri) + activity.startActivity(intent) +end + +function 安装APP(file) + import "android.content.Intent" + import "android.net.Uri" + intent = Intent(Intent.ACTION_VIEW) + intent.setDataAndType(Uri.parse("file://"..file), "application/vnd.android.package-archive") + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + activity.startActivity(intent) +end + +function 系统下载文件(url,directory,name) + import "android.content.Context" + import "android.net.Uri" + downloadManager=activity.getSystemService(Context.DOWNLOAD_SERVICE); + url=Uri.parse(url); + request=DownloadManager.Request(url); + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE|DownloadManager.Request.NETWORK_WIFI); + request.setDestinationInExternalPublicDir(directory,name); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + downloadManager.enqueue(request); +end + +function 波纹(id,color) + import "android.content.res.ColorStateList" + local attrsArray = {android.R.attr.selectableItemBackgroundBorderless} + local typedArray =activity.obtainStyledAttributes(attrsArray) + ripple=typedArray.getResourceId(0,0) + aoos=activity.Resources.getDrawable(ripple) + aoos.setColor(ColorStateList(int[0].class{int{}},int{color})) + id.setBackground(aoos.setColor(ColorStateList(int[0].class{int{}},int{color}))) +end + + +function 随机数(min,max) + return math.random(min,max) +end + +function 删除控件(id,id2) + return (id).removeView(id2) +end + +function 状态栏亮色() + if Build.VERSION.SDK_INT >= 23 then + activity.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + end +end + +import"android.view.animation.*" +import"android.view.animation.Animation$AnimationListener" +import"android.graphics.drawable.GradientDrawable" +import "android.widget.LinearLayout" +import "android.view.View" +import "android.view.animation.TranslateAnimation" +import "android.widget.CardView" +import "android.view.WindowManager" +import "android.graphics.drawable.GradientDrawable" +import "android.view.Gravity" +import "android.widget.PageView" +import "android.view.animation.Animation$AnimationListener" +import "android.app.AlertDialog" +import "android.widget.PageLayout$OnPageChangeListener" +import "android.widget.PageView$OnPageChangeListener" +import "android.R$id" +import "android.graphics.drawable.ColorDrawable" +import "com.androlua.R$drawable" +import "android.R$drawable" +import "android.view.animation.Animation$AnimationListener" +import "android.view.animation.AlphaAnimation" +import "android.widget.AbsoluteLayout" +MyDialog={} +MyDialog.设置布局=function(v) MyDialog.layout=v or MyDialog.layout return MyDialog end + +MyDialog.弹窗高度="fill" +MyDialog.弹窗圆角="5dp" +MyDialog.弹窗外部颜色="#00000000" +MyDialog.弹窗阴影="0dp" +MyDialog.弹窗背景="#FFFFFFFF" +MyDialog.弹窗宽度="100%w" +MyDialog.弹窗上边距="0dp" +MyDialog.弹窗下边距="0dp" +MyDialog.设置弹窗下边距=function(v) MyDialog.弹窗下边距=v or MyDialog.弹窗下边距 return MyDialog end +MyDialog.设置弹窗外部点击事件=function(v) MyDialog.弹窗外部点击事件=v or MyDialog.弹窗外部点击事件 return MyDialog end +MyDialog.设置弹窗上边距=function(v) MyDialog.弹窗上边距=v or MyDialog.弹窗上边距 return MyDialog end +MyDialog.设置弹窗宽度=function(v) MyDialog.弹窗宽度= v or MyDialog.弹窗宽度 return MyDialog end +MyDialog.设置弹窗背景=function(v) MyDialog.弹窗背景=v or MyDialog.弹窗背景 return MyDialog end +MyDialog.设置弹窗阴影=function(v) MyDialog.弹窗阴影=v or MyDialog.弹窗阴影 return MyDialog end +MyDialog.设置弹窗外部颜色=function(v) MyDialog.弹窗外部颜色=v or MyDialog.弹窗外部颜色 return MyDialog end +MyDialog.设置弹窗圆角=function(v) MyDialog.弹窗圆角=v or MyDialog.弹窗圆角 return MyDialog end +MyDialog.设置弹窗高度=function(v) MyDialog.弹窗高度=v or MyDialog.弹窗高度 return MyDialog end + + + +MyDialog.弹窗获取高宽 = function(A0_100) + A0_100.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)) + MyDialog.弹窗高= A0_100.getMeasuredHeight() + MyDialog.弹窗宽= A0_100.getMeasuredWidth() + return MyDialog.弹窗高, MyDialog.弹窗宽 +end + +MyDialog.layout={} +MyDialog.弹窗高=50 +MyDialog.弹窗外部点击事件=function()MyDialog.弹窗关闭()end +MyDialog.弹窗快速消失动画 = AlphaAnimation(1, 0.2).setDuration(0).setFillAfter(true) +MyDialog.弹窗消失动画= AlphaAnimation(1, 0).setDuration(250).setFillAfter(true) +MyDialog.弹窗显示动画= AlphaAnimation(0, 1).setDuration(250).setFillAfter(true) +MyDialog.弹窗快速消失动画 = AlphaAnimation(1, 0).setDuration(0).setFillAfter(true) +MyDialog.弹窗上移动画 = TranslateAnimation(0, 0, 2000, 0).setDuration(300).setFillAfter(true) +MyDialog.弹窗下移动画 = TranslateAnimation(0, 0, 0, 2000).setDuration(300).setFillAfter(true) +MyDialog.弹窗设置圆角 = function(控件,颜色,上圆角, 下圆角) + drawable = GradientDrawable() + drawable.setShape(GradientDrawable.RECTANGLE) + drawable.setColor(颜色) + drawable.setCornerRadii({ + 上圆角, + 上圆角, + 上圆角, + 上圆角, + 下圆角, + 下圆角, + 下圆角, + 下圆角 + }) + 控件.setBackgroundDrawable(rawable) + return MyDialog +end + +MyDialog.弹窗状态改变事件=function()end +MyDialog.弹窗位置改变事件 = function(A0_115) + if A0_115 == 1 then + MyDialog.弹窗关闭() + end +end + +MyDialog.弹窗滑动事件=function()end +MyDialog.弹窗关闭=function() + _弹窗区域.startAnimation(MyDialog.弹窗下移动画) + _弹窗阴影区域.startAnimation(MyDialog.弹窗消失动画) + MyDialog.弹窗下移动画.setAnimationListener(AnimationListener({ + onAnimationEnd = function() + _弹窗主布局.startAnimation(MyDialog.弹窗快速消失动画) + _弹窗主布局.setVisibility(View.GONE) + MyDialog.dialog.dismiss() + end + })) +end +MyDialog.显示=function() + import "android.graphics.Typeface" + import "android.graphics.drawable.ColorDrawable" + local aly2= { + AbsoluteLayout, + id = "_弹窗主布局", + layout_height = "100%h", + layout_width = "100%w", + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + { + LinearLayout, + id = "_弹窗圆角布局", + layout_width = "0dp", + background = MyDialog.弹窗背景, + { + LinearLayout, + layout_height = MyDialog.弹窗圆角, + } + }, + + { + LinearLayout, + id = "_弹窗阴影区域", + background = MyDialog.弹窗外部颜色, + layout_height = "100%h", + layout_width = "100%w", + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + layout_gravity = "bottom", + + { + LinearLayout, + rotation = "270", + layout_width = "100%h", + layout_height = "fill_parent", + gravity = "bottom", + layout_gravity = "bottom", + + { + PageView, + background = "#00000000", + id = "_弹窗页面布局", + + OnPageChangeListener=(PageView.OnPageChangeListener({ + onPageSelected = function(A0_105) + MyDialog.弹窗位置改变事件(A0_105) + end, + onPageScrolled = function(A0_106, A1_107, A2_108) + end, + onPageScrollStateChanged = function(A0_109) + MyDialog.弹窗状态改变事件(A0_109) + end + })), + pages = { + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + + rotation = "90", + background = "#00000000", + { + LinearLayout, + id = "_弹窗父布局", + layout_height = "100%h", + layout_width = "100%w", + gravity = "bottom|center", + onClick=function()MyDialog.弹窗外部点击事件()end, + { + CardView, + id = "_弹窗区域", + elevation = MyDialog.弹窗阴影, + layout_gravity = "bottom|center", + layout_marginTop = MyDialog.弹窗上边距, + layout_marginBottom = MyDialog.弹窗下边距, + layout_width = MyDialog.弹窗宽度, + Radius=MyDialog.弹窗圆角, + onClick=function()end, + { + LinearLayout, + id = "_弹窗区域布局", + layout_width = MyDialog.弹窗宽度, + layout_height = MyDialog.弹窗高度, + gravity = "top|center", + onClick=function()end, + MyDialog.layout, + } + } + } + }, + { + LinearLayout, + layout_height = "100%h", + layout_width = "100%w", + + } + } + } + } + } + } + } + } + dialog= AlertDialog.Builder(this) + dialog1=dialog.show() + MyDialog.dialog=dialog1 + dialog1.getWindow().setContentView(loadlayout(aly2)); + + dialog1.getWindow().setBackgroundDrawable(ColorDrawable(0x00000000)); + + local dialogWindow = dialog1.getWindow(); + + dialogWindow.setGravity(Gravity.BOTTOM); + dialog1.setCanceledOnTouchOutside(false); + dialog1.getWindow().getAttributes().width=(activity.Width); + dialog1.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + + + + _弹窗页面布局.addOnPageChangeListener(PageView.OnPageChangeListener({ + onPageSelected = function(A0_105) + MyDialog.弹窗位置改变事件(A0_105) + end, + onPageScrolled = function(A0_106, A1_107, A2_108) + end, + onPageScrollStateChanged = function(A0_109) + MyDialog.弹窗状态改变事件(A0_109) + end + })) + _弹窗主布局.setVisibility(0) + return MyDialog +end + + +function MyBottomSheetDialog() return MyDialog end diff --git a/app/src/main/java/android/app/AlertDialogBuilder.java b/app/src/main/java/android/app/AlertDialogBuilder.java new file mode 100644 index 0000000..0c6fa37 --- /dev/null +++ b/app/src/main/java/android/app/AlertDialogBuilder.java @@ -0,0 +1,18 @@ +package android.app; + +import android.content.Context; + +import com.androlua.LuaDialog; + +public class AlertDialogBuilder extends LuaDialog { + + public AlertDialogBuilder(Context context) { + super(context); + } + + public AlertDialogBuilder(Context context, int theme) { + super(context, theme); + } + + +} diff --git a/app/src/main/java/android/app/FloatWindow.java b/app/src/main/java/android/app/FloatWindow.java new file mode 100644 index 0000000..e782a9a --- /dev/null +++ b/app/src/main/java/android/app/FloatWindow.java @@ -0,0 +1,308 @@ +package android.app; + +import android.content.*; +import android.content.res.*; +import android.graphics.*; +import android.graphics.drawable.*; +import android.view.*; +import android.widget.*; +import android.util.*; + +import com.osfans.trime.Trime; + +public class FloatWindow { + + private Context mContext; + + private FloatWindow.TitleBar mTitlebar; + + private WindowManager mWindowManager; + + private WindowManager.LayoutParams mLayoutParams; + + private LinearLayout mLayout; + + private FrameLayout content; + + private int textColor; + + private DisplayMetrics dm; + + private int mWidth; + + private int mHeight; + + public FloatWindow(Context context) { + mContext = context; + dm = context.getResources().getDisplayMetrics(); + mWidth = getWidth(); + mHeight = getHeight(); + init(context); + } + + private void init(Context context) { + // TODO: Implement this method + mWindowManager = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + mLayoutParams = new WindowManager.LayoutParams(); + mLayoutParams.format = PixelFormat.RGBA_8888; + mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; + //mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mLayoutParams.type = Trime.getDialogType(); + mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; + mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + mLayout = new ContentView(context); + mLayout.setPadding(dp(8), dp(8), dp(8), dp(8)); + mLayout.setOrientation(LinearLayout.VERTICAL); + + TypedArray array = context.getTheme().obtainStyledAttributes(new int[] { + android.R.attr.colorBackground, + android.R.attr.textColorPrimary, + }); + int backgroundColor = array.getColor(0, 0xFF00FF); + textColor = array.getColor(1, 0xFF00FF); + array.recycle(); + + GradientDrawable gd=new GradientDrawable(); + gd.setColor(backgroundColor); + gd.setCornerRadius(4); + gd.setStroke(2, textColor); + gd.setAlpha(0x88); + mLayout.setBackgroundDrawable(gd); + mWindowManager.addView(mLayout, mLayoutParams); + mLayout.setVisibility(View.GONE); + mTitlebar = new TitleBar(context); + content = new FrameLayout(context); + mLayout.addView(mTitlebar); + mLayout.addView(content); + } + + + private int getWidth() { + return mContext.getResources().getDisplayMetrics().widthPixels; + } + + private int getHeight() { + return mContext.getResources().getDisplayMetrics().heightPixels; + } + + private void setFocus(boolean f) { + if (f) { + if (mLayoutParams.flags == (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) { + mWindowManager.removeView(mLayout); + mWindowManager.addView(mLayout, mLayoutParams); + mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; + mWindowManager.updateViewLayout(mLayout, mLayoutParams); + } + } + else { + mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mWindowManager.updateViewLayout(mLayout, mLayoutParams); + } + } + + private int dp(float n) { + // TODO: Implement this method + return (int)TypedValue.applyDimension(1, n, dm); + } + + public void setBackground(Drawable bg) { + mLayout.setBackgroundDrawable(bg); + } + + public Drawable getBackground() { + return mLayout.getBackground(); + } + + public void setTitle(CharSequence title) { + mTitlebar.setTitle(title); + } + + public void setContentView(View v) { + content.removeAllViews(); + content.addView(v); + } + + public void show() { + mLayout.setVisibility(View.VISIBLE); + } + + public void hide() { + mLayout.setVisibility(View.GONE); + } + + public void dismiss() { + mWindowManager.removeView(mLayout); + } + + public void setFlags(int flags) { + mLayoutParams.flags = flags; + mWindowManager.updateViewLayout(mLayout, mLayoutParams); + } + + public void setFormat(int format) { + mLayoutParams.format = format; + mWindowManager.updateViewLayout(mLayout, mLayoutParams); + } + + public void setType(int type) { + mLayoutParams.type = type; + mWindowManager.updateViewLayout(mLayout, mLayoutParams); + } + + private class TitleBar extends LinearLayout { + + private TextView mTitle; + public TitleBar(Context context) { + super(context); + mTitle = new TitleView(context); + mTitle.setSingleLine(true); + TextView mClose=new TextView(context); + mClose.setText("X"); + mClose.setGravity(Gravity.CENTER); + GradientDrawable gd=new GradientDrawable(); + gd.setColor(0x440000ff); + gd.setCornerRadius(4); + gd.setStroke(2, textColor); + gd.setAlpha(0x88); + mClose.setBackgroundDrawable(gd); + mClose.setTextSize(1, 18); + mClose.setOnClickListener(new OnClickListener(){ + + @Override + public void onClick(View p1) { + // TODO: Implement this method + dismiss(); + } + }); + addView(mTitle, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, dp(24), 1)); + addView(mClose, new LinearLayout.LayoutParams(dp(24), dp(24))); + } + public void setTitle(CharSequence title) { + mTitle.setText(title); + } + } + + private class TitleView extends TextView { + + private int lastX=0; + private int lastY=0; + private int vx=0; + private int vy=0; + private int h=0; + private int ry; + private int rx; + + public TitleView(Context context) { + super(context); + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + // TODO: Implement this method + Rect frame=new Rect(); + getWindowVisibleDisplayFrame(frame); + h = frame.top; + ry = (int) e.getRawY();//获取触摸绝对Y位置 + rx = (int) e.getRawX();//获取触摸绝对X位置 + if (e.getAction() == MotionEvent.ACTION_DOWN) { + vy = ry - (int) e.getY();//获取视图的Y位置 + vx = rx - (int) e.getX();//获取视图的X位置 + lastY = ry;//记录按下的Y位置 + lastX = rx;//记录按下的X位置 + } + else if (e.getAction() == MotionEvent.ACTION_MOVE) { + mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP ;//调整悬浮窗口至左上角 + mLayoutParams.x = vx + (rx - lastX);//移动的相对位置 + mLayoutParams.y = vy + (ry - lastY) - h + 3;//移动的相对位置 + mWindowManager.updateViewLayout(mLayout, mLayoutParams);//调整悬浮窗至指定的位置 + } + return true; + + //return super.onTouchEvent(event); + } + + } + + private class ContentView extends LinearLayout { + + private int lastX=0; + private int lastY=0; + private int ry; + private int rx; + + private int vw; + + private int vh; + + private int vx; + + private int vy; + + private boolean zoomX; + + private int m; + + private boolean zoomY; + + public ContentView(Context context) { + super(context); + m = dp(8); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + // TODO: Implement this method + if (e.getAction() == MotionEvent.ACTION_OUTSIDE) { + setFocus(false); + } + else if (e.getAction() == MotionEvent.ACTION_DOWN) { + setFocus(true); + } + + return super.onInterceptTouchEvent(e); + } + + + + @Override + public boolean onTouchEvent(MotionEvent e) { + // TODO: Implement this method + ry = (int) e.getRawY();//获取触摸绝对Y位置 + rx = (int) e.getRawX();//获取触摸绝对X位置 + if (e.getAction() == MotionEvent.ACTION_OUTSIDE) { + setFocus(false); + } + else if (e.getAction() == MotionEvent.ACTION_DOWN) { + setFocus(true); + } + if (e.getAction() == MotionEvent.ACTION_DOWN) { + if (getWidth() - e.getX() < m) { + zoomX = true; + } + if (getHeight() - e.getY() < m) { + zoomY = true; + } + vw = getWidth();//获取视图的Y位置 + vh = getHeight();//获取视图的X位置 + lastY = ry;//记录按下的Y位置 + lastX = rx;//记录按下的X位置 + vx = mLayoutParams.x; + vy = mLayoutParams.y; + } + else if (e.getAction() == MotionEvent.ACTION_MOVE) { + mLayoutParams.x = vx; + mLayoutParams.y = vy; + if (zoomX) + mLayoutParams.width = Math.min(vw + (rx - lastX), mWidth);//移动的相宽度 + if (zoomY) + mLayoutParams.height = Math.min(vh + (ry - lastY), mHeight);//移动的相对高度 + mWindowManager.updateViewLayout(mLayout, mLayoutParams);//调整悬浮窗至指定的大小 + } + else if (e.getAction() == MotionEvent.ACTION_UP) { + zoomX=false; + zoomY=false; + } + return true; + } + } +} diff --git a/app/src/main/java/android/content/FileProvider.java b/app/src/main/java/android/content/FileProvider.java new file mode 100644 index 0000000..f2c6104 --- /dev/null +++ b/app/src/main/java/android/content/FileProvider.java @@ -0,0 +1,362 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package android.content; + +import android.content.pm.ProviderInfo; +import android.content.res.XmlResourceParser; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.net.Uri.Builder; +import android.os.Build.VERSION; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.support.annotation.GuardedBy; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.webkit.MimeTypeMap; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; + +public class FileProvider extends ContentProvider { + private static final String[] COLUMNS = new String[]{"_display_name", "_size"}; + private static final String META_DATA_FILE_PROVIDER_PATHS = "android.support.FILE_PROVIDER_PATHS"; + private static final String TAG_ROOT_PATH = "root-path"; + private static final String TAG_FILES_PATH = "files-path"; + private static final String TAG_CACHE_PATH = "cache-path"; + private static final String TAG_EXTERNAL = "external-path"; + private static final String TAG_EXTERNAL_FILES = "external-files-path"; + private static final String TAG_EXTERNAL_CACHE = "external-cache-path"; + private static final String TAG_EXTERNAL_MEDIA = "external-media-path"; + private static final String ATTR_NAME = "name"; + private static final String ATTR_PATH = "path"; + private static final File DEVICE_ROOT = new File("/"); + @GuardedBy("sCache") + private static HashMap sCache = new HashMap(); + private FileProvider.PathStrategy mStrategy; + + public FileProvider() { + } + + public boolean onCreate() { + return true; + } + + public void attachInfo(@NonNull Context context, @NonNull ProviderInfo info) { + super.attachInfo(context, info); + if (info.exported) { + throw new SecurityException("Provider must not be exported"); + } else if (!info.grantUriPermissions) { + throw new SecurityException("Provider must grant uri permissions"); + } else { + this.mStrategy = getPathStrategy(context, info.authority); + } + } + + public static Uri getUriForFile(@NonNull Context context, @NonNull String authority, @NonNull File file) { + FileProvider.PathStrategy strategy = getPathStrategy(context, authority); + return strategy.getUriForFile(file); + } + + public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { + File file = this.mStrategy.getFileForUri(uri); + if (projection == null) { + projection = COLUMNS; + } + + String[] cols = new String[projection.length]; + Object[] values = new Object[projection.length]; + int i = 0; + String[] var10 = projection; + int var11 = projection.length; + + for (int var12 = 0; var12 < var11; ++var12) { + String col = var10[var12]; + if ("_display_name".equals(col)) { + cols[i] = "_display_name"; + values[i++] = file.getName(); + } else if ("_size".equals(col)) { + cols[i] = "_size"; + values[i++] = Long.valueOf(file.length()); + } + } + + cols = copyOf(cols, i); + values = copyOf(values, i); + MatrixCursor cursor = new MatrixCursor(cols, 1); + cursor.addRow(values); + return cursor; + } + + public String getType(@NonNull Uri uri) { + File file = this.mStrategy.getFileForUri(uri); + int lastDot = file.getName().lastIndexOf(46); + if (lastDot >= 0) { + String extension = file.getName().substring(lastDot + 1); + String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (mime != null) { + return mime; + } + } + + return "application/octet-stream"; + } + + public Uri insert(@NonNull Uri uri, ContentValues values) { + throw new UnsupportedOperationException("No external inserts"); + } + + public int update(@NonNull Uri uri, ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { + throw new UnsupportedOperationException("No external updates"); + } + + public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { + File file = this.mStrategy.getFileForUri(uri); + return file.delete() ? 1 : 0; + } + + public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { + File file = this.mStrategy.getFileForUri(uri); + int fileMode = modeToMode(mode); + return ParcelFileDescriptor.open(file, fileMode); + } + + private static FileProvider.PathStrategy getPathStrategy(Context context, String authority) { + HashMap var3 = sCache; + synchronized (sCache) { + FileProvider.PathStrategy strat = (FileProvider.PathStrategy) sCache.get(authority); + if (strat == null) { + try { + strat = parsePathStrategy(context, authority); + } catch (IOException var6) { + throw new IllegalArgumentException("Failed to parse android.support.FILE_PROVIDER_PATHS meta-data", var6); + } catch (XmlPullParserException var7) { + throw new IllegalArgumentException("Failed to parse android.support.FILE_PROVIDER_PATHS meta-data", var7); + } + + sCache.put(authority, strat); + } + + return strat; + } + } + + private static FileProvider.PathStrategy parsePathStrategy(Context context, String authority) throws IOException, XmlPullParserException { + FileProvider.SimplePathStrategy strat = new FileProvider.SimplePathStrategy(authority); + ProviderInfo info = context.getPackageManager().resolveContentProvider(authority, 128); + XmlResourceParser in = info.loadXmlMetaData(context.getPackageManager(), "android.support.FILE_PROVIDER_PATHS"); + if (in == null) { + throw new IllegalArgumentException("Missing android.support.FILE_PROVIDER_PATHS meta-data"); + } else { + int type; + while ((type = in.next()) != 1) { + if (type == 2) { + String tag = in.getName(); + String name = in.getAttributeValue((String) null, "name"); + String path = in.getAttributeValue((String) null, "path"); + File target = null; + if ("root-path".equals(tag)) { + target = DEVICE_ROOT; + } else if ("files-path".equals(tag)) { + target = context.getFilesDir(); + } else if ("cache-path".equals(tag)) { + target = context.getCacheDir(); + } else if ("external-path".equals(tag)) { + target = Environment.getExternalStorageDirectory(); + } else { + File[] externalMediaDirs; + if ("external-files-path".equals(tag)) { + externalMediaDirs = getExternalFilesDirs(context, (String) null); + if (externalMediaDirs.length > 0) { + target = externalMediaDirs[0]; + } + } else if ("external-cache-path".equals(tag)) { + externalMediaDirs = getExternalCacheDirs(context); + if (externalMediaDirs.length > 0) { + target = externalMediaDirs[0]; + } + } else if (VERSION.SDK_INT >= 21 && "external-media-path".equals(tag)) { + externalMediaDirs = context.getExternalMediaDirs(); + if (externalMediaDirs.length > 0) { + target = externalMediaDirs[0]; + } + } + } + + if (target != null) { + strat.addRoot(name, buildPath(target, new String[]{path})); + } + } + } + + return strat; + } + } + + @NonNull + public static File[] getExternalFilesDirs(@NonNull Context context, @Nullable String type) { + return VERSION.SDK_INT >= 19 ? context.getExternalFilesDirs(type) : new File[]{context.getExternalFilesDir(type)}; + } + + @NonNull + public static File[] getExternalCacheDirs(@NonNull Context context) { + return VERSION.SDK_INT >= 19 ? context.getExternalCacheDirs() : new File[]{context.getExternalCacheDir()}; + } + + private static int modeToMode(String mode) { + int modeBits; + if ("r".equals(mode)) { + modeBits = 268435456; + } else if (!"w".equals(mode) && !"wt".equals(mode)) { + if ("wa".equals(mode)) { + modeBits = 704643072; + } else if ("rw".equals(mode)) { + modeBits = 939524096; + } else { + if (!"rwt".equals(mode)) { + throw new IllegalArgumentException("Invalid mode: " + mode); + } + + modeBits = 1006632960; + } + } else { + modeBits = 738197504; + } + + return modeBits; + } + + private static File buildPath(File base, String... segments) { + File cur = base; + String[] var3 = segments; + int var4 = segments.length; + + for (int var5 = 0; var5 < var4; ++var5) { + String segment = var3[var5]; + if (segment != null) { + cur = new File(cur, segment); + } + } + + return cur; + } + + private static String[] copyOf(String[] original, int newLength) { + String[] result = new String[newLength]; + System.arraycopy(original, 0, result, 0, newLength); + return result; + } + + private static Object[] copyOf(Object[] original, int newLength) { + Object[] result = new Object[newLength]; + System.arraycopy(original, 0, result, 0, newLength); + return result; + } + + static class SimplePathStrategy implements FileProvider.PathStrategy { + private final String mAuthority; + private final HashMap mRoots = new HashMap(); + + SimplePathStrategy(String authority) { + this.mAuthority = authority; + } + + void addRoot(String name, File root) { + if (TextUtils.isEmpty(name)) { + throw new IllegalArgumentException("Name must not be empty"); + } else { + try { + root = root.getCanonicalFile(); + } catch (IOException var4) { + throw new IllegalArgumentException("Failed to resolve canonical path for " + root, var4); + } + + this.mRoots.put(name, root); + } + } + + public Uri getUriForFile(File file) { + String path; + try { + path = file.getCanonicalPath(); + } catch (IOException var7) { + throw new IllegalArgumentException("Failed to resolve canonical path for " + file); + } + + Entry mostSpecific = null; + Iterator var4 = this.mRoots.entrySet().iterator(); + + while (true) { + Entry root; + String rootPath; + do { + do { + if (!var4.hasNext()) { + if (mostSpecific == null) { + throw new IllegalArgumentException("Failed to find configured root that contains " + path); + } + + rootPath = ((File) mostSpecific.getValue()).getPath(); + if (rootPath.endsWith("/")) { + path = path.substring(rootPath.length()); + } else { + path = path.substring(rootPath.length() + 1); + } + + path = Uri.encode((String) mostSpecific.getKey()) + '/' + Uri.encode(path, "/"); + return (new Builder()).scheme("content").authority(this.mAuthority).encodedPath(path).build(); + } + + root = (Entry) var4.next(); + rootPath = ((File) root.getValue()).getPath(); + } while (!path.startsWith(rootPath)); + } + while (mostSpecific != null && rootPath.length() <= ((File) mostSpecific.getValue()).getPath().length()); + + mostSpecific = root; + } + } + + public File getFileForUri(Uri uri) { + String path = uri.getEncodedPath(); + int splitIndex = path.indexOf(47, 1); + String tag = Uri.decode(path.substring(1, splitIndex)); + path = Uri.decode(path.substring(splitIndex + 1)); + File root = (File) this.mRoots.get(tag); + if (root == null) { + throw new IllegalArgumentException("Unable to find configured root for " + uri); + } else { + File file = new File(root, path); + + try { + file = file.getCanonicalFile(); + } catch (IOException var8) { + throw new IllegalArgumentException("Failed to resolve canonical path for " + file); + } + + if (!file.getPath().startsWith(root.getPath())) { + throw new SecurityException("Resolved path jumped beyond configured root"); + } else { + return file; + } + } + } + } + + interface PathStrategy { + Uri getUriForFile(File var1); + + File getFileForUri(Uri var1); + } +} diff --git a/app/src/main/java/android/support/multidex/MultiDex.java b/app/src/main/java/android/support/multidex/MultiDex.java new file mode 100644 index 0000000..bdb1ddd --- /dev/null +++ b/app/src/main/java/android/support/multidex/MultiDex.java @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.support.multidex; + +import android.content.*; +import android.content.pm.*; +import android.content.pm.PackageManager.*; +import android.os.*; +import android.util.*; +import com.androlua.*; +import dalvik.system.*; +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.regex.*; +import java.util.zip.*; + +/** + * Monkey patches {@link Context#getClassLoader() the application context class + * loader} in order to load classes from more than one dex file. The primary + * {@code classes.dex} must contain the classes necessary for calling this + * class methods. Secondary dex files named classes2.dex, classes3.dex... found + * in the application apk will be added to the classloader after first call to + * {@link #install(Context)}. + * + *

+ * This library provides compatibility for platforms with API level 4 through 20. This library does + * nothing on newer versions of the platform which provide built-in support for secondary dex files. + */ +public final class MultiDex { + + static final String TAG = "MultiDex"; + + private static final String SECONDARY_FOLDER_NAME = "secondary-dexes"; + + private static final int MAX_SUPPORTED_SDK_VERSION = 20; + + private static final int MIN_SDK_VERSION = 4; + + private static final int VM_WITH_MULTIDEX_VERSION_MAJOR = 2; + + private static final int VM_WITH_MULTIDEX_VERSION_MINOR = 1; + + private static final Set installedApk = new HashSet(); + + private static final boolean IS_VM_MULTIDEX_CAPABLE = + isVMMultidexCapable(System.getProperty("java.vm.version")); + + private MultiDex() {} + + public static void installLibs(LuaActivity context) throws IllegalAccessException, IllegalArgumentException, IOException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException { + File d=new File(context.getLuaDir() + "/libs"); + String dir=d.getAbsolutePath(); + if (!d.exists()) + return; + String[] ls=d.list(); + ArrayList arr=new ArrayList(); + for (String s:ls) + { + if(s.endsWith(".dex")) + { + arr.add(new File(dir+"/"+s)); + Log.i(TAG,"install "+dir+"/"+s); + } + else if(s.endsWith(".jar")) + { + arr.add(new File(dir+"/"+s)); + context.loadResources(dir+"/"+s); + Log.i(TAG,"install "+dir+"/"+s); + } + } + if(arr.isEmpty()) + return; + File odex=new File(((LuaApplication)context.getApplication()).getOdexDir()); + installDexes(context.getClass().getClassLoader(),odex, arr); + } + + public static void installDexes(ClassLoader loader, File dexDir, List files) + throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, + InvocationTargetException, NoSuchMethodException, IOException + { + installSecondaryDexes(loader,dexDir,files); + } + /** + * Patches the application context class loader by appending extra dex files + * loaded from the application apk. This method should be called in the + * attachBaseContext of your {@link Application}, see + * {@link MultiDexApplication} for more explanation and an example. + * + * @param context application context. + * @throws RuntimeException if an error occurred preventing the classloader + * extension. + */ + public static void install(Context context) { + Log.i(TAG, "install"); + if (IS_VM_MULTIDEX_CAPABLE) { + Log.i(TAG, "VM has multidex support, MultiDex support library is disabled."); + try { + clearOldDexDir(context); + } catch (Throwable t) { + Log.w(TAG, "Something went wrong when trying to clear old MultiDex extraction, " + + "continuing without cleaning.", t); + } + return; + } + + if (Build.VERSION.SDK_INT < MIN_SDK_VERSION) { + throw new RuntimeException("Multi dex installation failed. SDK " + Build.VERSION.SDK_INT + + " is unsupported. Min SDK version is " + MIN_SDK_VERSION + "."); + } + + try { + ApplicationInfo applicationInfo = getApplicationInfo(context); + if (applicationInfo == null) { + // Looks like running on a test Context, so just return without patching. + return; + } + + synchronized (installedApk) { + String apkPath = applicationInfo.sourceDir; + if (installedApk.contains(apkPath)) { + return; + } + installedApk.add(apkPath); + + if (Build.VERSION.SDK_INT > MAX_SUPPORTED_SDK_VERSION) { + Log.w(TAG, "MultiDex is not guaranteed to work in SDK version " + + Build.VERSION.SDK_INT + ": SDK version higher than " + + MAX_SUPPORTED_SDK_VERSION + " should be backed by " + + "runtime with built-in multidex capabilty but it's not the " + + "case here: java.vm.version=\"" + + System.getProperty("java.vm.version") + "\""); + } + + /* The patched class loader is expected to be a descendant of + * dalvik.system.BaseDexClassLoader. We modify its + * dalvik.system.DexPathList pathList field to append additional DEX + * file entries. + */ + ClassLoader loader; + try { + loader = context.getClassLoader(); + } catch (RuntimeException e) { + /* Ignore those exceptions so that we don't break tests relying on Context like + * a android.test.mock.MockContext or a android.content.ContextWrapper with a + * null base Context. + */ + Log.w(TAG, "Failure while trying to obtain Context class loader. " + + "Must be running in test mode. Skip patching.", e); + return; + } + if (loader == null) { + // Note, the context class loader is null when running Robolectric tests. + Log.e(TAG, + "Context class loader is null. Must be running in test mode. " + + "Skip patching."); + return; + } + + File dexDir = new File(context.getFilesDir(), SECONDARY_FOLDER_NAME); + List files = MultiDexExtractor.load(context, applicationInfo, dexDir, false); + if (checkValidZipFiles(files)) { + installSecondaryDexes(loader, dexDir, files); + } else { + Log.w(TAG, "Files were not valid zip files. Forcing a reload."); + // Try again, but this time force a reload of the zip file. + files = MultiDexExtractor.load(context, applicationInfo, dexDir, true); + + if (checkValidZipFiles(files)) { + installSecondaryDexes(loader, dexDir, files); + } else { + // Second time didn't work, give up + throw new RuntimeException("Zip files were not valid."); + } + } + } + + } catch (Exception e) { + Log.e(TAG, "Multidex installation failure", e); + throw new RuntimeException("Multi dex installation failed (" + e.getMessage() + ")."); + } + Log.i(TAG, "install done"); + } + + private static ApplicationInfo getApplicationInfo(Context context) + throws NameNotFoundException { + PackageManager pm; + String packageName; + try { + pm = context.getPackageManager(); + packageName = context.getPackageName(); + } catch (RuntimeException e) { + /* Ignore those exceptions so that we don't break tests relying on Context like + * a android.test.mock.MockContext or a android.content.ContextWrapper with a null + * base Context. + */ + Log.w(TAG, "Failure while trying to obtain ApplicationInfo from Context. " + + "Must be running in test mode. Skip patching.", e); + return null; + } + if (pm == null || packageName == null) { + // This is most likely a mock context, so just return without patching. + return null; + } + ApplicationInfo applicationInfo = + pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); + return applicationInfo; + } + + /** + * Identifies if the current VM has a native support for multidex, meaning there is no need for + * additional installation by this library. + * @return true if the VM handles multidex + */ + /* package visible for test */ + static boolean isVMMultidexCapable(String versionString) { + boolean isMultidexCapable = false; + if (versionString != null) { + Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString); + if (matcher.matches()) { + try { + int major = Integer.parseInt(matcher.group(1)); + int minor = Integer.parseInt(matcher.group(2)); + isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR) + || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR) + && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR)); + } catch (NumberFormatException e) { + // let isMultidexCapable be false + } + } + } + Log.i(TAG, "VM with version " + versionString + + (isMultidexCapable ? + " has multidex support" : + " does not have multidex support")); + return isMultidexCapable; + } + + + private static void installSecondaryDexes(ClassLoader loader, File dexDir, List files) + throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, + InvocationTargetException, NoSuchMethodException, IOException { + if (!files.isEmpty()) { + if (Build.VERSION.SDK_INT >= 19) { + V19.install(loader, files, dexDir); + } else if (Build.VERSION.SDK_INT >= 14) { + V14.install(loader, files, dexDir); + } else { + V4.install(loader, files); + } + } + } + + /** + * Returns whether all files in the list are valid zip files. If {@code files} is empty, then + * returns true. + */ + private static boolean checkValidZipFiles(List files) { + for (File file : files) { + if (!MultiDexExtractor.verifyZipFile(file)) { + return false; + } + } + return true; + } + + /** + * Locates a given field anywhere in the class inheritance hierarchy. + * + * @param instance an object to search the field into. + * @param name field name + * @return a field object + * @throws NoSuchFieldException if the field cannot be located + */ + private static Field findField(Object instance, String name) throws NoSuchFieldException { + for (Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) { + try { + Field field = clazz.getDeclaredField(name); + + + if (!field.isAccessible()) { + field.setAccessible(true); + } + + return field; + } catch (NoSuchFieldException e) { + // ignore and search next + } + } + + throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass()); + } + + /** + * Locates a given method anywhere in the class inheritance hierarchy. + * + * @param instance an object to search the method into. + * @param name method name + * @param parameterTypes method parameter types + * @return a method object + * @throws NoSuchMethodException if the method cannot be located + */ + private static Method findMethod(Object instance, String name, Class... parameterTypes) + throws NoSuchMethodException { + for (Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) { + try { + Method method = clazz.getDeclaredMethod(name, parameterTypes); + + + if (!method.isAccessible()) { + method.setAccessible(true); + } + + return method; + } catch (NoSuchMethodException e) { + // ignore and search next + } + } + + throw new NoSuchMethodException("Method " + name + " with parameters " + + Arrays.asList(parameterTypes) + " not found in " + instance.getClass()); + } + + /** + * Replace the value of a field containing a non null array, by a new array containing the + * elements of the original array plus the elements of extraElements. + * @param instance the instance whose field is to be modified. + * @param fieldName the field to modify. + * @param extraElements elements to append at the end of the array. + */ + private static void expandFieldArray(Object instance, String fieldName, + Object[] extraElements) throws NoSuchFieldException, IllegalArgumentException, + IllegalAccessException { + Field jlrField = findField(instance, fieldName); + Object[] original = (Object[]) jlrField.get(instance); + Object[] combined = (Object[]) Array.newInstance( + original.getClass().getComponentType(), original.length + extraElements.length); + System.arraycopy(original, 0, combined, 0, original.length); + System.arraycopy(extraElements, 0, combined, original.length, extraElements.length); + jlrField.set(instance, combined); + } + + private static void clearOldDexDir(Context context) throws Exception { + ApplicationInfo applicationInfo = getApplicationInfo(context); + if (applicationInfo == null) { + // Looks like running on a test Context, so just return. + return; + } + + synchronized (installedApk) { + String apkPath = applicationInfo.sourceDir; + if (installedApk.contains(apkPath)) { + return; + } + installedApk.add(apkPath); + } + File dexDir = new File(context.getFilesDir(), SECONDARY_FOLDER_NAME); + if (dexDir.isDirectory()) { + Log.i(TAG, "Clearing old secondary dex dir (" + dexDir.getPath() + ")."); + File[] files = dexDir.listFiles(); + if (files == null) { + Log.w(TAG, "Failed to list secondary dex dir content (" + dexDir.getPath() + ")."); + return; + } + for (File oldFile : files) { + Log.i(TAG, "Trying to delete old file " + oldFile.getPath() + " of size " + + oldFile.length()); + if (!oldFile.delete()) { + Log.w(TAG, "Failed to delete old file " + oldFile.getPath()); + } else { + Log.i(TAG, "Deleted old file " + oldFile.getPath()); + } + } + if (!dexDir.delete()) { + Log.w(TAG, "Failed to delete secondary dex dir " + dexDir.getPath()); + } else { + Log.i(TAG, "Deleted old secondary dex dir " + dexDir.getPath()); + } + } + } + + /** + * Installer for platform versions 19. + */ + private static final class V19 { + + private static void install(ClassLoader loader, List additionalClassPathEntries, + File optimizedDirectory) + throws IllegalArgumentException, IllegalAccessException, + NoSuchFieldException, InvocationTargetException, NoSuchMethodException { + /* The patched class loader is expected to be a descendant of + * dalvik.system.BaseDexClassLoader. We modify its + * dalvik.system.DexPathList pathList field to append additional DEX + * file entries. + */ + Field pathListField = findField(loader, "pathList"); + Object dexPathList = pathListField.get(loader); + ArrayList suppressedExceptions = new ArrayList(); + expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, + new ArrayList(additionalClassPathEntries), optimizedDirectory, + suppressedExceptions)); + if (suppressedExceptions.size() > 0) { + for (IOException e : suppressedExceptions) { + Log.w(TAG, "Exception in makeDexElement", e); + } + Field suppressedExceptionsField = + findField(loader, "dexElementsSuppressedExceptions"); + IOException[] dexElementsSuppressedExceptions = + (IOException[]) suppressedExceptionsField.get(loader); + + if (dexElementsSuppressedExceptions == null) { + dexElementsSuppressedExceptions = + suppressedExceptions.toArray( + new IOException[suppressedExceptions.size()]); + } else { + IOException[] combined = + new IOException[suppressedExceptions.size() + + dexElementsSuppressedExceptions.length]; + suppressedExceptions.toArray(combined); + System.arraycopy(dexElementsSuppressedExceptions, 0, combined, + suppressedExceptions.size(), dexElementsSuppressedExceptions.length); + dexElementsSuppressedExceptions = combined; + } + + suppressedExceptionsField.set(loader, dexElementsSuppressedExceptions); + } + } + + /** + * A wrapper around + * {@code private static final dalvik.system.DexPathList#makeDexElements}. + */ + private static Object[] makeDexElements( + Object dexPathList, ArrayList files, File optimizedDirectory, + ArrayList suppressedExceptions) + throws IllegalAccessException, InvocationTargetException, + NoSuchMethodException { + Method makeDexElements = + findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class, + ArrayList.class); + + return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory, + suppressedExceptions); + } + } + + /** + * Installer for platform versions 14, 15, 16, 17 and 18. + */ + private static final class V14 { + + private static void install(ClassLoader loader, List additionalClassPathEntries, + File optimizedDirectory) + throws IllegalArgumentException, IllegalAccessException, + NoSuchFieldException, InvocationTargetException, NoSuchMethodException { + /* The patched class loader is expected to be a descendant of + * dalvik.system.BaseDexClassLoader. We modify its + * dalvik.system.DexPathList pathList field to append additional DEX + * file entries. + */ + Field pathListField = findField(loader, "pathList"); + Object dexPathList = pathListField.get(loader); + expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, + new ArrayList(additionalClassPathEntries), optimizedDirectory)); + } + + /** + * A wrapper around + * {@code private static final dalvik.system.DexPathList#makeDexElements}. + */ + private static Object[] makeDexElements( + Object dexPathList, ArrayList files, File optimizedDirectory) + throws IllegalAccessException, InvocationTargetException, + NoSuchMethodException { + Method makeDexElements = + findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class); + + return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory); + } + } + + /** + * Installer for platform versions 4 to 13. + */ + private static final class V4 { + private static void install(ClassLoader loader, List additionalClassPathEntries) + throws IllegalArgumentException, IllegalAccessException, + NoSuchFieldException, IOException { + /* The patched class loader is expected to be a descendant of + * dalvik.system.DexClassLoader. We modify its + * fields mPaths, mFiles, mZips and mDexs to append additional DEX + * file entries. + */ + int extraSize = additionalClassPathEntries.size(); + + Field pathField = findField(loader, "path"); + + StringBuilder path = new StringBuilder((String) pathField.get(loader)); + String[] extraPaths = new String[extraSize]; + File[] extraFiles = new File[extraSize]; + ZipFile[] extraZips = new ZipFile[extraSize]; + DexFile[] extraDexs = new DexFile[extraSize]; + for (ListIterator iterator = additionalClassPathEntries.listIterator(); + iterator.hasNext();) { + File additionalEntry = iterator.next(); + String entryPath = additionalEntry.getAbsolutePath(); + path.append(':').append(entryPath); + int index = iterator.previousIndex(); + extraPaths[index] = entryPath; + extraFiles[index] = additionalEntry; + extraZips[index] = new ZipFile(additionalEntry); + extraDexs[index] = DexFile.loadDex(entryPath, entryPath + ".dex", 0); + } + + pathField.set(loader, path.toString()); + expandFieldArray(loader, "mPaths", extraPaths); + expandFieldArray(loader, "mFiles", extraFiles); + expandFieldArray(loader, "mZips", extraZips); + expandFieldArray(loader, "mDexs", extraDexs); + } + } + +} diff --git a/app/src/main/java/android/support/multidex/MultiDexExtractor.java b/app/src/main/java/android/support/multidex/MultiDexExtractor.java new file mode 100644 index 0000000..fd70dee --- /dev/null +++ b/app/src/main/java/android/support/multidex/MultiDexExtractor.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.support.multidex; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.os.Build; +import android.util.Log; + +import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +/** + * Exposes application secondary dex files as files in the application data + * directory. + */ +final class MultiDexExtractor { + + private static final String TAG = MultiDex.TAG; + + /** + * We look for additional dex files named {@code classes2.dex}, + * {@code classes3.dex}, etc. + */ + private static final String DEX_PREFIX = "classes"; + private static final String DEX_SUFFIX = ".dex"; + + private static final String EXTRACTED_NAME_EXT = ".classes"; + private static final String EXTRACTED_SUFFIX = ".zip"; + private static final int MAX_EXTRACT_ATTEMPTS = 3; + + private static final String PREFS_FILE = "multidex.version"; + private static final String KEY_TIME_STAMP = "timestamp"; + private static final String KEY_CRC = "crc"; + private static final String KEY_DEX_NUMBER = "dex.number"; + + /** + * Size of reading buffers. + */ + private static final int BUFFER_SIZE = 0x4000; + /* Keep value away from 0 because it is a too probable time stamp value */ + private static final long NO_VALUE = -1L; + + /** + * Extracts application secondary dexes into files in the application data + * directory. + * + * @return a list of files that were created. The list may be empty if there + * are no secondary dex files. + * @throws IOException if encounters a problem while reading or writing + * secondary dex files + */ + static List load(Context context, ApplicationInfo applicationInfo, File dexDir, + boolean forceReload) throws IOException { + Log.i(TAG, "MultiDexExtractor.load(" + applicationInfo.sourceDir + ", " + forceReload + ")"); + final File sourceApk = new File(applicationInfo.sourceDir); + + File archive = new File(applicationInfo.sourceDir); + long currentCrc = getZipCrc(archive); + + List files; + if (!forceReload && !isModified(context, archive, currentCrc)) { + try { + files = loadExistingExtractions(context, sourceApk, dexDir); + } catch (IOException ioe) { + Log.w(TAG, "Failed to reload existing extracted secondary dex files," + + " falling back to fresh extraction", ioe); + files = performExtractions(sourceApk, dexDir); + putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1); + + } + } else { + Log.i(TAG, "Detected that extraction must be performed."); + files = performExtractions(sourceApk, dexDir); + putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1); + } + + Log.i(TAG, "load found " + files.size() + " secondary dex files"); + return files; + } + + private static List loadExistingExtractions(Context context, File sourceApk, File dexDir) + throws IOException { + Log.i(TAG, "loading existing secondary dex files"); + + final String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT; + int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1); + final List files = new ArrayList(totalDexNumber); + + for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) { + String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX; + File extractedFile = new File(dexDir, fileName); + if (extractedFile.isFile()) { + files.add(extractedFile); + if (!verifyZipFile(extractedFile)) { + Log.i(TAG, "Invalid zip file: " + extractedFile); + throw new IOException("Invalid ZIP file."); + } + } else { + throw new IOException("Missing extracted secondary dex file '" + + extractedFile.getPath() + "'"); + } + } + + return files; + } + + private static boolean isModified(Context context, File archive, long currentCrc) { + SharedPreferences prefs = getMultiDexPreferences(context); + return (prefs.getLong(KEY_TIME_STAMP, NO_VALUE) != getTimeStamp(archive)) + || (prefs.getLong(KEY_CRC, NO_VALUE) != currentCrc); + } + + private static long getTimeStamp(File archive) { + long timeStamp = archive.lastModified(); + if (timeStamp == NO_VALUE) { + // never return NO_VALUE + timeStamp--; + } + return timeStamp; + } + + + private static long getZipCrc(File archive) throws IOException { + long computedValue = ZipUtil.getZipCrc(archive); + if (computedValue == NO_VALUE) { + // never return NO_VALUE + computedValue--; + } + return computedValue; + } + + private static List performExtractions(File sourceApk, File dexDir) + throws IOException { + + final String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT; + + // Ensure that whatever deletions happen in prepareDexDir only happen if the zip that + // contains a secondary dex file in there is not consistent with the latest apk. Otherwise, + // multi-process race conditions can cause a crash loop where one process deletes the zip + // while another had created it. + prepareDexDir(dexDir, extractedFilePrefix); + + List files = new ArrayList(); + + final ZipFile apk = new ZipFile(sourceApk); + try { + + int secondaryNumber = 2; + + ZipEntry dexFile = apk.getEntry(DEX_PREFIX + secondaryNumber + DEX_SUFFIX); + while (dexFile != null) { + String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX; + File extractedFile = new File(dexDir, fileName); + files.add(extractedFile); + + Log.i(TAG, "Extraction is needed for file " + extractedFile); + int numAttempts = 0; + boolean isExtractionSuccessful = false; + while (numAttempts < MAX_EXTRACT_ATTEMPTS && !isExtractionSuccessful) { + numAttempts++; + + // Create a zip file (extractedFile) containing only the secondary dex file + // (dexFile) from the apk. + extract(apk, dexFile, extractedFile, extractedFilePrefix); + + // Verify that the extracted file is indeed a zip file. + isExtractionSuccessful = verifyZipFile(extractedFile); + + // Log the sha1 of the extracted zip file + Log.i(TAG, "Extraction " + (isExtractionSuccessful ? "success" : "failed") + + " - length " + extractedFile.getAbsolutePath() + ": " + + extractedFile.length()); + if (!isExtractionSuccessful) { + // Delete the extracted file + extractedFile.delete(); + if (extractedFile.exists()) { + Log.w(TAG, "Failed to delete corrupted secondary dex '" + + extractedFile.getPath() + "'"); + } + } + } + if (!isExtractionSuccessful) { + throw new IOException("Could not create zip file " + + extractedFile.getAbsolutePath() + " for secondary dex (" + + secondaryNumber + ")"); + } + secondaryNumber++; + dexFile = apk.getEntry(DEX_PREFIX + secondaryNumber + DEX_SUFFIX); + } + } finally { + try { + apk.close(); + } catch (IOException e) { + Log.w(TAG, "Failed to close resource", e); + } + } + + return files; + } + + private static void putStoredApkInfo(Context context, long timeStamp, long crc, + int totalDexNumber) { + SharedPreferences prefs = getMultiDexPreferences(context); + SharedPreferences.Editor edit = prefs.edit(); + edit.putLong(KEY_TIME_STAMP, timeStamp); + edit.putLong(KEY_CRC, crc); + /* SharedPreferences.Editor doc says that apply() and commit() "atomically performs the + * requested modifications" it should be OK to rely on saving the dex files number (getting + * old number value would go along with old crc and time stamp). + */ + edit.putInt(KEY_DEX_NUMBER, totalDexNumber); + apply(edit); + } + + private static SharedPreferences getMultiDexPreferences(Context context) { + return context.getSharedPreferences(PREFS_FILE, + Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB + ? Context.MODE_PRIVATE + : Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); + } + + /** + * This removes any files that do not have the correct prefix. + */ + private static void prepareDexDir(File dexDir, final String extractedFilePrefix) + throws IOException { + dexDir.mkdir(); + if (!dexDir.isDirectory()) { + throw new IOException("Failed to create dex directory " + dexDir.getPath()); + } + + // Clean possible old files + FileFilter filter = new FileFilter() { + + @Override + public boolean accept(File pathname) { + return !pathname.getName().startsWith(extractedFilePrefix); + } + }; + File[] files = dexDir.listFiles(filter); + if (files == null) { + Log.w(TAG, "Failed to list secondary dex dir content (" + dexDir.getPath() + ")."); + return; + } + for (File oldFile : files) { + Log.i(TAG, "Trying to delete old file " + oldFile.getPath() + " of size " + + oldFile.length()); + if (!oldFile.delete()) { + Log.w(TAG, "Failed to delete old file " + oldFile.getPath()); + } else { + Log.i(TAG, "Deleted old file " + oldFile.getPath()); + } + } + } + + private static void extract(ZipFile apk, ZipEntry dexFile, File extractTo, + String extractedFilePrefix) throws IOException, FileNotFoundException { + + InputStream in = apk.getInputStream(dexFile); + ZipOutputStream out = null; + File tmp = File.createTempFile(extractedFilePrefix, EXTRACTED_SUFFIX, + extractTo.getParentFile()); + Log.i(TAG, "Extracting " + tmp.getPath()); + try { + out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tmp))); + try { + ZipEntry classesDex = new ZipEntry("classes.dex"); + // keep zip entry time since it is the criteria used by Dalvik + classesDex.setTime(dexFile.getTime()); + out.putNextEntry(classesDex); + + byte[] buffer = new byte[BUFFER_SIZE]; + int length = in.read(buffer); + while (length != -1) { + out.write(buffer, 0, length); + length = in.read(buffer); + } + out.closeEntry(); + } finally { + out.close(); + } + Log.i(TAG, "Renaming to " + extractTo.getPath()); + if (!tmp.renameTo(extractTo)) { + throw new IOException("Failed to rename \"" + tmp.getAbsolutePath() + + "\" to \"" + extractTo.getAbsolutePath() + "\""); + } + } finally { + closeQuietly(in); + tmp.delete(); // return status ignored + } + } + + /** + * Returns whether the file is a valid zip file. + */ + static boolean verifyZipFile(File file) { + try { + ZipFile zipFile = new ZipFile(file); + try { + zipFile.close(); + return true; + } catch (IOException e) { + Log.w(TAG, "Failed to close zip file: " + file.getAbsolutePath()); + } + } catch (ZipException ex) { + Log.w(TAG, "File " + file.getAbsolutePath() + " is not a valid zip file.", ex); + } catch (IOException ex) { + Log.w(TAG, "Got an IOException trying to open zip file: " + file.getAbsolutePath(), ex); + } + return false; + } + + /** + * Closes the given {@code Closeable}. Suppresses any IO exceptions. + */ + private static void closeQuietly(Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + Log.w(TAG, "Failed to close resource", e); + } + } + + // The following is taken from SharedPreferencesCompat to avoid having a dependency of the + // multidex support library on another support library. + private static Method sApplyMethod; // final + static { + try { + Class cls = SharedPreferences.Editor.class; + sApplyMethod = cls.getMethod("apply"); + } catch (NoSuchMethodException unused) { + sApplyMethod = null; + } + } + + private static void apply(SharedPreferences.Editor editor) { + if (sApplyMethod != null) { + try { + sApplyMethod.invoke(editor); + return; + } catch (InvocationTargetException unused) { + // fall through + } catch (IllegalAccessException unused) { + // fall through + } + } + editor.commit(); + } +} diff --git a/app/src/main/java/android/support/multidex/ZipUtil.java b/app/src/main/java/android/support/multidex/ZipUtil.java new file mode 100644 index 0000000..cd518cc --- /dev/null +++ b/app/src/main/java/android/support/multidex/ZipUtil.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Apache Harmony HEADER because the code in this class comes mostly from ZipFile, ZipEntry and + * ZipConstants from android libcore. + */ + +package android.support.multidex; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.zip.CRC32; +import java.util.zip.ZipException; + +/** + * Tools to build a quick partial crc of zip files. + */ +final class ZipUtil { + static class CentralDirectory { + long offset; + long size; + } + + /* redefine those constant here because of bug 13721174 preventing to compile using the + * constants defined in ZipFile */ + private static final int ENDHDR = 22; + private static final int ENDSIG = 0x6054b50; + + /** + * Size of reading buffers. + */ + private static final int BUFFER_SIZE = 0x4000; + + /** + * Compute crc32 of the central directory of an apk. The central directory contains + * the crc32 of each entries in the zip so the computed result is considered valid for the whole + * zip file. Does not support zip64 nor multidisk but it should be OK for now since ZipFile does + * not either. + */ + static long getZipCrc(File apk) throws IOException { + RandomAccessFile raf = new RandomAccessFile(apk, "r"); + try { + CentralDirectory dir = findCentralDirectory(raf); + + return computeCrcOfCentralDir(raf, dir); + } finally { + raf.close(); + } + } + + /* Package visible for testing */ + static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException, + ZipException { + long scanOffset = raf.length() - ENDHDR; + if (scanOffset < 0) { + throw new ZipException("File too short to be a zip file: " + raf.length()); + } + + long stopOffset = scanOffset - 0x10000 /* ".ZIP file comment"'s max length */; + if (stopOffset < 0) { + stopOffset = 0; + } + + int endSig = Integer.reverseBytes(ENDSIG); + while (true) { + raf.seek(scanOffset); + if (raf.readInt() == endSig) { + break; + } + + scanOffset--; + if (scanOffset < stopOffset) { + throw new ZipException("End Of Central Directory signature not found"); + } + } + // Read the End Of Central Directory. ENDHDR includes the signature + // bytes, + // which we've already read. + + // Pull out the information we need. + raf.skipBytes(2); // diskNumber + raf.skipBytes(2); // diskWithCentralDir + raf.skipBytes(2); // numEntries + raf.skipBytes(2); // totalNumEntries + CentralDirectory dir = new CentralDirectory(); + dir.size = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL; + dir.offset = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL; + return dir; + } + + /* Package visible for testing */ + static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir) + throws IOException { + CRC32 crc = new CRC32(); + long stillToRead = dir.size; + raf.seek(dir.offset); + int length = (int) Math.min(BUFFER_SIZE, stillToRead); + byte[] buffer = new byte[BUFFER_SIZE]; + length = raf.read(buffer, 0, length); + while (length != -1) { + crc.update(buffer, 0, length); + stillToRead -= length; + if (stillToRead == 0) { + break; + } + length = (int) Math.min(BUFFER_SIZE, stillToRead); + length = raf.read(buffer, 0, length); + } + return crc.getValue(); + } +} diff --git a/app/src/main/java/android/support/v4/app/Fragment.java b/app/src/main/java/android/support/v4/app/Fragment.java new file mode 100644 index 0000000..504e81a --- /dev/null +++ b/app/src/main/java/android/support/v4/app/Fragment.java @@ -0,0 +1,4 @@ +package android.support.v4.app; + +public class Fragment { +} diff --git a/app/src/main/java/android/widget/ArrayExpandableListAdapter.java b/app/src/main/java/android/widget/ArrayExpandableListAdapter.java new file mode 100644 index 0000000..43fa77a --- /dev/null +++ b/app/src/main/java/android/widget/ArrayExpandableListAdapter.java @@ -0,0 +1,138 @@ +package android.widget; +import android.content.*; +import android.view.*; +import java.util.*; + +public class ArrayExpandableListAdapter extends BaseExpandableListAdapter +{ + + private Context mContext; + + private List> mChildData; + + private List mGroupData; + + private int mGroupLayout; + + private int mChildLayout; + + private LayoutInflater mLayoutInflater; + + private boolean mNotifyOnChange=true; + + public ArrayExpandableListAdapter(Context context) + { + this(context, new ArrayList(),android.R.layout.simple_expandable_list_item_1,new ArrayList>(),android.R.layout.simple_expandable_list_item_1); + } + + public ArrayExpandableListAdapter(Context context,List groupData,List> childData) + { + this(context,groupData,android.R.layout.simple_expandable_list_item_1,childData,android.R.layout.simple_expandable_list_item_1); + } + + public ArrayExpandableListAdapter(Context context,List groupData,int groupLayout,List> childData,int childLayout) + { + mContext=context; + mGroupData=groupData; + mGroupLayout=groupLayout; + mChildData=childData; + mChildLayout=childLayout; + mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + } + + + @Override + public int getGroupCount() + { + // TODO: Implement this method + return mGroupData.size(); + } + + @Override + public int getChildrenCount(int p1) + { + // TODO: Implement this method + return mChildData.get(p1).size(); + } + + @Override + public Object getGroup(int p1) + { + // TODO: Implement this method + return mGroupData.get(p1); + } + + @Override + public Object getChild(int p1, int p2) + { + // TODO: Implement this method + return mChildData.get(p1).get(p2); + } + + @Override + public long getGroupId(int p1) + { + // TODO: Implement this method + return p1; + } + + @Override + public long getChildId(int p1, int p2) + { + // TODO: Implement this method + return 0; + } + + @Override + public boolean hasStableIds() + { + // TODO: Implement this method + return false; + } + + @Override + public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) + { + // TODO: Implement this method + if(convertView==null) + convertView=mLayoutInflater.inflate(mGroupLayout,parent,false); + ((TextView)convertView).setText(mGroupData.get(groupPosition)); + return convertView; + } + + @Override + public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) + { + // TODO: Implement this method + if(convertView==null) + convertView=mLayoutInflater.inflate(mChildLayout,parent,false); + ((TextView)convertView).setText(mChildData.get(groupPosition).get(childPosition)); + return convertView; + } + + @Override + public boolean isChildSelectable(int p1, int p2) + { + // TODO: Implement this method + return true; + } + + public void add(String groutData, List childData) + { + mGroupData.add(groutData); + mChildData.add(childData); + if (mNotifyOnChange) notifyDataSetChanged(); + } + + public void add(String groutData, String[] childData) + { + mGroupData.add(groutData); + mChildData.add(Arrays.asList(childData)); + if (mNotifyOnChange) notifyDataSetChanged(); + } + + public void setNotifyOnChange(boolean notifyOnChange) { + mNotifyOnChange = notifyOnChange; + } +} diff --git a/app/src/main/java/android/widget/ArrayListAdapter.java b/app/src/main/java/android/widget/ArrayListAdapter.java new file mode 100644 index 0000000..6910c33 --- /dev/null +++ b/app/src/main/java/android/widget/ArrayListAdapter.java @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.luajava.LuaException; +import com.luajava.LuaFunction; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * A concrete BaseAdapter that is backed by an array of arbitrary + * objects. By default this class expects that the provided resource id references + * a single TextView. If you want to use a more complex layout, use the constructors that + * also takes a field id. That field id should reference a TextView in the larger layout + * resource. + *

+ *

However the TextView is referenced, it will be filled with the toString() of each object in + * the array. You can add lists or arrays of custom objects. Override the toString() method + * of your objects to determine what text will be displayed for the item in the list. + *

+ *

To use something other than TextViews for the array display, for instance, ImageViews, + * or to have some of data besides toString() results fill the views, + * override {@link #getView(int, View, ViewGroup)} to return the type of view you want. + */ +public class ArrayListAdapter extends BaseAdapter implements Filterable { + /** + * Contains the list of objects that represent the data of this ArrayAdapter. + * The content of this list is referred to as "the array" in the documentation. + */ + private ArrayList mObjects; + + /** + * Lock used to modify the content of {@link #mObjects}. Any write operation + * performed on the array should be synchronized on this lock. This lock is also + * used by the filter (see {@link #getFilter()} to make a synchronized copy of + * the original array of data. + */ + private final Object mLock = new Object(); + + /** + * The resource indicating what views to inflate to display the content of this + * array adapter. + */ + private int mResource; + + /** + * The resource indicating what views to inflate to display the content of this + * array adapter in a drop down widget. + */ + private int mDropDownResource; + + /** + * If the inflated resource is not a TextView, {@link #mFieldId} is used to find + * a TextView inside the inflated views hierarchy. This field must contain the + * identifier that matches the one defined in the resource file. + */ + private int mFieldId = 0; + + /** + * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever + * {@link #mObjects} is modified. + */ + private boolean mNotifyOnChange = true; + + private Context mContext; + + // A copy of the original mObjects array, initialized from and then used instead as soon as + // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values. + private ArrayList mOriginalValues; + private ArrayFilter mFilter; + + private LayoutInflater mInflater; + private LuaFunction mLuaFilter; + + /** + * Constructor + * + * @param context The current context. + */ + public ArrayListAdapter(Context context) { + init(context, android.R.layout.simple_list_item_1, 0, new ArrayList()); + } + + public ArrayListAdapter(Context context, T[] objects) { + init(context, android.R.layout.simple_list_item_1, 0, Arrays.asList(objects)); + } + + public ArrayListAdapter(Context context, List objects) { + init(context, android.R.layout.simple_list_item_1, 0, objects); + } + + + /** + * Constructor + * + * @param context The current context. + * @param textViewResourceId The resource ID for a layout file containing a TextView to use when + * instantiating views. + */ + public ArrayListAdapter(Context context, int textViewResourceId) { + init(context, textViewResourceId, 0, new ArrayList()); + } + + /** + * Constructor + * + * @param context The current context. + * @param resource The resource ID for a layout file containing a layout to use when + * instantiating views. + * @param textViewResourceId The id of the TextView within the layout resource to be populated + */ + public ArrayListAdapter(Context context, int resource, int textViewResourceId) { + init(context, resource, textViewResourceId, new ArrayList()); + } + + /** + * Constructor + * + * @param context The current context. + * @param textViewResourceId The resource ID for a layout file containing a TextView to use when + * instantiating views. + * @param objects The objects to represent in the ListView. + */ + public ArrayListAdapter(Context context, int textViewResourceId, T[] objects) { + init(context, textViewResourceId, 0, Arrays.asList(objects)); + } + + /** + * Constructor + * + * @param context The current context. + * @param resource The resource ID for a layout file containing a layout to use when + * instantiating views. + * @param textViewResourceId The id of the TextView within the layout resource to be populated + * @param objects The objects to represent in the ListView. + */ + public ArrayListAdapter(Context context, int resource, int textViewResourceId, T[] objects) { + init(context, resource, textViewResourceId, Arrays.asList(objects)); + } + + /** + * Constructor + * + * @param context The current context. + * @param textViewResourceId The resource ID for a layout file containing a TextView to use when + * instantiating views. + * @param objects The objects to represent in the ListView. + */ + public ArrayListAdapter(Context context, int textViewResourceId, List objects) { + init(context, textViewResourceId, 0, objects); + } + + /** + * Constructor + * + * @param context The current context. + * @param resource The resource ID for a layout file containing a layout to use when + * instantiating views. + * @param textViewResourceId The id of the TextView within the layout resource to be populated + * @param objects The objects to represent in the ListView. + */ + public ArrayListAdapter(Context context, int resource, int textViewResourceId, List objects) { + init(context, resource, textViewResourceId, objects); + } + + /** + * Adds the specified object at the end of the array. + * + * @param object The object to add at the end of the array. + */ + public void add(T object) { + synchronized (mLock) { + if (mOriginalValues != null) { + mOriginalValues.add(object); + } else { + mObjects.add(object); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + /** + * Adds the specified Collection at the end of the array. + * + * @param collection The Collection to add at the end of the array. + */ + public void addAll(Collection collection) { + synchronized (mLock) { + if (mOriginalValues != null) { + mOriginalValues.addAll(collection); + } else { + mObjects.addAll(collection); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + /** + * Adds the specified items at the end of the array. + * + * @param items The items to add at the end of the array. + */ + public void addAll(T... items) { + synchronized (mLock) { + if (mOriginalValues != null) { + Collections.addAll(mOriginalValues, items); + } else { + Collections.addAll(mObjects, items); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + /** + * Inserts the specified object at the specified index in the array. + * + * @param object The object to insert into the array. + * @param index The index at which the object must be inserted. + */ + public void insert(int index, T object) { + synchronized (mLock) { + if (mOriginalValues != null) { + mOriginalValues.add(index, object); + } else { + mObjects.add(index, object); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + /** + * Removes the specified object from the array. + * + * @param object The object to remove. + */ + public void remove(T object) { + synchronized (mLock) { + if (mOriginalValues != null) { + mOriginalValues.remove(object); + } else { + mObjects.remove(object); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + public void remove(int idx) { + synchronized (mLock) { + if (mOriginalValues != null) { + mOriginalValues.remove(idx); + } else { + mObjects.remove(idx); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + /** + * Remove all elements from the list. + */ + public void clear() { + synchronized (mLock) { + if (mOriginalValues != null) { + mOriginalValues.clear(); + } else { + mObjects.clear(); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + /** + * Sorts the content of this adapter using the specified comparator. + * + * @param comparator The comparator used to sort the objects contained + * in this adapter. + */ + public void sort(Comparator comparator) { + synchronized (mLock) { + if (mOriginalValues != null) { + Collections.sort(mOriginalValues, comparator); + } else { + Collections.sort(mObjects, comparator); + } + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + + /** + * {@inheritDoc} + */ + @Override + public void notifyDataSetChanged() { + super.notifyDataSetChanged(); + mNotifyOnChange = true; + } + + /** + * Control whether methods that change the list ({@link #add}, + * {@link #insert}, {@link #remove}, {@link #clear}) automatically call + * {@link #notifyDataSetChanged}. If set to false, caller must + * manually call notifyDataSetChanged() to have the changes + * reflected in the attached view. + *

+ * The default is true, and calling notifyDataSetChanged() + * resets the flag to true. + * + * @param notifyOnChange if true, modifications to the list will + * automatically call {@link + * #notifyDataSetChanged} + */ + public void setNotifyOnChange(boolean notifyOnChange) { + mNotifyOnChange = notifyOnChange; + } + + private void init(Context context, int resource, int textViewResourceId, List objects) { + mContext = context; + mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mResource = mDropDownResource = resource; + mObjects = new ArrayList(objects); + mFieldId = textViewResourceId; + } + + public Object getData() { + return mObjects; + } + + /** + * Returns the context associated with this array adapter. The context is used + * to create views from the resource passed to the constructor. + * + * @return The Context associated with this adapter. + */ + public Context getContext() { + return mContext; + } + + /** + * {@inheritDoc} + */ + public int getCount() { + return mObjects.size(); + } + + /** + * {@inheritDoc} + */ + public T getItem(int position) { + return mObjects.get(position); + } + + /** + * Returns the position of the specified item in the array. + * + * @param item The item to retrieve the position of. + * @return The position of the specified item. + */ + public int getPosition(T item) { + return mObjects.indexOf(item); + } + + /** + * {@inheritDoc} + */ + public long getItemId(int position) { + return position + 1; + } + + /** + * {@inheritDoc} + */ + public View getView(int position, View convertView, ViewGroup parent) { + return createViewFromResource(position, convertView, parent, mResource); + } + + private View createViewFromResource(int position, View convertView, ViewGroup parent, + int resource) { + View view; + TextView text; + + if (convertView == null) { + view = mInflater.inflate(resource, parent, false); + } else { + view = convertView; + } + + try { + if (mFieldId == 0) { + // If no custom field is assigned, assume the whole resource is a TextView + text = (TextView) view; + } else { + // Otherwise, find the TextView field within the layout + text = (TextView) view.findViewById(mFieldId); + } + } catch (ClassCastException e) { + Log.e("ArrayAdapter", "You must supply a resource ID for a TextView"); + throw new IllegalStateException( + "ArrayAdapter requires the resource ID to be a TextView", e); + } + + T item = getItem(position); + if (item instanceof CharSequence) { + text.setText((CharSequence) item); + } else { + text.setText(item.toString()); + } + + return view; + } + + /** + *

Sets the layout resource to create the drop down views.

+ * + * @param resource the layout resource defining the drop down views + * @see #getDropDownView(int, android.view.View, android.view.ViewGroup) + */ + public void setDropDownViewResource(int resource) { + this.mDropDownResource = resource; + } + + /** + * {@inheritDoc} + */ + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + return createViewFromResource(position, convertView, parent, mDropDownResource); + } + + /** + * Creates a new ArrayAdapter from external resources. The content of the array is + * obtained through {@link android.content.res.Resources#getTextArray(int)}. + * + * @param context The application's environment. + * @param textArrayResId The identifier of the array to use as the data source. + * @param textViewResId The identifier of the layout used to create views. + * @return An ArrayAdapter. + */ + public static ArrayListAdapter createFromResource(Context context, + int textArrayResId, int textViewResId) { + CharSequence[] strings = context.getResources().getTextArray(textArrayResId); + return new ArrayListAdapter(context, textViewResId, strings); + } + + /** + * {@inheritDoc} + */ + @Override + public Filter getFilter() { + if (mFilter == null) { + mFilter = new ArrayFilter(); + } + return mFilter; + } + + public void filter(CharSequence constraint) { + getFilter().filter(constraint); + } + + public void setFilter(LuaFunction filter) { + mLuaFilter = filter; + } + + /** + *

An array filter constrains the content of the array adapter with + * a prefix. Each item that does not start with the supplied prefix + * is removed from the list.

+ */ + private class ArrayFilter extends Filter { + @Override + protected FilterResults performFiltering(CharSequence prefix) { + FilterResults results = new FilterResults(); + + if (mOriginalValues == null) { + synchronized (mLock) { + mOriginalValues = new ArrayList(mObjects); + } + } else if (TextUtils.isEmpty(prefix)) { + results.values = new ArrayList<>(mOriginalValues); + results.count = mOriginalValues.size(); + mOriginalValues = null; + return results; + } + if (mLuaFilter != null) { + final ArrayList newValues = new ArrayList(); + try { + mLuaFilter.call(new ArrayList<>(mOriginalValues), newValues, prefix); + } catch (LuaException e) { + e.printStackTrace(); + } + results.values = newValues; + results.count = newValues.size(); + return results; + } + if (prefix == null || prefix.length() == 0) { + ArrayList list; + synchronized (mLock) { + list = new ArrayList(mOriginalValues); + } + results.values = list; + results.count = list.size(); + } else { + String prefixString = prefix.toString().toLowerCase(); + + ArrayList values; + synchronized (mLock) { + values = new ArrayList(mOriginalValues); + } + + final int count = values.size(); + final ArrayList newValues = new ArrayList(); + + for (int i = 0; i < count; i++) { + final T value = values.get(i); + final String valueText = value.toString().toLowerCase(); + + // First match against the whole, non-splitted value + if (valueText.contains(prefixString)) { + newValues.add(value); + }/* else { + final String[] words = valueText.split(" "); + final int wordCount = words.length; + + // Start at index 0, in case valueText starts with space(s) + for (int k = 0; k < wordCount; k++) { + if (words[k].startsWith(prefixString)) { + newValues.add(value); + break; + } + } + }*/ + } + + results.values = newValues; + results.count = newValues.size(); + } + + return results; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + //noinspection unchecked + mObjects = (ArrayList) results.values; + if (results.count > 0) { + notifyDataSetChanged(); + } else { + notifyDataSetInvalidated(); + } + } + } +} diff --git a/app/src/main/java/android/widget/ArrayPageAdapter.java b/app/src/main/java/android/widget/ArrayPageAdapter.java new file mode 100644 index 0000000..4c9ff47 --- /dev/null +++ b/app/src/main/java/android/widget/ArrayPageAdapter.java @@ -0,0 +1,72 @@ +package android.widget; + +/** + * PageView适配器 + */ + +import android.view.View; + +import java.util.ArrayList; +import java.util.Arrays; + +public class ArrayPageAdapter extends BasePageAdapter { + public ArrayList mListViews; + + public ArrayPageAdapter() { + this.mListViews = new ArrayList<>(); + } + + public ArrayPageAdapter(ArrayList views) { + this.mListViews = views; + } + + public ArrayPageAdapter(View[] views) { + this.mListViews = new ArrayList<>(Arrays.asList(views)); + } + + @Override + public void destroyItem(View arg0, int arg1, Object arg2) { + ((PageView) arg0).removeView(mListViews.get(arg1)); + } + + @Override + public int getCount() { + return mListViews.size(); + } + + @Override + public Object instantiateItem(View arg0, int arg1) { + ((PageView) arg0).addView(mListViews.get(arg1), 0); + return mListViews.get(arg1); + } + + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0 == (arg1); + } + + public void add(View view) { + mListViews.add(view); + } + + public void insert(int index, View view) { + mListViews.add(index, view); + } + + public View remove(int index) { + return mListViews.remove(index); + } + + public boolean remove(View view) { + return mListViews.remove(view); + } + + public View getItem(int index) { + return mListViews.get(index); + } + + public ArrayList getData() { + return mListViews; + } + +} diff --git a/app/src/main/java/android/widget/BasePageAdapter.java b/app/src/main/java/android/widget/BasePageAdapter.java new file mode 100644 index 0000000..61f38e2 --- /dev/null +++ b/app/src/main/java/android/widget/BasePageAdapter.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.database.DataSetObservable; +import android.database.DataSetObserver; +import android.os.Parcelable; +import android.view.View; +import android.view.ViewGroup; + +public abstract class BasePageAdapter { + private DataSetObservable mObservable = new DataSetObservable(); + + public static final int POSITION_UNCHANGED = -1; + public static final int POSITION_NONE = -2; + + /** + * Return the number of views available. + */ + public abstract int getCount(); + + /** + * Called when a change in the shown pages is going to start being made. + * @param container The containing View which is displaying this adapter's + * page views. + */ + public void startUpdate(ViewGroup container) { + startUpdate((View) container); + } + + /** + * Create the page for the given position. The adapter is responsible + * for adding the view to the container given here, although it only + * must ensure this is done by the time it returns from + * {@link #finishUpdate(ViewGroup)}. + * + * @param container The containing View in which the page will be shown. + * @param position The page position to be instantiated. + * @return Returns an Object representing the new page. This does not + * need to be a View, but can be some other container of the page. + */ + public Object instantiateItem(ViewGroup container, int position) { + return instantiateItem((View) container, position); + } + + /** + * Remove a page for the given position. The adapter is responsible + * for removing the view from its container, although it only must ensure + * this is done by the time it returns from {@link #finishUpdate(ViewGroup)}. + * + * @param container The containing View from which the page will be removed. + * @param position The page position to be removed. + * @param object The same object that was returned by + * {@link #instantiateItem(View, int)}. + */ + public void destroyItem(ViewGroup container, int position, Object object) { + destroyItem((View) container, position, object); + } + + /** + * Called to inform the adapter of which item is currently considered to + * be the "primary", that is the one show to the user as the current page. + * + * @param container The containing View from which the page will be removed. + * @param position The page position that is now the primary. + * @param object The same object that was returned by + * {@link #instantiateItem(View, int)}. + */ + public void setPrimaryItem(ViewGroup container, int position, Object object) { + setPrimaryItem((View) container, position, object); + } + + /** + * Called when the a change in the shown pages has been completed. At this + * point you must ensure that all of the pages have actually been added or + * removed from the container as appropriate. + * @param container The containing View which is displaying this adapter's + * page views. + */ + public void finishUpdate(ViewGroup container) { + finishUpdate((View) container); + } + + /** + * Called when a change in the shown pages is going to start being made. + * @param container The containing View which is displaying this adapter's + * page views. + * + * @deprecated Use {@link #startUpdate(ViewGroup)} + */ + public void startUpdate(View container) { + } + + /** + * Create the page for the given position. The adapter is responsible + * for adding the view to the container given here, although it only + * must ensure this is done by the time it returns from + * {@link #finishUpdate(ViewGroup)}. + * + * @param container The containing View in which the page will be shown. + * @param position The page position to be instantiated. + * @return Returns an Object representing the new page. This does not + * need to be a View, but can be some other container of the page. + * + * @deprecated Use {@link #instantiateItem(ViewGroup, int)} + */ + public Object instantiateItem(View container, int position) { + throw new UnsupportedOperationException( + "Required method instantiateItem was not overridden"); + } + + /** + * Remove a page for the given position. The adapter is responsible + * for removing the view from its container, although it only must ensure + * this is done by the time it returns from {@link #finishUpdate(View)}. + * + * @param container The containing View from which the page will be removed. + * @param position The page position to be removed. + * @param object The same object that was returned by + * {@link #instantiateItem(View, int)}. + * + * @deprecated Use {@link #destroyItem(ViewGroup, int, Object)} + */ + public void destroyItem(View container, int position, Object object) { + throw new UnsupportedOperationException("Required method destroyItem was not overridden"); + } + + /** + * Called to inform the adapter of which item is currently considered to + * be the "primary", that is the one show to the user as the current page. + * + * @param container The containing View from which the page will be removed. + * @param position The page position that is now the primary. + * @param object The same object that was returned by + * {@link #instantiateItem(View, int)}. + * + * @deprecated Use {@link #setPrimaryItem(ViewGroup, int, Object)} + */ + public void setPrimaryItem(View container, int position, Object object) { + } + + /** + * Called when the a change in the shown pages has been completed. At this + * point you must ensure that all of the pages have actually been added or + * removed from the container as appropriate. + * @param container The containing View which is displaying this adapter's + * page views. + * + * @deprecated Use {@link #finishUpdate(ViewGroup)} + */ + public void finishUpdate(View container) { + } + + /** + * Determines whether a page View is associated with a specific key object + * as returned by {@link #instantiateItem(ViewGroup, int)}. This method is + * required for a PagerAdapter to function properly. + * + * @param view Page View to check for association with object + * @param object Object to check for association with view + * @return true if view is associated with the key object object + */ + public abstract boolean isViewFromObject(View view, Object object); + + /** + * Save any instance state associated with this adapter and its pages that should be + * restored if the current UI state needs to be reconstructed. + * + * @return Saved state for this adapter + */ + public Parcelable saveState() { + return null; + } + + /** + * Restore any instance state associated with this adapter and its pages + * that was previously saved by {@link #saveState()}. + * + * @param state State previously saved by a call to {@link #saveState()} + * @param loader A ClassLoader that should be used to instantiate any restored objects + */ + public void restoreState(Parcelable state, ClassLoader loader) { + } + + /** + * Called when the host view is attempting to determine if an item's position + * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given + * item has not changed or {@link #POSITION_NONE} if the item is no longer present + * in the adapter. + * + *

The default implementation assumes that items will never + * change position and always returns {@link #POSITION_UNCHANGED}. + * + * @param object Object representing an item, previously returned by a call to + * {@link #instantiateItem(View, int)}. + * @return object's new position index from [0, {@link #getCount()}), + * {@link #POSITION_UNCHANGED} if the object's position has not changed, + * or {@link #POSITION_NONE} if the item is no longer present. + */ + public int getItemPosition(Object object) { + return POSITION_UNCHANGED; + } + + /** + * This method should be called by the application if the data backing this adapter has changed + * and associated views should update. + */ + public void notifyDataSetChanged() { + mObservable.notifyChanged(); + } + + /** + * Register an observer to receive callbacks related to the adapter's data changing. + * + * @param observer The {@link android.database.DataSetObserver} which will receive callbacks. + */ + public void registerDataSetObserver(DataSetObserver observer) { + mObservable.registerObserver(observer); + } + + /** + * Unregister an observer from callbacks related to the adapter's data changing. + * + * @param observer The {@link android.database.DataSetObserver} which will be unregistered. + */ + public void unregisterDataSetObserver(DataSetObserver observer) { + mObservable.unregisterObserver(observer); + } + + /** + * This method may be called by the ViewPager to obtain a title string + * to describe the specified page. This method may return null + * indicating no title for this page. The default implementation returns + * null. + * + * @param position The position of the title requested + * @return A title for the requested page + */ + public CharSequence getPageTitle(int position) { + return null; + } + + /** + * Returns the proportional width of a given page as a percentage of the + * ViewPager's measured width from (0.f-1.f] + * + * @param position The position of the page requested + * @return Proportional width for the given page position + */ + public float getPageWidth(int position) { + return 1.f; + } +} diff --git a/app/src/main/java/android/widget/CardView.java b/app/src/main/java/android/widget/CardView.java new file mode 100644 index 0000000..5e6bb0e --- /dev/null +++ b/app/src/main/java/android/widget/CardView.java @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.os.Build; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.View; + +/** + * A FrameLayout with a rounded corner background and shadow. + *

+ * CardView uses elevation property on L for shadows and falls back to a custom shadow + * implementation on older platforms. + *

+ * Due to expensive nature of rounded corner clipping, on platforms before L, CardView does not + * clip its children that intersect with rounded corners. Instead, it adds padding to avoid such + * intersection (See {@link #setPreventCornerOverlap(boolean)} to change this behavior). + *

+ * Before L, CardView adds padding to its content and draws shadows to that area. This padding + * amount is equal to maxCardElevation + (1 - cos45) * cornerRadius on the sides and + * maxCardElevation * 1.5 + (1 - cos45) * cornerRadius on top and bottom. + *

+ * Since padding is used to offset content for shadows, you cannot set padding on CardView. + * Instead, + * you can use content padding attributes in XML or {@link #setContentPadding(int, int, int, int)} + * in code to set the padding between the edges of the Card and children of CardView. + *

+ * Note that, if you specify exact dimensions for the CardView, because of the shadows, its content + * area will be different between platforms before L and after L. By using api version specific + * resource values, you can avoid these changes. Alternatively, If you want CardView to add inner + * padding on platforms L and after as well, you can set {@link #setUseCompatPadding(boolean)} to + * true. + *

+ * To change CardView's elevation in a backward compatible way, use + * {@link #setCardElevation(float)}. CardView will use elevation API on L and before L, it will + * change the shadow size. To avoid moving the View while shadow size is changing, shadow size is + * clamped by {@link #getMaxCardElevation()}. If you want to change elevation dynamically, you + * should call {@link #setMaxCardElevation(float)} when CardView is initialized. + * + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardCornerRadius + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardMaxElevation + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardUseCompatPadding + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardPreventCornerOverlap + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPadding + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingLeft + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingTop + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingRight + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingBottom + */ +public class CardView extends FrameLayout implements CardViewDelegate { + + private static final CardViewImpl IMPL; + + private DisplayMetrics dm; + + static { + if (Build.VERSION.SDK_INT >= 21) { + IMPL = new CardViewApi21(); + } else if (Build.VERSION.SDK_INT >= 17) { + IMPL = new CardViewJellybeanMr1(); + } else { + IMPL = new CardViewEclairMr1(); + } + IMPL.initStatic(); + } + + private boolean mCompatPadding; + + private boolean mPreventCornerOverlap; + + private final Rect mContentPadding = new Rect(); + + private final Rect mShadowBounds = new Rect(); + + + public CardView(Context context) { + super(context); + initialize(context, null, 0); + } + + public CardView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context, attrs, 0); + } + + public CardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(context, attrs, defStyleAttr); + } + + @Override + public void setPadding(int left, int top, int right, int bottom) { + // NO OP + } + + public void setPaddingRelative(int start, int top, int end, int bottom) { + // NO OP + } + + /** + * Returns whether CardView will add inner padding on platforms L and after. + * + * @return True CardView adds inner padding on platforms L and after to have same dimensions + * with platforms before L. + */ + @Override + public boolean getUseCompatPadding() { + return mCompatPadding; + } + + /** + * CardView adds additional padding to draw shadows on platforms before L. + *

+ * This may cause Cards to have different sizes between L and before L. If you need to align + * CardView with other Views, you may need api version specific dimension resources to account + * for the changes. + * As an alternative, you can set this flag to true and CardView will add the same + * padding values on platforms L and after. + *

+ * Since setting this flag to true adds unnecessary gaps in the UI, default value is + * false. + * + * @param useCompatPadding True if CardView should add padding for the shadows on platforms L + * and above. + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardUseCompatPadding + */ + public void setUseCompatPadding(boolean useCompatPadding) { + if (mCompatPadding == useCompatPadding) { + return; + } + mCompatPadding = useCompatPadding; + IMPL.onCompatPaddingChanged(this); + } + + /** + * Sets the padding between the Card's edges and the children of CardView. + *

+ * Depending on platform version or {@link #getUseCompatPadding()} settings, CardView may + * update these values before calling {@link android.view.View#setPadding(int, int, int, int)}. + * + * @param left The left padding in pixels + * @param top The top padding in pixels + * @param right The right padding in pixels + * @param bottom The bottom padding in pixels + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPadding + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingLeft + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingTop + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingRight + * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingBottom + */ + public void setContentPadding(int left, int top, int right, int bottom) { + mContentPadding.set(left, top, right, bottom); + IMPL.updatePadding(this); + } + + @SuppressLint("SwitchIntDef") + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (!(IMPL instanceof CardViewApi21)) { + final int widthMode = MeasureSpec.getMode(widthMeasureSpec); + switch (widthMode) { + case MeasureSpec.EXACTLY: + case MeasureSpec.AT_MOST: + final int minWidth = (int) Math.ceil(IMPL.getMinWidth(this)); + widthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minWidth, + MeasureSpec.getSize(widthMeasureSpec)), widthMode); + break; + } + + final int heightMode = MeasureSpec.getMode(heightMeasureSpec); + switch (heightMode) { + case MeasureSpec.EXACTLY: + case MeasureSpec.AT_MOST: + final int minHeight = (int) Math.ceil(IMPL.getMinHeight(this)); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minHeight, + MeasureSpec.getSize(heightMeasureSpec)), heightMode); + break; + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + private void initialize(Context context, AttributeSet attrs, int defStyleAttr) { + dm=context.getResources().getDisplayMetrics(); + TypedArray array = context.getTheme().obtainStyledAttributes(new int[] { + android.R.attr.colorBackground, + }); + int backgroundColor = array.getColor(0, 0x00FFFAFAFA); + array.recycle(); + + //TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CardView, defStyleAttr, + // R.style.CardView_Light); + //int backgroundColor = 0x00FFFAFAFA; + + //a.getColor(R.styleable.CardView_cardBackgroundColor, 0); + float radius = dp(2); + //a.getDimension(R.styleable.CardView_cardCornerRadius, 0); + float elevation = dp(2); + //a.getDimension(R.styleable.CardView_cardElevation, 0); + float maxElevation =dp(2); + //a.getDimension(R.styleable.CardView_cardMaxElevation, 0); + mCompatPadding = false; + //a.getBoolean(R.styleable.CardView_cardUseCompatPadding, false); + mPreventCornerOverlap = true; + //a.getBoolean(R.styleable.CardView_cardPreventCornerOverlap, true); + int defaultPadding = 0; + //a.getDimensionPixelSize(R.styleable.CardView_contentPadding, 0); + mContentPadding.left = 0; + //a.getDimensionPixelSize(R.styleable.CardView_contentPaddingLeft, + //defaultPadding); + mContentPadding.top = 0; + //a.getDimensionPixelSize(R.styleable.CardView_contentPaddingTop, + //defaultPadding); + mContentPadding.right = 0; + //a.getDimensionPixelSize(R.styleable.CardView_contentPaddingRight, + //defaultPadding); + mContentPadding.bottom = 0; + //a.getDimensionPixelSize(R.styleable.CardView_contentPaddingBottom, + //defaultPadding); + if (elevation > maxElevation) { + maxElevation = elevation; + } + //a.recycle(); + IMPL.initialize(this, context, backgroundColor, radius, elevation, maxElevation); + } + + private float dp(float n) { + // TODO: Implement this method + return TypedValue.applyDimension(1,n,dm); + } + + + /** + * Updates the background color of the CardView + * + * @param color The new color to set for the card background + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor + */ + public void setCardBackgroundColor(int color) { + IMPL.setBackgroundColor(this, color); + } + + public void setBackgroundColor(int color) { + IMPL.setBackgroundColor(this, color); + } + + /** + * Returns the inner padding after the Card's left edge + * + * @return the inner padding after the Card's left edge + */ + public int getContentPaddingLeft() { + return mContentPadding.left; + } + + /** + * Returns the inner padding before the Card's right edge + * + * @return the inner padding before the Card's right edge + */ + public int getContentPaddingRight() { + return mContentPadding.right; + } + + /** + * Returns the inner padding after the Card's top edge + * + * @return the inner padding after the Card's top edge + */ + public int getContentPaddingTop() { + return mContentPadding.top; + } + + /** + * Returns the inner padding before the Card's bottom edge + * + * @return the inner padding before the Card's bottom edge + */ + public int getContentPaddingBottom() { + return mContentPadding.bottom; + } + + /** + * Updates the corner radius of the CardView. + * + * @param radius The radius in pixels of the corners of the rectangle shape + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardCornerRadius + * @see #setRadius(float) + */ + public void setRadius(float radius) { + IMPL.setRadius(this, radius); + } + + /** + * Returns the corner radius of the CardView. + * + * @return Corner radius of the CardView + * @see #getRadius() + */ + public float getRadius() { + return IMPL.getRadius(this); + } + + /** + * Internal method used by CardView implementations to update the padding. + * + * @hide + */ + @Override + public void setShadowPadding(int left, int top, int right, int bottom) { + mShadowBounds.set(left, top, right, bottom); + super.setPadding(left + mContentPadding.left, top + mContentPadding.top, + right + mContentPadding.right, bottom + mContentPadding.bottom); + } + + /** + * Updates the backward compatible elevation of the CardView. + * + * @param radius The backward compatible elevation in pixels. + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation + * @see #getCardElevation() + * @see #setMaxCardElevation(float) + */ + public void setCardElevation(float radius) { + IMPL.setElevation(this, radius); + } + + /** + * Returns the backward compatible elevation of the CardView. + * + * @return Elevation of the CardView + * @see #setCardElevation(float) + * @see #getMaxCardElevation() + */ + public float getCardElevation() { + return IMPL.getElevation(this); + } + + /** + * Updates the backward compatible elevation of the CardView. + *

+ * Calling this method has no effect if device OS version is L or newer and + * {@link #getUseCompatPadding()} is false. + * + * @param radius The backward compatible elevation in pixels. + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation + * @see #setCardElevation(float) + * @see #getMaxCardElevation() + */ + public void setMaxCardElevation(float radius) { + IMPL.setMaxElevation(this, radius); + } + + /** + * Returns the backward compatible elevation of the CardView. + * + * @return Elevation of the CardView + * @see #setMaxCardElevation(float) + * @see #getCardElevation() + */ + public float getMaxCardElevation() { + return IMPL.getMaxElevation(this); + } + + /** + * Returns whether CardView should add extra padding to content to avoid overlaps with rounded + * corners on API versions 20 and below. + * + * @return True if CardView prevents overlaps with rounded corners on platforms before L. + * Default value is true. + */ + @Override + public boolean getPreventCornerOverlap() { + return mPreventCornerOverlap; + } + + /** + * On API 20 and before, CardView does not clip the bounds of the Card for the rounded corners. + * Instead, it adds padding to content so that it won't overlap with the rounded corners. + * You can disable this behavior by setting this field to false. + *

+ * Setting this value on API 21 and above does not have any effect unless you have enabled + * compatibility padding. + * + * @param preventCornerOverlap Whether CardView should add extra padding to content to avoid + * overlaps with the CardView corners. + * @attr ref android.support.v7.cardview.R.styleable#CardView_cardPreventCornerOverlap + * @see #setUseCompatPadding(boolean) + */ + public void setPreventCornerOverlap(boolean preventCornerOverlap) { + if (preventCornerOverlap == mPreventCornerOverlap) { + return; + } + mPreventCornerOverlap = preventCornerOverlap; + IMPL.onPreventCornerOverlapChanged(this); + } + + + @SuppressLint("NewApi") + static class CardViewApi21 implements CardViewImpl { + + @Override + public void initialize(CardViewDelegate cardView, Context context, int backgroundColor, + float radius, float elevation, float maxElevation) { + final RoundRectDrawable backgroundDrawable = new RoundRectDrawable(backgroundColor, radius); + cardView.setBackgroundDrawable(backgroundDrawable); + View view = (View) cardView; + view.setClipToOutline(true); + view.setElevation(elevation); + setMaxElevation(cardView, maxElevation); + } + + @Override + public void setRadius(CardViewDelegate cardView, float radius) { + ((RoundRectDrawable) (cardView.getBackground())).setRadius(radius); + } + + @Override + public void initStatic() { + } + + @Override + public void setMaxElevation(CardViewDelegate cardView, float maxElevation) { + ((RoundRectDrawable) (cardView.getBackground())).setPadding(maxElevation, + cardView.getUseCompatPadding(), cardView.getPreventCornerOverlap()); + updatePadding(cardView); + } + + @Override + public float getMaxElevation(CardViewDelegate cardView) { + return ((RoundRectDrawable) (cardView.getBackground())).getPadding(); + } + + @Override + public float getMinWidth(CardViewDelegate cardView) { + return getRadius(cardView) * 2; + } + + @Override + public float getMinHeight(CardViewDelegate cardView) { + return getRadius(cardView) * 2; + } + + @Override + public float getRadius(CardViewDelegate cardView) { + return ((RoundRectDrawable) (cardView.getBackground())).getRadius(); + } + + @Override + public void setElevation(CardViewDelegate cardView, float elevation) { + ((View) cardView).setElevation(elevation); + } + + @Override + public float getElevation(CardViewDelegate cardView) { + return ((View) cardView).getElevation(); + } + + @Override + public void updatePadding(CardViewDelegate cardView) { + if (!cardView.getUseCompatPadding()) { + cardView.setShadowPadding(0, 0, 0, 0); + return; + } + float elevation = getMaxElevation(cardView); + final float radius = getRadius(cardView); + int hPadding = (int) Math.ceil(RoundRectDrawableWithShadow + .calculateHorizontalPadding(elevation, radius, cardView.getPreventCornerOverlap())); + int vPadding = (int) Math.ceil(RoundRectDrawableWithShadow + .calculateVerticalPadding(elevation, radius, cardView.getPreventCornerOverlap())); + cardView.setShadowPadding(hPadding, vPadding, hPadding, vPadding); + } + + @Override + public void onCompatPaddingChanged(CardViewDelegate cardView) { + setMaxElevation(cardView, getMaxElevation(cardView)); + } + + @Override + public void onPreventCornerOverlapChanged(CardViewDelegate cardView) { + setMaxElevation(cardView, getMaxElevation(cardView)); + } + + @Override + public void setBackgroundColor(CardViewDelegate cardView, int color) { + ((RoundRectDrawable) (cardView.getBackground())).setColor(color); + } + } + + static class CardViewEclairMr1 implements CardViewImpl { + + final RectF sCornerRect = new RectF(); + + @Override + public void initStatic() { + // Draws a round rect using 7 draw operations. This is faster than using + // canvas.drawRoundRect before JBMR1 because API 11-16 used alpha mask textures to draw + // shapes. + RoundRectDrawableWithShadow.sRoundRectHelper + = new RoundRectDrawableWithShadow.RoundRectHelper() { + @Override + public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, + Paint paint) { + final float twoRadius = cornerRadius * 2; + final float innerWidth = bounds.width() - twoRadius - 1; + final float innerHeight = bounds.height() - twoRadius - 1; + // increment it to account for half pixels. + if (cornerRadius >= 1f) { + cornerRadius += .5f; + sCornerRect.set(-cornerRadius, -cornerRadius, cornerRadius, cornerRadius); + int saved = canvas.save(); + canvas.translate(bounds.left + cornerRadius, bounds.top + cornerRadius); + canvas.drawArc(sCornerRect, 180, 90, true, paint); + canvas.translate(innerWidth, 0); + canvas.rotate(90); + canvas.drawArc(sCornerRect, 180, 90, true, paint); + canvas.translate(innerHeight, 0); + canvas.rotate(90); + canvas.drawArc(sCornerRect, 180, 90, true, paint); + canvas.translate(innerWidth, 0); + canvas.rotate(90); + canvas.drawArc(sCornerRect, 180, 90, true, paint); + canvas.restoreToCount(saved); + //draw top and bottom pieces + canvas.drawRect(bounds.left + cornerRadius - 1f, bounds.top, + bounds.right - cornerRadius + 1f, bounds.top + cornerRadius, + paint); + canvas.drawRect(bounds.left + cornerRadius - 1f, + bounds.bottom - cornerRadius + 1f, bounds.right - cornerRadius + 1f, + bounds.bottom, paint); + } +//// center + canvas.drawRect(bounds.left, bounds.top + Math.max(0, cornerRadius - 1f), + bounds.right, bounds.bottom - cornerRadius + 1f, paint); + } + }; + } + + @Override + public void initialize(CardViewDelegate cardView, Context context, int backgroundColor, + float radius, float elevation, float maxElevation) { + RoundRectDrawableWithShadow background = createBackground(context, backgroundColor, radius, + elevation, maxElevation); + background.setAddPaddingForCorners(cardView.getPreventCornerOverlap()); + cardView.setBackgroundDrawable(background); + updatePadding(cardView); + } + + RoundRectDrawableWithShadow createBackground(Context context, int backgroundColor, + float radius, float elevation, float maxElevation) { + return new RoundRectDrawableWithShadow(context.getResources(), backgroundColor, radius, + elevation, maxElevation); + } + + @Override + public void updatePadding(CardViewDelegate cardView) { + Rect shadowPadding = new Rect(); + getShadowBackground(cardView).getMaxShadowAndCornerPadding(shadowPadding); + ((View) cardView).setMinimumHeight((int) Math.ceil(getMinHeight(cardView))); + ((View) cardView).setMinimumWidth((int) Math.ceil(getMinWidth(cardView))); + cardView.setShadowPadding(shadowPadding.left, shadowPadding.top, + shadowPadding.right, shadowPadding.bottom); + } + + @Override + public void onCompatPaddingChanged(CardViewDelegate cardView) { + // NO OP + } + + @Override + public void onPreventCornerOverlapChanged(CardViewDelegate cardView) { + getShadowBackground(cardView).setAddPaddingForCorners(cardView.getPreventCornerOverlap()); + updatePadding(cardView); + } + + @Override + public void setBackgroundColor(CardViewDelegate cardView, int color) { + getShadowBackground(cardView).setColor(color); + } + + @Override + public void setRadius(CardViewDelegate cardView, float radius) { + getShadowBackground(cardView).setCornerRadius(radius); + updatePadding(cardView); + } + + @Override + public float getRadius(CardViewDelegate cardView) { + return getShadowBackground(cardView).getCornerRadius(); + } + + @Override + public void setElevation(CardViewDelegate cardView, float elevation) { + getShadowBackground(cardView).setShadowSize(elevation); + } + + @Override + public float getElevation(CardViewDelegate cardView) { + return getShadowBackground(cardView).getShadowSize(); + } + + @Override + public void setMaxElevation(CardViewDelegate cardView, float maxElevation) { + getShadowBackground(cardView).setMaxShadowSize(maxElevation); + updatePadding(cardView); + } + + @Override + public float getMaxElevation(CardViewDelegate cardView) { + return getShadowBackground(cardView).getMaxShadowSize(); + } + + @Override + public float getMinWidth(CardViewDelegate cardView) { + return getShadowBackground(cardView).getMinWidth(); + } + + @Override + public float getMinHeight(CardViewDelegate cardView) { + return getShadowBackground(cardView).getMinHeight(); + } + + private RoundRectDrawableWithShadow getShadowBackground(CardViewDelegate cardView) { + return ((RoundRectDrawableWithShadow) cardView.getBackground()); + } + } + + + static class CardViewJellybeanMr1 extends CardViewEclairMr1 { + + @Override + public void initStatic() { + RoundRectDrawableWithShadow.sRoundRectHelper + = new RoundRectDrawableWithShadow.RoundRectHelper() { + @Override + public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, + Paint paint) { + canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint); + } + }; + } + } + +} diff --git a/app/src/main/java/android/widget/CardViewDelegate.java b/app/src/main/java/android/widget/CardViewDelegate.java new file mode 100644 index 0000000..be12c73 --- /dev/null +++ b/app/src/main/java/android/widget/CardViewDelegate.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.widget; + +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +/** + * Interface provided by CardView to implementations. + *

+ * Necessary to resolve circular dependency between base CardView and platform implementations. + */ +interface CardViewDelegate { + void setBackgroundDrawable(Drawable paramDrawable); + Drawable getBackground(); + boolean getUseCompatPadding(); + boolean getPreventCornerOverlap(); + float getRadius(); + void setShadowPadding(int left, int top, int right, int bottom); +} diff --git a/app/src/main/java/android/widget/CardViewImpl.java b/app/src/main/java/android/widget/CardViewImpl.java new file mode 100644 index 0000000..5c3117c --- /dev/null +++ b/app/src/main/java/android/widget/CardViewImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.widget; + +import android.content.Context; +/** + * Interface for platform specific CardView implementations. + */ +interface CardViewImpl { + void initialize(CardViewDelegate cardView, Context context, int backgroundColor, float radius, + float elevation, float maxElevation); + + void setRadius(CardViewDelegate cardView, float radius); + + float getRadius(CardViewDelegate cardView); + + void setElevation(CardViewDelegate cardView, float elevation); + + float getElevation(CardViewDelegate cardView); + + void initStatic(); + + void setMaxElevation(CardViewDelegate cardView, float maxElevation); + + float getMaxElevation(CardViewDelegate cardView); + + float getMinWidth(CardViewDelegate cardView); + + float getMinHeight(CardViewDelegate cardView); + + void updatePadding(CardViewDelegate cardView); + + void onCompatPaddingChanged(CardViewDelegate cardView); + + void onPreventCornerOverlapChanged(CardViewDelegate cardView); + + void setBackgroundColor(CardViewDelegate cardView, int color); +} diff --git a/app/src/main/java/android/widget/CircleImageView.java b/app/src/main/java/android/widget/CircleImageView.java new file mode 100644 index 0000000..167783f --- /dev/null +++ b/app/src/main/java/android/widget/CircleImageView.java @@ -0,0 +1,441 @@ +/* + * Copyright 2014 - 2015 Henning Dodenhof + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.util.AttributeSet; +import android.widget.ImageView; + +public class CircleImageView extends ImageView { + + private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; + + private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; + private static final int COLORDRAWABLE_DIMENSION = 2; + + private static final int DEFAULT_BORDER_WIDTH = 0; + private static final int DEFAULT_BORDER_COLOR = Color.BLACK; + private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT; + private static final boolean DEFAULT_BORDER_OVERLAY = false; + + private final RectF mDrawableRect = new RectF(); + private final RectF mBorderRect = new RectF(); + + private final Matrix mShaderMatrix = new Matrix(); + private final Paint mBitmapPaint = new Paint(); + private final Paint mBorderPaint = new Paint(); + private final Paint mFillPaint = new Paint(); + + private int mBorderColor = DEFAULT_BORDER_COLOR; + private int mBorderWidth = DEFAULT_BORDER_WIDTH; + private int mFillColor = DEFAULT_FILL_COLOR; + + private Bitmap mBitmap; + private BitmapShader mBitmapShader; + private int mBitmapWidth; + private int mBitmapHeight; + + private float mDrawableRadius; + private float mBorderRadius; + + private ColorFilter mColorFilter; + + private boolean mReady; + private boolean mSetupPending; + private boolean mBorderOverlay; + private boolean mDisableCircularTransformation; + + private float mElevation; + + public CircleImageView(Context context) { + super(context); + + init(); + } + + public CircleImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircleImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + //TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); + + mBorderWidth = DEFAULT_BORDER_WIDTH;//a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH); + mBorderColor = DEFAULT_BORDER_COLOR;// a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR); + mBorderOverlay = DEFAULT_BORDER_OVERLAY;//a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY); + mFillColor = DEFAULT_FILL_COLOR;//a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR); + + //a.recycle(); + + init(); + } + + private void init() { + super.setScaleType(SCALE_TYPE); + mReady = true; + + if (mSetupPending) { + setup(); + mSetupPending = false; + } + } + + public void setElevation2(float elevation) { + + mElevation=elevation; + mFillPaint.setShadowLayer(elevation, 0, elevation/2, 0xff000000); + invalidate(); + //setPadding(getPaddingLeft(),getPaddingTop(),getPaddingRight(),getPaddingBottom()-(int)radius); + } + + + @Override + public ScaleType getScaleType() { + return SCALE_TYPE; + } + + @Override + public void setScaleType(ScaleType scaleType) { + if (scaleType != SCALE_TYPE) { + throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); + } + } + + @Override + public void setAdjustViewBounds(boolean adjustViewBounds) { + if (adjustViewBounds) { + throw new IllegalArgumentException("adjustViewBounds not supported."); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (mDisableCircularTransformation) { + super.onDraw(canvas); + return; + } + + if (mBitmap == null) { + return; + } + + if (mFillColor != Color.TRANSPARENT) { + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius-mElevation, mFillPaint); + } + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius-mElevation, mBitmapPaint); + if (mBorderWidth > 0) { + canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius-mElevation, mBorderPaint); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + setup(); + } + + public int getBorderColor() { + return mBorderColor; + } + + public void setBorderColor(int borderColor) { + if (borderColor == mBorderColor) { + return; + } + + mBorderColor = borderColor; + mBorderPaint.setColor(mBorderColor); + invalidate(); + } + + /** + * @deprecated Use {@link #setBorderColor(int)} instead + */ + @Deprecated + public void setBorderColorResource(int borderColorRes) { + setBorderColor(getContext().getResources().getColor(borderColorRes)); + } + + /** + * Return the color drawn behind the circle-shaped drawable. + * + * @return The color drawn behind the drawable + * + * @deprecated Fill color support is going to be removed in the future + */ + @Deprecated + public int getFillColor() { + return mFillColor; + } + + /** + * Set a color to be drawn behind the circle-shaped drawable. Note that + * this has no effect if the drawable is opaque or no drawable is set. + * + * @param fillColor The color to be drawn behind the drawable + * + * @deprecated Fill color support is going to be removed in the future + */ + @Deprecated + public void setFillColor(int fillColor) { + if (fillColor == mFillColor) { + return; + } + + mFillColor = fillColor; + mFillPaint.setColor(fillColor); + invalidate(); + } + + + @Override + public void setBackgroundColor(int color) + { + setFillColor(color); + } + + /** + * Set a color to be drawn behind the circle-shaped drawable. Note that + * this has no effect if the drawable is opaque or no drawable is set. + * + * @param fillColorRes The color resource to be resolved to a color and + * drawn behind the drawable + * + * @deprecated Fill color support is going to be removed in the future + */ + @Deprecated + public void setFillColorResource(int fillColorRes) { + setFillColor(getContext().getResources().getColor(fillColorRes)); + } + + public int getBorderWidth() { + return mBorderWidth; + } + + public void setBorderWidth(int borderWidth) { + if (borderWidth == mBorderWidth) { + return; + } + + mBorderWidth = borderWidth; + setup(); + } + + public boolean isBorderOverlay() { + return mBorderOverlay; + } + + public void setBorderOverlay(boolean borderOverlay) { + if (borderOverlay == mBorderOverlay) { + return; + } + + mBorderOverlay = borderOverlay; + setup(); + } + + public boolean isDisableCircularTransformation() { + return mDisableCircularTransformation; + } + + public void setDisableCircularTransformation(boolean disableCircularTransformation) { + if (mDisableCircularTransformation == disableCircularTransformation) { + return; + } + + mDisableCircularTransformation = disableCircularTransformation; + initializeBitmap(); + } + + @Override + public void setImageBitmap(Bitmap bm) { + super.setImageBitmap(bm); + initializeBitmap(); + } + + @Override + public void setImageDrawable(Drawable drawable) { + super.setImageDrawable(drawable); + initializeBitmap(); + } + + @Override + public void setImageResource(int resId) { + super.setImageResource(resId); + initializeBitmap(); + } + + @Override + public void setImageURI(Uri uri) { + super.setImageURI(uri); + initializeBitmap(); + } + + @Override + public void setColorFilter(ColorFilter cf) { + if (cf == mColorFilter) { + return; + } + + mColorFilter = cf; + applyColorFilter(); + invalidate(); + } + + @Override + public ColorFilter getColorFilter() { + return mColorFilter; + } + + private void applyColorFilter() { + if (mBitmapPaint != null) { + mBitmapPaint.setColorFilter(mColorFilter); + } + } + + private Bitmap getBitmapFromDrawable(Drawable drawable) { + if (drawable == null) { + return null; + } + + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + + try { + Bitmap bitmap; + + if (drawable instanceof ColorDrawable) { + bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth()-(int)(mElevation*2), drawable.getIntrinsicHeight()-(int)(mElevation*2), BITMAP_CONFIG); + } + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private void initializeBitmap() { + if (mDisableCircularTransformation) { + mBitmap = null; + } else { + mBitmap = getBitmapFromDrawable(getDrawable()); + } + setup(); + } + + private void setup() { + if (!mReady) { + mSetupPending = true; + return; + } + + if (getWidth() == 0 && getHeight() == 0) { + return; + } + + if (mBitmap == null) { + invalidate(); + return; + } + + mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + + mBitmapPaint.setAntiAlias(true); + mBitmapPaint.setShader(mBitmapShader); + + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setColor(mBorderColor); + mBorderPaint.setStrokeWidth(mBorderWidth); + + mFillPaint.setStyle(Paint.Style.FILL); + mFillPaint.setAntiAlias(true); + mFillPaint.setColor(mFillColor); + + mBitmapHeight = mBitmap.getHeight(); + mBitmapWidth = mBitmap.getWidth(); + + mBorderRect.set(calculateBounds()); + mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f); + + mDrawableRect.set(mBorderRect); + if (!mBorderOverlay && mBorderWidth > 0) { + mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f); + } + mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f); + + applyColorFilter(); + updateShaderMatrix(); + invalidate(); + } + + private RectF calculateBounds() { + int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom(); + + int sideLength = Math.min(availableWidth, availableHeight); + + float left = getPaddingLeft() + (availableWidth - sideLength) / 2f; + float top = getPaddingTop() + (availableHeight - sideLength) / 2f; + + return new RectF(left, top, left + sideLength, top + sideLength); + } + + private void updateShaderMatrix() { + float scale; + float dx = 0; + float dy = 0; + + mShaderMatrix.set(null); + + if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { + scale = mDrawableRect.height() / (float) mBitmapHeight; + dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; + } else { + scale = mDrawableRect.width() / (float) mBitmapWidth; + dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; + } + + mShaderMatrix.setScale(scale, scale); + mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top); + + mBitmapShader.setLocalMatrix(mShaderMatrix); + } + +} diff --git a/app/src/main/java/android/widget/DrawerLayout.java b/app/src/main/java/android/widget/DrawerLayout.java new file mode 100644 index 0000000..c246a72 --- /dev/null +++ b/app/src/main/java/android/widget/DrawerLayout.java @@ -0,0 +1,2079 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowInsets; +import android.view.accessibility.AccessibilityEvent; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; + +/** + * DrawerLayout acts as a top-level container for window content that allows for + * interactive "drawer" views to be pulled out from the edge of the window. + * + *

Drawer positioning and layout is controlled using the android:layout_gravity + * attribute on child views corresponding to which side of the view you want the drawer + * to emerge from: left or right. (Or start/end on platform versions that support layout direction.) + *

+ * + *

To use a DrawerLayout, position your primary content view as the first child with + * a width and height of match_parent. Add drawers as child views after the main + * content view and set the layout_gravity appropriately. Drawers commonly use + * match_parent for height with a fixed width.

+ * + *

{@link DrawerListener} can be used to monitor the state and motion of drawer views. + * Avoid performing expensive operations such as layout during animation as it can cause + * stuttering; try to perform expensive operations during the {@link #STATE_IDLE} state. + * {@link SimpleDrawerListener} offers default/no-op implementations of each callback method.

+ * + *

As per the Android Design + * guide, any drawers positioned to the left/start should + * always contain content for navigating around the application, whereas any drawers + * positioned to the right/end should always contain actions to take on the current content. + * This preserves the same navigation left, actions right structure present in the Action Bar + * and elsewhere.

+ * + *

For more information about how to use DrawerLayout, read Creating a Navigation + * Drawer.

+ */ +public class DrawerLayout extends ViewGroup implements DrawerLayoutImpl { + private static final String TAG = "DrawerLayout"; + + //@IntDef({STATE_IDLE, STATE_DRAGGING, STATE_SETTLING}) + @Retention(RetentionPolicy.SOURCE) + private @interface State {} + + /** + * Indicates that any drawers are in an idle, settled state. No animation is in progress. + */ + public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE; + + /** + * Indicates that a drawer is currently being dragged by the user. + */ + public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING; + + /** + * Indicates that a drawer is in the process of settling to a final position. + */ + public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING; + + /** @hide */ + //@IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN}) + @Retention(RetentionPolicy.SOURCE) + private @interface LockMode {} + + /** + * The drawer is unlocked. + */ + public static final int LOCK_MODE_UNLOCKED = 0; + + /** + * The drawer is locked closed. The user may not open it, though + * the app may open it programmatically. + */ + public static final int LOCK_MODE_LOCKED_CLOSED = 1; + + /** + * The drawer is locked open. The user may not close it, though the app + * may close it programmatically. + */ + public static final int LOCK_MODE_LOCKED_OPEN = 2; + + /** @hide */ + //@IntDef({Gravity.LEFT, Gravity.RIGHT, Gravity.START, Gravity.END}) + @Retention(RetentionPolicy.SOURCE) + private @interface EdgeGravity {} + + + private static final int MIN_DRAWER_MARGIN = 64; // dp + private static final int DRAWER_ELEVATION = 10; //dp + + private static final int DEFAULT_SCRIM_COLOR = 0x99000000; + + /** + * Length of time to delay before peeking the drawer. + */ + private static final int PEEK_DELAY = 160; // ms + + /** + * Minimum velocity that will be detected as a fling + */ + private static final int MIN_FLING_VELOCITY = 400; // dips per second + + /** + * Experimental feature. + */ + private static final boolean ALLOW_EDGE_LOCK = false; + + private static final boolean CHILDREN_DISALLOW_INTERCEPT = true; + + private static final float TOUCH_SLOP_SENSITIVITY = 1.f; + + private static final int[] LAYOUT_ATTRS = new int[] { + android.R.attr.layout_gravity + }; + + /** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */ + private static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19; + + /** Whether the drawer shadow comes from setting elevation on the drawer. */ + private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION = + Build.VERSION.SDK_INT >= 21; + + private final AccessibilityDelegate mChildAccessibilityDelegate = + new AccessibilityDelegate(); + private float mDrawerElevation; + + private int mMinDrawerMargin; + + private int mScrimColor = DEFAULT_SCRIM_COLOR; + private float mScrimOpacity; + private Paint mScrimPaint = new Paint(); + + private final ViewDragHelper mLeftDragger; + private final ViewDragHelper mRightDragger; + private final ViewDragCallback mLeftCallback; + private final ViewDragCallback mRightCallback; + private int mDrawerState; + private boolean mInLayout; + private boolean mFirstLayout = true; + private int mLockModeLeft; + private int mLockModeRight; + private boolean mDisallowInterceptRequested; + private boolean mChildrenCanceledTouch; + + private DrawerListener mListener; + + private float mInitialMotionX; + private float mInitialMotionY; + + private Drawable mStatusBarBackground; + private Drawable mShadowLeftResolved; + private Drawable mShadowRightResolved; + + private CharSequence mTitleLeft; + private CharSequence mTitleRight; + + private Object mLastInsets; + private boolean mDrawStatusBarBackground; + + /** Shadow drawables for different gravity */ + private Drawable mShadowStart = null; + private Drawable mShadowEnd = null; + private Drawable mShadowLeft = null; + private Drawable mShadowRight = null; + + private final ArrayList mNonDrawerViews; + + /** + * Listener for monitoring events about drawers. + */ + public interface DrawerListener { + /** + * Called when a drawer's position changes. + * @param drawerView The child view that was moved + * @param slideOffset The new offset of this drawer within its range, from 0-1 + */ + public void onDrawerSlide(View drawerView, float slideOffset); + + /** + * Called when a drawer has settled in a completely open state. + * The drawer is interactive at this point. + * + * @param drawerView Drawer view that is now open + */ + public void onDrawerOpened(View drawerView); + + /** + * Called when a drawer has settled in a completely closed state. + * + * @param drawerView Drawer view that is now closed + */ + public void onDrawerClosed(View drawerView); + + /** + * Called when the drawer motion state changes. The new state will + * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}. + * + * @param newState The new drawer motion state + */ + public void onDrawerStateChanged(@State int newState); + } + + /** + * Stub/no-op implementations of all methods of {@link DrawerListener}. + * Override this if you only care about a few of the available callback methods. + */ + public static abstract class SimpleDrawerListener implements DrawerListener { + @Override + public void onDrawerSlide(View drawerView, float slideOffset) { + } + + @Override + public void onDrawerOpened(View drawerView) { + } + + @Override + public void onDrawerClosed(View drawerView) { + } + + @Override + public void onDrawerStateChanged(int newState) { + } + } + + static interface DrawerLayoutCompatImpl { + void configureApplyInsets(View drawerLayout); + void dispatchChildInsets(View child, Object insets, int drawerGravity); + void applyMarginInsets(MarginLayoutParams lp, Object insets, int drawerGravity); + int getTopInset(Object lastInsets); + Drawable getDefaultStatusBarBackground(Context context); + } + + @SuppressLint("NewApi") + static class DrawerLayoutCompatImplBase implements DrawerLayoutCompatImpl { + public void configureApplyInsets(View drawerLayout) { + // This space for rent + } + + public void dispatchChildInsets(View child, Object insets, int drawerGravity) { + // This space for rent + } + + public void applyMarginInsets(MarginLayoutParams lp, Object insets, int drawerGravity) { + // This space for rent + } + + public int getTopInset(Object insets) { + return 0; + } + + @Override + public Drawable getDefaultStatusBarBackground(Context context) { + return null; + } + } + + @SuppressLint("NewApi") + static class DrawerLayoutCompatImplApi21 implements DrawerLayoutCompatImpl { + public void configureApplyInsets(View drawerLayout) { + DrawerLayoutCompatApi21.configureApplyInsets(drawerLayout); + } + + public void dispatchChildInsets(View child, Object insets, int drawerGravity) { + DrawerLayoutCompatApi21.dispatchChildInsets(child, insets, drawerGravity); + } + + public void applyMarginInsets(MarginLayoutParams lp, Object insets, int drawerGravity) { + DrawerLayoutCompatApi21.applyMarginInsets(lp, insets, drawerGravity); + } + + public int getTopInset(Object insets) { + return DrawerLayoutCompatApi21.getTopInset(insets); + } + + @Override + public Drawable getDefaultStatusBarBackground(Context context) { + return DrawerLayoutCompatApi21.getDefaultStatusBarBackground(context); + } + } + + static { + final int version = Build.VERSION.SDK_INT; + if (version >= 21) { + IMPL = new DrawerLayoutCompatImplApi21(); + } else { + IMPL = new DrawerLayoutCompatImplBase(); + } + } + + static final DrawerLayoutCompatImpl IMPL; + + public DrawerLayout(Context context) { + this(context, null); + } + + public DrawerLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DrawerLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); + final float density = getResources().getDisplayMetrics().density; + mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f); + final float minVel = MIN_FLING_VELOCITY * density; + + mLeftCallback = new ViewDragCallback(Gravity.LEFT); + mRightCallback = new ViewDragCallback(Gravity.RIGHT); + + mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback); + mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); + mLeftDragger.setMinVelocity(minVel); + mLeftCallback.setDragger(mLeftDragger); + + mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback); + mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT); + mRightDragger.setMinVelocity(minVel); + mRightCallback.setDragger(mRightDragger); + + // So that we can catch the back button + setFocusableInTouchMode(true); + + setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_YES); + + setAccessibilityDelegate(new AccessibilityDelegate()); + setMotionEventSplittingEnabled(false); + if (getFitsSystemWindows()) { + IMPL.configureApplyInsets(this); + mStatusBarBackground = IMPL.getDefaultStatusBarBackground(context); + } + + mDrawerElevation = DRAWER_ELEVATION * density; + + mNonDrawerViews = new ArrayList(); + } + + /** + * Sets the base elevation of the drawer(s) relative to the parent, in pixels. Note that the + * elevation change is only supported in API 21 and above. + * + * @param elevation The base depth position of the view, in pixels. + */ + public void setDrawerElevation(float elevation) { + mDrawerElevation = elevation; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (isDrawerView(child)) { + child.setElevation(mDrawerElevation); + } + } + } + } + + /** + * The base elevation of the drawer(s) relative to the parent, in pixels. Note that the + * elevation change is only supported in API 21 and above. For unsupported API levels, 0 will + * be returned as the elevation. + * + * @return The base depth position of the view, in pixels. + */ + public float getDrawerElevation() { + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + return mDrawerElevation; + } + return 0f; + } + + /** + * @hide Internal use only; called to apply window insets when configured + * with fitsSystemWindows="true" + */ + @Override + public void setChildInsets(Object insets, boolean draw) { + mLastInsets = insets; + mDrawStatusBarBackground = draw; + setWillNotDraw(!draw && getBackground() == null); + requestLayout(); + } + + /** + * Set a simple drawable used for the left or right shadow. The drawable provided must have a + * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer + * instead of the drawable provided. + * + *

Note that for better support for both left-to-right and right-to-left layout + * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be + * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity + * {@link Gravity#START}. Alternatively, for API 23 and above, the drawable can + * auto-mirrored such that the drawable will be mirrored in RTL layout.

+ * + * @param shadowDrawable Shadow drawable to use at the edge of a drawer + * @param gravity Which drawer the shadow should apply to + */ + public void setDrawerShadow(Drawable shadowDrawable, @EdgeGravity int gravity) { + /* + * TODO Someone someday might want to set more complex drawables here. + * They're probably nuts, but we might want to consider registering callbacks, + * setting states, etc. properly. + */ + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + // No op. Drawer shadow will come from setting an elevation on the drawer. + return; + } + if ((gravity & Gravity.START) == Gravity.START) { + mShadowStart = shadowDrawable; + } else if ((gravity & Gravity.END) == Gravity.END) { + mShadowEnd = shadowDrawable; + } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) { + mShadowLeft = shadowDrawable; + } else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) { + mShadowRight = shadowDrawable; + } else { + return; + } + resolveShadowDrawables(); + invalidate(); + } + + /** + * Set a simple drawable used for the left or right shadow. The drawable provided must have a + * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer + * instead of the drawable provided. + * + *

Note that for better support for both left-to-right and right-to-left layout + * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be + * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity + * {@link Gravity#START}. Alternatively, for API 23 and above, the drawable can + * auto-mirrored such that the drawable will be mirrored in RTL layout.

+ * + * @param resId Resource id of a shadow drawable to use at the edge of a drawer + * @param gravity Which drawer the shadow should apply to + */ + public void setDrawerShadow(int resId, int gravity) { + setDrawerShadow(getResources().getDrawable(resId), gravity); + } + + /** + * Set a color to use for the scrim that obscures primary content while a drawer is open. + * + * @param color Color to use in 0xAARRGGBB format. + */ + public void setScrimColor( int color) { + mScrimColor = color; + invalidate(); + } + + /** + * Set a listener to be notified of drawer events. + * + * @param listener Listener to notify when drawer events occur + * @see DrawerListener + */ + public void setDrawerListener(DrawerListener listener) { + mListener = listener; + } + + /** + * Enable or disable interaction with all drawers. + * + *

This allows the application to restrict the user's ability to open or close + * any drawer within this layout. DrawerLayout will still respond to calls to + * {@link #openDrawer(int)}, {@link #closeDrawer(int)} and friends if a drawer is locked.

+ * + *

Locking drawers open or closed will implicitly open or close + * any drawers as appropriate.

+ * + * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED}, + * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}. + */ + public void setDrawerLockMode(@LockMode int lockMode) { + setDrawerLockMode(lockMode, Gravity.LEFT); + setDrawerLockMode(lockMode, Gravity.RIGHT); + } + + /** + * Enable or disable interaction with the given drawer. + * + *

This allows the application to restrict the user's ability to open or close + * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)}, + * {@link #closeDrawer(int)} and friends if a drawer is locked.

+ * + *

Locking a drawer open or closed will implicitly open or close + * that drawer as appropriate.

+ * + * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED}, + * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}. + * @param edgeGravity Gravity.LEFT, RIGHT, START or END. + * Expresses which drawer to change the mode for. + * + * @see #LOCK_MODE_UNLOCKED + * @see #LOCK_MODE_LOCKED_CLOSED + * @see #LOCK_MODE_LOCKED_OPEN + */ + public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) { + final int absGravity = Gravity.getAbsoluteGravity(edgeGravity, + getLayoutDirection()); + if (absGravity == Gravity.LEFT) { + mLockModeLeft = lockMode; + } else if (absGravity == Gravity.RIGHT) { + mLockModeRight = lockMode; + } + if (lockMode != LOCK_MODE_UNLOCKED) { + // Cancel interaction in progress + final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger; + helper.cancel(); + } + switch (lockMode) { + case LOCK_MODE_LOCKED_OPEN: + final View toOpen = findDrawerWithGravity(absGravity); + if (toOpen != null) { + openDrawer(toOpen); + } + break; + case LOCK_MODE_LOCKED_CLOSED: + final View toClose = findDrawerWithGravity(absGravity); + if (toClose != null) { + closeDrawer(toClose); + } + break; + // default: do nothing + } + } + + /** + * Enable or disable interaction with the given drawer. + * + *

This allows the application to restrict the user's ability to open or close + * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)}, + * {@link #closeDrawer(int)} and friends if a drawer is locked.

+ * + *

Locking a drawer open or closed will implicitly open or close + * that drawer as appropriate.

+ * + * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED}, + * {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}. + * @param drawerView The drawer view to change the lock mode for + * + * @see #LOCK_MODE_UNLOCKED + * @see #LOCK_MODE_LOCKED_CLOSED + * @see #LOCK_MODE_LOCKED_OPEN + */ + public void setDrawerLockMode(@LockMode int lockMode, View drawerView) { + if (!isDrawerView(drawerView)) { + throw new IllegalArgumentException("View " + drawerView + " is not a " + + "drawer with appropriate layout_gravity"); + } + final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity; + setDrawerLockMode(lockMode, gravity); + } + + /** + * Check the lock mode of the drawer with the given gravity. + * + * @param edgeGravity Gravity of the drawer to check + * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or + * {@link #LOCK_MODE_LOCKED_OPEN}. + */ + @LockMode + public int getDrawerLockMode(@EdgeGravity int edgeGravity) { + final int absGravity = Gravity.getAbsoluteGravity( + edgeGravity, getLayoutDirection()); + if (absGravity == Gravity.LEFT) { + return mLockModeLeft; + } else if (absGravity == Gravity.RIGHT) { + return mLockModeRight; + } + return LOCK_MODE_UNLOCKED; + } + + /** + * Check the lock mode of the given drawer view. + * + * @param drawerView Drawer view to check lock mode + * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or + * {@link #LOCK_MODE_LOCKED_OPEN}. + */ + @LockMode + public int getDrawerLockMode(View drawerView) { + final int absGravity = getDrawerViewAbsoluteGravity(drawerView); + if (absGravity == Gravity.LEFT) { + return mLockModeLeft; + } else if (absGravity == Gravity.RIGHT) { + return mLockModeRight; + } + return LOCK_MODE_UNLOCKED; + } + + /** + * Sets the title of the drawer with the given gravity. + *

+ * When accessibility is turned on, this is the title that will be used to + * identify the drawer to the active accessibility service. + * + * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which + * drawer to set the title for. + * @param title The title for the drawer. + */ + public void setDrawerTitle(@EdgeGravity int edgeGravity, CharSequence title) { + final int absGravity = Gravity.getAbsoluteGravity( + edgeGravity, getLayoutDirection()); + if (absGravity == Gravity.LEFT) { + mTitleLeft = title; + } else if (absGravity == Gravity.RIGHT) { + mTitleRight = title; + } + } + + /** + * Returns the title of the drawer with the given gravity. + * + * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which + * drawer to return the title for. + * @return The title of the drawer, or null if none set. + * @see #setDrawerTitle(int, CharSequence) + */ + //@Nullable + public CharSequence getDrawerTitle(@EdgeGravity int edgeGravity) { + final int absGravity = Gravity.getAbsoluteGravity( + edgeGravity, getLayoutDirection()); + if (absGravity == Gravity.LEFT) { + return mTitleLeft; + } else if (absGravity == Gravity.RIGHT) { + return mTitleRight; + } + return null; + } + + /** + * Resolve the shared state of all drawers from the component ViewDragHelpers. + * Should be called whenever a ViewDragHelper's state changes. + */ + void updateDrawerState(int forGravity, @State int activeState, View activeDrawer) { + final int leftState = mLeftDragger.getViewDragState(); + final int rightState = mRightDragger.getViewDragState(); + + final int state; + if (leftState == STATE_DRAGGING || rightState == STATE_DRAGGING) { + state = STATE_DRAGGING; + } else if (leftState == STATE_SETTLING || rightState == STATE_SETTLING) { + state = STATE_SETTLING; + } else { + state = STATE_IDLE; + } + + if (activeDrawer != null && activeState == STATE_IDLE) { + final LayoutParams lp = (LayoutParams) activeDrawer.getLayoutParams(); + if (lp.onScreen == 0) { + dispatchOnDrawerClosed(activeDrawer); + } else if (lp.onScreen == 1) { + dispatchOnDrawerOpened(activeDrawer); + } + } + + if (state != mDrawerState) { + mDrawerState = state; + + if (mListener != null) { + mListener.onDrawerStateChanged(state); + } + } + } + + void dispatchOnDrawerClosed(View drawerView) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if (lp.knownOpen) { + lp.knownOpen = false; + if (mListener != null) { + mListener.onDrawerClosed(drawerView); + } + + updateChildrenImportantForAccessibility(drawerView, false); + + // Only send WINDOW_STATE_CHANGE if the host has window focus. This + // may change if support for multiple foreground windows (e.g. IME) + // improves. + if (hasWindowFocus()) { + final View rootView = getRootView(); + if (rootView != null) { + rootView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + } + } + } + } + + void dispatchOnDrawerOpened(View drawerView) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if (!lp.knownOpen) { + lp.knownOpen = true; + if (mListener != null) { + mListener.onDrawerOpened(drawerView); + } + + updateChildrenImportantForAccessibility(drawerView, true); + + // Only send WINDOW_STATE_CHANGE if the host has window focus. + if (hasWindowFocus()) { + sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + } + + drawerView.requestFocus(); + } + } + + private void updateChildrenImportantForAccessibility(View drawerView, boolean isDrawerOpen) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (!isDrawerOpen && !isDrawerView(child) + || isDrawerOpen && child == drawerView) { + // Drawer is closed and this is a content view or this is an + // open drawer view, so it should be visible. + child.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_YES); + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + child.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } + } + } + } + + void dispatchOnDrawerSlide(View drawerView, float slideOffset) { + if (mListener != null) { + mListener.onDrawerSlide(drawerView, slideOffset); + } + } + + void setDrawerViewOffset(View drawerView, float slideOffset) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + if (slideOffset == lp.onScreen) { + return; + } + + lp.onScreen = slideOffset; + dispatchOnDrawerSlide(drawerView, slideOffset); + } + + float getDrawerViewOffset(View drawerView) { + return ((LayoutParams) drawerView.getLayoutParams()).onScreen; + } + + /** + * @return the absolute gravity of the child drawerView, resolved according + * to the current layout direction + */ + int getDrawerViewAbsoluteGravity(View drawerView) { + final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity; + return Gravity.getAbsoluteGravity(gravity, getLayoutDirection()); + } + + boolean checkDrawerViewAbsoluteGravity(View drawerView, int checkFor) { + final int absGravity = getDrawerViewAbsoluteGravity(drawerView); + return (absGravity & checkFor) == checkFor; + } + + View findOpenDrawer() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (((LayoutParams) child.getLayoutParams()).knownOpen) { + return child; + } + } + return null; + } + + void moveDrawerToOffset(View drawerView, float slideOffset) { + final float oldOffset = getDrawerViewOffset(drawerView); + final int width = drawerView.getWidth(); + final int oldPos = (int) (width * oldOffset); + final int newPos = (int) (width * slideOffset); + final int dx = newPos - oldPos; + + drawerView.offsetLeftAndRight( + checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT) ? dx : -dx); + setDrawerViewOffset(drawerView, slideOffset); + } + + /** + * @param gravity the gravity of the child to return. If specified as a + * relative value, it will be resolved according to the current + * layout direction. + * @return the drawer with the specified gravity + */ + View findDrawerWithGravity(int gravity) { + final int absHorizGravity = Gravity.getAbsoluteGravity( + gravity, getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final int childAbsGravity = getDrawerViewAbsoluteGravity(child); + if ((childAbsGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == absHorizGravity) { + return child; + } + } + return null; + } + + /** + * Simple gravity to string - only supports LEFT and RIGHT for debugging output. + * + * @param gravity Absolute gravity value + * @return LEFT or RIGHT as appropriate, or a hex string + */ + static String gravityToString(@EdgeGravity int gravity) { + if ((gravity & Gravity.LEFT) == Gravity.LEFT) { + return "LEFT"; + } + if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) { + return "RIGHT"; + } + return Integer.toHexString(gravity); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mFirstLayout = true; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mFirstLayout = true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) { + if (isInEditMode()) { + // Don't crash the layout editor. Consume all of the space if specified + // or pick a magic number from thin air otherwise. + // TODO Better communication with tools of this bogus state. + // It will crash on a real device. + if (widthMode == MeasureSpec.AT_MOST) { + widthMode = MeasureSpec.EXACTLY; + } else if (widthMode == MeasureSpec.UNSPECIFIED) { + widthMode = MeasureSpec.EXACTLY; + widthSize = 300; + } + if (heightMode == MeasureSpec.AT_MOST) { + heightMode = MeasureSpec.EXACTLY; + } + else if (heightMode == MeasureSpec.UNSPECIFIED) { + heightMode = MeasureSpec.EXACTLY; + heightSize = 300; + } + } else { + throw new IllegalArgumentException( + "DrawerLayout must be measured with MeasureSpec.EXACTLY."); + } + } + + setMeasuredDimension(widthSize, heightSize); + + final boolean applyInsets = mLastInsets != null && getFitsSystemWindows(); + final int layoutDirection = getLayoutDirection(); + + // Gravity value for each drawer we've seen. Only one of each permitted. + int foundDrawers = 0; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + + if (child.getVisibility() == GONE) { + continue; + } + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (applyInsets) { + final int cgrav = Gravity.getAbsoluteGravity(lp.gravity, layoutDirection); + if (child.getFitsSystemWindows()) { + IMPL.dispatchChildInsets(child, mLastInsets, cgrav); + } else { + IMPL.applyMarginInsets(lp, mLastInsets, cgrav); + } + } + + if (isContentView(child)) { + // Content views get measured at exactly the layout's size. + final int contentWidthSpec = MeasureSpec.makeMeasureSpec( + widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY); + final int contentHeightSpec = MeasureSpec.makeMeasureSpec( + heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY); + child.measure(contentWidthSpec, contentHeightSpec); + } else if (isDrawerView(child)) { + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + if (child.getElevation() != mDrawerElevation) { + child.setElevation(mDrawerElevation); + } + } + final int childGravity = + getDrawerViewAbsoluteGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK; + if ((foundDrawers & childGravity) != 0) { + throw new IllegalStateException("Child drawer has absolute gravity " + + gravityToString(childGravity) + " but this " + TAG + " already has a " + + "drawer view along that edge"); + } + final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec, + mMinDrawerMargin + lp.leftMargin + lp.rightMargin, + lp.width); + final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec, + lp.topMargin + lp.bottomMargin, + lp.height); + child.measure(drawerWidthSpec, drawerHeightSpec); + } else { + throw new IllegalStateException("Child " + child + " at index " + i + + " does not have a valid layout_gravity - must be Gravity.LEFT, " + + "Gravity.RIGHT or Gravity.NO_GRAVITY"); + } + } + } + + private void resolveShadowDrawables() { + if (SET_DRAWER_SHADOW_FROM_ELEVATION) { + return; + } + mShadowLeftResolved = resolveLeftShadow(); + mShadowRightResolved = resolveRightShadow(); + } + + private Drawable resolveLeftShadow() { + int layoutDirection = getLayoutDirection(); + // Prefer shadows defined with start/end gravity over left and right. + if (layoutDirection == View.LAYOUT_DIRECTION_LTR) { + if (mShadowStart != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowStart, layoutDirection); + return mShadowStart; + } + } else { + if (mShadowEnd != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowEnd, layoutDirection); + return mShadowEnd; + } + } + return mShadowLeft; + } + + private Drawable resolveRightShadow() { + int layoutDirection = getLayoutDirection(); + if (layoutDirection == View.LAYOUT_DIRECTION_LTR) { + if (mShadowEnd != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowEnd, layoutDirection); + return mShadowEnd; + } + } else { + if (mShadowStart != null) { + // Correct drawable layout direction, if needed. + mirror(mShadowStart, layoutDirection); + return mShadowStart; + } + } + return mShadowRight; + } + + /** + * Change the layout direction of the given drawable. + * Return true if auto-mirror is supported and drawable's layout direction can be changed. + * Otherwise, return false. + */ + private boolean mirror(Drawable drawable, int layoutDirection) { + if (drawable == null) { + return false; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (!drawable.isAutoMirrored()) { + return false; + } + } + + setLayoutDirection(layoutDirection); + return true; + } + + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mInLayout = true; + final int width = r - l; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + + if (child.getVisibility() == GONE) { + continue; + } + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (isContentView(child)) { + child.layout(lp.leftMargin, lp.topMargin, + lp.leftMargin + child.getMeasuredWidth(), + lp.topMargin + child.getMeasuredHeight()); + } else { // Drawer, if it wasn't onMeasure would have thrown an exception. + final int childWidth = child.getMeasuredWidth(); + final int childHeight = child.getMeasuredHeight(); + int childLeft; + + final float newOffset; + if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + childLeft = -childWidth + (int) (childWidth * lp.onScreen); + newOffset = (float) (childWidth + childLeft) / childWidth; + } else { // Right; onMeasure checked for us. + childLeft = width - (int) (childWidth * lp.onScreen); + newOffset = (float) (width - childLeft) / childWidth; + } + + final boolean changeOffset = newOffset != lp.onScreen; + + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (vgrav) { + default: + case Gravity.TOP: { + child.layout(childLeft, lp.topMargin, childLeft + childWidth, + lp.topMargin + childHeight); + break; + } + + case Gravity.BOTTOM: { + final int height = b - t; + child.layout(childLeft, + height - lp.bottomMargin - child.getMeasuredHeight(), + childLeft + childWidth, + height - lp.bottomMargin); + break; + } + + case Gravity.CENTER_VERTICAL: { + final int height = b - t; + int childTop = (height - childHeight) / 2; + + // Offset for margins. If things don't fit right because of + // bad measurement before, oh well. + if (childTop < lp.topMargin) { + childTop = lp.topMargin; + } else if (childTop + childHeight > height - lp.bottomMargin) { + childTop = height - lp.bottomMargin - childHeight; + } + child.layout(childLeft, childTop, childLeft + childWidth, + childTop + childHeight); + break; + } + } + + if (changeOffset) { + setDrawerViewOffset(child, newOffset); + } + + final int newVisibility = lp.onScreen > 0 ? VISIBLE : INVISIBLE; + if (child.getVisibility() != newVisibility) { + child.setVisibility(newVisibility); + } + } + } + mInLayout = false; + mFirstLayout = false; + } + + @Override + public void requestLayout() { + if (!mInLayout) { + super.requestLayout(); + } + } + + @Override + public void computeScroll() { + final int childCount = getChildCount(); + float scrimOpacity = 0; + for (int i = 0; i < childCount; i++) { + final float onscreen = ((LayoutParams) getChildAt(i).getLayoutParams()).onScreen; + scrimOpacity = Math.max(scrimOpacity, onscreen); + } + mScrimOpacity = scrimOpacity; + + // "|" used on purpose; both need to run. + if (mLeftDragger.continueSettling(true) | mRightDragger.continueSettling(true)) { + postInvalidateOnAnimation(); + } + } + + private static boolean hasOpaqueBackground(View v) { + final Drawable bg = v.getBackground(); + if (bg != null) { + return bg.getOpacity() == PixelFormat.OPAQUE; + } + return false; + } + + /** + * Set a drawable to draw in the insets area for the status bar. + * Note that this will only be activated if this DrawerLayout fitsSystemWindows. + * + * @param bg Background drawable to draw behind the status bar + */ + public void setStatusBarBackground(Drawable bg) { + mStatusBarBackground = bg; + invalidate(); + } + + /** + * Gets the drawable used to draw in the insets area for the status bar. + * + * @return The status bar background drawable, or null if none set + */ + public Drawable getStatusBarBackgroundDrawable() { + return mStatusBarBackground; + } + + /** + * Set a drawable to draw in the insets area for the status bar. + * Note that this will only be activated if this DrawerLayout fitsSystemWindows. + * + * @param resId Resource id of a background drawable to draw behind the status bar + */ + public void setStatusBarBackground(int resId) { + mStatusBarBackground = resId != 0 ? getContext().getResources().getDrawable(resId) : null; + invalidate(); + } + + /** + * Set a drawable to draw in the insets area for the status bar. + * Note that this will only be activated if this DrawerLayout fitsSystemWindows. + * + * @param color Color to use as a background drawable to draw behind the status bar + * in 0xAARRGGBB format. + */ + public void setStatusBarBackgroundColor( int color) { + mStatusBarBackground = new ColorDrawable(color); + invalidate(); + } + + public void onRtlPropertiesChanged(int layoutDirection) { + resolveShadowDrawables(); + } + + @Override + public void onDraw(Canvas c) { + super.onDraw(c); + if (mDrawStatusBarBackground && mStatusBarBackground != null) { + final int inset = IMPL.getTopInset(mLastInsets); + if (inset > 0) { + mStatusBarBackground.setBounds(0, 0, getWidth(), inset); + mStatusBarBackground.draw(c); + } + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + final int height = getHeight(); + final boolean drawingContent = isContentView(child); + int clipLeft = 0, clipRight = getWidth(); + + final int restoreCount = canvas.save(); + if (drawingContent) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View v = getChildAt(i); + if (v == child || v.getVisibility() != VISIBLE || + !hasOpaqueBackground(v) || !isDrawerView(v) || + v.getHeight() < height) { + continue; + } + + if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) { + final int vright = v.getRight(); + if (vright > clipLeft) clipLeft = vright; + } else { + final int vleft = v.getLeft(); + if (vleft < clipRight) clipRight = vleft; + } + } + canvas.clipRect(clipLeft, 0, clipRight, getHeight()); + } + final boolean result = super.drawChild(canvas, child, drawingTime); + canvas.restoreToCount(restoreCount); + + if (mScrimOpacity > 0 && drawingContent) { + final int baseAlpha = (mScrimColor & 0xff000000) >>> 24; + final int imag = (int) (baseAlpha * mScrimOpacity); + final int color = imag << 24 | (mScrimColor & 0xffffff); + mScrimPaint.setColor(color); + + canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint); + } else if (mShadowLeftResolved != null + && checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + final int shadowWidth = mShadowLeftResolved.getIntrinsicWidth(); + final int childRight = child.getRight(); + final int drawerPeekDistance = mLeftDragger.getEdgeSize(); + final float alpha = + Math.max(0, Math.min((float) childRight / drawerPeekDistance, 1.f)); + mShadowLeftResolved.setBounds(childRight, child.getTop(), + childRight + shadowWidth, child.getBottom()); + mShadowLeftResolved.setAlpha((int) (0xff * alpha)); + mShadowLeftResolved.draw(canvas); + } else if (mShadowRightResolved != null + && checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) { + final int shadowWidth = mShadowRightResolved.getIntrinsicWidth(); + final int childLeft = child.getLeft(); + final int showing = getWidth() - childLeft; + final int drawerPeekDistance = mRightDragger.getEdgeSize(); + final float alpha = + Math.max(0, Math.min((float) showing / drawerPeekDistance, 1.f)); + mShadowRightResolved.setBounds(childLeft - shadowWidth, child.getTop(), + childLeft, child.getBottom()); + mShadowRightResolved.setAlpha((int) (0xff * alpha)); + mShadowRightResolved.draw(canvas); + } + return result; + } + + boolean isContentView(View child) { + return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY; + } + + boolean isDrawerView(View child) { + final int gravity = ((LayoutParams) child.getLayoutParams()).gravity; + final int absGravity = Gravity.getAbsoluteGravity(gravity, + child.getLayoutDirection()); + return (absGravity & (Gravity.LEFT | Gravity.RIGHT)) != 0; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + final int action = ev.getActionMasked(); + + // "|" used deliberately here; both methods should be invoked. + final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev) | + mRightDragger.shouldInterceptTouchEvent(ev); + + boolean interceptForTap = false; + + switch (action) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + mInitialMotionX = x; + mInitialMotionY = y; + if (mScrimOpacity > 0) { + final View child = mLeftDragger.findTopChildUnder((int) x, (int) y); + if (child != null && isContentView(child)) { + interceptForTap = true; + } + } + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + break; + } + + case MotionEvent.ACTION_MOVE: { + // If we cross the touch slop, don't perform the delayed peek for an edge touch. + if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) { + mLeftCallback.removeCallbacks(); + mRightCallback.removeCallbacks(); + } + break; + } + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + closeDrawers(true); + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + } + } + + return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + mLeftDragger.processTouchEvent(ev); + mRightDragger.processTouchEvent(ev); + + final int action = ev.getAction(); + boolean wantTouchEvents = true; + + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + mInitialMotionX = x; + mInitialMotionY = y; + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + break; + } + + case MotionEvent.ACTION_UP: { + final float x = ev.getX(); + final float y = ev.getY(); + boolean peekingOnly = true; + final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y); + if (touchedView != null && isContentView(touchedView)) { + final float dx = x - mInitialMotionX; + final float dy = y - mInitialMotionY; + final int slop = mLeftDragger.getTouchSlop(); + if (dx * dx + dy * dy < slop * slop) { + // Taps close a dimmed open drawer but only if it isn't locked open. + final View openDrawer = findOpenDrawer(); + if (openDrawer != null) { + peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN; + } + } + } + closeDrawers(peekingOnly); + mDisallowInterceptRequested = false; + break; + } + + case MotionEvent.ACTION_CANCEL: { + closeDrawers(true); + mDisallowInterceptRequested = false; + mChildrenCanceledTouch = false; + break; + } + } + + return wantTouchEvents; + } + + public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { + if (CHILDREN_DISALLOW_INTERCEPT || + (!mLeftDragger.isEdgeTouched(ViewDragHelper.EDGE_LEFT) && + !mRightDragger.isEdgeTouched(ViewDragHelper.EDGE_RIGHT))) { + // If we have an edge touch we want to skip this and track it for later instead. + super.requestDisallowInterceptTouchEvent(disallowIntercept); + } + mDisallowInterceptRequested = disallowIntercept; + if (disallowIntercept) { + closeDrawers(true); + } + } + + /** + * Close all currently open drawer views by animating them out of view. + */ + public void closeDrawers() { + closeDrawers(false); + } + + void closeDrawers(boolean peekingOnly) { + boolean needsInvalidate = false; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (!isDrawerView(child) || (peekingOnly && !lp.isPeeking)) { + continue; + } + + final int childWidth = child.getWidth(); + + if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + needsInvalidate |= mLeftDragger.smoothSlideViewTo(child, + -childWidth, child.getTop()); + } else { + needsInvalidate |= mRightDragger.smoothSlideViewTo(child, + getWidth(), child.getTop()); + } + + lp.isPeeking = false; + } + + mLeftCallback.removeCallbacks(); + mRightCallback.removeCallbacks(); + + if (needsInvalidate) { + invalidate(); + } + } + + /** + * Open the specified drawer view by animating it into view. + * + * @param drawerView Drawer view to open + */ + public void openDrawer(View drawerView) { + if (!isDrawerView(drawerView)) { + throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer"); + } + + if (mFirstLayout) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + lp.onScreen = 1.f; + lp.knownOpen = true; + + updateChildrenImportantForAccessibility(drawerView, true); + } else { + if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) { + mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop()); + } else { + mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(), + drawerView.getTop()); + } + } + invalidate(); + } + + /** + * Open the specified drawer by animating it out of view. + * + * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right. + * Gravity.START or Gravity.END may also be used. + */ + public void openDrawer(@EdgeGravity int gravity) { + final View drawerView = findDrawerWithGravity(gravity); + if (drawerView == null) { + throw new IllegalArgumentException("No drawer view found with gravity " + + gravityToString(gravity)); + } + openDrawer(drawerView); + } + + /** + * Close the specified drawer view by animating it into view. + * + * @param drawerView Drawer view to close + */ + public void closeDrawer(View drawerView) { + if (!isDrawerView(drawerView)) { + throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer"); + } + + if (mFirstLayout) { + final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); + lp.onScreen = 0.f; + lp.knownOpen = false; + } else { + if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) { + mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(), + drawerView.getTop()); + } else { + mRightDragger.smoothSlideViewTo(drawerView, getWidth(), drawerView.getTop()); + } + } + invalidate(); + } + + /** + * Close the specified drawer by animating it out of view. + * + * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right. + * Gravity.START or Gravity.END may also be used. + */ + public void closeDrawer(@EdgeGravity int gravity) { + final View drawerView = findDrawerWithGravity(gravity); + if (drawerView == null) { + throw new IllegalArgumentException("No drawer view found with gravity " + + gravityToString(gravity)); + } + closeDrawer(drawerView); + } + + /** + * Check if the given drawer view is currently in an open state. + * To be considered "open" the drawer must have settled into its fully + * visible state. To check for partial visibility use + * {@link #isDrawerVisible(android.view.View)}. + * + * @param drawer Drawer view to check + * @return true if the given drawer view is in an open state + * @see #isDrawerVisible(android.view.View) + */ + public boolean isDrawerOpen(View drawer) { + if (!isDrawerView(drawer)) { + throw new IllegalArgumentException("View " + drawer + " is not a drawer"); + } + return ((LayoutParams) drawer.getLayoutParams()).knownOpen; + } + + /** + * Check if the given drawer view is currently in an open state. + * To be considered "open" the drawer must have settled into its fully + * visible state. If there is no drawer with the given gravity this method + * will return false. + * + * @param drawerGravity Gravity of the drawer to check + * @return true if the given drawer view is in an open state + */ + public boolean isDrawerOpen(@EdgeGravity int drawerGravity) { + final View drawerView = findDrawerWithGravity(drawerGravity); + if (drawerView != null) { + return isDrawerOpen(drawerView); + } + return false; + } + + /** + * Check if a given drawer view is currently visible on-screen. The drawer + * may be only peeking onto the screen, fully extended, or anywhere inbetween. + * + * @param drawer Drawer view to check + * @return true if the given drawer is visible on-screen + * @see #isDrawerOpen(android.view.View) + */ + public boolean isDrawerVisible(View drawer) { + if (!isDrawerView(drawer)) { + throw new IllegalArgumentException("View " + drawer + " is not a drawer"); + } + return ((LayoutParams) drawer.getLayoutParams()).onScreen > 0; + } + + /** + * Check if a given drawer view is currently visible on-screen. The drawer + * may be only peeking onto the screen, fully extended, or anywhere in between. + * If there is no drawer with the given gravity this method will return false. + * + * @param drawerGravity Gravity of the drawer to check + * @return true if the given drawer is visible on-screen + */ + public boolean isDrawerVisible(@EdgeGravity int drawerGravity) { + final View drawerView = findDrawerWithGravity(drawerGravity); + if (drawerView != null) { + return isDrawerVisible(drawerView); + } + return false; + } + + private boolean hasPeekingDrawer() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); + if (lp.isPeeking) { + return true; + } + } + return false; + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams + ? new LayoutParams((LayoutParams) p) + : p instanceof ViewGroup.MarginLayoutParams + ? new LayoutParams((MarginLayoutParams) p) + : new LayoutParams(p); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams && super.checkLayoutParams(p); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + @Override + public void addFocusables(ArrayList views, int direction, int focusableMode) { + if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) { + return; + } + + // Only the views in the open drawers are focusables. Add normal child views when + // no drawers are opened. + final int childCount = getChildCount(); + boolean isDrawerOpen = false; + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (isDrawerView(child)) { + if (isDrawerOpen(child)) { + isDrawerOpen = true; + child.addFocusables(views, direction, focusableMode); + } + } else { + mNonDrawerViews.add(child); + } + } + + if (!isDrawerOpen) { + final int nonDrawerViewsCount = mNonDrawerViews.size(); + for (int i = 0; i < nonDrawerViewsCount; ++i) { + final View child = mNonDrawerViews.get(i); + if (child.getVisibility() == View.VISIBLE) { + child.addFocusables(views, direction, focusableMode); + } + } + } + + mNonDrawerViews.clear(); + } + + private boolean hasVisibleDrawer() { + return findVisibleDrawer() != null; + } + + private View findVisibleDrawer() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (isDrawerView(child) && isDrawerVisible(child)) { + return child; + } + } + return null; + } + + void cancelChildViewTouch() { + // Cancel child touches + if (!mChildrenCanceledTouch) { + final long now = SystemClock.uptimeMillis(); + final MotionEvent cancelEvent = MotionEvent.obtain(now, now, + MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + getChildAt(i).dispatchTouchEvent(cancelEvent); + } + cancelEvent.recycle(); + mChildrenCanceledTouch = true; + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && hasVisibleDrawer()) { + event.startTracking(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + final View visibleDrawer = findVisibleDrawer(); + if (visibleDrawer != null && getDrawerLockMode(visibleDrawer) == LOCK_MODE_UNLOCKED) { + closeDrawers(); + } + return visibleDrawer != null; + } + return super.onKeyUp(keyCode, event); + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + final SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + + if (ss.openDrawerGravity != Gravity.NO_GRAVITY) { + final View toOpen = findDrawerWithGravity(ss.openDrawerGravity); + if (toOpen != null) { + openDrawer(toOpen); + } + } + + setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT); + setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT); + } + + @Override + protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + final SavedState ss = new SavedState(superState); + + final View openDrawer = findOpenDrawer(); + if (openDrawer != null) { + ss.openDrawerGravity = ((LayoutParams) openDrawer.getLayoutParams()).gravity; + } + + ss.lockModeLeft = mLockModeLeft; + ss.lockModeRight = mLockModeRight; + + return ss; + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + super.addView(child, index, params); + + final View openDrawer = findOpenDrawer(); + if (openDrawer != null || isDrawerView(child)) { + // A drawer is already open or the new view is a drawer, so the + // new view should start out hidden. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + child.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } + } else { + // Otherwise this is a content view and no drawer is open, so the + // new view should start out visible. + child.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_YES); + } + + // We only need a delegate here if the framework doesn't understand + // NO_HIDE_DESCENDANTS importance. + if (!CAN_HIDE_DESCENDANTS) { + child.setAccessibilityDelegate( mChildAccessibilityDelegate); + } + } + + private static boolean includeChildForAccessibility(View child) { + // If the child is not important for accessibility we make + // sure this hides the entire subtree rooted at it as the + // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDATS is not + // supported on older platforms but we want to hide the entire + // content and not opened drawers if a drawer is opened. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + return child.getImportantForAccessibility() + != View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + && child.getImportantForAccessibility() + != View.IMPORTANT_FOR_ACCESSIBILITY_NO; + }else{ + return child.getImportantForAccessibility() + != View.IMPORTANT_FOR_ACCESSIBILITY_NO; + } + } + + /** + * State persisted across instances + */ + protected static class SavedState extends BaseSavedState { + int openDrawerGravity = Gravity.NO_GRAVITY; + int lockModeLeft = LOCK_MODE_UNLOCKED; + int lockModeRight = LOCK_MODE_UNLOCKED; + + public SavedState(Parcel in) { + super(in); + openDrawerGravity = in.readInt(); + } + + public SavedState(Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(openDrawerGravity); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public SavedState createFromParcel(Parcel source) { + return new SavedState(source); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + private class ViewDragCallback extends ViewDragHelper.Callback { + private final int mAbsGravity; + private ViewDragHelper mDragger; + + private final Runnable mPeekRunnable = new Runnable() { + @Override public void run() { + peekDrawer(); + } + }; + + public ViewDragCallback(int gravity) { + mAbsGravity = gravity; + } + + public void setDragger(ViewDragHelper dragger) { + mDragger = dragger; + } + + public void removeCallbacks() { + DrawerLayout.this.removeCallbacks(mPeekRunnable); + } + + @Override + public boolean tryCaptureView(View child, int pointerId) { + // Only capture views where the gravity matches what we're looking for. + // This lets us use two ViewDragHelpers, one for each side drawer. + return isDrawerView(child) && checkDrawerViewAbsoluteGravity(child, mAbsGravity) + && getDrawerLockMode(child) == LOCK_MODE_UNLOCKED; + } + + @Override + public void onViewDragStateChanged(int state) { + updateDrawerState(mAbsGravity, state, mDragger.getCapturedView()); + } + + @Override + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { + float offset; + final int childWidth = changedView.getWidth(); + + // This reverses the positioning shown in onLayout. + if (checkDrawerViewAbsoluteGravity(changedView, Gravity.LEFT)) { + offset = (float) (childWidth + left) / childWidth; + } else { + final int width = getWidth(); + offset = (float) (width - left) / childWidth; + } + setDrawerViewOffset(changedView, offset); + changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE); + invalidate(); + } + + @Override + public void onViewCaptured(View capturedChild, int activePointerId) { + final LayoutParams lp = (LayoutParams) capturedChild.getLayoutParams(); + lp.isPeeking = false; + + closeOtherDrawer(); + } + + private void closeOtherDrawer() { + final int otherGrav = mAbsGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT; + final View toClose = findDrawerWithGravity(otherGrav); + if (toClose != null) { + closeDrawer(toClose); + } + } + + @Override + public void onViewReleased(View releasedChild, float xvel, float yvel) { + // Offset is how open the drawer is, therefore left/right values + // are reversed from one another. + final float offset = getDrawerViewOffset(releasedChild); + final int childWidth = releasedChild.getWidth(); + + int left; + if (checkDrawerViewAbsoluteGravity(releasedChild, Gravity.LEFT)) { + left = xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth; + } else { + final int width = getWidth(); + left = xvel < 0 || xvel == 0 && offset > 0.5f ? width - childWidth : width; + } + + mDragger.settleCapturedViewAt(left, releasedChild.getTop()); + invalidate(); + } + + @Override + public void onEdgeTouched(int edgeFlags, int pointerId) { + postDelayed(mPeekRunnable, PEEK_DELAY); + } + + private void peekDrawer() { + final View toCapture; + final int childLeft; + final int peekDistance = mDragger.getEdgeSize(); + final boolean leftEdge = mAbsGravity == Gravity.LEFT; + if (leftEdge) { + toCapture = findDrawerWithGravity(Gravity.LEFT); + childLeft = (toCapture != null ? -toCapture.getWidth() : 0) + peekDistance; + } else { + toCapture = findDrawerWithGravity(Gravity.RIGHT); + childLeft = getWidth() - peekDistance; + } + // Only peek if it would mean making the drawer more visible and the drawer isn't locked + if (toCapture != null && ((leftEdge && toCapture.getLeft() < childLeft) || + (!leftEdge && toCapture.getLeft() > childLeft)) && + getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) { + final LayoutParams lp = (LayoutParams) toCapture.getLayoutParams(); + mDragger.smoothSlideViewTo(toCapture, childLeft, toCapture.getTop()); + lp.isPeeking = true; + invalidate(); + + closeOtherDrawer(); + + cancelChildViewTouch(); + } + } + + @Override + public boolean onEdgeLock(int edgeFlags) { + if (ALLOW_EDGE_LOCK) { + final View drawer = findDrawerWithGravity(mAbsGravity); + if (drawer != null && !isDrawerOpen(drawer)) { + closeDrawer(drawer); + } + return true; + } + return false; + } + + @Override + public void onEdgeDragStarted(int edgeFlags, int pointerId) { + final View toCapture; + if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) { + toCapture = findDrawerWithGravity(Gravity.LEFT); + } else { + toCapture = findDrawerWithGravity(Gravity.RIGHT); + } + + if (toCapture != null && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) { + mDragger.captureChildView(toCapture, pointerId); + } + } + + @Override + public int getViewHorizontalDragRange(View child) { + return isDrawerView(child) ? child.getWidth() : 0; + } + + @Override + public int clampViewPositionHorizontal(View child, int left, int dx) { + if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) { + return Math.max(-child.getWidth(), Math.min(left, 0)); + } else { + final int width = getWidth(); + return Math.max(width - child.getWidth(), Math.min(left, width)); + } + } + + @Override + public int clampViewPositionVertical(View child, int top, int dy) { + return child.getTop(); + } + } + + public static class LayoutParams extends ViewGroup.MarginLayoutParams { + + public int gravity = Gravity.NO_GRAVITY; + float onScreen; + boolean isPeeking; + boolean knownOpen; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + + final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS); + this.gravity = a.getInt(0, Gravity.NO_GRAVITY); + a.recycle(); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(int width, int height, int gravity) { + this(width, height); + this.gravity = gravity; + } + + public LayoutParams(LayoutParams source) { + super(source); + this.gravity = source.gravity; + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + + public LayoutParams(ViewGroup.MarginLayoutParams source) { + super(source); + } + } + + + /** + * Provides functionality for DrawerLayout unique to API 21 + */ + @SuppressLint("NewApi") + public static class DrawerLayoutCompatApi21 { + + private static final int[] THEME_ATTRS = { + android.R.attr.colorPrimaryDark + }; + + public static void configureApplyInsets(View drawerLayout) { + if (drawerLayout instanceof DrawerLayoutImpl) { + drawerLayout.setOnApplyWindowInsetsListener(new InsetsListener()); + drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } + } + + public static void dispatchChildInsets(View child, Object insets, int gravity) { + WindowInsets wi = (WindowInsets) insets; + if (gravity == Gravity.LEFT) { + wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(), + wi.getSystemWindowInsetTop(), 0, wi.getSystemWindowInsetBottom()); + } else if (gravity == Gravity.RIGHT) { + wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(), + wi.getSystemWindowInsetRight(), wi.getSystemWindowInsetBottom()); + } + child.dispatchApplyWindowInsets(wi); + } + + public static void applyMarginInsets(ViewGroup.MarginLayoutParams lp, Object insets, + int gravity) { + WindowInsets wi = (WindowInsets) insets; + if (gravity == Gravity.LEFT) { + wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(), + wi.getSystemWindowInsetTop(), 0, wi.getSystemWindowInsetBottom()); + } else if (gravity == Gravity.RIGHT) { + wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(), + wi.getSystemWindowInsetRight(), wi.getSystemWindowInsetBottom()); + } + lp.leftMargin = wi.getSystemWindowInsetLeft(); + lp.topMargin = wi.getSystemWindowInsetTop(); + lp.rightMargin = wi.getSystemWindowInsetRight(); + lp.bottomMargin = wi.getSystemWindowInsetBottom(); + } + + public static int getTopInset(Object insets) { + return insets != null ? ((WindowInsets) insets).getSystemWindowInsetTop() : 0; + } + + public static Drawable getDefaultStatusBarBackground(Context context) { + final TypedArray a = context.obtainStyledAttributes(THEME_ATTRS); + try { + return a.getDrawable(0); + } finally { + a.recycle(); + } + } + + static class InsetsListener implements View.OnApplyWindowInsetsListener { + @Override + public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + final DrawerLayoutImpl drawerLayout = (DrawerLayoutImpl) v; + drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0); + return insets.consumeSystemWindowInsets(); + } + } + } + +} diff --git a/app/src/main/java/android/widget/DrawerLayoutImpl.java b/app/src/main/java/android/widget/DrawerLayoutImpl.java new file mode 100644 index 0000000..cae460d --- /dev/null +++ b/app/src/main/java/android/widget/DrawerLayoutImpl.java @@ -0,0 +1,10 @@ +package android.widget; + +/** + * Interface used to communicate from the v21-specific code for configuring a DrawerLayout + * to the DrawerLayout itself. + */ +public interface DrawerLayoutImpl { + void setChildInsets(Object insets, boolean drawStatusBar); +} + diff --git a/app/src/main/java/android/widget/ExListView.java b/app/src/main/java/android/widget/ExListView.java new file mode 100644 index 0000000..c22f2b7 --- /dev/null +++ b/app/src/main/java/android/widget/ExListView.java @@ -0,0 +1,9 @@ +package android.widget; +import android.content.*; + +public class ExListView extends ExpandableListView +{ + public ExListView(Context context){ + super(context); + } +} diff --git a/app/src/main/java/android/widget/FloatButton.java b/app/src/main/java/android/widget/FloatButton.java new file mode 100644 index 0000000..59877db --- /dev/null +++ b/app/src/main/java/android/widget/FloatButton.java @@ -0,0 +1,94 @@ +package android.widget; +import android.content.*; +import android.graphics.*; +import android.util.*; +import android.view.*; +import com.androlua.*; +import com.androlua.util.*; +import com.osfans.trime.pro.R; + +import android.graphics.drawable.*; + +public class FloatButton extends ImageView { + + private PopupWindow mWindow; + + private CircleImageView mButton; + + private int mGravity; + + private CardView mCard; + + private DisplayMetrics dm; + + private RippleHelper mRippleHelper; + + public FloatButton(Context context) { + super(context); + init(context); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + // TODO: Implement this method + super.onLayout(changed, left, top, left, top); + if (!mWindow.isShowing()) + mWindow.showAtLocation((View)getParent(), mGravity, 0, 0); + mWindow.update(); + //mWindow.update((View)getParent(),dp(64),dp(64)); + } + + public void setGravity(int gravity){ + mGravity=gravity; + } + + private int dp(float n) { + // TODO: Implement this method + return (int)TypedValue.applyDimension(1,n,dm); + } + + + private void init(Context context) { + + // TODO: Implement this method + dm=context.getResources().getDisplayMetrics(); + + FrameLayout layout=new FrameLayout(context); + FrameLayout.LayoutParams lp=new FrameLayout.LayoutParams(-2, -2); + lp.setMargins(dp(16),dp(16),dp(16),dp(16)); + mCard = new CardView(context); + mCard.setCardElevation(dp(8)); + //mCard.setCardBackgroundColor(0xff0000ff); + + mButton = new CircleImageView(context); + mButton.setImageResource(R.drawable.icon); + mRippleHelper=new RippleHelper(mButton); + FrameLayout.LayoutParams lp2=new FrameLayout.LayoutParams(dp(64), dp(64)); + layout.addView(mCard,lp); + mCard.addView(mButton,lp2); + mCard.setRadius(dp(32)); + mWindow = new PopupWindow(-2,-2); + + mWindow.setContentView(layout); + //setVisibility(GONE); + } + + public void setImageBitmap(Bitmap bm) { + // TODO: Implement this method + mButton.setImageBitmap(bm); + } + + public void setImageResource(int resId) { + // TODO: Implement this method + mButton.setImageResource(resId); + } + + public void setImageDrawable(Drawable drawable) { + // TODO: Implement this method + mButton.setImageDrawable(drawable); + } + + public void setRippleColor(int color) { + mRippleHelper.setRippleColor(color); + } +} diff --git a/app/src/main/java/android/widget/HorizontalListView.java b/app/src/main/java/android/widget/HorizontalListView.java new file mode 100644 index 0000000..fb02b5a --- /dev/null +++ b/app/src/main/java/android/widget/HorizontalListView.java @@ -0,0 +1,1520 @@ +/* + * The MIT License Copyright (c) 2011 Paul Soucy (paul@dev-smart.com) + * The MIT License Copyright (c) 2013 MeetMe, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// @formatter:off +/* + * This is based on HorizontalListView.java from: https://github.com/dinocore1/DevsmartLib-Android + * It has been substantially rewritten and added to from the original version. + */ +// @formatter:on +package android.widget; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.view.GestureDetector; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +// @formatter:off + +/** + * A view that shows items in a horizontally scrolling list. The items + * come from the {@link ListAdapter} associated with this view.
+ *
+ * Limitations: + *

    + *
  • Does not support keyboard navigation
  • + *
  • Does not support scroll bars
  • + *
  • Does not support header or footer views
  • + *
  • Does not support disabled items
  • + *
+ *
+ * Custom XML Parameters Supported:
+ *
+ *
    + *
  • divider - The divider to use between items. This can be a color or a drawable. If a drawable is used + * dividerWidth will automatically be set to the intrinsic width of the provided drawable, this can be overriden by providing a dividerWidth.
  • + *
  • dividerWidth - The width of the divider to be drawn.
  • + *
  • android:requiresFadingEdge - If horizontal fading edges are enabled this view will render them
  • + *
  • android:fadingEdgeLength - The length of the horizontal fading edges
  • + *
+ */ +// @formatter:on +public class HorizontalListView extends AdapterView { + /** + * Defines where to insert items into the ViewGroup, as defined in {@code ViewGroup #addViewInLayout(View, int, LayoutParams, boolean)} + */ + private static final int INSERT_AT_END_OF_LIST = -1; + private static final int INSERT_AT_START_OF_LIST = 0; + + /** + * The velocity to use for overscroll absorption + */ + private static final float FLING_DEFAULT_ABSORB_VELOCITY = 30f; + + /** + * The friction amount to use for the fling tracker + */ + private static final float FLING_FRICTION = 0.009f; + + /** + * Used for tracking the state data necessary to restore the HorizontalListView to its previous state after a rotation occurs + */ + private static final String BUNDLE_ID_CURRENT_X = "BUNDLE_ID_CURRENT_X"; + + /** + * The bundle id of the parents state. Used to restore the parent's state after a rotation occurs + */ + private static final String BUNDLE_ID_PARENT_STATE = "BUNDLE_ID_PARENT_STATE"; + private final DisplayMetrics dm; + + /** + * Tracks ongoing flings + */ + protected Scroller mFlingTracker = new Scroller(getContext()); + + /** + * Gesture listener to receive callbacks when gestures are detected + */ + private final GestureListener mGestureListener = new GestureListener(); + + /** + * Used for detecting gestures within this view so they can be handled + */ + private GestureDetector mGestureDetector; + + /** + * This tracks the starting layout position of the leftmost view + */ + private int mDisplayOffset; + + /** + * Holds a reference to the adapter bound to this view + */ + protected ListAdapter mAdapter; + + /** + * Holds a cache of recycled views to be reused as needed + */ + private List> mRemovedViewsCache = new ArrayList>(); + + /** + * Flag used to mark when the adapters data has changed, so the view can be relaid out + */ + private boolean mDataChanged = false; + + /** + * Temporary rectangle to be used for measurements + */ + private Rect mRect = new Rect(); + + /** + * Tracks the currently touched view, used to delegate touches to the view being touched + */ + private View mViewBeingTouched = null; + + /** + * The width of the divider that will be used between list items + */ + private int mDividerWidth = 0; + + /** + * The drawable that will be used as the list divider + */ + private Drawable mDivider = null; + + /** + * The x position of the currently rendered view + */ + protected int mCurrentX; + + /** + * The x position of the next to be rendered view + */ + protected int mNextX; + + /** + * Used to hold the scroll position to restore to post rotate + */ + private Integer mRestoreX = null; + + /** + * Tracks the maximum possible X position, stays at max value until last item is laid out and it can be determined + */ + private int mMaxX = Integer.MAX_VALUE; + + /** + * The adapter index of the leftmost view currently visible + */ + private int mLeftViewAdapterIndex; + + /** + * The adapter index of the rightmost view currently visible + */ + private int mRightViewAdapterIndex; + + /** + * This tracks the currently selected accessibility item + */ + private int mCurrentlySelectedAdapterIndex; + + /** + * Callback interface to notify listener that the user has scrolled this view to the point that it is low on data. + */ + private RunningOutOfDataListener mRunningOutOfDataListener = null; + + /** + * This tracks the user value set of how many items from the end will be considered running out of data. + */ + private int mRunningOutOfDataThreshold = 0; + + /** + * Tracks if we have told the listener that we are running low on data. We only want to tell them once. + */ + private boolean mHasNotifiedRunningLowOnData = false; + + /** + * Callback interface to be invoked when the scroll state has changed. + */ + private OnScrollStateChangedListener mOnScrollStateChangedListener = null; + + /** + * Represents the current scroll state of this view. Needed so we can detect when the state changes so scroll listener can be notified. + */ + private OnScrollStateChangedListener.ScrollState mCurrentScrollState = OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE; + + /** + * Tracks the state of the left edge glow. + */ + private EdgeEffect mEdgeGlowLeft; + + /** + * Tracks the state of the right edge glow. + */ + private EdgeEffect mEdgeGlowRight; + + /** + * The height measure spec for this view, used to help size children views + */ + private int mHeightMeasureSpec; + + /** + * Used to track if a view touch should be blocked because it stopped a fling + */ + private boolean mBlockTouchAction = false; + + /** + * Used to track if the parent vertically scrollable view has been told to DisallowInterceptTouchEvent + */ + private boolean mIsParentVerticiallyScrollableViewDisallowingInterceptTouchEvent = false; + + /** + * The listener that receives notifications when this view is clicked. + */ + private OnClickListener mOnClickListener; + private Rect mBound; + private int mSelectedColor = 0x88888888; + private Drawable mSelectedBackground; + private int mHeight; + + public HorizontalListView(Context context) { + this(context, null); + } + + public HorizontalListView(Context context, AttributeSet attrs) { + super(context, attrs); + dm = context.getResources().getDisplayMetrics(); + mEdgeGlowLeft = new EdgeEffect(context); + mEdgeGlowRight = new EdgeEffect(context); + mGestureDetector = new GestureDetector(context, mGestureListener); + //bindGestureDetector(); + initView(); + setWillNotDraw(false); + + HoneycombPlus.setFriction(mFlingTracker, FLING_FRICTION); + } + + /** + * Registers the gesture detector to receive gesture notifications for this view + */ + private void bindGestureDetector() { + // Generic touch listener that can be applied to any view that needs to process gestures + final View.OnTouchListener gestureListenerHandler = new View.OnTouchListener() { + @Override + public boolean onTouch(final View v, final MotionEvent event) { + // Delegate the touch event to our gesture detector + return mGestureDetector.onTouchEvent(event); + } + }; + + setOnTouchListener(gestureListenerHandler); + } + + /** + * When this HorizontalListView is embedded within a vertical scrolling view it is important to disable the parent view from interacting with + * any touch events while the user is scrolling within this HorizontalListView. This will start at this view and go up the view tree looking + * for a vertical scrolling view. If one is found it will enable or disable parent touch interception. + * + * @param disallowIntercept If true the parent will be prevented from intercepting child touch events + */ + private void requestParentListViewToNotInterceptTouchEvents(Boolean disallowIntercept) { + // Prevent calling this more than once needlessly + if (mIsParentVerticiallyScrollableViewDisallowingInterceptTouchEvent != disallowIntercept) { + View view = this; + + while (view.getParent() instanceof View) { + // If the parent is a ListView or ScrollView then disallow intercepting of touch events + if (view.getParent() instanceof ListView || view.getParent() instanceof ScrollView) { + view.getParent().requestDisallowInterceptTouchEvent(disallowIntercept); + mIsParentVerticiallyScrollableViewDisallowingInterceptTouchEvent = disallowIntercept; + return; + } + + view = (View) view.getParent(); + } + } + } + + + @Override + public Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + + // Add the parent state to the bundle + bundle.putParcelable(BUNDLE_ID_PARENT_STATE, super.onSaveInstanceState()); + + // Add our state to the bundle + bundle.putInt(BUNDLE_ID_CURRENT_X, mCurrentX); + + return bundle; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + + // Restore our state from the bundle + mRestoreX = Integer.valueOf((bundle.getInt(BUNDLE_ID_CURRENT_X))); + + // Restore out parent's state from the bundle + super.onRestoreInstanceState(bundle.getParcelable(BUNDLE_ID_PARENT_STATE)); + } + } + + /** + * Sets the drawable that will be drawn between each item in the list. If the drawable does + * not have an intrinsic width, you should also call {@link #setDividerWidth(int)} + * + * @param divider The drawable to use. + */ + public void setDivider(Drawable divider) { + mDivider = divider; + + if (divider != null) { + setDividerWidth(divider.getIntrinsicWidth()); + } else { + setDividerWidth(0); + } + } + + /** + * Sets the width of the divider that will be drawn between each item in the list. Calling + * this will override the intrinsic width as set by {@link #setDivider(Drawable)} + * + * @param width The width of the divider in pixels. + */ + public void setDividerWidth(int width) { + mDividerWidth = width; + + // Force the view to rerender itself + requestLayout(); + invalidate(); + } + + private void initView() { + mLeftViewAdapterIndex = -1; + mRightViewAdapterIndex = -1; + mCurrentlySelectedAdapterIndex = -1; + mDisplayOffset = 0; + mCurrentX = 0; + mNextX = 0; + mMaxX = Integer.MAX_VALUE; + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE); + } + + /** + * Will re-initialize the HorizontalListView to remove all child views rendered and reset to initial configuration. + */ + private void reset() { + initView(); + removeAllViewsInLayout(); + requestLayout(); + } + + /** + * DataSetObserver used to capture adapter data change events + */ + private DataSetObserver mAdapterDataObserver = new DataSetObserver() { + @Override + public void onChanged() { + mDataChanged = true; + + // Clear so we can notify again as we run out of data + mHasNotifiedRunningLowOnData = false; + + unpressTouchedChild(); + + // Invalidate and request layout to force this view to completely redraw itself + invalidate(); + requestLayout(); + } + + @Override + public void onInvalidated() { + // Clear so we can notify again as we run out of data + mHasNotifiedRunningLowOnData = false; + + unpressTouchedChild(); + reset(); + + // Invalidate and request layout to force this view to completely redraw itself + invalidate(); + requestLayout(); + } + }; + + @Override + public void setSelection(int position) { + mCurrentlySelectedAdapterIndex = position; + if (mAdapter == null || position < 0 || position > mAdapter.getCount()) { + invalidate(); + return; + } + View view = getSelectedView(); + if (view == null || view.getRight() > getWidth() || view.getLeft() < 0) { + int leftEdge = 0; + View recycledView = null; + for (int i = 0; i < position - 1; i++) { + View child = mAdapter.getView(i, recycledView, this); + recycledView = child; + // If first view, then no divider to the left of it + measureChild(child); + leftEdge += i == 0 ? child.getMeasuredWidth() : mDividerWidth + child.getMeasuredWidth(); + } + scrollTo(leftEdge); + } + + invalidate(); + } + + @Override + public View getSelectedView() { + return getChild(mCurrentlySelectedAdapterIndex); + } + + @Override + public void setAdapter(ListAdapter adapter) { + if (mAdapter != null) { + mAdapter.unregisterDataSetObserver(mAdapterDataObserver); + } + + if (adapter != null) { + // Clear so we can notify again as we run out of data + mHasNotifiedRunningLowOnData = false; + + mAdapter = adapter; + mAdapter.registerDataSetObserver(mAdapterDataObserver); + } + + initializeRecycledViewCache(mAdapter.getViewTypeCount()); + reset(); + } + + @Override + public ListAdapter getAdapter() { + return mAdapter; + } + + /** + * Will create and initialize a cache for the given number of different types of views. + * + * @param viewTypeCount - The total number of different views supported + */ + private void initializeRecycledViewCache(int viewTypeCount) { + // The cache is created such that the response from mAdapter.getItemViewType is the array index to the correct cache for that item. + mRemovedViewsCache.clear(); + for (int i = 0; i < viewTypeCount; i++) { + mRemovedViewsCache.add(new LinkedList()); + } + } + + /** + * Returns a recycled view from the cache that can be reused, or null if one is not available. + * + * @param adapterIndex + * @return + */ + private View getRecycledView(int adapterIndex) { + int itemViewType = mAdapter.getItemViewType(adapterIndex); + + if (isItemViewTypeValid(itemViewType)) { + return mRemovedViewsCache.get(itemViewType).poll(); + } + + return null; + } + + /** + * Adds the provided view to a recycled views cache. + * + * @param adapterIndex + * @param view + */ + private void recycleView(int adapterIndex, View view) { + // There is one Queue of views for each different type of view. + // Just add the view to the pile of other views of the same type. + // The order they are added and removed does not matter. + int itemViewType = mAdapter.getItemViewType(adapterIndex); + if (isItemViewTypeValid(itemViewType)) { + mRemovedViewsCache.get(itemViewType).offer(view); + } + } + + private boolean isItemViewTypeValid(int itemViewType) { + return itemViewType < mRemovedViewsCache.size(); + } + + /** + * Adds a child to this viewgroup and measures it so it renders the correct size + */ + private void addAndMeasureChild(final View child, int viewPos) { + LayoutParams params = getLayoutParams(child); + addViewInLayout(child, viewPos, params, true); + measureChild(child); + } + + /** + * Measure the provided child. + * + * @param child The child. + */ + private void measureChild(View child) { + ViewGroup.LayoutParams childLayoutParams = getLayoutParams(child); + int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec, getPaddingTop() + getPaddingBottom(), childLayoutParams.height); + + int childWidthSpec; + if (childLayoutParams.width > 0) { + childWidthSpec = MeasureSpec.makeMeasureSpec(childLayoutParams.width, MeasureSpec.EXACTLY); + } else { + childWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + } + + child.measure(childWidthSpec, childHeightSpec); + } + + /** + * Gets a child's layout parameters, defaults if not available. + */ + private ViewGroup.LayoutParams getLayoutParams(View child) { + ViewGroup.LayoutParams layoutParams = child.getLayoutParams(); + if (layoutParams == null) { + // Since this is a horizontal list view default to matching the parents height, and wrapping the width + layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); + } + + return layoutParams; + } + + @SuppressLint("WrongCall") + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + if (mAdapter == null) { + return; + } + + // Force the OS to redraw this view + invalidate(); + + // If the data changed then reset everything and render from scratch at the same offset as last time + if (mDataChanged) { + int oldCurrentX = mCurrentX; + initView(); + removeAllViewsInLayout(); + mNextX = oldCurrentX; + mDataChanged = false; + } + + // If restoring from a rotation + if (mRestoreX != null) { + mNextX = mRestoreX; + mRestoreX = null; + } + + // If in a fling + if (mFlingTracker.computeScrollOffset()) { + // Compute the next position + mNextX = mFlingTracker.getCurrX(); + } + + // Prevent scrolling past 0 so you can't scroll past the end of the list to the left + if (mNextX < 0) { + mNextX = 0; + + // Show an edge effect absorbing the current velocity + if (mEdgeGlowLeft.isFinished()) { + mEdgeGlowLeft.onAbsorb((int) determineFlingAbsorbVelocity()); + } + + mFlingTracker.forceFinished(true); + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE); + } else if (mNextX > mMaxX) { + // Clip the maximum scroll position at mMaxX so you can't scroll past the end of the list to the right + mNextX = mMaxX; + + // Show an edge effect absorbing the current velocity + if (mEdgeGlowRight.isFinished()) { + mEdgeGlowRight.onAbsorb((int) determineFlingAbsorbVelocity()); + } + + mFlingTracker.forceFinished(true); + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE); + } + + // Calculate our delta from the last time the view was drawn + int dx = mCurrentX - mNextX; + + removeNonVisibleChildren(dx); + fillList(dx); + positionChildren(dx); + + // Since the view has now been drawn, update our current position + mCurrentX = mNextX; + + // If we have scrolled enough to lay out all views, then determine the maximum scroll position now + if (determineMaxX()) { + // Redo the layout pass since we now know the maximum scroll position + onLayout(changed, left, top, right, bottom); + return; + } + + // If the fling has finished + if (mFlingTracker.isFinished()) { + // If the fling just ended + if (mCurrentScrollState == OnScrollStateChangedListener.ScrollState.SCROLL_STATE_FLING) { + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE); + } + } else { + // Still in a fling so schedule the next frame + postOnAnimation(mDelayedLayout); + } + } + + @Override + protected float getLeftFadingEdgeStrength() { + int horizontalFadingEdgeLength = getHorizontalFadingEdgeLength(); + + // If completely at the edge then disable the fading edge + if (mCurrentX == 0) { + return 0; + } else if (mCurrentX < horizontalFadingEdgeLength) { + // We are very close to the edge, so enable the fading edge proportional to the distance from the edge, and the width of the edge effect + return (float) mCurrentX / horizontalFadingEdgeLength; + } else { + // The current x position is more then the width of the fading edge so enable it fully. + return 1; + } + } + + @Override + protected float getRightFadingEdgeStrength() { + int horizontalFadingEdgeLength = getHorizontalFadingEdgeLength(); + + // If completely at the edge then disable the fading edge + if (mCurrentX == mMaxX) { + return 0; + } else if ((mMaxX - mCurrentX) < horizontalFadingEdgeLength) { + // We are very close to the edge, so enable the fading edge proportional to the distance from the ednge, and the width of the edge effect + return (float) (mMaxX - mCurrentX) / horizontalFadingEdgeLength; + } else { + // The distance from the maximum x position is more then the width of the fading edge so enable it fully. + return 1; + } + } + + /** + * Determines the current fling absorb velocity + */ + private float determineFlingAbsorbVelocity() { + // If the OS version is high enough get the real velocity */ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return IceCreamSandwichPlus.getCurrVelocity(mFlingTracker); + } else { + // Unable to get the velocity so just return a default. + // In actuality this is never used since EdgeEffectCompat does not draw anything unless the device is ICS+. + // Less then ICS EdgeEffectCompat essentially performs a NOP. + return FLING_DEFAULT_ABSORB_VELOCITY; + } + } + + /** + * Use to schedule a request layout via a runnable + */ + private Runnable mDelayedLayout = new Runnable() { + @Override + public void run() { + requestLayout(); + } + }; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + //Log.i("onMeasure", MeasureSpec.toString(heightMeasureSpec)); + // Cache off the measure spec + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { + setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(mHeight,MeasureSpec.EXACTLY)); + //Log.i("onMeasure", MeasureSpec.toString(MeasureSpec.makeMeasureSpec(mHeight,MeasureSpec.EXACTLY))); + } + mHeightMeasureSpec = heightMeasureSpec; + } + + + /** + * Determine the Max X position. This is the farthest that the user can scroll the screen. Until the last adapter item has been + * laid out it is impossible to calculate; once that has occurred this will perform the calculation, and if necessary force a + * redraw and relayout of this view. + * + * @return true if the maxx position was just determined + */ + private boolean determineMaxX() { + // If the last view has been laid out, then we can determine the maximum x position + if (isLastItemInAdapter(mRightViewAdapterIndex)) { + View rightView = getRightmostChild(); + + if (rightView != null) { + int oldMaxX = mMaxX; + + // Determine the maximum x position + mMaxX = mCurrentX + (rightView.getRight() - getPaddingLeft()) - getRenderWidth(); + + // Handle the case where the views do not fill at least 1 screen + if (mMaxX < 0) { + mMaxX = 0; + } + + if (mMaxX != oldMaxX) { + return true; + } + } + } + + return false; + } + + /** + * Adds children views to the left and right of the current views until the screen is full + */ + private void fillList(final int dx) { + // Get the rightmost child and determine its right edge + int edge = 0; + View child = getRightmostChild(); + if (child != null) { + edge = child.getRight(); + } + + // Add new children views to the right, until past the edge of the screen + fillListRight(edge, dx); + + // Get the leftmost child and determine its left edge + edge = 0; + child = getLeftmostChild(); + if (child != null) { + edge = child.getLeft(); + } + + // Add new children views to the left, until past the edge of the screen + fillListLeft(edge, dx); + } + + private void removeNonVisibleChildren(final int dx) { + View child = getLeftmostChild(); + + // Loop removing the leftmost child, until that child is on the screen + while (child != null && child.getRight() + dx <= 0) { + // The child is being completely removed so remove its width from the display offset and its divider if it has one. + // To remove add the size of the child and its divider (if it has one) to the offset. + // You need to add since its being removed from the left side, i.e. shifting the offset to the right. + mDisplayOffset += isLastItemInAdapter(mLeftViewAdapterIndex) ? child.getMeasuredWidth() : mDividerWidth + child.getMeasuredWidth(); + + // Add the removed view to the cache + recycleView(mLeftViewAdapterIndex, child); + + // Actually remove the view + removeViewInLayout(child); + + // Keep track of the adapter index of the left most child + mLeftViewAdapterIndex++; + + // Get the new leftmost child + child = getLeftmostChild(); + } + + child = getRightmostChild(); + + // Loop removing the rightmost child, until that child is on the screen + while (child != null && child.getLeft() + dx >= getWidth()) { + recycleView(mRightViewAdapterIndex, child); + removeViewInLayout(child); + mRightViewAdapterIndex--; + child = getRightmostChild(); + } + } + + private void fillListRight(int rightEdge, final int dx) { + // Loop adding views to the right until the screen is filled + while (rightEdge + dx + mDividerWidth < getWidth() && mRightViewAdapterIndex + 1 < mAdapter.getCount()) { + mRightViewAdapterIndex++; + + // If mLeftViewAdapterIndex < 0 then this is the first time a view is being added, and left == right + if (mLeftViewAdapterIndex < 0) { + mLeftViewAdapterIndex = mRightViewAdapterIndex; + } + + // Get the view from the adapter, utilizing a cached view if one is available + View child = mAdapter.getView(mRightViewAdapterIndex, getRecycledView(mRightViewAdapterIndex), this); + addAndMeasureChild(child, INSERT_AT_END_OF_LIST); + + // If first view, then no divider to the left of it, otherwise add the space for the divider width + rightEdge += (mRightViewAdapterIndex == 0 ? 0 : mDividerWidth) + child.getMeasuredWidth(); + + // Check if we are running low on data so we can tell listeners to go get more + determineIfLowOnData(); + } + } + + private void fillListLeft(int leftEdge, final int dx) { + // Loop adding views to the left until the screen is filled + //Log.i("fillListLeft 1:" , leftEdge+": "+(leftEdge + dx - mDividerWidth)+": "+mLeftViewAdapterIndex); + while (leftEdge + dx - mDividerWidth >= 0 && mLeftViewAdapterIndex >= 1) { + mLeftViewAdapterIndex--; + View child = mAdapter.getView(mLeftViewAdapterIndex, getRecycledView(mLeftViewAdapterIndex), this); + addAndMeasureChild(child, INSERT_AT_START_OF_LIST); + + // If first view, then no divider to the left of it + leftEdge -= mLeftViewAdapterIndex == 0 ? child.getMeasuredWidth() : mDividerWidth + child.getMeasuredWidth(); + // If on a clean edge then just remove the child, otherwise remove the divider as well + mDisplayOffset -= leftEdge + dx == 0 ? child.getMeasuredWidth() : mDividerWidth + child.getMeasuredWidth(); + //Log.i("fillListLeft 2:" , leftEdge+": "+(leftEdge + dx - mDividerWidth)+": "+mLeftViewAdapterIndex+";"+((TextView)child).getText()); + } + } + + /** + * Loops through each child and positions them onto the screen + */ + private void positionChildren(final int dx) { + int childCount = getChildCount(); + int old = mHeight; + mHeight=0; + if (childCount > 0) { + mDisplayOffset += dx; + int leftOffset = mDisplayOffset; + + // Loop each child view + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + int left = leftOffset + getPaddingLeft(); + int top = getPaddingTop(); + int right = left + child.getMeasuredWidth(); + int bottom = top + child.getMeasuredHeight(); + mHeight=Math.max(mHeight,bottom+getPaddingBottom()); + // Layout the child + child.layout(left, top, right, bottom); + + // Increment our offset by added child's size and divider width + leftOffset += child.getMeasuredWidth() + mDividerWidth; + } + if(old==0){ + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + requestLayout(); + } + },16*6); + } + } + } + + /** + * Gets the current child that is leftmost on the screen. + */ + private View getLeftmostChild() { + return getChildAt(0); + } + + /** + * Gets the current child that is rightmost on the screen. + */ + private View getRightmostChild() { + return getChildAt(getChildCount() - 1); + } + + /** + * Finds a child view that is contained within this view, given the adapter index. + * + * @return View The child view, or or null if not found. + */ + private View getChild(int adapterIndex) { + if (adapterIndex >= mLeftViewAdapterIndex && adapterIndex <= mRightViewAdapterIndex) { + return getChildAt(adapterIndex - mLeftViewAdapterIndex); + } + + return null; + } + + /** + * Returns the index of the child that contains the coordinates given. + * This is useful to determine which child has been touched. + * This can be used for a call to {@link #getChildAt(int)} + * + * @param x X-coordinate + * @param y Y-coordinate + * @return The index of the child that contains the coordinates. If no child is found then returns -1 + */ + private int getChildIndex(final int x, final int y) { + int childCount = getChildCount(); + + for (int index = 0; index < childCount; index++) { + getChildAt(index).getHitRect(mRect); + if (mRect.contains(x, y)) { + return index; + } + } + + return -1; + } + + /** + * Simple convenience method for determining if this index is the last index in the adapter + */ + private boolean isLastItemInAdapter(int index) { + return index == mAdapter.getCount() - 1; + } + + /** + * Gets the height in px this view will be rendered. (padding removed) + */ + private int getRenderHeight() { + return getHeight() - getPaddingTop() - getPaddingBottom(); + } + + /** + * Gets the width in px this view will be rendered. (padding removed) + */ + private int getRenderWidth() { + return getWidth() - getPaddingLeft() - getPaddingRight(); + } + + /** + * Scroll to the provided offset + */ + public void scrollTo(int x) { + mFlingTracker.startScroll(mNextX, 0, x - mNextX, 0); + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_FLING); + requestLayout(); + } + + @Override + public int getFirstVisiblePosition() { + return mLeftViewAdapterIndex; + } + + @Override + public int getLastVisiblePosition() { + return mRightViewAdapterIndex; + } + + /** + * Draws the overscroll edge glow effect on the left and right sides of the horizontal list + */ + private void drawEdgeGlow(Canvas canvas) { + if (mEdgeGlowLeft != null && !mEdgeGlowLeft.isFinished() && isEdgeGlowEnabled()) { + // The Edge glow is meant to come from the top of the screen, so rotate it to draw on the left side. + final int restoreCount = canvas.save(); + final int height = getHeight(); + + canvas.rotate(-90, 0, 0); + canvas.translate(-height + getPaddingBottom(), 0); + + mEdgeGlowLeft.setSize(getRenderHeight(), getRenderWidth()); + if (mEdgeGlowLeft.draw(canvas)) { + invalidate(); + } + + canvas.restoreToCount(restoreCount); + } else if (mEdgeGlowRight != null && !mEdgeGlowRight.isFinished() && isEdgeGlowEnabled()) { + // The Edge glow is meant to come from the top of the screen, so rotate it to draw on the right side. + final int restoreCount = canvas.save(); + final int width = getWidth(); + + canvas.rotate(90, 0, 0); + canvas.translate(getPaddingTop(), -width); + mEdgeGlowRight.setSize(getRenderHeight(), getRenderWidth()); + if (mEdgeGlowRight.draw(canvas)) { + invalidate(); + } + + canvas.restoreToCount(restoreCount); + } + } + + /** + * Draws the dividers that go in between the horizontal list view items + */ + private void drawDividers(Canvas canvas) { + final int count = getChildCount(); + + // Only modify the left and right in the loop, we set the top and bottom here since they are always the same + final Rect bounds = mRect; + mRect.top = getPaddingTop(); + mRect.bottom = mRect.top + getRenderHeight(); + + // Draw the list dividers + for (int i = 0; i < count; i++) { + // Don't draw a divider to the right of the last item in the adapter + if (!(i == count - 1 && isLastItemInAdapter(mRightViewAdapterIndex))) { + View child = getChildAt(i); + + bounds.left = child.getRight(); + bounds.right = child.getRight() + mDividerWidth; + + // Clip at the left edge of the screen + if (bounds.left < getPaddingLeft()) { + bounds.left = getPaddingLeft(); + } + + // Clip at the right edge of the screen + if (bounds.right > getWidth() - getPaddingRight()) { + bounds.right = getWidth() - getPaddingRight(); + } + + // Draw a divider to the right of the child + drawDivider(canvas, bounds); + + // If the first view, determine if a divider should be shown to the left of it. + // A divider should be shown if the left side of this view does not fill to the left edge of the screen. + if (i == 0 && child.getLeft() > getPaddingLeft()) { + bounds.left = getPaddingLeft(); + bounds.right = child.getLeft(); + drawDivider(canvas, bounds); + } + } + } + } + + /** + * Draws a divider in the given bounds. + * + * @param canvas The canvas to draw to. + * @param bounds The bounds of the divider. + */ + private void drawDivider(Canvas canvas, Rect bounds) { + if (mDivider != null) { + mDivider.setBounds(bounds); + mDivider.draw(canvas); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + drawDividers(canvas); + } + + private int dp(float n) { + return (int) TypedValue.applyDimension(1, n, dm); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (mBound != null) { + Paint p = new Paint(); + p.setColor(0x88888888); + canvas.drawRect(mBound, p); + } + if (mCurrentlySelectedAdapterIndex >= 0 && mLeftViewAdapterIndex <= mCurrentlySelectedAdapterIndex && mRightViewAdapterIndex >= mCurrentlySelectedAdapterIndex && mSelectedBackground != null) { + View child = getSelectedView(); + if (child != null) { + Rect bound = new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom()); + mSelectedBackground.setBounds(bound); + mSelectedBackground.draw(canvas); + } + } + super.dispatchDraw(canvas); + if (mCurrentlySelectedAdapterIndex >= 0 && mLeftViewAdapterIndex <= mCurrentlySelectedAdapterIndex && mRightViewAdapterIndex >= mCurrentlySelectedAdapterIndex) { + View child = getSelectedView(); + if (child != null) { + Rect bound = new Rect(child.getLeft(), child.getBottom() - dp(2), child.getRight(), child.getBottom()); + Paint p = new Paint(); + p.setColor(mSelectedColor); + canvas.drawRect(bound, p); + } + } + drawEdgeGlow(canvas); + } + + public void setSelectedColor(int color) { + mSelectedColor = color; + invalidate(); + } + + public void setSelectedBackground(Drawable drawable) { + mSelectedBackground = drawable; + invalidate(); + } + + public void setSelectedBackgroundColor(int color) { + mSelectedBackground = new ColorDrawable(color); + invalidate(); + } + + @Override + protected void dispatchSetPressed(boolean pressed) { + // Don't dispatch setPressed to our children. We call setPressed on ourselves to + // get the selector in the right state, but we don't want to press each child. + } + + protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + mFlingTracker.fling(mNextX, 0, (int) -velocityX, 0, 0, mMaxX, 0, 0); + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_FLING); + requestLayout(); + return true; + } + + protected boolean onDown(MotionEvent e) { + // If the user just caught a fling, then disable all touch actions until they release their finger + mBlockTouchAction = !mFlingTracker.isFinished(); + + // Allow a finger down event to catch a fling + mFlingTracker.forceFinished(true); + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE); + + unpressTouchedChild(); + + if (!mBlockTouchAction) { + // Find the child that was pressed + final int index = getChildIndex((int) e.getX(), (int) e.getY()); + if (index >= 0) { + // Save off view being touched so it can later be released + mViewBeingTouched = getChildAt(index); + + if (mViewBeingTouched != null) { + // Set the view as pressed + mViewBeingTouched.setPressed(true); + refreshDrawableState(); + } + } + } + + return true; + } + + /** + * If a view is currently pressed then unpress it + */ + private void unpressTouchedChild() { + if (mViewBeingTouched != null) { + // Set the view as not pressed + mViewBeingTouched.setPressed(false); + refreshDrawableState(); + + // Null out the view so we don't leak it + mViewBeingTouched = null; + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent e) { + boolean handled = super.dispatchTouchEvent(e); + handled |= mGestureDetector.onTouchEvent(e); + switch (e.getAction()) { + case MotionEvent.ACTION_DOWN: + final int index = getChildIndex((int) e.getX(), (int) e.getY()); + if (index >= 0) { + View child = getChildAt(index); + mBound = new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom()); + invalidate(); + break; + } + break; + case MotionEvent.ACTION_UP: + mBound = null; + invalidate(); + break; + case MotionEvent.ACTION_CANCEL: + mBound = null; + invalidate(); + break; + + } + return handled; + } + + + private class GestureListener extends GestureDetector.SimpleOnGestureListener { + @Override + public boolean onDown(MotionEvent e) { + return HorizontalListView.this.onDown(e); + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + mBound = null; + return HorizontalListView.this.onFling(e1, e2, velocityX, velocityY); + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + // Lock the user into interacting just with this view + mBound = null; + requestParentListViewToNotInterceptTouchEvents(true); + + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_TOUCH_SCROLL); + unpressTouchedChild(); + mNextX += (int) distanceX; + updateOverscrollAnimation(Math.round(distanceX)); + requestLayout(); + + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + unpressTouchedChild(); + OnItemClickListener onItemClickListener = getOnItemClickListener(); + + final int index = getChildIndex((int) e.getX(), (int) e.getY()); + + // If the tap is inside one of the child views, and we are not blocking touches + if (index >= 0 && !mBlockTouchAction) { + View child = getChildAt(index); + int adapterIndex = mLeftViewAdapterIndex + index; + + if (onItemClickListener != null) { + onItemClickListener.onItemClick(HorizontalListView.this, child, adapterIndex, mAdapter.getItemId(adapterIndex)); + return true; + } + } + + if (mOnClickListener != null && !mBlockTouchAction) { + mOnClickListener.onClick(HorizontalListView.this); + } + + return false; + } + + @Override + public void onLongPress(MotionEvent e) { + unpressTouchedChild(); + + final int index = getChildIndex((int) e.getX(), (int) e.getY()); + if (index >= 0 && !mBlockTouchAction) { + View child = getChildAt(index); + OnItemLongClickListener onItemLongClickListener = getOnItemLongClickListener(); + if (onItemLongClickListener != null) { + int adapterIndex = mLeftViewAdapterIndex + index; + boolean handled = onItemLongClickListener.onItemLongClick(HorizontalListView.this, child, adapterIndex, mAdapter + .getItemId(adapterIndex)); + + if (handled) { + // BZZZTT!!1! + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } + } + } + } + } + + ; + + @Override + public boolean onTouchEvent(MotionEvent event) { + // Detect when the user lifts their finger off the screen after a touch + switch (event.getAction()) { + case MotionEvent.ACTION_UP: + + // If not flinging then we are idle now. The user just finished a finger scroll. + if (mFlingTracker == null || mFlingTracker.isFinished()) { + setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE); + } + + // Allow the user to interact with parent views + requestParentListViewToNotInterceptTouchEvents(false); + + releaseEdgeGlow(); + break; + case MotionEvent.ACTION_CANCEL: + unpressTouchedChild(); + releaseEdgeGlow(); + + // Allow the user to interact with parent views + requestParentListViewToNotInterceptTouchEvents(false); + } + + return super.onTouchEvent(event); + } + + /** + * Release the EdgeGlow so it animates + */ + private void releaseEdgeGlow() { + if (mEdgeGlowLeft != null) { + mEdgeGlowLeft.onRelease(); + } + + if (mEdgeGlowRight != null) { + mEdgeGlowRight.onRelease(); + } + } + + /** + * Sets a listener to be called when the HorizontalListView has been scrolled to a point where it is + * running low on data. An example use case is wanting to auto download more data when the user + * has scrolled to the point where only 10 items are left to be rendered off the right of the + * screen. To get called back at that point just register with this function with a + * numberOfItemsLeftConsideredLow value of 10.
+ *
+ * This will only be called once to notify that the HorizontalListView is running low on data. + * Calling notifyDataSetChanged on the adapter will allow this to be called again once low on data. + * + * @param listener The listener to be notified when the number of array adapters items left to + * be shown is running low. + * @param numberOfItemsLeftConsideredLow The number of array adapter items that have not yet + * been displayed that is considered too low. + */ + public void setRunningOutOfDataListener(RunningOutOfDataListener listener, int numberOfItemsLeftConsideredLow) { + mRunningOutOfDataListener = listener; + mRunningOutOfDataThreshold = numberOfItemsLeftConsideredLow; + } + + /** + * This listener is used to allow notification when the HorizontalListView is running low on data to display. + */ + public static interface RunningOutOfDataListener { + /** + * Called when the HorizontalListView is running out of data and has reached at least the provided threshold. + */ + void onRunningOutOfData(); + } + + /** + * Determines if we are low on data and if so will call to notify the listener, if there is one, + * that we are running low on data. + */ + private void determineIfLowOnData() { + // Check if the threshold has been reached and a listener is registered + if (mRunningOutOfDataListener != null && mAdapter != null && + mAdapter.getCount() - (mRightViewAdapterIndex + 1) < mRunningOutOfDataThreshold) { + + // Prevent notification more than once + if (!mHasNotifiedRunningLowOnData) { + mHasNotifiedRunningLowOnData = true; + mRunningOutOfDataListener.onRunningOutOfData(); + } + } + } + + /** + * Register a callback to be invoked when the HorizontalListView has been clicked. + * + * @param listener The callback that will be invoked. + */ + @Override + public void setOnClickListener(OnClickListener listener) { + mOnClickListener = listener; + } + + /** + * Interface definition for a callback to be invoked when the view scroll state has changed. + */ + public interface OnScrollStateChangedListener { + public enum ScrollState { + /** + * The view is not scrolling. Note navigating the list using the trackball counts as being + * in the idle state since these transitions are not animated. + */ + SCROLL_STATE_IDLE, + + /** + * The user is scrolling using touch, and their finger is still on the screen + */ + SCROLL_STATE_TOUCH_SCROLL, + + /** + * The user had previously been scrolling using touch and had performed a fling. The + * animation is now coasting to a stop + */ + SCROLL_STATE_FLING + } + + /** + * Callback method to be invoked when the scroll state changes. + * + * @param scrollState The current scroll state. + */ + public void onScrollStateChanged(ScrollState scrollState); + } + + /** + * Sets a listener to be invoked when the scroll state has changed. + * + * @param listener The listener to be invoked. + */ + public void setOnScrollStateChangedListener(OnScrollStateChangedListener listener) { + mOnScrollStateChangedListener = listener; + } + + /** + * Call to set the new scroll state. + * If it has changed and a listener is registered then it will be notified. + */ + private void setCurrentScrollState(OnScrollStateChangedListener.ScrollState newScrollState) { + // If the state actually changed then notify listener if there is one + if (mCurrentScrollState != newScrollState && mOnScrollStateChangedListener != null) { + mOnScrollStateChangedListener.onScrollStateChanged(newScrollState); + } + + mCurrentScrollState = newScrollState; + } + + /** + * Updates the over scroll animation based on the scrolled offset. + * + * @param scrolledOffset The scroll offset + */ + private void updateOverscrollAnimation(final int scrolledOffset) { + if (mEdgeGlowLeft == null || mEdgeGlowRight == null) return; + + // Calculate where the next scroll position would be + int nextScrollPosition = mCurrentX + scrolledOffset; + + // If not currently in a fling (Don't want to allow fling offset updates to cause over scroll animation) + if (mFlingTracker == null || mFlingTracker.isFinished()) { + // If currently scrolled off the left side of the list and the adapter is not empty + if (nextScrollPosition < 0) { + + // Calculate the amount we have scrolled since last frame + int overscroll = Math.abs(scrolledOffset); + + // Tell the edge glow to redraw itself at the new offset + mEdgeGlowLeft.onPull((float) overscroll / getRenderWidth()); + + // Cancel animating right glow + if (!mEdgeGlowRight.isFinished()) { + mEdgeGlowRight.onRelease(); + } + } else if (nextScrollPosition > mMaxX) { + // Scrolled off the right of the list + + // Calculate the amount we have scrolled since last frame + int overscroll = Math.abs(scrolledOffset); + + // Tell the edge glow to redraw itself at the new offset + mEdgeGlowRight.onPull((float) overscroll / getRenderWidth()); + + // Cancel animating left glow + if (!mEdgeGlowLeft.isFinished()) { + mEdgeGlowLeft.onRelease(); + } + } + } + } + + /** + * Checks if the edge glow should be used enabled. + * The glow is not enabled unless there are more views than can fit on the screen at one time. + */ + private boolean isEdgeGlowEnabled() { + if (mAdapter == null || mAdapter.isEmpty()) return false; + + // If the maxx is more then zero then the user can scroll, so the edge effects should be shown + return mMaxX > 0; + } + + @TargetApi(11) + /** Wrapper class to protect access to API version 11 and above features */ + private static final class HoneycombPlus { + static { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + throw new RuntimeException("Should not get to HoneycombPlus class unless sdk is >= 11!"); + } + } + + /** + * Sets the friction for the provided scroller + */ + public static void setFriction(Scroller scroller, float friction) { + if (scroller != null) { + scroller.setFriction(friction); + } + } + } + + @TargetApi(14) + /** Wrapper class to protect access to API version 14 and above features */ + private static final class IceCreamSandwichPlus { + static { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + throw new RuntimeException("Should not get to IceCreamSandwichPlus class unless sdk is >= 14!"); + } + } + + /** + * Gets the velocity for the provided scroller + */ + public static float getCurrVelocity(Scroller scroller) { + return scroller.getCurrVelocity(); + } + } +} diff --git a/app/src/main/java/android/widget/PageAdapter.java b/app/src/main/java/android/widget/PageAdapter.java new file mode 100644 index 0000000..4a42d23 --- /dev/null +++ b/app/src/main/java/android/widget/PageAdapter.java @@ -0,0 +1,48 @@ +package android.widget; + +import android.view.View; + +/** + * Created by Administrator on 2018/09/02 0002. + */ + +public class PageAdapter extends BasePageAdapter { + private final Adapter mAdapter; + private View[] mView; + + public PageAdapter(Adapter adapter) { + mAdapter = adapter; + mView=new View[adapter.getViewTypeCount()]; + } + + + @Override + public void destroyItem(View container, int position, Object object) { + View view = (View) object; + ((PageView) container).removeView(view); + mView[mAdapter.getItemViewType(position)] = view; + } + + @Override + public int getCount() { + return mAdapter.getCount(); + } + + @Override + public Object instantiateItem(View container, int position) { + int type=mAdapter.getItemViewType(position); + if (mView[type] != null) + ((PageView) container).removeView(mView[type]); + View view = mAdapter.getView(position, mView[type], ((PageView) container)); + ((PageView) container).addView(view, 0); + mView[type]=null; + return view; + } + + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0 == (arg1); + } + + +} diff --git a/app/src/main/java/android/widget/PageLayout.java b/app/src/main/java/android/widget/PageLayout.java new file mode 100644 index 0000000..1041fe3 --- /dev/null +++ b/app/src/main/java/android/widget/PageLayout.java @@ -0,0 +1,205 @@ +package android.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.view.*; +import android.view.ViewGroup.*; +import android.widget.PageLayout.*; +import android.util.*; + + +public class PageLayout extends HorizontalScrollView { + + private int mTouchScale = 0; + + private LinearLayout wrapper; + + private PageLayout.OnPageChangeListener mOnPageChangeListener; + + private int mIdx; + + private Scroller mScroller; + private int mTouchSlop; + private int mMinimumVelocity; + private int mMaximumVelocity; + private VelocityTracker mVelocityTracker; + + private int mCount; + private int mWidth; + + + public PageLayout(Context context) { + super(context); + init(context); + } + + public PageLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public void setTouchScale(int touchScale) { + this.mTouchScale = touchScale; + } + + public int getTouchScale() { + return mTouchScale; + } + + private void init(Context context) { + setHorizontalScrollBarEnabled(false); + mWidth = context.getResources().getDisplayMetrics().widthPixels; + mTouchScale = mWidth / 2; + wrapper = new LinearLayout(context); + super.addView(wrapper); + + mScroller = new Scroller(getContext()); + setFocusable(true); + setWillNotDraw(false); + final ViewConfiguration configuration = ViewConfiguration.get(context); + mTouchSlop = configuration.getScaledTouchSlop(); + mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); + mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int w=getMeasuredWidth(); + int count=wrapper.getChildCount(); + if (mCount != count || mWidth != w) { + mCount = count; + mWidth = w; + for (int i=0;i < count;i++) { + ViewGroup chid=(ViewGroup) wrapper.getChildAt(i); + ViewGroup.LayoutParams lp=chid.getLayoutParams(); + lp.width = mWidth; + chid.setLayoutParams(lp); + chid.requestLayout(); + } + ViewGroup.LayoutParams lp=wrapper.getLayoutParams(); + lp.width = mWidth * count; + wrapper.setLayoutParams(lp); + wrapper.requestLayout(); + requestLayout(); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + showPage(mIdx); + + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + if (changed) { + showPage(mIdx); + } + } + + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + // TODO: Implement this method + FrameLayout l=new FrameLayout(getContext()); + + l.addView(child, params); + wrapper.addView(l); + } + + @Override + public void addView(View child) { + // TODO: Implement this method + FrameLayout l=new FrameLayout(getContext()); + l.addView(child); + wrapper.addView(l); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ev.getX() < mTouchScale || ev.getX() > mWidth - mTouchScale) { + return super.onInterceptTouchEvent(ev); + } + else { + return false; + } + } + + private void obtainVelocityTracker(MotionEvent event) { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(event); + } + + private void releaseVelocityTracker() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + int action = ev.getAction(); + obtainVelocityTracker(ev); + switch (action) { + // Up时,进行判断,如果显示区域大于页面宽度一半则完全显示 + case MotionEvent.ACTION_UP: + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialVelocityY = (int) velocityTracker.getYVelocity(); + int initialVelocityX = (int) velocityTracker.getXVelocity(); + releaseVelocityTracker(); + int absX=Math.abs(initialVelocityX); + int absY=Math.abs(initialVelocityY); + if (absX > mMinimumVelocity && absX > absY) { + if (initialVelocityX > 0) + showPage(Math.max(0, mIdx - 1)); + else + showPage(Math.min(wrapper.getChildCount() - 1, mIdx + 1)); + return true; + } + + int scrollX = getScrollX(); + int x=scrollX % mWidth; + if (x < mWidth / 2) + showPage(scrollX / mWidth); + else + showPage(scrollX / mWidth + 1); + return true; + } + return super.onTouchEvent(ev); + } + + public void showPage(int idx) { + //wrapper.getChildAt(idx); + smoothScrollTo(mWidth * idx, 0); + if (mOnPageChangeListener != null && mIdx != idx) + mOnPageChangeListener.onPageChange(this, idx); + mIdx = idx; + } + + public void showPage(View v) { + int n=wrapper.getChildCount(); + for (int i=0;i < n;i++) + if (wrapper.getChildAt(i).equals(v)) + showPage(i); + } + + public View getPage(int idx) { + return wrapper.getChildAt(idx); + } + + public void setOnPageChangeListener(OnPageChangeListener ltr) { + mOnPageChangeListener = ltr; + } + + + public static interface OnPageChangeListener { + public void onPageChange(View v, int idx); + } +} diff --git a/app/src/main/java/android/widget/PageView.java b/app/src/main/java/android/widget/PageView.java new file mode 100644 index 0000000..f10112c --- /dev/null +++ b/app/src/main/java/android/widget/PageView.java @@ -0,0 +1,2897 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.content.*; +import android.content.res.*; +import android.database.*; +import android.graphics.*; +import android.graphics.drawable.*; +import android.os.*; +import android.util.*; +import android.view.*; +import android.view.accessibility.*; + +import java.lang.reflect.*; +import java.util.*; + +import android.view.animation.Interpolator; + +/** + * Layout manager that allows the user to flip left and right + * through pages of data. You supply an implementation of a + * {@link PageAdapter} to generate the pages that the view shows. + *

+ *

Note this class is currently under early design and + * development. The API will likely change in later updates of + * the compatibility library, requiring changes to the source code + * of apps when they are compiled against the newer version.

+ *

+ *

PageView is most often used in conjunction with {@link android.app.Fragment}, + * which is a convenient way to supply and manage the lifecycle of each page. + * There are standard adapters implemented for using fragments with the PageView, + * which cover the most common use cases. These are + * classes have simple code showing how to build a full user interface + * with them. + *

+ *

For more information about how to use PageView, read Creating Swipe Views with + * Tabs.

+ *

+ *

Below is a more complicated example of PageView, using it in conjunction + * with {@link android.app.ActionBar} tabs. You can find other examples of using + * PageView in the API 4+ Support Demos and API 13+ Support Demos sample code. + *

+ * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPage.java + * complete} + */ +public class PageView extends ViewGroup { + /** + * Indicates that the page is in an idle, settled state. The current page + * is fully in view and no animation is in progress. + */ + public static final int SCROLL_STATE_IDLE = 0; + /** + * Indicates that the page is currently being dragged by the user. + */ + public static final int SCROLL_STATE_DRAGGING = 1; + /** + * Indicates that the page is in the process of settling to a final position. + */ + public static final int SCROLL_STATE_SETTLING = 2; + private static final String TAG = "PageView"; + private static final boolean DEBUG = false; + private static final boolean USE_CACHE = false; + private static final int DEFAULT_OFFSCREEN_PAGES = 1; + private static final int MAX_SETTLE_DURATION = 600; // ms + private static final int MIN_DISTANCE_FOR_FLING = 25; // dips + private static final int DEFAULT_GUTTER_SIZE = 16; // dips + private static final int MIN_FLING_VELOCITY = 400; // dips + private static final int[] LAYOUT_ATTRS = new int[]{ + android.R.attr.layout_gravity + }; + private static final Comparator COMPARATOR = new Comparator() { + @Override + public int compare(ItemInfo lhs, ItemInfo rhs) { + return lhs.position - rhs.position; + } + }; + private static final Interpolator sInterpolator = new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + /** + * Sentinel value for no current active pointer. + * Used by {@link #mActivePointerId}. + */ + private static final int INVALID_POINTER = -1; + // If the page is at least this close to its final position, complete the scroll + // on touch down and let the user interact with the content inside instead of + // "catching" the flinging page. + private static final int CLOSE_ENOUGH = 2; // dp + private static final int DRAW_ORDER_DEFAULT = 0; + private static final int DRAW_ORDER_FORWARD = 1; + private static final int DRAW_ORDER_REVERSE = 2; + private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator(); + private final ArrayList mItems = new ArrayList(); + private final ItemInfo mTempItem = new ItemInfo(); + private final Rect mTempRect = new Rect(); + /** + * Used to track what the expected number of items in the adapter should be. + * If the app changes this when we don't expect it, we'll throw a big obnoxious exception. + */ + private int mExpectedAdapterCount; + private BasePageAdapter mAdapter; + private int mCurItem; // Index of currently displayed page. + private int mRestoredCurItem = -1; + private Parcelable mRestoredAdapterState = null; + private ClassLoader mRestoredClassLoader = null; + private Scroller mScroller; + private PageObserver mObserver; + private int mPageMargin; + private Drawable mMarginDrawable; + private int mTopPageBounds; + private int mBottomPageBounds; + // Offsets of the first and last items, if known. + // Set during population, used to determine if we are at the beginning + // or end of the page data set during touch scrolling. + private float mFirstOffset = -Float.MAX_VALUE; + private float mLastOffset = Float.MAX_VALUE; + private int mChildWidthMeasureSpec; + private int mChildHeightMeasureSpec; + private boolean mInLayout; + private boolean mScrollingCacheEnabled; + private boolean mPopulatePending; + private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; + private boolean mIsBeingDragged; + private boolean mIsUnableToDrag; + private int mDefaultGutterSize; + private int mGutterSize; + private int mTouchSlop; + /** + * Position of the last motion event. + */ + private float mLastMotionX; + private float mLastMotionY; + private float mInitialMotionX; + private float mInitialMotionY; + /** + * ID of the active pointer. This is used to retain consistency during + * drags/flings if multiple pointers are used. + */ + private int mActivePointerId = INVALID_POINTER; + /** + * Determines speed during touch scrolling + */ + private VelocityTracker mVelocityTracker; + private int mMinimumVelocity; + private int mMaximumVelocity; + private int mFlingDistance; + private int mCloseEnough; + private boolean mFakeDragging; + private long mFakeDragBeginTime; + private EdgeEffect mLeftEdge; + private EdgeEffect mRightEdge; + private boolean mFirstLayout = true; + private boolean mNeedCalculatePageOffsets = false; + private boolean mCalledSuper; + private int mDecorChildCount; + private List mOnPageChangeListeners; + private OnPageChangeListener mOnPageChangeListener; + private OnPageChangeListener mInternalPageChangeListener; + private OnAdapterChangeListener mAdapterChangeListener; + private PageTransformer mPageTransformer; + private Method mSetChildrenDrawingOrderEnabled; + private int mDrawingOrder; + private ArrayList mDrawingOrderedChildren; + private int mScrollState = SCROLL_STATE_IDLE; + private final Runnable mEndScrollRunnable = new Runnable() { + public void run() { + setScrollState(SCROLL_STATE_IDLE); + populate(); + } + }; + + public PageView(Context context) { + super(context); + initPageView(); + } + + public PageView(Context context, AttributeSet attrs) { + super(context, attrs); + initPageView(); + } + + void initPageView() { + setWillNotDraw(false); + setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + setFocusable(true); + final Context context = getContext(); + mScroller = new Scroller(context, sInterpolator); + final ViewConfiguration configuration = ViewConfiguration.get(context); + final float density = context.getResources().getDisplayMetrics().density; + + mTouchSlop = configuration.getScaledPagingTouchSlop(); + mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); + mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mLeftEdge = new EdgeEffect(context); + mRightEdge = new EdgeEffect(context); + + mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); + mCloseEnough = (int) (CLOSE_ENOUGH * density); + mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); + + setAccessibilityDelegate(new AccessibilityDelegate()); + if (Build.VERSION.SDK_INT < 16) + return; + + if (getImportantForAccessibility() + == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_YES); + } + } + + @Override + protected void onDetachedFromWindow() { + removeCallbacks(mEndScrollRunnable); + super.onDetachedFromWindow(); + } + + private void setScrollState(int newState) { + if (mScrollState == newState) { + return; + } + + mScrollState = newState; + if (mPageTransformer != null) { + // PageTransformers can do complex things that benefit from hardware layers. + enableLayers(newState != SCROLL_STATE_IDLE); + } + dispatchOnScrollStateChanged(newState); + } + + private void removeNonDecorViews() { + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) { + removeViewAt(i); + i--; + } + } + } + + /** + * Retrieve the current adapter supplying pages. + * + * @return The currently registered PageAdapter + */ + public BasePageAdapter getAdapter() { + return mAdapter; + } + + /** + * Set a PageAdapter that will supply views for this page as needed. + * + * @param adapter Adapter to use + */ + public void setAdapter(BasePageAdapter adapter) { + if (mAdapter != null) { + mAdapter.unregisterDataSetObserver(mObserver); + mAdapter.startUpdate(this); + for (int i = 0; i < mItems.size(); i++) { + final ItemInfo ii = mItems.get(i); + mAdapter.destroyItem(this, ii.position, ii.object); + } + mAdapter.finishUpdate(this); + mItems.clear(); + removeNonDecorViews(); + mCurItem = 0; + scrollTo(0, 0); + } + + final BasePageAdapter oldAdapter = mAdapter; + mAdapter = adapter; + mExpectedAdapterCount = 0; + + if (mAdapter != null) { + if (mObserver == null) { + mObserver = new PageObserver(); + } + mAdapter.registerDataSetObserver(mObserver); + mPopulatePending = false; + final boolean wasFirstLayout = mFirstLayout; + mFirstLayout = true; + mExpectedAdapterCount = mAdapter.getCount(); + if (mRestoredCurItem >= 0) { + mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); + setCurrentItemInternal(mRestoredCurItem, false, true); + mRestoredCurItem = -1; + mRestoredAdapterState = null; + mRestoredClassLoader = null; + } else if (!wasFirstLayout) { + populate(); + } else { + requestLayout(); + } + } + + if (mAdapterChangeListener != null && oldAdapter != adapter) { + mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); + } + } + + void setOnAdapterChangeListener(OnAdapterChangeListener listener) { + mAdapterChangeListener = listener; + } + + private int getClientWidth() { + return getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); + } + + public void showPage(int item) { + setCurrentItem(item, true); + } + + /** + * Set the currently selected page. + * + * @param item Item index to select + * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately + */ + public void setCurrentItem(int item, boolean smoothScroll) { + mPopulatePending = false; + setCurrentItemInternal(item, smoothScroll, false); + } + + public int getCurrentItem() { + return mCurItem; + } + + /** + * Set the currently selected page. If the PageView has already been through its first + * layout with its current adapter there will be a smooth animated transition between + * the current item and the specified item. + * + * @param item Item index to select + */ + public void setCurrentItem(int item) { + mPopulatePending = false; + setCurrentItemInternal(item, !mFirstLayout, false); + } + + void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { + setCurrentItemInternal(item, smoothScroll, always, 0); + } + + void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { + if (mAdapter == null || mAdapter.getCount() <= 0) { + setScrollingCacheEnabled(false); + return; + } + if (!always && mCurItem == item && mItems.size() != 0) { + setScrollingCacheEnabled(false); + return; + } + + if (item < 0) { + item = 0; + } else if (item >= mAdapter.getCount()) { + item = mAdapter.getCount() - 1; + } + final int pageLimit = mOffscreenPageLimit; + if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { + // We are doing a jump by more than one page. To avoid + // glitches, we want to keep all current pages in the view + // until the scroll ends. + for (int i = 0; i < mItems.size(); i++) { + mItems.get(i).scrolling = true; + } + } + final boolean dispatchSelected = mCurItem != item; + + if (mFirstLayout) { + // We don't have any idea how big we are yet and shouldn't have any pages either. + // Just set things up and let the pending layout handle things. + mCurItem = item; + if (dispatchSelected) { + dispatchOnPageSelected(item); + } + requestLayout(); + } else { + populate(item); + scrollToItem(item, smoothScroll, velocity, dispatchSelected); + } + } + + private void scrollToItem(int item, boolean smoothScroll, int velocity, + boolean dispatchSelected) { + final ItemInfo curInfo = infoForPosition(item); + int destX = 0; + if (curInfo != null) { + final int width = getClientWidth(); + destX = (int) (width * Math.max(mFirstOffset, + Math.min(curInfo.offset, mLastOffset))); + } + if (smoothScroll) { + smoothScrollTo(destX, 0, velocity); + if (dispatchSelected) { + dispatchOnPageSelected(item); + } + } else { + if (dispatchSelected) { + dispatchOnPageSelected(item); + } + completeScroll(false); + scrollTo(destX, 0); + pageScrolled(destX); + } + } + + /** + * Set a listener that will be invoked whenever the page changes or is incrementally + * scrolled. See {@link OnPageChangeListener}. + * + * @param listener Listener to set + * @deprecated Use {@link #addOnPageChangeListener(OnPageChangeListener)} + * and {@link #removeOnPageChangeListener(OnPageChangeListener)} instead. + */ + + public void setOnPageChangeListener(OnPageChangeListener listener) { + mOnPageChangeListener = listener; + } + + /** + * Add a listener that will be invoked whenever the page changes or is incrementally + * scrolled. See {@link OnPageChangeListener}. + *

+ *

Components that add a listener should take care to remove it when finished. + * Other components that take ownership of a view may call {@link #clearOnPageChangeListeners()} + * to remove all attached listeners.

+ * + * @param listener listener to add + */ + public void addOnPageChangeListener(OnPageChangeListener listener) { + if (mOnPageChangeListeners == null) { + mOnPageChangeListeners = new ArrayList<>(); + } + mOnPageChangeListeners.add(listener); + } + + /** + * Remove a listener that was previously added via + * {@link #addOnPageChangeListener(OnPageChangeListener)}. + * + * @param listener listener to remove + */ + public void removeOnPageChangeListener(OnPageChangeListener listener) { + if (mOnPageChangeListeners != null) { + mOnPageChangeListeners.remove(listener); + } + } + + /** + * Remove all listeners that are notified of any changes in scroll state or position. + */ + public void clearOnPageChangeListeners() { + if (mOnPageChangeListeners != null) { + mOnPageChangeListeners.clear(); + } + } + + /** + * Set a {@link PageTransformer} that will be called for each attached page whenever + * the scroll position is changed. This allows the application to apply custom property + * transformations to each page, overriding the default sliding look and feel. + *

+ *

Note: Prior to Android 3.0 the property animation APIs did not exist. + * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.

+ * + * @param reverseDrawingOrder true if the supplied PageTransformer requires page views + * to be drawn from last to first instead of first to last. + * @param transformer PageTransformer that will modify each page's animation properties + */ + public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) { + if (Build.VERSION.SDK_INT >= 11) { + final boolean hasTransformer = transformer != null; + final boolean needsPopulate = hasTransformer != (mPageTransformer != null); + mPageTransformer = transformer; + setChildrenDrawingOrderEnabledCompat(hasTransformer); + if (hasTransformer) { + mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; + } else { + mDrawingOrder = DRAW_ORDER_DEFAULT; + } + if (needsPopulate) populate(); + } + } + + void setChildrenDrawingOrderEnabledCompat(boolean enable) { + if (Build.VERSION.SDK_INT >= 7) { + if (mSetChildrenDrawingOrderEnabled == null) { + try { + mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( + "setChildrenDrawingOrderEnabled", new Class[]{Boolean.TYPE}); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); + } + } + try { + mSetChildrenDrawingOrderEnabled.invoke(this, enable); + } catch (Exception e) { + Log.e(TAG, "Error changing children drawing order", e); + } + } + } + + @Override + protected int getChildDrawingOrder(int childCount, int i) { + final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i; + final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex; + return result; + } + + /** + * Set a separate OnPageChangeListener for internal use by the support library. + * + * @param listener Listener to set + * @return The old listener that was set, if any. + */ + OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { + OnPageChangeListener oldListener = mInternalPageChangeListener; + mInternalPageChangeListener = listener; + return oldListener; + } + + /** + * Returns the number of pages that will be retained to either side of the + * current page in the view hierarchy in an idle state. Defaults to 1. + * + * @return How many pages will be kept offscreen on either side + * @see #setOffscreenPageLimit(int) + */ + public int getOffscreenPageLimit() { + return mOffscreenPageLimit; + } + + /** + * Set the number of pages that should be retained to either side of the + * current page in the view hierarchy in an idle state. Pages beyond this + * limit will be recreated from the adapter when needed. + *

+ *

This is offered as an optimization. If you know in advance the number + * of pages you will need to support or have lazy-loading mechanisms in place + * on your pages, tweaking this setting can have benefits in perceived smoothness + * of paging animations and interaction. If you have a small number of pages (3-4) + * that you can keep active all at once, less time will be spent in layout for + * newly created view subtrees as the user pages back and forth.

+ *

+ *

You should keep this limit low, especially if your pages have complex layouts. + * This setting defaults to 1.

+ * + * @param limit How many pages will be kept offscreen in an idle state. + */ + public void setOffscreenPageLimit(int limit) { + if (limit < DEFAULT_OFFSCREEN_PAGES) { + Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + + DEFAULT_OFFSCREEN_PAGES); + limit = DEFAULT_OFFSCREEN_PAGES; + } + if (limit != mOffscreenPageLimit) { + mOffscreenPageLimit = limit; + populate(); + } + } + + /** + * Return the margin between pages. + * + * @return The size of the margin in pixels + */ + public int getPageMargin() { + return mPageMargin; + } + + /** + * Set the margin between pages. + * + * @param marginPixels Distance between adjacent pages in pixels + * @see #getPageMargin() + * @see #setPageMarginDrawable(Drawable) + * @see #setPageMarginDrawable(int) + */ + public void setPageMargin(int marginPixels) { + final int oldMargin = mPageMargin; + mPageMargin = marginPixels; + + final int width = getWidth(); + recomputeScrollPosition(width, width, marginPixels, oldMargin); + + requestLayout(); + } + + /** + * Set a drawable that will be used to fill the margin between pages. + * + * @param d Drawable to display between pages + */ + public void setPageMarginDrawable(Drawable d) { + mMarginDrawable = d; + if (d != null) refreshDrawableState(); + setWillNotDraw(d == null); + invalidate(); + } + + /** + * Set a drawable that will be used to fill the margin between pages. + * + * @param resId Resource ID of a drawable to display between pages + */ + public void setPageMarginDrawable(int resId) { + setPageMarginDrawable(getContext().getResources().getDrawable(resId)); + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || who == mMarginDrawable; + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + final Drawable d = mMarginDrawable; + if (d != null && d.isStateful()) { + d.setState(getDrawableState()); + } + } + + // We want the duration of the page snap animation to be influenced by the distance that + // the screen has to travel, however, we don't want this duration to be effected in a + // purely linear fashion. Instead, we use this method to moderate the effect that the distance + // of travel has on the overall snap duration. + float distanceInfluenceForSnapDuration(float f) { + f -= 0.5f; // center the values about 0. + f *= 0.3f * Math.PI / 2.0f; + return (float) Math.sin(f); + } + + /** + * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. + * + * @param x the number of pixels to scroll by on the X axis + * @param y the number of pixels to scroll by on the Y axis + */ + void smoothScrollTo(int x, int y) { + smoothScrollTo(x, y, 0); + } + + /** + * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. + * + * @param x the number of pixels to scroll by on the X axis + * @param y the number of pixels to scroll by on the Y axis + * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) + */ + void smoothScrollTo(int x, int y, int velocity) { + if (getChildCount() == 0) { + // Nothing to do. + setScrollingCacheEnabled(false); + return; + } + int sx = getScrollX(); + int sy = getScrollY(); + int dx = x - sx; + int dy = y - sy; + if (dx == 0 && dy == 0) { + completeScroll(false); + populate(); + setScrollState(SCROLL_STATE_IDLE); + return; + } + + setScrollingCacheEnabled(true); + setScrollState(SCROLL_STATE_SETTLING); + + final int width = getClientWidth(); + final int halfWidth = width / 2; + final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); + final float distance = halfWidth + halfWidth * + distanceInfluenceForSnapDuration(distanceRatio); + + int duration = 0; + velocity = Math.abs(velocity); + if (velocity > 0) { + duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); + } else { + final float pageWidth = width * mAdapter.getPageWidth(mCurItem); + final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); + duration = (int) ((pageDelta + 1) * 100); + } + duration = Math.min(duration, MAX_SETTLE_DURATION); + + mScroller.startScroll(sx, sy, dx, dy, duration); + postInvalidateOnAnimation(); + } + + ItemInfo addNewItem(int position, int index) { + ItemInfo ii = new ItemInfo(); + ii.position = position; + ii.object = mAdapter.instantiateItem(this, position); + ii.widthFactor = mAdapter.getPageWidth(position); + if (index < 0 || index >= mItems.size()) { + mItems.add(ii); + } else { + mItems.add(index, ii); + } + return ii; + } + + void dataSetChanged() { + // This method only gets called if our observer is attached, so mAdapter is non-null. + + final int adapterCount = mAdapter.getCount(); + mExpectedAdapterCount = adapterCount; + boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && + mItems.size() < adapterCount; + int newCurrItem = mCurItem; + + boolean isUpdating = false; + for (int i = 0; i < mItems.size(); i++) { + final ItemInfo ii = mItems.get(i); + final int newPos = mAdapter.getItemPosition(ii.object); + + if (newPos == BasePageAdapter.POSITION_UNCHANGED) { + continue; + } + + if (newPos == BasePageAdapter.POSITION_NONE) { + mItems.remove(i); + i--; + + if (!isUpdating) { + mAdapter.startUpdate(this); + isUpdating = true; + } + + mAdapter.destroyItem(this, ii.position, ii.object); + needPopulate = true; + + if (mCurItem == ii.position) { + // Keep the current item in the valid range + newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); + needPopulate = true; + } + continue; + } + + if (ii.position != newPos) { + if (ii.position == mCurItem) { + // Our current item changed position. Follow it. + newCurrItem = newPos; + } + + ii.position = newPos; + needPopulate = true; + } + } + + if (isUpdating) { + mAdapter.finishUpdate(this); + } + + Collections.sort(mItems, COMPARATOR); + + if (needPopulate) { + // Reset our known page widths; populate will recompute them. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) { + lp.widthFactor = 0.f; + } + } + + setCurrentItemInternal(newCurrItem, false, true); + requestLayout(); + } + } + + void populate() { + populate(mCurItem); + } + + void populate(int newCurrentItem) { + ItemInfo oldCurInfo = null; + int focusDirection = View.FOCUS_FORWARD; + if (mCurItem != newCurrentItem) { + focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT; + oldCurInfo = infoForPosition(mCurItem); + mCurItem = newCurrentItem; + } + + if (mAdapter == null) { + sortChildDrawingOrder(); + return; + } + + // Bail now if we are waiting to populate. This is to hold off + // on creating views from the time the user releases their finger to + // fling to a new position until we have finished the scroll to + // that position, avoiding glitches from happening at that point. + if (mPopulatePending) { + if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); + sortChildDrawingOrder(); + return; + } + + // Also, don't populate until we are attached to a window. This is to + // avoid trying to populate before we have restored our view hierarchy + // state and conflicting with what is restored. + if (getWindowToken() == null) { + return; + } + + mAdapter.startUpdate(this); + + final int pageLimit = mOffscreenPageLimit; + final int startPos = Math.max(0, mCurItem - pageLimit); + final int N = mAdapter.getCount(); + final int endPos = Math.min(N - 1, mCurItem + pageLimit); + + /*if (N != mExpectedAdapterCount) { + String resName; + try { + resName = getResources().getResourceName(getId()); + } catch (Resources.NotFoundException e) { + resName = Integer.toHexString(getId()); + } + throw new IllegalStateException("The application's PageAdapter changed the adapter's" + + " contents without calling PageAdapter#notifyDataSetChanged!" + + " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N + + " Page id: " + resName + + " Page class: " + getClass() + + " Problematic adapter: " + mAdapter.getClass()); + }*/ + + // Locate the currently focused item or add it if needed. + int curIndex = -1; + ItemInfo curItem = null; + for (curIndex = 0; curIndex < mItems.size(); curIndex++) { + final ItemInfo ii = mItems.get(curIndex); + if (ii.position >= mCurItem) { + if (ii.position == mCurItem) curItem = ii; + break; + } + } + + if (curItem == null && N > 0) { + curItem = addNewItem(mCurItem, curIndex); + } + + // Fill 3x the available width or up to the number of offscreen + // pages requested to either side, whichever is larger. + // If we have no current item we have no work to do. + if (curItem != null) { + float extraWidthLeft = 0.f; + int itemIndex = curIndex - 1; + ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + final int clientWidth = getClientWidth(); + final float leftWidthNeeded = clientWidth <= 0 ? 0 : + 2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth; + for (int pos = mCurItem - 1; pos >= 0; pos--) { + if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { + if (ii == null) { + break; + } + if (pos == ii.position && !ii.scrolling) { + mItems.remove(itemIndex); + mAdapter.destroyItem(this, pos, ii.object); + if (DEBUG) { + Log.i(TAG, "populate() - destroyItem() with pos: " + pos + + " view: " + ((View) ii.object)); + } + itemIndex--; + curIndex--; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } + } else if (ii != null && pos == ii.position) { + extraWidthLeft += ii.widthFactor; + itemIndex--; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } else { + ii = addNewItem(pos, itemIndex + 1); + extraWidthLeft += ii.widthFactor; + curIndex++; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } + } + + float extraWidthRight = curItem.widthFactor; + itemIndex = curIndex + 1; + if (extraWidthRight < 2.f) { + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + final float rightWidthNeeded = clientWidth <= 0 ? 0 : + (float) getPaddingRight() / (float) clientWidth + 2.f; + for (int pos = mCurItem + 1; pos < N; pos++) { + if (extraWidthRight >= rightWidthNeeded && pos > endPos) { + if (ii == null) { + break; + } + if (pos == ii.position && !ii.scrolling) { + mItems.remove(itemIndex); + mAdapter.destroyItem(this, pos, ii.object); + if (DEBUG) { + Log.i(TAG, "populate() - destroyItem() with pos: " + pos + + " view: " + ((View) ii.object)); + } + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } + } else if (ii != null && pos == ii.position) { + extraWidthRight += ii.widthFactor; + itemIndex++; + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } else { + ii = addNewItem(pos, itemIndex); + itemIndex++; + extraWidthRight += ii.widthFactor; + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } + } + } + + calculatePageOffsets(curItem, curIndex, oldCurInfo); + } + + if (DEBUG) { + Log.i(TAG, "Current page list:"); + for (int i = 0; i < mItems.size(); i++) { + Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); + } + } + + mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); + + mAdapter.finishUpdate(this); + + // Check width measurement of current pages and drawing sort order. + // Update LayoutParams as needed. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + lp.childIndex = i; + if (!lp.isDecor && lp.widthFactor == 0.f) { + // 0 means requery the adapter for this, it doesn't have a valid width. + final ItemInfo ii = infoForChild(child); + if (ii != null) { + lp.widthFactor = ii.widthFactor; + lp.position = ii.position; + } + } + } + sortChildDrawingOrder(); + + if (hasFocus()) { + View currentFocused = findFocus(); + ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; + if (ii == null || ii.position != mCurItem) { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + if (child.requestFocus(focusDirection)) { + break; + } + } + } + } + } + } + + private void sortChildDrawingOrder() { + if (mDrawingOrder != DRAW_ORDER_DEFAULT) { + if (mDrawingOrderedChildren == null) { + mDrawingOrderedChildren = new ArrayList(); + } else { + mDrawingOrderedChildren.clear(); + } + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + mDrawingOrderedChildren.add(child); + } + Collections.sort(mDrawingOrderedChildren, sPositionComparator); + } + } + + private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { + final int N = mAdapter.getCount(); + final int width = getClientWidth(); + final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; + // Fix up offsets for later layout. + if (oldCurInfo != null) { + final int oldCurPosition = oldCurInfo.position; + // Base offsets off of oldCurInfo. + if (oldCurPosition < curItem.position) { + int itemIndex = 0; + ItemInfo ii = null; + float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; + for (int pos = oldCurPosition + 1; + pos <= curItem.position && itemIndex < mItems.size(); pos++) { + ii = mItems.get(itemIndex); + while (pos > ii.position && itemIndex < mItems.size() - 1) { + itemIndex++; + ii = mItems.get(itemIndex); + } + while (pos < ii.position) { + // We don't have an item populated for this, + // ask the adapter for an offset. + offset += mAdapter.getPageWidth(pos) + marginOffset; + pos++; + } + ii.offset = offset; + offset += ii.widthFactor + marginOffset; + } + } else if (oldCurPosition > curItem.position) { + int itemIndex = mItems.size() - 1; + ItemInfo ii = null; + float offset = oldCurInfo.offset; + for (int pos = oldCurPosition - 1; + pos >= curItem.position && itemIndex >= 0; pos--) { + ii = mItems.get(itemIndex); + while (pos < ii.position && itemIndex > 0) { + itemIndex--; + ii = mItems.get(itemIndex); + } + while (pos > ii.position) { + // We don't have an item populated for this, + // ask the adapter for an offset. + offset -= mAdapter.getPageWidth(pos) + marginOffset; + pos--; + } + offset -= ii.widthFactor + marginOffset; + ii.offset = offset; + } + } + } + + // Base all offsets off of curItem. + final int itemCount = mItems.size(); + float offset = curItem.offset; + int pos = curItem.position - 1; + mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; + mLastOffset = curItem.position == N - 1 ? + curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; + // Previous pages + for (int i = curIndex - 1; i >= 0; i--, pos--) { + final ItemInfo ii = mItems.get(i); + while (pos > ii.position) { + offset -= mAdapter.getPageWidth(pos--) + marginOffset; + } + offset -= ii.widthFactor + marginOffset; + ii.offset = offset; + if (ii.position == 0) mFirstOffset = offset; + } + offset = curItem.offset + curItem.widthFactor + marginOffset; + pos = curItem.position + 1; + // Next pages + for (int i = curIndex + 1; i < itemCount; i++, pos++) { + final ItemInfo ii = mItems.get(i); + while (pos < ii.position) { + offset += mAdapter.getPageWidth(pos++) + marginOffset; + } + if (ii.position == N - 1) { + mLastOffset = offset + ii.widthFactor - 1; + } + ii.offset = offset; + offset += ii.widthFactor + marginOffset; + } + + mNeedCalculatePageOffsets = false; + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.position = mCurItem; + if (mAdapter != null) { + ss.adapterState = mAdapter.saveState(); + } + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + + if (mAdapter != null) { + mAdapter.restoreState(ss.adapterState, ss.loader); + setCurrentItemInternal(ss.position, false, true); + } else { + mRestoredCurItem = ss.position; + mRestoredAdapterState = ss.adapterState; + mRestoredClassLoader = ss.loader; + } + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (!checkLayoutParams(params)) { + params = generateLayoutParams(params); + } + final LayoutParams lp = (LayoutParams) params; + lp.isDecor |= child instanceof Decor; + if (mInLayout) { + if (lp != null && lp.isDecor) { + throw new IllegalStateException("Cannot add page decor view during layout"); + } + lp.needsMeasure = true; + addViewInLayout(child, index, params); + } else { + super.addView(child, index, params); + } + + if (USE_CACHE) { + if (child.getVisibility() != GONE) { + child.setDrawingCacheEnabled(mScrollingCacheEnabled); + } else { + child.setDrawingCacheEnabled(false); + } + } + } + + @Override + public void removeView(View view) { + if (mInLayout) { + removeViewInLayout(view); + } else { + super.removeView(view); + } + } + + ItemInfo infoForChild(View child) { + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (mAdapter.isViewFromObject(child, ii.object)) { + return ii; + } + } + return null; + } + + ItemInfo infoForAnyChild(View child) { + ViewParent parent; + while ((parent = child.getParent()) != this) { + if (parent == null || !(parent instanceof View)) { + return null; + } + child = (View) parent; + } + return infoForChild(child); + } + + ItemInfo infoForPosition(int position) { + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (ii.position == position) { + return ii; + } + } + return null; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mFirstLayout = true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // For simple implementation, our internal size is always 0. + // We depend on the container to specify the layout size of + // our view. We can't really know what it is since we will be + // adding and removing different arbitrary views and do not + // want the layout to change as this happens. + + setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), + getDefaultSize(0, heightMeasureSpec)); + + final int measuredWidth = getMeasuredWidth(); + final int maxGutterSize = measuredWidth / 10; + mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); + + // Children are just made to fill our space. + int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); + int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); + + /* + * Make sure all children have been properly measured. Decor views first. + * Right now we cheat and make this less complicated by assuming decor + * views won't intersect. We will pin to edges based on gravity. + */ + int size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp != null && lp.isDecor) { + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + int widthMode = MeasureSpec.AT_MOST; + int heightMode = MeasureSpec.AT_MOST; + boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; + boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; + + if (consumeVertical) { + widthMode = MeasureSpec.EXACTLY; + } else if (consumeHorizontal) { + heightMode = MeasureSpec.EXACTLY; + } + + int widthSize = childWidthSize; + int heightSize = childHeightSize; + if (lp.width != LayoutParams.WRAP_CONTENT) { + widthMode = MeasureSpec.EXACTLY; + if (lp.width != LayoutParams.FILL_PARENT) { + widthSize = lp.width; + } + } + if (lp.height != LayoutParams.WRAP_CONTENT) { + heightMode = MeasureSpec.EXACTLY; + if (lp.height != LayoutParams.FILL_PARENT) { + heightSize = lp.height; + } + } + final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); + final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); + child.measure(widthSpec, heightSpec); + + if (consumeVertical) { + childHeightSize -= child.getMeasuredHeight(); + } else if (consumeHorizontal) { + childWidthSize -= child.getMeasuredWidth(); + } + } + } + } + + mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); + mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); + + // Make sure we have created all fragments that we need to have shown. + mInLayout = true; + populate(); + mInLayout = false; + + // Page views next. + size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child + + ": " + mChildWidthMeasureSpec); + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp == null || !lp.isDecor) { + final int widthSpec = MeasureSpec.makeMeasureSpec( + (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); + child.measure(widthSpec, mChildHeightMeasureSpec); + } + } + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + // Make sure scroll position is set correctly. + if (w != oldw) { + recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); + } + } + + private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { + if (oldWidth > 0 && !mItems.isEmpty()) { + final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin; + final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight() + + oldMargin; + final int xpos = getScrollX(); + final float pageOffset = (float) xpos / oldWidthWithMargin; + final int newOffsetPixels = (int) (pageOffset * widthWithMargin); + + scrollTo(newOffsetPixels, getScrollY()); + if (!mScroller.isFinished()) { + // We now return to your regularly scheduled scroll, already in progress. + final int newDuration = mScroller.getDuration() - mScroller.timePassed(); + ItemInfo targetInfo = infoForPosition(mCurItem); + mScroller.startScroll(newOffsetPixels, 0, + (int) (targetInfo.offset * width), 0, newDuration); + } + } else { + final ItemInfo ii = infoForPosition(mCurItem); + final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; + final int scrollPos = (int) (scrollOffset * + (width - getPaddingLeft() - getPaddingRight())); + if (scrollPos != getScrollX()) { + completeScroll(false); + scrollTo(scrollPos, getScrollY()); + } + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int count = getChildCount(); + int width = r - l; + int height = b - t; + int paddingLeft = getPaddingLeft(); + int paddingTop = getPaddingTop(); + int paddingRight = getPaddingRight(); + int paddingBottom = getPaddingBottom(); + final int scrollX = getScrollX(); + + int decorCount = 0; + + // First pass - decor views. We need to do this in two passes so that + // we have the proper offsets for non-decor views later. + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + int childLeft = 0; + int childTop = 0; + if (lp.isDecor) { + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + switch (hgrav) { + default: + childLeft = paddingLeft; + break; + case Gravity.LEFT: + childLeft = paddingLeft; + paddingLeft += child.getMeasuredWidth(); + break; + case Gravity.CENTER_HORIZONTAL: + childLeft = Math.max((width - child.getMeasuredWidth()) / 2, + paddingLeft); + break; + case Gravity.RIGHT: + childLeft = width - paddingRight - child.getMeasuredWidth(); + paddingRight += child.getMeasuredWidth(); + break; + } + switch (vgrav) { + default: + childTop = paddingTop; + break; + case Gravity.TOP: + childTop = paddingTop; + paddingTop += child.getMeasuredHeight(); + break; + case Gravity.CENTER_VERTICAL: + childTop = Math.max((height - child.getMeasuredHeight()) / 2, + paddingTop); + break; + case Gravity.BOTTOM: + childTop = height - paddingBottom - child.getMeasuredHeight(); + paddingBottom += child.getMeasuredHeight(); + break; + } + childLeft += scrollX; + child.layout(childLeft, childTop, + childLeft + child.getMeasuredWidth(), + childTop + child.getMeasuredHeight()); + decorCount++; + } + } + } + + final int childWidth = width - paddingLeft - paddingRight; + // Page views. Do this once we have the right padding offsets from above. + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + ItemInfo ii; + if (!lp.isDecor && (ii = infoForChild(child)) != null) { + int loff = (int) (childWidth * ii.offset); + int childLeft = paddingLeft + loff; + int childTop = paddingTop; + if (lp.needsMeasure) { + // This was added during layout and needs measurement. + // Do it now that we know what we're working with. + lp.needsMeasure = false; + final int widthSpec = MeasureSpec.makeMeasureSpec( + (int) (childWidth * lp.widthFactor), + MeasureSpec.EXACTLY); + final int heightSpec = MeasureSpec.makeMeasureSpec( + (int) (height - paddingTop - paddingBottom), + MeasureSpec.EXACTLY); + child.measure(widthSpec, heightSpec); + } + if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object + + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() + + "x" + child.getMeasuredHeight()); + child.layout(childLeft, childTop, + childLeft + child.getMeasuredWidth(), + childTop + child.getMeasuredHeight()); + } + } + } + mTopPageBounds = paddingTop; + mBottomPageBounds = height - paddingBottom; + mDecorChildCount = decorCount; + + if (mFirstLayout) { + scrollToItem(mCurItem, false, 0, true); + } + mFirstLayout = false; + } + + @Override + public void computeScroll() { + if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { + int oldX = getScrollX(); + int oldY = getScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + + if (oldX != x || oldY != y) { + scrollTo(x, y); + if (!pageScrolled(x)) { + mScroller.abortAnimation(); + scrollTo(0, y); + } + } + + // Keep on drawing until the animation has finished. + postInvalidateOnAnimation(); + return; + } + + // Done with scroll, clean up state. + completeScroll(true); + } + + private boolean pageScrolled(int xpos) { + if (mItems.size() == 0) { + mCalledSuper = false; + onPageScrolled(0, 0, 0); + if (!mCalledSuper) { + throw new IllegalStateException( + "onPageScrolled did not call superclass implementation"); + } + return false; + } + final ItemInfo ii = infoForCurrentScrollPosition(); + final int width = getClientWidth(); + final int widthWithMargin = width + mPageMargin; + final float marginOffset = (float) mPageMargin / width; + final int currentPage = ii.position; + final float pageOffset = (((float) xpos / width) - ii.offset) / + (ii.widthFactor + marginOffset); + final int offsetPixels = (int) (pageOffset * widthWithMargin); + + mCalledSuper = false; + onPageScrolled(currentPage, pageOffset, offsetPixels); + if (!mCalledSuper) { + throw new IllegalStateException( + "onPageScrolled did not call superclass implementation"); + } + return true; + } + + /** + * This method will be invoked when the current page is scrolled, either as part + * of a programmatically initiated smooth scroll or a user initiated touch scroll. + * If you override this method you must call through to the superclass implementation + * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled + * returns. + * + * @param position Position index of the first page currently being displayed. + * Page position+1 will be visible if positionOffset is nonzero. + * @param offset Value from [0, 1) indicating the offset from the page at position. + * @param offsetPixels Value in pixels indicating the offset from position. + */ + + protected void onPageScrolled(int position, float offset, int offsetPixels) { + // Offset any decor views if needed - keep them on-screen at all times. + if (mDecorChildCount > 0) { + final int scrollX = getScrollX(); + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + final int width = getWidth(); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) continue; + + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + int childLeft = 0; + switch (hgrav) { + default: + childLeft = paddingLeft; + break; + case Gravity.LEFT: + childLeft = paddingLeft; + paddingLeft += child.getWidth(); + break; + case Gravity.CENTER_HORIZONTAL: + childLeft = Math.max((width - child.getMeasuredWidth()) / 2, + paddingLeft); + break; + case Gravity.RIGHT: + childLeft = width - paddingRight - child.getMeasuredWidth(); + paddingRight += child.getMeasuredWidth(); + break; + } + childLeft += scrollX; + + final int childOffset = childLeft - child.getLeft(); + if (childOffset != 0) { + child.offsetLeftAndRight(childOffset); + } + } + } + + dispatchOnPageScrolled(position, offset, offsetPixels); + + if (mPageTransformer != null) { + final int scrollX = getScrollX(); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (lp.isDecor) continue; + + final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth(); + mPageTransformer.transformPage(child, transformPos); + } + } + + mCalledSuper = true; + } + + private void dispatchOnPageScrolled(int position, float offset, int offsetPixels) { + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); + } + if (mOnPageChangeListeners != null) { + for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) { + OnPageChangeListener listener = mOnPageChangeListeners.get(i); + if (listener != null) { + listener.onPageScrolled(position, offset, offsetPixels); + } + } + } + if (mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); + } + } + + private void dispatchOnPageSelected(int position) { + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(position); + mOnPageChangeListener.onPageChange(getChildAt(position), position); + } + if (mOnPageChangeListeners != null) { + for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) { + OnPageChangeListener listener = mOnPageChangeListeners.get(i); + if (listener != null) { + listener.onPageSelected(position); + } + } + } + if (mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(position); + } + } + + private void dispatchOnScrollStateChanged(int state) { + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrollStateChanged(state); + } + if (mOnPageChangeListeners != null) { + for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) { + OnPageChangeListener listener = mOnPageChangeListeners.get(i); + if (listener != null) { + listener.onPageScrollStateChanged(state); + } + } + } + if (mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageScrollStateChanged(state); + } + } + + private void completeScroll(boolean postEvents) { + boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; + if (needPopulate) { + // Done with scroll, no longer want to cache view drawing. + setScrollingCacheEnabled(false); + mScroller.abortAnimation(); + int oldX = getScrollX(); + int oldY = getScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + if (oldX != x || oldY != y) { + scrollTo(x, y); + if (x != oldX) { + pageScrolled(x); + } + } + } + mPopulatePending = false; + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (ii.scrolling) { + needPopulate = true; + ii.scrolling = false; + } + } + if (needPopulate) { + if (postEvents) { + postOnAnimation(mEndScrollRunnable); + } else { + mEndScrollRunnable.run(); + } + } + } + + private boolean isGutterDrag(float x, float dx) { + return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0); + } + + private void enableLayers(boolean enable) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final int layerType = enable ? + View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE; + getChildAt(i).setLayerType(layerType, null); + } + } + + private boolean mTouchScrollEnabled =true; + public void setTouchEnabled(boolean enabled){ + mTouchScrollEnabled =enabled; + } + + public void setScrollEnabled(boolean enabled){ + mTouchScrollEnabled =enabled; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + /* + * This method JUST determines whether we want to intercept the motion. + * If we return true, onMotionEvent will be called and we do the actual + * scrolling there. + */ + if(!mTouchScrollEnabled) + return false; + + final int action = ev.getAction() & MotionEvent.ACTION_MASK; + + // Always take care of the touch gesture being complete. + if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { + // Release the drag. + if (DEBUG) Log.v(TAG, "Intercept done!"); + resetTouch(); + return false; + } + + // Nothing more to do here if we have decided whether or not we + // are dragging. + if (action != MotionEvent.ACTION_DOWN) { + if (mIsBeingDragged) { + if (DEBUG) Log.v(TAG, "Intercept returning true!"); + return true; + } + if (mIsUnableToDrag) { + if (DEBUG) Log.v(TAG, "Intercept returning false!"); + return false; + } + } + + switch (action) { + case MotionEvent.ACTION_MOVE: { + /* + * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check + * whether the user has moved far enough from his original down touch. + */ + + /* + * Locally do absolute value. mLastMotionY is set to the y value + * of the down event. + */ + final int activePointerId = mActivePointerId; + if (activePointerId == INVALID_POINTER) { + // If we don't have a valid id, the touch down wasn't on content. + break; + } + + final int pointerIndex = ev.findPointerIndex(activePointerId); + final float x = ev.getX(pointerIndex); + final float dx = x - mLastMotionX; + final float xDiff = Math.abs(dx); + final float y = ev.getY(pointerIndex); + final float yDiff = Math.abs(y - mInitialMotionY); + if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); + + if (dx != 0 && !isGutterDrag(mLastMotionX, dx) && + canScroll(this, false, (int) dx, (int) x, (int) y)) { + // Nested view has scrollable area under this point. Let it be handled there. + mLastMotionX = x; + mLastMotionY = y; + mIsUnableToDrag = true; + return false; + } + if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) { + if (DEBUG) Log.v(TAG, "Starting drag!"); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + setScrollState(SCROLL_STATE_DRAGGING); + mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop : + mInitialMotionX - mTouchSlop; + mLastMotionY = y; + setScrollingCacheEnabled(true); + } else if (yDiff > mTouchSlop) { + // The finger has moved enough in the vertical + // direction to be counted as a drag... abort + // any attempt to drag horizontally, to work correctly + // with children that have scrolling containers. + if (DEBUG) Log.v(TAG, "Starting unable to drag!"); + mIsUnableToDrag = true; + } + if (mIsBeingDragged) { + // Scroll to follow the motion event + if (performDrag(x)) { + postInvalidateOnAnimation(); + } + } + break; + } + + case MotionEvent.ACTION_DOWN: { + /* + * Remember location of down touch. + * ACTION_DOWN always refers to pointer index 0. + */ + mLastMotionX = mInitialMotionX = ev.getX(); + mLastMotionY = mInitialMotionY = ev.getY(); + mActivePointerId = ev.getPointerId(0); + mIsUnableToDrag = false; + + mScroller.computeScrollOffset(); + if (mScrollState == SCROLL_STATE_SETTLING && + Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { + // Let the user 'catch' the page as it animates. + mScroller.abortAnimation(); + mPopulatePending = false; + populate(); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + setScrollState(SCROLL_STATE_DRAGGING); + } else { + completeScroll(false); + mIsBeingDragged = false; + } + + if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY + + " mIsBeingDragged=" + mIsBeingDragged + + "mIsUnableToDrag=" + mIsUnableToDrag); + break; + } + + case MotionEvent.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + /* + * The only time we want to intercept motion events is if we are in the + * drag mode. + */ + return mIsBeingDragged; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (mFakeDragging) { + // A fake drag is in progress already, ignore this real one + // but still eat the touch events. + // (It is likely that the user is multi-touching the screen.) + return true; + } + + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { + // Don't handle edge touches immediately -- they may actually belong to one of our + // descendants. + return false; + } + + if (mAdapter == null || mAdapter.getCount() == 0) { + // Nothing to present or scroll; nothing to touch. + return false; + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + final int action = ev.getAction(); + boolean needsInvalidate = false; + + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + mScroller.abortAnimation(); + mPopulatePending = false; + populate(); + + // Remember where the motion event started + mLastMotionX = mInitialMotionX = ev.getX(); + mLastMotionY = mInitialMotionY = ev.getY(); + mActivePointerId = ev.getPointerId(0); + break; + } + case MotionEvent.ACTION_MOVE: + if (!mIsBeingDragged) { + final int pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex == -1) { + // A child has consumed some touch events and put us into an inconsistent state. + needsInvalidate = resetTouch(); + break; + } + final float x = ev.getX(pointerIndex); + final float xDiff = Math.abs(x - mLastMotionX); + final float y = ev.getY(pointerIndex); + final float yDiff = Math.abs(y - mLastMotionY); + if (DEBUG) + Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); + if (xDiff > mTouchSlop && xDiff > yDiff) { + if (DEBUG) Log.v(TAG, "Starting drag!"); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : + mInitialMotionX - mTouchSlop; + mLastMotionY = y; + setScrollState(SCROLL_STATE_DRAGGING); + setScrollingCacheEnabled(true); + + // Disallow Parent Intercept, just in case + ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + } + } + // Not else! Note that mIsBeingDragged can be set above. + if (mIsBeingDragged) { + // Scroll to follow the motion event + final int activePointerIndex = ev.findPointerIndex( + mActivePointerId); + final float x = ev.getX(activePointerIndex); + needsInvalidate |= performDrag(x); + } + break; + case MotionEvent.ACTION_UP: + if (mIsBeingDragged) { + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialVelocity = (int) velocityTracker.getXVelocity( + mActivePointerId); + mPopulatePending = true; + final int width = getClientWidth(); + final int scrollX = getScrollX(); + final ItemInfo ii = infoForCurrentScrollPosition(); + final int currentPage = ii.position; + final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; + final int activePointerIndex = + ev.findPointerIndex(mActivePointerId); + final float x = ev.getX(activePointerIndex); + final int totalDelta = (int) (x - mInitialMotionX); + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, + totalDelta); + setCurrentItemInternal(nextPage, true, true, initialVelocity); + + needsInvalidate = resetTouch(); + } + break; + case MotionEvent.ACTION_CANCEL: + if (mIsBeingDragged) { + scrollToItem(mCurItem, true, 0, false); + needsInvalidate = resetTouch(); + } + break; + case MotionEvent.ACTION_POINTER_DOWN: { + final int index = ev.getActionIndex(); + final float x = ev.getX(index); + mLastMotionX = x; + mActivePointerId = ev.getPointerId(index); + break; + } + case MotionEvent.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId)); + break; + } + if (needsInvalidate) { + postInvalidateOnAnimation(); + } + return true; + } + + private boolean resetTouch() { + mActivePointerId = INVALID_POINTER; + endDrag(); + + mLeftEdge.onRelease(); + mRightEdge.onRelease(); + return true; + } + + private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) { + final ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(disallowIntercept); + } + } + + private boolean performDrag(float x) { + boolean needsInvalidate = false; + + final float deltaX = mLastMotionX - x; + mLastMotionX = x; + + float oldScrollX = getScrollX(); + float scrollX = oldScrollX + deltaX; + final int width = getClientWidth(); + + float leftBound = width * mFirstOffset; + float rightBound = width * mLastOffset; + boolean leftAbsolute = true; + boolean rightAbsolute = true; + + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + if (firstItem.position != 0) { + leftAbsolute = false; + leftBound = firstItem.offset * width; + } + if (lastItem.position != mAdapter.getCount() - 1) { + rightAbsolute = false; + rightBound = lastItem.offset * width; + } + + if (scrollX < leftBound) { + if (leftAbsolute) { + float over = leftBound - scrollX; + mLeftEdge.onPull(Math.abs(over) / width); + } + scrollX = leftBound; + } else if (scrollX > rightBound) { + if (rightAbsolute) { + float over = scrollX - rightBound; + mRightEdge.onPull(Math.abs(over) / width); + } + scrollX = rightBound; + } + // Don't lose the rounded component + mLastMotionX += scrollX - (int) scrollX; + scrollTo((int) scrollX, getScrollY()); + pageScrolled((int) scrollX); + + return needsInvalidate; + } + + /** + * @return Info about the page at the current scroll position. + * This can be synthetic for a missing middle page; the 'object' field can be null. + */ + private ItemInfo infoForCurrentScrollPosition() { + final int width = getClientWidth(); + final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; + final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; + int lastPos = -1; + float lastOffset = 0.f; + float lastWidth = 0.f; + boolean first = true; + + ItemInfo lastItem = null; + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + float offset; + if (!first && ii.position != lastPos + 1) { + // Create a synthetic item for a missing page. + ii = mTempItem; + ii.offset = lastOffset + lastWidth + marginOffset; + ii.position = lastPos + 1; + ii.widthFactor = mAdapter.getPageWidth(ii.position); + i--; + } + offset = ii.offset; + + final float leftBound = offset; + final float rightBound = offset + ii.widthFactor + marginOffset; + if (first || scrollOffset >= leftBound) { + if (scrollOffset < rightBound || i == mItems.size() - 1) { + return ii; + } + } else { + return lastItem; + } + first = false; + lastPos = ii.position; + lastOffset = offset; + lastWidth = ii.widthFactor; + lastItem = ii; + } + + return lastItem; + } + + private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { + int targetPage; + if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { + targetPage = velocity > 0 ? currentPage : currentPage + 1; + } else { + final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; + targetPage = (int) (currentPage + pageOffset + truncator); + } + + if (mItems.size() > 0) { + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + + // Only let the user target pages we have items for + targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); + } + + return targetPage; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + boolean needsInvalidate = false; + + final int overScrollMode = getOverScrollMode(); + if (overScrollMode == View.OVER_SCROLL_ALWAYS || + (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && + mAdapter != null && mAdapter.getCount() > 1)) { + if (!mLeftEdge.isFinished()) { + final int restoreCount = canvas.save(); + final int height = getHeight() - getPaddingTop() - getPaddingBottom(); + final int width = getWidth(); + + canvas.rotate(270); + canvas.translate(-height + getPaddingTop(), mFirstOffset * width); + mLeftEdge.setSize(height, width); + needsInvalidate |= mLeftEdge.draw(canvas); + canvas.restoreToCount(restoreCount); + } + if (!mRightEdge.isFinished()) { + final int restoreCount = canvas.save(); + final int width = getWidth(); + final int height = getHeight() - getPaddingTop() - getPaddingBottom(); + + canvas.rotate(90); + canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); + mRightEdge.setSize(height, width); + needsInvalidate |= mRightEdge.draw(canvas); + canvas.restoreToCount(restoreCount); + } + } else { + mLeftEdge.finish(); + mRightEdge.finish(); + } + + if (needsInvalidate) { + // Keep animating + postInvalidateOnAnimation(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // Draw the margin drawable between pages if needed. + if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { + final int scrollX = getScrollX(); + final int width = getWidth(); + + final float marginOffset = (float) mPageMargin / width; + int itemIndex = 0; + ItemInfo ii = mItems.get(0); + float offset = ii.offset; + final int itemCount = mItems.size(); + final int firstPos = ii.position; + final int lastPos = mItems.get(itemCount - 1).position; + for (int pos = firstPos; pos < lastPos; pos++) { + while (pos > ii.position && itemIndex < itemCount) { + ii = mItems.get(++itemIndex); + } + + float drawAt; + if (pos == ii.position) { + drawAt = (ii.offset + ii.widthFactor) * width; + offset = ii.offset + ii.widthFactor + marginOffset; + } else { + float widthFactor = mAdapter.getPageWidth(pos); + drawAt = (offset + widthFactor) * width; + offset += widthFactor + marginOffset; + } + + if (drawAt + mPageMargin > scrollX) { + mMarginDrawable.setBounds((int) drawAt, mTopPageBounds, + (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); + mMarginDrawable.draw(canvas); + } + + if (drawAt > scrollX + width) { + break; // No more visible, no sense in continuing + } + } + } + } + + /** + * Start a fake drag of the page. + *

+ *

A fake drag can be useful if you want to synchronize the motion of the PageView + * with the touch scrolling of another view, while still letting the PageView + * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) + * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call + * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. + *

+ *

During a fake drag the PageView will ignore all touch events. If a real drag + * is already in progress, this method will return false. + * + * @return true if the fake drag began successfully, false if it could not be started. + * @see #fakeDragBy(float) + * @see #endFakeDrag() + */ + public boolean beginFakeDrag() { + if (mIsBeingDragged) { + return false; + } + mFakeDragging = true; + setScrollState(SCROLL_STATE_DRAGGING); + mInitialMotionX = mLastMotionX = 0; + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + final long time = SystemClock.uptimeMillis(); + final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); + mVelocityTracker.addMovement(ev); + ev.recycle(); + mFakeDragBeginTime = time; + return true; + } + + /** + * End a fake drag of the page. + * + * @see #beginFakeDrag() + * @see #fakeDragBy(float) + */ + public void endFakeDrag() { + if (!mFakeDragging) { + throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); + } + + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialVelocity = (int) velocityTracker.getXVelocity( + mActivePointerId); + mPopulatePending = true; + final int width = getClientWidth(); + final int scrollX = getScrollX(); + final ItemInfo ii = infoForCurrentScrollPosition(); + final int currentPage = ii.position; + final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; + final int totalDelta = (int) (mLastMotionX - mInitialMotionX); + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, + totalDelta); + setCurrentItemInternal(nextPage, true, true, initialVelocity); + endDrag(); + + mFakeDragging = false; + } + + /** + * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. + * + * @param xOffset Offset in pixels to drag by. + * @see #beginFakeDrag() + * @see #endFakeDrag() + */ + public void fakeDragBy(float xOffset) { + if (!mFakeDragging) { + throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); + } + + mLastMotionX += xOffset; + + float oldScrollX = getScrollX(); + float scrollX = oldScrollX - xOffset; + final int width = getClientWidth(); + + float leftBound = width * mFirstOffset; + float rightBound = width * mLastOffset; + + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + if (firstItem.position != 0) { + leftBound = firstItem.offset * width; + } + if (lastItem.position != mAdapter.getCount() - 1) { + rightBound = lastItem.offset * width; + } + + if (scrollX < leftBound) { + scrollX = leftBound; + } else if (scrollX > rightBound) { + scrollX = rightBound; + } + // Don't lose the rounded component + mLastMotionX += scrollX - (int) scrollX; + scrollTo((int) scrollX, getScrollY()); + pageScrolled((int) scrollX); + + // Synthesize an event for the VelocityTracker. + final long time = SystemClock.uptimeMillis(); + final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, + mLastMotionX, 0, 0); + mVelocityTracker.addMovement(ev); + ev.recycle(); + } + + /** + * Returns true if a fake drag is in progress. + * + * @return true if currently in a fake drag, false otherwise. + * @see #beginFakeDrag() + * @see #fakeDragBy(float) + * @see #endFakeDrag() + */ + public boolean isFakeDragging() { + return mFakeDragging; + } + + private void onSecondaryPointerUp(MotionEvent ev) { + final int pointerIndex = ev.getActionIndex(); + final int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + mLastMotionX = ev.getX(newPointerIndex); + mActivePointerId = ev.getPointerId(newPointerIndex); + if (mVelocityTracker != null) { + mVelocityTracker.clear(); + } + } + } + + private void endDrag() { + mIsBeingDragged = false; + mIsUnableToDrag = false; + + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + private void setScrollingCacheEnabled(boolean enabled) { + if (mScrollingCacheEnabled != enabled) { + mScrollingCacheEnabled = enabled; + if (USE_CACHE) { + final int size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + child.setDrawingCacheEnabled(enabled); + } + } + } + } + } + + public boolean canScrollHorizontally(int direction) { + if (mAdapter == null) { + return false; + } + + final int width = getClientWidth(); + final int scrollX = getScrollX(); + if (direction < 0) { + return (scrollX > (int) (width * mFirstOffset)); + } else if (direction > 0) { + return (scrollX < (int) (width * mLastOffset)); + } else { + return false; + } + } + + /** + * Tests scrollability within child views of v given a delta of dx. + * + * @param v View to test for horizontal scrollability + * @param checkV Whether the view v passed should itself be checked for scrollability (true), + * or just its children (false). + * @param dx Delta scrolled in pixels + * @param x X coordinate of the active touch point + * @param y Y coordinate of the active touch point + * @return true if child views of v can be scrolled by delta of dx. + */ + protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { + if (v instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) v; + final int scrollX = v.getScrollX(); + final int scrollY = v.getScrollY(); + final int count = group.getChildCount(); + // Count backwards - let topmost views consume scroll distance first. + for (int i = count - 1; i >= 0; i--) { + // TODO: Add versioned support here for transformed views. + // This will not work for transformed views in Honeycomb+ + final View child = group.getChildAt(i); + if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && + y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && + canScroll(child, true, dx, x + scrollX - child.getLeft(), + y + scrollY - child.getTop())) { + return true; + } + } + } + + return checkV && v.canScrollHorizontally(-dx); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + // Let the focused view and/or our descendants get the key first + return super.dispatchKeyEvent(event) || executeKeyEvent(event); + } + + /** + * You can call this function yourself to have the scroll view perform + * scrolling from a key event, just as if the event had been dispatched to + * it by the view hierarchy. + * + * @param event The key event to execute. + * @return Return true if the event was handled, else false. + */ + public boolean executeKeyEvent(KeyEvent event) { + boolean handled = false; + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_LEFT: + handled = arrowScroll(FOCUS_LEFT); + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + handled = arrowScroll(FOCUS_RIGHT); + break; + case KeyEvent.KEYCODE_TAB: + if (Build.VERSION.SDK_INT >= 11) { + // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD + // before Android 3.0. Ignore the tab key on those devices. + if (event.hasNoModifiers()) { + handled = arrowScroll(FOCUS_FORWARD); + } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { + handled = arrowScroll(FOCUS_BACKWARD); + } + } + break; + } + } + return handled; + } + + public boolean arrowScroll(int direction) { + View currentFocused = findFocus(); + if (currentFocused == this) { + currentFocused = null; + } else if (currentFocused != null) { + boolean isChild = false; + for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; + parent = parent.getParent()) { + if (parent == this) { + isChild = true; + break; + } + } + if (!isChild) { + // This would cause the focus search down below to fail in fun ways. + final StringBuilder sb = new StringBuilder(); + sb.append(currentFocused.getClass().getSimpleName()); + for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; + parent = parent.getParent()) { + sb.append(" => ").append(parent.getClass().getSimpleName()); + } + Log.e(TAG, "arrowScroll tried to find focus based on non-child " + + "current focused view " + sb.toString()); + currentFocused = null; + } + } + + boolean handled = false; + + View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, + direction); + if (nextFocused != null && nextFocused != currentFocused) { + if (direction == View.FOCUS_LEFT) { + // If there is nothing to the left, or this is causing us to + // jump to the right, then what we really want to do is page left. + final int nextLeft = getChildRectInPageCoordinates(mTempRect, nextFocused).left; + final int currLeft = getChildRectInPageCoordinates(mTempRect, currentFocused).left; + if (currentFocused != null && nextLeft >= currLeft) { + handled = pageLeft(); + } else { + handled = nextFocused.requestFocus(); + } + } else if (direction == View.FOCUS_RIGHT) { + // If there is nothing to the right, or this is causing us to + // jump to the left, then what we really want to do is page right. + final int nextLeft = getChildRectInPageCoordinates(mTempRect, nextFocused).left; + final int currLeft = getChildRectInPageCoordinates(mTempRect, currentFocused).left; + if (currentFocused != null && nextLeft <= currLeft) { + handled = pageRight(); + } else { + handled = nextFocused.requestFocus(); + } + } + } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { + // Trying to move left and nothing there; try to page. + handled = pageLeft(); + } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { + // Trying to move right and nothing there; try to page. + handled = pageRight(); + } + if (handled) { + playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); + } + return handled; + } + + private Rect getChildRectInPageCoordinates(Rect outRect, View child) { + if (outRect == null) { + outRect = new Rect(); + } + if (child == null) { + outRect.set(0, 0, 0, 0); + return outRect; + } + outRect.left = child.getLeft(); + outRect.right = child.getRight(); + outRect.top = child.getTop(); + outRect.bottom = child.getBottom(); + + ViewParent parent = child.getParent(); + while (parent instanceof ViewGroup && parent != this) { + final ViewGroup group = (ViewGroup) parent; + outRect.left += group.getLeft(); + outRect.right += group.getRight(); + outRect.top += group.getTop(); + outRect.bottom += group.getBottom(); + + parent = group.getParent(); + } + return outRect; + } + + boolean pageLeft() { + if (mCurItem > 0) { + setCurrentItem(mCurItem - 1, true); + return true; + } + return false; + } + + boolean pageRight() { + if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) { + setCurrentItem(mCurItem + 1, true); + return true; + } + return false; + } + + /** + * We only want the current page that is being shown to be focusable. + */ + @Override + public void addFocusables(ArrayList views, int direction, int focusableMode) { + final int focusableCount = views.size(); + + final int descendantFocusability = getDescendantFocusability(); + + if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + child.addFocusables(views, direction, focusableMode); + } + } + } + } + + // we add ourselves (if focusable) in all cases except for when we are + // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is + // to avoid the focus search finding layouts when a more precise search + // among the focusable children would be more interesting. + if ( + descendantFocusability != FOCUS_AFTER_DESCENDANTS || + // No focusable descendants + (focusableCount == views.size())) { + // Note that we can't call the superclass here, because it will + // add all views in. So we need to do the same thing View does. + if (!isFocusable()) { + return; + } + if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && + isInTouchMode() && !isFocusableInTouchMode()) { + return; + } + if (views != null) { + views.add(this); + } + } + } + + /** + * We only want the current page that is being shown to be touchable. + */ + @Override + public void addTouchables(ArrayList views) { + // Note that we don't call super.addTouchables(), which means that + // we don't call View.addTouchables(). This is okay because a PageView + // is itself not touchable. + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + child.addTouchables(views); + } + } + } + } + + /** + * We only want the current page that is being shown to be focusable. + */ + @Override + protected boolean onRequestFocusInDescendants(int direction, + Rect previouslyFocusedRect) { + int index; + int increment; + int end; + int count = getChildCount(); + if ((direction & FOCUS_FORWARD) != 0) { + index = 0; + increment = 1; + end = count; + } else { + index = count - 1; + increment = -1; + end = -1; + } + for (int i = index; i != end; i += increment) { + View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + if (child.requestFocus(direction, previouslyFocusedRect)) { + return true; + } + } + } + } + return false; + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + // Dispatch scroll events from this PageView. + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { + return super.dispatchPopulateAccessibilityEvent(event); + } + + // Dispatch all other accessibility events from the current page. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + final ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem && + child.dispatchPopulateAccessibilityEvent(event)) { + return true; + } + } + } + + return false; + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return generateDefaultLayoutParams(); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams && super.checkLayoutParams(p); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + /** + * Callback interface for responding to changing state of the selected page. + */ + public interface OnPageChangeListener { + + /** + * This method will be invoked when the current page is scrolled, either as part + * of a programmatically initiated smooth scroll or a user initiated touch scroll. + * + * @param position Position index of the first page currently being displayed. + * Page position+1 will be visible if positionOffset is nonzero. + * @param positionOffset Value from [0, 1) indicating the offset from the page at position. + * @param positionOffsetPixels Value in pixels indicating the offset from position. + */ + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); + + /** + * This method will be invoked when a new page becomes selected. Animation is not + * necessarily complete. + * + * @param position Position index of the new selected page. + */ + public void onPageSelected(int position); + + public void onPageChange(View view, int position); + + /** + * Called when the scroll state changes. Useful for discovering when the user + * begins dragging, when the page is automatically settling to the current page, + * or when it is fully stopped/idle. + * + * @param state The new scroll state. + * @see PageView#SCROLL_STATE_IDLE + * @see PageView#SCROLL_STATE_DRAGGING + * @see PageView#SCROLL_STATE_SETTLING + */ + public void onPageScrollStateChanged(int state); + } + + /** + * A PageTransformer is invoked whenever a visible/attached page is scrolled. + * This offers an opportunity for the application to apply a custom transformation + * to the page views using animation properties. + *

+ *

As property animation is only supported as of Android 3.0 and forward, + * setting a PageTransformer on a PageView on earlier platform versions will + * be ignored.

+ */ + public interface PageTransformer { + /** + * Apply a property transformation to the given page. + * + * @param page Apply the transformation to this page + * @param position Position of page relative to the current front-and-center + * position of the page. 0 is front and center. 1 is one full + * page position to the right, and -1 is one page position to the left. + */ + public void transformPage(View page, float position); + } + + /** + * Used internally to monitor when adapters are switched. + */ + interface OnAdapterChangeListener { + public void onAdapterChanged(BasePageAdapter oldAdapter, BasePageAdapter newAdapter); + } + + /** + * Used internally to tag special types of child views that should be added as + * page decorations by default. + */ + interface Decor { + } + + static class ItemInfo { + Object object; + int position; + boolean scrolling; + float widthFactor; + float offset; + } + + /** + * Simple implementation of the {@link OnPageChangeListener} interface with stub + * implementations of each method. Extend this if you do not intend to override + * every method of {@link OnPageChangeListener}. + */ + public static class SimpleOnPageChangeListener implements OnPageChangeListener { + + @Override + public void onPageChange(View view, int position) { + // TODO: Implement this method + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + // This space for rent + } + + @Override + public void onPageSelected(int position) { + // This space for rent + } + + @Override + public void onPageScrollStateChanged(int state) { + // This space for rent + } + } + + /** + * This is the persistent state that is saved by PageView. Only needed + * if you are creating a sublass of PageView that must save its own + * state, in which case it should implement a subclass of this which + * contains that state. + */ + public static class SavedState extends BaseSavedState { + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + int position; + Parcelable adapterState; + ClassLoader loader; + + public SavedState(Parcelable superState) { + super(superState); + } + + SavedState(Parcel in) { + super(in); + ClassLoader loader = getClass().getClassLoader(); + + position = in.readInt(); + adapterState = in.readParcelable(loader); + this.loader = loader; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(position); + out.writeParcelable(adapterState, flags); + } + + @Override + public String toString() { + return "FragmentPage.SavedState{" + + Integer.toHexString(System.identityHashCode(this)) + + " position=" + position + "}"; + } + } + + /** + * Layout parameters that should be supplied for views added to a + * PageView. + */ + public static class LayoutParams extends ViewGroup.LayoutParams { + /** + * true if this view is a decoration on the page itself and not + * a view supplied by the adapter. + */ + public boolean isDecor; + + /** + * Gravity setting for use on decor views only: + * Where to position the view page within the overall PageView + * container; constants are defined in {@link android.view.Gravity}. + */ + public int gravity; + + /** + * Width as a 0-1 multiplier of the measured page width + */ + float widthFactor = 0.f; + + /** + * true if this view was added during layout and needs to be measured + * before being positioned. + */ + boolean needsMeasure; + + /** + * Adapter position this view is for if !isDecor + */ + int position; + + /** + * Current child index within the PageView that this view occupies + */ + int childIndex; + + public LayoutParams() { + super(FILL_PARENT, FILL_PARENT); + } + + public LayoutParams(ViewGroup.LayoutParams lp) { + super(FILL_PARENT, FILL_PARENT); + } + + public LayoutParams(Context context, AttributeSet attrs) { + super(context, attrs); + + final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); + gravity = a.getInteger(0, Gravity.TOP); + a.recycle(); + } + } + + static class ViewPositionComparator implements Comparator { + @Override + public int compare(View lhs, View rhs) { + final LayoutParams llp = (LayoutParams) lhs.getLayoutParams(); + final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams(); + if (llp.isDecor != rlp.isDecor) { + return llp.isDecor ? 1 : -1; + } + return llp.position - rlp.position; + } + } + + private class PageObserver extends DataSetObserver { + @Override + public void onChanged() { + dataSetChanged(); + } + + @Override + public void onInvalidated() { + dataSetChanged(); + } + } +} diff --git a/app/src/main/java/android/widget/PullingLayout.java b/app/src/main/java/android/widget/PullingLayout.java new file mode 100644 index 0000000..78d10fb --- /dev/null +++ b/app/src/main/java/android/widget/PullingLayout.java @@ -0,0 +1,1521 @@ +package android.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.LinearInterpolator; +import android.view.animation.RotateAnimation; +import android.webkit.WebView; + +import java.util.Timer; +import java.util.TimerTask; + + +/** + * 自定义的布局,用来管理三个子控件,其中一个是下拉头,一个是包含内容的pullableView(可以是实现Pullable接口的的任何View), + * 还有一个上拉头,更多详解见博客http://blog.csdn.net/zhongkejingwang/article/details/38868463 + * + * @author 陈靖 + * @mod nirenr + * 修改适合在androlua使用,懒得注释了 + */ +@SuppressWarnings("deprecation") +public class PullingLayout extends RelativeLayout { + public static final String TAG = "PullToRefreshLayout"; + // 初始状态 + public static final int INIT = 0; + // 释放刷新 + public static final int RELEASE_TO_REFRESH = 1; + // 正在刷新 + public static final int REFRESHING = 2; + // 释放加载 + public static final int RELEASE_TO_LOAD = 3; + // 正在加载 + public static final int LOADING = 4; + // 操作完毕 + public static final int DONE = 5; + // 刷新成功 + public static final int SUCCEED = 0; + // 刷新失败 + public static final int FAIL = 1; + // 没有内容 + public static final int NOTHING = 2; + // 下拉的距离。注意:pullDownY和pullUpY不可能同时不为0 + public float pullDownY = 0; + // 回滚速度 + public float MOVE_SPEED = 8; + // 当前状态 + private int state = INIT; + // 刷新回调接口 + private OnRefreshListener mRefreshListener; + // 按下Y坐标,上一个事件点Y坐标 + private float downY, lastY; + // 上拉的距离 + private float pullUpY = 0; + // 释放刷新的距离 + private float refreshDist = 200; + // 释放加载的距离 + private float loadmoreDist = 200; + private MyTimer timer; + // 第一次执行布局 + private boolean isLayout = false; + // 在刷新过程中滑动操作 + private boolean isTouch = false; + // 手指滑动距离与下拉头的滑动距离比,中间会随正切函数变化 + private float radio = 2; + + // 下拉箭头的转180°动画 + private RotateAnimation rotateAnimation; + // 均匀旋转动画 + private RotateAnimation refreshingAnimation; + + // 下拉头 + private HeadView refreshView; + // 下拉的箭头 + private View pullView; + // 正在刷新的图标 + private View refreshingView; + // 刷新结果图标 + private ImageView refreshStateImageView; + // 刷新结果:成功或失败 + private TextView refreshStateTextView; + + // 上拉头 + private FootView loadmoreView; + // 上拉的箭头 + private View pullUpView; + // 正在加载的图标 + private View loadingView; + // 加载结果图标 + private ImageView loadStateImageView; + // 加载结果:成功或失败 + private TextView loadStateTextView; + private int mStateColor; + // 实现了Pullable接口的View + private FrameLayout pullableLayout; + private View pullableView; + // 过滤多点触碰 + private int mEvents; + // 这两个变量用来控制pull的方向,如果不加控制,当情况满足可上拉又可下拉时没法下拉 + private boolean canPullDown = true; + private boolean canPullUp = true; + private Context mContext; + private boolean mPullUp; + private boolean mPullDown; + private LayoutInflater mInflater; + private OnLoadMoreListener mLoadMoreListener; + private PullingLayout.OnPullUpListener mPullUpListener; + private PullingLayout.OnPullDownListener mPullDownListener; + private DisplayMetrics dm; + private int mForegroundColor; + private int mBackgroundColor; + private String refresh_succeed = "刷新成功"; + private String refresh_nothing = "暂无更新"; + private String refresh_fail = "刷新失败"; + private String load_succeed = "加载成功"; + private String load_nothing = "没有更多内容"; + private String load_fail = "加载失败"; + private String pullup_to_load = "上拉加载更多"; + private String release_to_refresh = "释放立即刷新"; + private String refreshing = "正在刷新..."; + private String release_to_load = "释放立即加载"; + private String pull_to_refresh = "下拉刷新"; + private String loading = "正在加载..."; + /** + * 执行自动回滚的handler + */ + Handler updateHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + // 回弹速度随下拉距离moveDeltaY增大而增大 + MOVE_SPEED = (float) (8 + 5 * Math.tan(Math.PI / 2 + / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY)))); + if (!isTouch) { + // 正在刷新,且没有往上推的话则悬停,显示"正在刷新..." + if (state == REFRESHING && pullDownY <= refreshDist) { + pullDownY = refreshDist; + timer.cancel(); + } else if (state == LOADING && -pullUpY <= loadmoreDist) { + pullUpY = -loadmoreDist; + timer.cancel(); + } + + } + if (pullDownY > 0) + pullDownY -= MOVE_SPEED; + else if (pullUpY < 0) + pullUpY += MOVE_SPEED; + if (pullDownY < 0) { + // 已完成回弹 + pullDownY = 0; + pullView.clearAnimation(); + // 隐藏下拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态 + if (state != REFRESHING && state != LOADING) + changeState(INIT); + timer.cancel(); + requestLayout(); + } + if (pullUpY > 0) { + // 已完成回弹 + pullUpY = 0; + pullUpView.clearAnimation(); + // 隐藏上拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态 + if (state != REFRESHING && state != LOADING) + changeState(INIT); + timer.cancel(); + requestLayout(); + } + // 刷新布局,会自动调用onLayout + requestLayout(); + // 没有拖拉或者回弹完成 + if (pullDownY + Math.abs(pullUpY) == 0) + timer.cancel(); + } + + }; + + public PullingLayout(Context context) { + super(context); + initView(context); + } + + public PullingLayout(Context context, AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + public PullingLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initView(context); + } + + public String getRefreshSucceed() { + return refresh_succeed; + } + + public void setRefreshSucceed(String refresh_succeed) { + this.refresh_succeed = refresh_succeed; + } + + public String getRefreshNothing() { + return refresh_nothing; + } + + public void setRefreshNothing(String refresh_nothing) { + this.refresh_nothing = refresh_nothing; + } + + public String getRefreshFail() { + return refresh_fail; + } + + public void setRefreshFail(String refresh_fail) { + this.refresh_fail = refresh_fail; + } + + public String getLoadSucceed() { + return load_succeed; + } + + public void setLoadSucceed(String load_succeed) { + this.load_succeed = load_succeed; + } + + public String getLoadNothing() { + return load_nothing; + } + + public void setLoadNothing(String load_nothing) { + this.load_nothing = load_nothing; + } + + public String getLoadFail() { + return load_fail; + } + + public void setLoadFail(String load_fail) { + this.load_fail = load_fail; + } + + public String getPullupToLoad() { + return pullup_to_load; + } + + public void setPullupToLoad(String pullup_to_load) { + this.pullup_to_load = pullup_to_load; + } + + public String getReleaseToRefresh() { + return release_to_refresh; + } + + public void setReleaseToRefresh(String release_to_refresh) { + this.release_to_refresh = release_to_refresh; + } + + public String getRefreshing() { + return refreshing; + } + + public void setRefreshing(String refreshing) { + this.refreshing = refreshing; + } + + public String getReleaseToLoad() { + return release_to_load; + } + + public void setReleaseToLoad(String release_to_load) { + this.release_to_load = release_to_load; + } + + /** + * 完成刷新操作,显示刷新结果。注意:刷新完成后一定要调用这个方法 + */ + + public String getPulldownToRefresh() { + return pull_to_refresh; + } + + public void setPulldownToRefresh(String pull_to_refresh) { + this.pull_to_refresh = pull_to_refresh; + } + + public String getLoading() { + return loading; + } + + public void setLoading(String loading) { + this.loading = loading; + } + + public void setOnRefreshListener(OnRefreshListener listener) { + mRefreshListener = listener; + } + + public void setOnLoadMoreListener(OnLoadMoreListener listener) { + mLoadMoreListener = listener; + } + + public void setOnPullUpListener(OnPullUpListener listener) { + mPullUpListener = listener; + } + + public void setOnPullDownListener(OnPullDownListener listener) { + mPullDownListener = listener; + } + + private int dp(float n) { + + return (int) TypedValue.applyDimension(1, n, dm); + } + + public void setStateColor(int color) { + mStateColor = color; + } + + private void initView(Context context) { + dm = context.getResources().getDisplayMetrics(); + + mContext = context; + TypedArray array = mContext.getTheme().obtainStyledAttributes(new int[]{ + android.R.attr.colorForeground, + android.R.attr.colorBackground, + }); + mForegroundColor = array.getColor(0, 0xFFFFFFFF); + mBackgroundColor = array.getColor(1, 0xFF000000); + array.recycle(); + setStateColor(mForegroundColor); + + mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + refreshView = new HeadView(mContext); + super.addView(refreshView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + pullableLayout = new FrameLayout(mContext); + super.addView(pullableLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + loadmoreView = new FootView(mContext); + super.addView(loadmoreView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + pullableLayout = (FrameLayout) getChildAt(1); + initView(); + + timer = new MyTimer(updateHandler); + rotateAnimation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); + rotateAnimation.setDuration(100); + rotateAnimation.setRepeatCount(0); + rotateAnimation.setFillAfter(true); + + refreshingAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); + refreshingAnimation.setDuration(1500); + refreshingAnimation.setRepeatCount(-1); + refreshingAnimation.setFillAfter(true); + + // 添加匀速转动动画 + LinearInterpolator lir = new LinearInterpolator(); + rotateAnimation.setInterpolator(lir); + refreshingAnimation.setInterpolator(lir); + } + + private void hide() { + timer.schedule(5); + } + + /** + * @param refreshResult PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败 + */ + public void refreshFinish(int refreshResult) { + if (state != REFRESHING) + return; + refreshingView.clearAnimation(); + refreshingView.setVisibility(View.GONE); + switch (refreshResult) { + case SUCCEED: + // 刷新成功 + refreshStateImageView.setVisibility(View.VISIBLE); + refreshStateTextView.setText(refresh_succeed); + refreshStateImageView + .setBackgroundDrawable(new SucceedDrawable()); + break; + case NOTHING: + // 没有更新 + refreshStateImageView.setVisibility(View.VISIBLE); + refreshStateTextView.setText(refresh_nothing); + refreshStateImageView + .setBackgroundDrawable(new FailDrawable()); + break; + case FAIL: + default: + // 刷新失败 + refreshStateImageView.setVisibility(View.VISIBLE); + refreshStateTextView.setText(refresh_fail); + refreshStateImageView + .setBackgroundDrawable(new FailDrawable()); + break; + } + if (pullDownY > 0) { + // 刷新结果停留1秒 + new Handler() { + @Override + public void handleMessage(Message msg) { + changeState(DONE); + hide(); + } + }.sendEmptyMessageDelayed(0, 1000); + } else { + changeState(DONE); + hide(); + } + } + + /** + * 加载完毕,显示加载结果。注意:加载完成后一定要调用这个方法 + * + * @param refreshResult PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败 + */ + public void loadmoreFinish(int refreshResult) { + if (state != LOADING) + return; + loadingView.clearAnimation(); + loadingView.setVisibility(View.GONE); + switch (refreshResult) { + case SUCCEED: + // 加载成功 + loadStateImageView.setVisibility(View.VISIBLE); + loadStateTextView.setText(load_succeed); + loadStateImageView.setBackgroundDrawable(new SucceedDrawable()); + break; + case NOTHING: + // 没有更多内容 + loadStateImageView.setVisibility(View.VISIBLE); + loadStateTextView.setText(load_nothing); + loadStateImageView.setBackgroundDrawable(new FailDrawable()); + break; + case FAIL: + default: + // 加载失败 + loadStateImageView.setVisibility(View.VISIBLE); + loadStateTextView.setText(load_fail); + loadStateImageView.setBackgroundDrawable(new FailDrawable()); + break; + } + if (pullUpY < 0) { + // 刷新结果停留1秒 + new Handler() { + @Override + public void handleMessage(Message msg) { + changeState(DONE); + hide(); + } + }.sendEmptyMessageDelayed(0, 1000); + } else { + changeState(DONE); + hide(); + } + } + + private void changeState(int to) { + state = to; + switch (state) { + case INIT: + // 下拉布局初始状态 + refreshStateImageView.setVisibility(View.GONE); + refreshStateTextView.setText(pull_to_refresh); + pullView.clearAnimation(); + pullView.setVisibility(View.VISIBLE); + // 上拉布局初始状态 + loadStateImageView.setVisibility(View.GONE); + loadStateTextView.setText(pullup_to_load); + pullUpView.clearAnimation(); + pullUpView.setVisibility(View.VISIBLE); + break; + case RELEASE_TO_REFRESH: + // 释放刷新状态 + refreshStateTextView.setText(release_to_refresh); + pullView.startAnimation(rotateAnimation); + break; + case REFRESHING: + // 正在刷新状态 + pullView.clearAnimation(); + refreshingView.setVisibility(View.VISIBLE); + pullView.setVisibility(View.INVISIBLE); + //refreshingView.startAnimation(refreshingAnimation); + refreshStateTextView.setText(refreshing); + break; + case RELEASE_TO_LOAD: + // 释放加载状态 + loadStateTextView.setText(release_to_load); + pullUpView.startAnimation(rotateAnimation); + break; + case LOADING: + // 正在加载状态 + pullUpView.clearAnimation(); + loadingView.setVisibility(View.VISIBLE); + pullUpView.setVisibility(View.INVISIBLE); + //loadingView.startAnimation(refreshingAnimation); + loadStateTextView.setText(loading); + break; + case DONE: + // 刷新或加载完毕,啥都不做 + break; + } + } + + /** + * 不限制上拉或下拉 + */ + private void releasePull() { + canPullDown = true; + canPullUp = true; + } + + /* + * (非 Javadoc)由父控件决定是否分发事件,防止事件冲突 + * + * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent) + */ + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + downY = ev.getY(); + lastY = downY; + timer.cancel(); + mEvents = 0; + releasePull(); + break; + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_POINTER_UP: + // 过滤多点触碰 + mEvents = -1; + break; + case MotionEvent.ACTION_MOVE: + if (mEvents == 0) { + if (pullDownY > 0 + || (canPullDown() + && canPullDown && state != LOADING)) { + // 可以下拉,正在加载时不能下拉 + // 对实际滑动距离做缩小,造成用力拉的感觉 + pullDownY = pullDownY + (ev.getY() - lastY) / radio; + if (pullDownY < 0) { + pullDownY = 0; + canPullDown = false; + canPullUp = true; + } + if (pullDownY > getMeasuredHeight()) + pullDownY = getMeasuredHeight(); + if (state == REFRESHING) { + // 正在刷新的时候触摸移动 + isTouch = true; + } + } else if (pullUpY < 0 + || (canPullUp() && canPullUp && state != REFRESHING)) { + // 可以上拉,正在刷新时不能上拉 + pullUpY = pullUpY + (ev.getY() - lastY) / radio; + if (pullUpY > 0) { + pullUpY = 0; + canPullDown = true; + canPullUp = false; + } + if (pullUpY < -getMeasuredHeight()) + pullUpY = -getMeasuredHeight(); + if (state == LOADING) { + // 正在加载的时候触摸移动 + isTouch = true; + } + } else + releasePull(); + } else + mEvents = 0; + lastY = ev.getY(); + // 根据下拉距离改变比例 + radio = (float) (2 + 2 * Math.tan(Math.PI / 2 / getMeasuredHeight() + * (pullDownY + Math.abs(pullUpY)))); + if (pullDownY > 0 || pullUpY < 0) + requestLayout(); + if (pullDownY > 0) { + if (pullDownY <= refreshDist + && (state == RELEASE_TO_REFRESH || state == DONE)) { + // 如果下拉距离没达到刷新的距离且当前状态是释放刷新,改变状态为下拉刷新 + changeState(INIT); + } + if (pullDownY >= refreshDist && state == INIT) { + // 如果下拉距离达到刷新的距离且当前状态是初始状态刷新,改变状态为释放刷新 + changeState(RELEASE_TO_REFRESH); + } + } else if (pullUpY < 0) { + // 下面是判断上拉加载的,同上,注意pullUpY是负值 + if (-pullUpY <= loadmoreDist + && (state == RELEASE_TO_LOAD || state == DONE)) { + changeState(INIT); + } + // 上拉操作 + if (-pullUpY >= loadmoreDist && state == INIT) { + changeState(RELEASE_TO_LOAD); + } + + } + // 因为刷新和加载操作不能同时进行,所以pullDownY和pullUpY不会同时不为0,因此这里用(pullDownY + + // Math.abs(pullUpY))就可以不对当前状态作区分了 + if ((pullDownY + Math.abs(pullUpY)) > 8) { + // 防止下拉过程中误触发长按事件和点击事件 + ev.setAction(MotionEvent.ACTION_CANCEL); + } + break; + case MotionEvent.ACTION_UP: + if (pullDownY > refreshDist || -pullUpY > loadmoreDist) { + isTouch = false; + } + if (state == RELEASE_TO_REFRESH) { + changeState(REFRESHING); + // 刷新操作 + if (mRefreshListener != null) + mRefreshListener.onRefresh(this); + } else if (state == RELEASE_TO_LOAD) { + changeState(LOADING); + // 加载操作 + if (mLoadMoreListener != null) + mLoadMoreListener.onLoadMore(this); + } + hide(); + break; + default: + break; + } + // 事件分发交给父类 + super.dispatchTouchEvent(ev); + return true; + } + + public void setPullUpEnabled(boolean canPullUp) { + + mPullUp = canPullUp; + } + + private boolean canPullUp() { + + if (!mPullUp || pullableView == null) + return false; + if (mPullUpListener != null) + return mPullUpListener.onPullUp(pullableView); + + if (pullableView instanceof ListView) + return listViewCanPullUp((ListView) pullableView); + if (pullableView instanceof GridView) + return gridViewCanPullUp((GridView) pullableView); + if (pullableView instanceof ExpandableListView) + return expandableListViewCanPullUp((ExpandableListView) pullableView); + if (pullableView instanceof ScrollView) + return scrollViewCanPullUp((ScrollView) pullableView); + if (pullableView instanceof WebView) + return webViewCanPullUp((WebView) pullableView); + + return true; + } + + private boolean expandableListViewCanPullUp(ExpandableListView view) { + + if (view.getCount() == 0) { + // 没有item的时候也可以上拉加载 + return true; + } else if (view.getLastVisiblePosition() == (view.getCount() - 1)) { + // 滑到底部了 + if (view.getChildAt(view.getLastVisiblePosition() - view.getFirstVisiblePosition()) != null + && view.getChildAt( + view.getLastVisiblePosition() + - view.getFirstVisiblePosition()).getBottom() <= view.getMeasuredHeight()) + return true; + } + return false; + } + + private boolean gridViewCanPullUp(GridView view) { + + if (view.getCount() == 0) { + // 没有item的时候也可以上拉加载 + return true; + } else if (view.getLastVisiblePosition() == (view.getCount() - 1)) { + // 滑到底部了 + if (view.getChildAt(view.getLastVisiblePosition() - view.getFirstVisiblePosition()) != null + && view.getChildAt( + view.getLastVisiblePosition() + - view.getFirstVisiblePosition()).getBottom() <= view.getMeasuredHeight()) + return true; + } + return false; + + } + + private boolean scrollViewCanPullUp(ScrollView view) { + + if (view.getScrollY() >= (view.getChildAt(0).getHeight() - view.getMeasuredHeight())) + return true; + else + return false; + } + + private boolean webViewCanPullUp(WebView view) { + + if (view.getScrollY() >= view.getContentHeight() * view.getScale() + - view.getMeasuredHeight()) + return true; + else + return false; + + } + + private boolean listViewCanPullUp(ListView view) { + + if (view.getCount() == 0) { + // 没有item的时候也可以上拉加载 + return true; + } else if (view.getLastVisiblePosition() == (view.getCount() - 1)) { + // 滑到底部了 + if (view.getChildAt(view.getLastVisiblePosition() - view.getFirstVisiblePosition()) != null + && view.getChildAt( + view.getLastVisiblePosition() + - view.getFirstVisiblePosition()).getBottom() <= view.getMeasuredHeight()) + return true; + } + return false; + } + + public void setPullDownEnabled(boolean canPullDown) { + + mPullDown = canPullDown; + } + + private boolean canPullDown() { + + if (mPullDown == false || pullableView == null) + return false; + if (mPullDownListener != null) + return mPullDownListener.onPullDown(pullableView); + + if (pullableView instanceof AbsListView) + return absListViewCanPullDown((AbsListView) pullableView); + if (pullableView instanceof ScrollView) + return viewCanPullDown((ScrollView) pullableView); + if (pullableView instanceof WebView) + return viewCanPullDown((WebView) pullableView); + + return true; + } + + private boolean viewCanPullDown(View view) { + + if (view.getScrollY() == 0) + return true; + else + return false; + + } + + private boolean absListViewCanPullDown(AbsListView view) { + + if (view.getCount() == 0) { + // 没有item的时候也可以下拉刷新 + return true; + } else if (view.getFirstVisiblePosition() == 0 + && view.getChildAt(0).getTop() >= 0) { + // 滑到ListView的顶部了 + return true; + } else + return false; + + } + + /** + * 自动刷新 + */ + public void autoRefresh() { + AutoRefreshAndLoadTask task = new AutoRefreshAndLoadTask(); + task.execute(20); + } + + /** + * 自动加载 + */ + public void autoLoad() { + pullUpY = -loadmoreDist; + requestLayout(); + changeState(LOADING); + // 加载操作 + if (mLoadMoreListener != null) + mLoadMoreListener.onLoadMore(this); + } + + private void initView() { + // 初始化下拉布局 + pullView = refreshView.getPullView(); + refreshStateTextView = refreshView.getStateText(); + refreshingView = refreshView.getLoadingView(); + refreshStateImageView = refreshView.getStateView(); + // 初始化上拉布局 + pullUpView = loadmoreView.getPullView(); + loadStateTextView = loadmoreView.getStateText(); + loadingView = loadmoreView.getLoadingView(); + loadStateImageView = loadmoreView.getStateView(); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (!isLayout) { + // 这里是第一次进来的时候做一些初始化 + isLayout = true; + refreshDist = ((ViewGroup) refreshView).getChildAt(0) + .getMeasuredHeight(); + loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(0) + .getMeasuredHeight(); + loadStateTextView.setTextColor(mStateColor); + refreshStateTextView.setTextColor(mStateColor); + } + // 改变子控件的布局,这里直接用(pullDownY + pullUpY)作为偏移量,这样就可以不对当前状态作区分 + refreshView.layout(0, + (int) (pullDownY + pullUpY) - refreshView.getMeasuredHeight(), + refreshView.getMeasuredWidth(), (int) (pullDownY + pullUpY)); + pullableLayout.layout(0, (int) (pullDownY + pullUpY), + pullableLayout.getMeasuredWidth(), (int) (pullDownY + pullUpY) + + pullableLayout.getMeasuredHeight()); + loadmoreView.layout(0, + (int) (pullDownY + pullUpY) + pullableLayout.getMeasuredHeight(), + loadmoreView.getMeasuredWidth(), + (int) (pullDownY + pullUpY) + pullableLayout.getMeasuredHeight() + + loadmoreView.getMeasuredHeight()); + } + + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + + child.setLayoutParams(new FrameLayout.LayoutParams(params.width, params.height)); + pullableView = child; + pullableLayout.addView(child); + } + + @Override + public void addView(View child) { + + pullableView = child; + pullableLayout.addView(child); + } + + /** + * 刷新回调接口 + * + * @author chenjing + */ + public interface OnRefreshListener { + /** + * 刷新操作 + */ + void onRefresh(PullingLayout pullToRefreshLayout); + } + + /** + * 加载回调接口 + * + * @author chenjing + */ + public interface OnLoadMoreListener { + + /** + * 加载操作 + */ + void onLoadMore(PullingLayout pullToRefreshLayout); + } + + public interface OnPullUpListener { + public boolean onPullUp(View view); + } + + public interface OnPullDownListener { + public boolean onPullDown(View view); + } + + /** + * @author chenjing 自动模拟手指滑动的task + */ + private class AutoRefreshAndLoadTask extends + AsyncTask { + + @Override + protected String doInBackground(Integer... params) { + while (pullDownY < 4 / 3 * refreshDist) { + pullDownY += MOVE_SPEED; + publishProgress(pullDownY); + try { + Thread.sleep(params[0]); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return null; + } + + @Override + protected void onPostExecute(String result) { + changeState(REFRESHING); + // 刷新操作 + if (mRefreshListener != null) + mRefreshListener.onRefresh(PullingLayout.this); + hide(); + } + + @Override + protected void onProgressUpdate(Float... values) { + if (pullDownY > refreshDist) + changeState(RELEASE_TO_REFRESH); + requestLayout(); + } + + } + + class MyTimer { + private Handler handler; + private Timer timer; + private MyTask mTask; + + public MyTimer(Handler handler) { + this.handler = handler; + timer = new Timer(); + } + + public void schedule(long period) { + if (mTask != null) { + mTask.cancel(); + mTask = null; + } + mTask = new MyTask(handler); + timer.schedule(mTask, 0, period); + } + + public void cancel() { + if (mTask != null) { + mTask.cancel(); + mTask = null; + } + } + + class MyTask extends TimerTask { + private Handler handler; + + public MyTask(Handler handler) { + this.handler = handler; + } + + @Override + public void run() { + handler.obtainMessage().sendToTarget(); + } + + } + } + + public class HeadView extends RelativeLayout { + + private ImageView mLoadingView; + private TextView mStateText; + private ImageView mStateView; + private ImageView mPullView; + + public HeadView(Context context) { + super(context); + initView(context); + } + + + public HeadView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + public HeadView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initView(context); + } + + public ImageView getStateView() { + return mStateView; + } + + public TextView getStateText() { + return mStateText; + } + + public ImageView getLoadingView() { + return mLoadingView; + } + + public ImageView getPullView() { + return mPullView; + } + + private void initView(Context context) { + + int w = dp(30); + + RelativeLayout layout = new RelativeLayout(context); + layout.setPadding(0, dp(20), 0, dp(20)); + RelativeLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp.addRule(12); + addView(layout, lp); + + RelativeLayout layout2 = new RelativeLayout(context); + RelativeLayout.LayoutParams lp2 = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp2.addRule(13); + layout.addView(layout2, lp2); + + mPullView = new ImageView(context); + mPullView.setBackgroundDrawable(new PullDownDrawable()); + RelativeLayout.LayoutParams lp3 = new LayoutParams(w, w); + lp3.setMargins(dp(60), 0, 0, 0); + lp3.addRule(15); + layout2.addView(mPullView, lp3); + + mLoadingView = new ImageView(context); + mLoadingView.setVisibility(GONE); + mLoadingView.setBackgroundDrawable(new LoadingDrawable()); + RelativeLayout.LayoutParams lp4 = new LayoutParams(w, w); + lp4.setMargins(dp(60), 0, 0, 0); + lp4.addRule(15); + layout2.addView(mLoadingView, lp4); + + mStateText = new TextView(context); + mStateText.setText(pull_to_refresh); + mStateText.setTextSize(16); + RelativeLayout.LayoutParams lp5 = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + lp5.addRule(13); + layout2.addView(mStateText, lp5); + + mStateView = new ImageView(context); + mStateView.setVisibility(GONE); + RelativeLayout.LayoutParams lp6 = new LayoutParams(w, w); + lp6.setMargins(dp(60), 0, 0, 0); + lp6.addRule(15); + layout2.addView(mStateView, lp6); + } + + } + + public class FootView extends RelativeLayout { + + private ImageView mLoadingView; + private TextView mStateText; + private ImageView mStateView; + private ImageView mPullView; + + public FootView(Context context) { + super(context); + initView(context); + } + + public FootView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + public FootView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initView(context); + } + + public ImageView getStateView() { + return mStateView; + } + + public TextView getStateText() { + return mStateText; + } + + public ImageView getLoadingView() { + return mLoadingView; + } + + public ImageView getPullView() { + return mPullView; + } + + private void initView(Context context) { + + int w = dp(30); + RelativeLayout layout = new RelativeLayout(context); + layout.setPadding(0, dp(20), 0, dp(20)); + RelativeLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp.addRule(10); + addView(layout, lp); + + RelativeLayout layout2 = new RelativeLayout(context); + RelativeLayout.LayoutParams lp2 = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp2.addRule(13); + layout.addView(layout2, lp2); + + mPullView = new ImageView(context); + mPullView.setBackgroundDrawable(new PullUpDrawable()); + RelativeLayout.LayoutParams lp3 = new LayoutParams(w, w); + lp3.setMargins(dp(60), 0, 0, 0); + lp3.addRule(15); + layout2.addView(mPullView, lp3); + + mLoadingView = new ImageView(context); + mLoadingView.setVisibility(GONE); + mLoadingView.setBackgroundDrawable(new LoadingDrawable()); + RelativeLayout.LayoutParams lp4 = new LayoutParams(w, w); + lp4.setMargins(dp(60), 0, 0, 0); + lp4.addRule(15); + layout2.addView(mLoadingView, lp4); + + mStateText = new TextView(context); + mStateText.setText(pullup_to_load); + mStateText.setTextSize(16); + RelativeLayout.LayoutParams lp5 = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + lp5.addRule(13); + layout2.addView(mStateText, lp5); + + mStateView = new ImageView(context); + mStateView.setVisibility(GONE); + RelativeLayout.LayoutParams lp6 = new LayoutParams(w, w); + lp6.setMargins(dp(60), 0, 0, 0); + lp6.addRule(15); + layout2.addView(mStateView, lp6); + + } + + } + + private class PullDownDrawable extends Drawable { + + private Paint p; + + PullDownDrawable() { + p = new Paint(); + p.setStyle(Paint.Style.STROKE); + p.setAntiAlias(true); + p.setStrokeWidth(dp(2)); + //p.setShadowLayer(dp(2),dp(2),dp(2), Color.GRAY); + } + + @Override + public void draw(Canvas c) { + + p.setColor(mStateColor); + Rect b = getBounds(); + int r = (int) ((float) Math.min(b.right, b.bottom) * 0.35); + c.drawCircle(b.right / 2, b.bottom / 2, r, p); + Path path = new Path(); + path.moveTo(b.right * 0.5f, b.bottom * 0.25f); + path.lineTo(b.right * 0.5f, b.bottom * 0.75f); + path.moveTo(b.right * 0.25f, b.bottom * 0.5f); + path.lineTo(b.right * 0.5f, b.bottom * 0.75f); + path.lineTo(b.right * 0.75f, b.bottom * 0.5f); + c.drawPath(path, p); + //c.drawLine(b.right / 2, b.bottom / 4, b.right / 2, b.bottom / 4 * 3, p); + //c.drawLine(b.right / 4, b.bottom / 2, b.right / 2, b.bottom / 4 * 3, p); + //c.drawLine(b.right / 4 * 3, b.bottom / 2, b.right / 2, b.bottom / 4 * 3, p); + } + + @Override + public void setAlpha(int p1) { + + p.setAlpha(p1); + } + + @Override + public void setColorFilter(ColorFilter p1) { + + p.setColorFilter(p1); + } + + @Override + public int getOpacity() { + + return PixelFormat.UNKNOWN; + } + } + + private class PullUpDrawable extends Drawable { + + private Paint p; + + PullUpDrawable() { + p = new Paint(); + p.setStyle(Paint.Style.STROKE); + p.setAntiAlias(true); + p.setStrokeWidth(dp(2)); + //p.setShadowLayer(dp(2),dp(2),dp(2), Color.GRAY); + } + + @Override + public void draw(Canvas c) { + + p.setColor(mStateColor); + Rect b = getBounds(); + int r = (int) ((float) Math.min(b.right, b.bottom) * 0.35); + c.drawCircle(b.right / 2, b.bottom / 2, r, p); + Path path = new Path(); + path.moveTo(b.right * 0.5f, b.bottom * 0.25f); + path.lineTo(b.right * 0.5f, b.bottom * 0.75f); + path.moveTo(b.right * 0.25f, b.bottom * 0.5f); + path.lineTo(b.right * 0.5f, b.bottom * 0.25f); + path.lineTo(b.right * 0.75f, b.bottom * 0.5f); + c.drawPath(path, p); + //c.drawLine(b.right / 2, b.bottom / 4, b.right / 2, b.bottom / 4 * 3, p); + //c.drawLine(b.right / 4, b.bottom / 2, b.right / 2, b.bottom / 4, p); + //c.drawLine(b.right / 4 * 3, b.bottom / 2, b.right / 2, b.bottom / 4, p); + } + + @Override + public void setAlpha(int p1) { + + p.setAlpha(p1); + } + + @Override + public void setColorFilter(ColorFilter p1) { + + p.setColorFilter(p1); + } + + @Override + public int getOpacity() { + + return PixelFormat.UNKNOWN; + } + } + + private class LoadingDrawable2 extends Drawable { + + private Paint p; + private int n = 0; + private int m = 0; + private int sn = 6; + private int sm = 2; + + LoadingDrawable2() { + p = new Paint(); + p.setStyle(Paint.Style.STROKE); + p.setAntiAlias(true); + p.setStrokeWidth(dp(2)); + //p.setShadowLayer(dp(2),dp(2),dp(2), Color.GRAY); + } + + @Override + public void draw(Canvas c) { + + p.setColor(mStateColor); + Rect b = getBounds(); + int r = (int) ((float) Math.min(b.right, b.bottom) * 0.35); + RectF f = new RectF(r / 2, r / 2, r * 2.5f, r * 2.5f); + if (n > 360) { + sm += sn; + sn = 0 - sn; + } else if (n < 6) { + sn = 6; + sm = 2; + } + n += sn; + m += sm; + c.drawArc(f, m % 360, n, false, p); + invalidateSelf(); + /*float f = (float) r * 1.5f; + SweepGradient mShader = new SweepGradient(f, f, mBackgroundColor, mStateColor); + p.setShader(mShader); + DashPathEffect effects = new DashPathEffect(new float[]{r / 5, r / 6}, 1); + p.setPathEffect(effects); + c.drawCircle(b.right / 2, b.bottom / 2, r, p);*/ + } + + @Override + public void setAlpha(int p1) { + + p.setAlpha(p1); + } + + @Override + public void setColorFilter(ColorFilter p1) { + + p.setColorFilter(p1); + } + + @Override + public int getOpacity() { + + return PixelFormat.UNKNOWN; + } + } + + + private class SucceedDrawable2 extends Drawable { + + private Paint p; + + SucceedDrawable2() { + p = new Paint(); + p.setStyle(Paint.Style.STROKE); + p.setAntiAlias(true); + p.setStrokeWidth(dp(2)); + //p.setShadowLayer(dp(2),dp(2),dp(2), Color.GRAY); + } + + @Override + public void draw(Canvas c) { + + p.setColor(mStateColor); + Rect b = getBounds(); + int r = (int) ((float) Math.min(b.right, b.bottom) * 0.35); + c.drawCircle(b.right / 2, b.bottom / 2, r, p); + Path path = new Path(); + path.moveTo(b.right * 0.3f, b.bottom * 0.5f); + path.lineTo(b.right * 0.45f, b.bottom * 0.7f); + path.lineTo(b.right * 0.75f, b.bottom * 0.4f); + c.drawPath(path, p); + //c.drawLine(b.right * 0.3f, b.bottom / 2, b.right * 0.45f, b.bottom * 0.7f, p); + //c.drawLine(b.right / 4 * 3, b.bottom * 0.4f, b.right * 0.45f, b.bottom * 0.7f, p); + } + + @Override + public void setAlpha(int p1) { + + p.setAlpha(p1); + } + + @Override + public void setColorFilter(ColorFilter p1) { + + p.setColorFilter(p1); + } + + @Override + public int getOpacity() { + + return PixelFormat.UNKNOWN; + } + } + + private class FailDrawable2 extends Drawable { + + private Paint p; + + FailDrawable2() { + p = new Paint(); + p.setStyle(Paint.Style.STROKE); + p.setAntiAlias(true); + p.setStrokeWidth(dp(2)); + //p.setShadowLayer(dp(2),dp(2),dp(2), Color.GRAY); + } + + @Override + public void draw(Canvas c) { + + p.setColor(mStateColor); + Rect b = getBounds(); + int r = (int) ((float) Math.min(b.right, b.bottom) * 0.35); + c.drawCircle(b.right / 2, b.bottom / 2, r, p); + c.drawLine(b.right / 2, b.bottom * 0.25f, b.right / 2, b.bottom * 0.65f, p); + c.drawLine(b.right / 2, b.bottom * 0.7f, b.right / 2, b.bottom * 0.75f, p); + } + + @Override + public void setAlpha(int p1) { + p.setAlpha(p1); + } + + @Override + public void setColorFilter(ColorFilter p1) { + + p.setColorFilter(p1); + } + + @Override + public int getOpacity() { + + return PixelFormat.UNKNOWN; + } + } + + private int n = 0; + private int m = 0; + private int x = 0; + private int y = 0; + private int sn = 6; + private int sm = 2; + + private class LoadingDrawable extends Drawable { + + static final int STATE_LOADING = 0; + static final int STATE_SUCCESS = 1; + static final int STATE_FAIL = -1; + private Paint p; + private int mState; + + LoadingDrawable() { + p = new Paint(); + p.setStyle(Paint.Style.STROKE); + p.setAntiAlias(true); + p.setStrokeWidth(dp(2)); + } + + void setState(int state) { + mState = state; + } + + void loading() { + reset(); + } + + void succe() { + mState = STATE_SUCCESS; + } + + void fail() { + mState = STATE_FAIL; + } + + void reset() { + mState = STATE_LOADING; + sn = 6; + sm = 2; + n = 0; + m = 0; + x = 0; + y = 0; + invalidateSelf(); + } + + @Override + public void draw(Canvas c) { + + p.setColor(mStateColor); + Rect b = getBounds(); + int r = (int) ((float) Math.min(b.right, b.bottom)); + RectF f = new RectF(r * 0.15f, r * 0.15f, r * 0.85f, r * 0.85f); + if (n >= 360 && mState == STATE_LOADING) { + sm = 8; + sn = 0 - 6; + } else if (n <= 6) { + sn = 6; + sm = 2; + } + if (n < 360 || mState == STATE_LOADING) { + if (mState == STATE_LOADING) { + n += sn; + m += sm; + m %= 360; + } else { + n += sn * 2; + m += sm * 2; + m %= 360; + } + } + c.drawArc(f, m, n, false, p); + + if (n >= 360) { + sn = -6; + sm = 8; + + if (mState == STATE_SUCCESS) { + Path path = new Path(); + path.moveTo(b.right * 0.3f, b.bottom * 0.5f); + path.lineTo(b.right * 0.45f, b.bottom * 0.7f); + path.lineTo(b.right * 0.75f, b.bottom * 0.4f); + c.drawPath(path, p); + } else if (mState == STATE_FAIL) { + c.drawLine(b.right / 2, b.bottom * 0.25f, b.right / 2, b.bottom * 0.65f, p); + c.drawLine(b.right / 2, b.bottom * 0.7f, b.right / 2, b.bottom * 0.75f, p); + } + } + invalidateSelf(); + } + + @Override + public void setAlpha(int p1) { + + p.setAlpha(p1); + } + + @Override + public void setColorFilter(ColorFilter p1) { + + p.setColorFilter(p1); + } + + @Override + public int getOpacity() { + + return PixelFormat.UNKNOWN; + } + } + + private class SucceedDrawable extends LoadingDrawable { + + SucceedDrawable() { + super(); + succe(); + } + + } + + private class FailDrawable extends LoadingDrawable { + + FailDrawable() { + super(); + fail(); + } + } +} + diff --git a/app/src/main/java/android/widget/RippleHelper.java b/app/src/main/java/android/widget/RippleHelper.java new file mode 100644 index 0000000..383b1ff --- /dev/null +++ b/app/src/main/java/android/widget/RippleHelper.java @@ -0,0 +1,258 @@ +package android.widget; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.Shader; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; + +import com.androlua.util.TimerTaskX; +import com.androlua.util.TimerX; + +public class RippleHelper extends Drawable implements View.OnTouchListener { + + private final DisplayMetrics dm; + private int state; + + private int mWidth; + + private int mStep; + + private boolean mCircle; + private boolean mEnabled; + private int mRadius; + private TimerX mTimer; + private RippleHelper.task mTask; + private Paint mPaint2; + private float mX; + private float mY; + private View mView; + private Drawable mBackground; + private int mAlpha; + + public boolean isSingle() { + return mSingle; + } + + public void setSingle(boolean mSingle) { + this.mSingle = mSingle; + } + + private boolean mSingle; + private int mRippleLineColor; + private int mRippleColor; + + + public RippleHelper(View view) { + mView = view; + dm = view.getResources().getDisplayMetrics(); + init(); + } + + public boolean isCircle() { + return mCircle; + } + + public void setCircle(boolean circle) { + mCircle = circle; + } + + @Override + public boolean onTouch(View p1, MotionEvent p2) { + // TODO: Implement this method + onTouchEvent(p2); + return false; + } + + private void init() { + if (mView.isClickable()) + mEnabled = true; + + mBackground = mView.getBackground(); + mView.setBackgroundDrawable(this); + mView.setOnTouchListener(this); + mPaint2 = new Paint(); + mPaint2.setColor(0x44aaaaaa); + mPaint2.setAntiAlias(true); + mPaint2.setStrokeWidth(dp(4)); + mAlpha = mPaint2.getAlpha(); + mTimer = new TimerX(); + mTask = new task(); + mTimer.schedule(mTask, 0, 16); + + mTask.setEnabled(false); + mRadius = 0; + } + + public void onTouchEvent(MotionEvent event) { + // TODO: Implement this method + /*if (!mView.hasOnClickListeners() && !mEnabled) + return;*/ + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + Rect rect = getBounds(); + if (mCircle) { + mY = rect.bottom / 2; + mX = rect.right / 2; + mWidth = Math.max(rect.bottom, rect.right) / 2; + } else { + mX = event.getX(); + mY = event.getY(); + mWidth = (int) Math.hypot(rect.bottom, rect.right); + } + mStep = Math.max(mWidth / 60, 1); + mRadius = 0; + mTask.setEnabled(true); + //mEnabled = true; + mPaint2.setAlpha(mAlpha); + state = 1; + break; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_OUTSIDE: + case MotionEvent.ACTION_UP: + state = 2; + } + + } + + private int dp(float n) { + return (int) TypedValue.applyDimension(1, n, dm); + } + private static int rgb(double red, double green, double blue) { + return 0xff000000 | + ((int) (red * 255.0f + 0.5f) << 16) | + ((int) (green * 255.0f + 0.5f) << 8) | + (int) (blue * 255.0f + 0.5f); + } + @Override + public void draw(Canvas canvas) { + if (mBackground != null) { + mBackground.setBounds(getBounds()); + mBackground.draw(canvas); + } + mPaint2.setColor(mRippleColor); + mPaint2.setAlpha(cAlpha); + + + if (state != 0) { + + if (mCircle) + canvas.drawCircle(mX, mY, mWidth, mPaint2); + else + canvas.drawRect(getBounds(), mPaint2); + int w = mWidth; + int n = 0; + + if (mSingle) { + canvas.drawCircle(mX, mY, Math.min(mRadius, mWidth), mPaint2); + return; + } + + + for (int r = mRadius; r >= 0; r = r - w) { + //canvas.drawCircle(mX, mY, Math.min(r, w), mPaint2); + n++; + //if (n >= 2) { + int clr = rgb(Math.random(), Math.random(), Math.random()); + mPaint2.setShader(new RadialGradient(mX, mY, dp(6), new int[]{0x44ffffff, clr, 0x44000000}, null, Shader.TileMode.MIRROR)); + mPaint2.setStyle(Paint.Style.STROKE); + mPaint2.setColor(clr); + canvas.drawCircle(mX, mY, mRadius % w, mPaint2); + break; + //} + } + mPaint2.setShader(null); + mPaint2.setStyle(Paint.Style.FILL); + } + } + + public void setBackgroundColor(int color) { + // TODO: Implement this method + mBackground = new ColorDrawable(color); + } + + public void setRippleColor(int color) { + // TODO: Implement this method + mRippleColor = color; + mPaint2.setColor(color); + mAlpha = mPaint2.getAlpha(); + } + + public void setRippleLineColor(int color) { + // TODO: Implement this method + mRippleLineColor = color; + } + + @Override + public void setAlpha(int p1) { + // TODO: Implement this method + mAlpha = p1; + mPaint2.setAlpha(p1); + } + + @Override + public void setColorFilter(ColorFilter p1) { + // TODO: Implement this method + mPaint2.setColorFilter(p1); + } + + @Override + public int getOpacity() { + // TODO: Implement this method + return PixelFormat.UNKNOWN; + } + + private int cAlpha; + + private class task extends TimerTaskX { + + + @Override + public void run() { + // TODO: Implement this method + switch (state) { + case 1: + if (mSingle) + mRadius += Math.max(mRadius / 16, mStep); + else + mRadius += mStep; + cAlpha = Math.min(mAlpha, mRadius / mStep); + mView.postInvalidate(); + break; + case 2: + mRadius += mStep * 4; + cAlpha = Math.min(mAlpha, mRadius / mStep * 2); + mView.postInvalidate(); + if (mRadius / mWidth >= 1) { + mRadius = mWidth; + cAlpha = mAlpha; + state = 3; + } + break; + case 3: + cAlpha -= Math.max(cAlpha / 16, 4); + mPaint2.setAlpha(cAlpha); + + mView.postInvalidate(); + if (cAlpha < 4) { + //cAlpha = mAlpha; + //mPaint2.setAlpha(mAlpha); + state = 0; + } + break; + default: + mRadius = 0; + setEnabled(false); + } + } + } + +} diff --git a/app/src/main/java/android/widget/RippleLayout.java b/app/src/main/java/android/widget/RippleLayout.java new file mode 100644 index 0000000..4f29d3b --- /dev/null +++ b/app/src/main/java/android/widget/RippleLayout.java @@ -0,0 +1,82 @@ +package android.widget; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.ViewGroup; + +public class RippleLayout extends FrameLayout { + + private int mChildCount; + + private int count; + + private int mRippleColor=0x44aaaaaa; + + private boolean mCircle; + private boolean mSingle; + private int mRippleLineColor; + + public void setCircle(boolean circle) { + mCircle = circle; + } + + public boolean isCircle() { + return mCircle; + } + + public RippleLayout(Context context) { + super(context); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + // TODO: Implement this method + super.onLayout(changed, left, top, right, bottom); + count = getChildCount(); + if (mChildCount == count) + return; + mChildCount = count; + setRippleDrawable(this); + } + + private void setRippleDrawable(View view) { + // TODO: Implement this method + if (view instanceof ViewGroup) { + + ViewGroup g=(ViewGroup) view; + int n=g.getChildCount(); + for (int i=0;i < n;i++) { + View v=g.getChildAt(i); + if (!(v instanceof RippleLayout)) + setRippleDrawable(v); + } + } + else { + Drawable bg=view.getBackground(); + RippleHelper rip; + if (bg instanceof RippleHelper) { + rip = (RippleHelper)bg; + } + else { + rip = new RippleHelper(view); + } + rip.setRippleColor(mRippleColor); + rip.setRippleLineColor(mRippleLineColor); + rip.setCircle(mCircle); + rip.setSingle(mSingle); + } + } + + public void setSingle(boolean single) { + mSingle = single; + } + public void setRippleColor(int color) { + mRippleColor = color; + } + + public void setRippleLineColor(int color) { + // TODO: Implement this method + mRippleLineColor=color; + } + +} diff --git a/app/src/main/java/android/widget/RoundRectDrawable.java b/app/src/main/java/android/widget/RoundRectDrawable.java new file mode 100644 index 0000000..dacd4f2 --- /dev/null +++ b/app/src/main/java/android/widget/RoundRectDrawable.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.widget; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Build; + +import static android.widget.RoundRectDrawableWithShadow.calculateVerticalPadding; +import static android.widget.RoundRectDrawableWithShadow.calculateHorizontalPadding; + +/** + * Very simple drawable that draws a rounded rectangle background with arbitrary corners and also + * reports proper outline for L. + *

+ * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable. + */ +public class RoundRectDrawable extends Drawable { + private float mRadius; + private final Paint mPaint; + private final RectF mBoundsF; + private final Rect mBoundsI; + private float mPadding; + private boolean mInsetForPadding = false; + private boolean mInsetForRadius = true; + + public RoundRectDrawable(int backgroundColor, float radius) { + mRadius = radius; + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + mPaint.setColor(backgroundColor); + mBoundsF = new RectF(); + mBoundsI = new Rect(); + } + + void setPadding(float padding, boolean insetForPadding, boolean insetForRadius) { + if (padding == mPadding && mInsetForPadding == insetForPadding && + mInsetForRadius == insetForRadius) { + return; + } + mPadding = padding; + mInsetForPadding = insetForPadding; + mInsetForRadius = insetForRadius; + updateBounds(null); + invalidateSelf(); + } + + float getPadding() { + return mPadding; + } + + @Override + public void draw(Canvas canvas) { + canvas.drawRoundRect(mBoundsF, mRadius, mRadius, mPaint); + } + + private void updateBounds(Rect bounds) { + if (bounds == null) { + bounds = getBounds(); + } + mBoundsF.set(bounds.left, bounds.top, bounds.right, bounds.bottom); + mBoundsI.set(bounds); + if (mInsetForPadding) { + float vInset = calculateVerticalPadding(mPadding, mRadius, mInsetForRadius); + float hInset = calculateHorizontalPadding(mPadding, mRadius, mInsetForRadius); + mBoundsI.inset((int) Math.ceil(hInset), (int) Math.ceil(vInset)); + // to make sure they have same bounds. + mBoundsF.set(mBoundsI); + } + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + updateBounds(bounds); + } + + @Override + public void getOutline( Outline outline) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + outline.setRoundRect(mBoundsI, mRadius); + } + } + + void setRadius(float radius) { + if (radius == mRadius) { + return; + } + mRadius = radius; + updateBounds(null); + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + // not supported because older versions do not support + } + + @Override + public void setColorFilter(ColorFilter cf) { + // not supported because older versions do not support + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + public float getRadius() { + return mRadius; + } + + public void setColor(int color) { + mPaint.setColor(color); + invalidateSelf(); + } +} diff --git a/app/src/main/java/android/widget/RoundRectDrawableWithShadow.java b/app/src/main/java/android/widget/RoundRectDrawableWithShadow.java new file mode 100644 index 0000000..0f05186 --- /dev/null +++ b/app/src/main/java/android/widget/RoundRectDrawableWithShadow.java @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.widget; + +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import com.androlua.*; +import android.util.*; + +/** + * A rounded rectangle drawable which also includes a shadow around. + */ +class RoundRectDrawableWithShadow extends Drawable { + // used to calculate content padding + final static double COS_45 = Math.cos(Math.toRadians(45)); + + final static float SHADOW_MULTIPLIER = 1.5f; + + final int mInsetShadow; // extra shadow to avoid gaps between card and shadow + + /* + * This helper is set by CardView implementations. + *

+ * Prior to API 17, canvas.drawRoundRect is expensive; which is why we need this interface + * to draw efficient rounded rectangles before 17. + * */ + static RoundRectHelper sRoundRectHelper; + + Paint mPaint; + + Paint mCornerShadowPaint; + + Paint mEdgeShadowPaint; + + final RectF mCardBounds; + + float mCornerRadius; + + Path mCornerShadowPath; + + // updated value with inset + float mMaxShadowSize; + + // actual value set by developer + float mRawMaxShadowSize; + + // multiplied value to account for shadow offset + float mShadowSize; + + // actual value set by developer + float mRawShadowSize; + + private boolean mDirty = true; + + private final int mShadowStartColor; + + private final int mShadowEndColor; + + private boolean mAddPaddingForCorners = true; + + /** + * If shadow size is set to a value above max shadow, we print a warning + */ + private boolean mPrintedShadowClipWarning = false; + + private DisplayMetrics dm; + + RoundRectDrawableWithShadow(Resources resources, int backgroundColor, float radius, + float shadowSize, float maxShadowSize) { + mShadowStartColor = 0x37000000; + //resources.getColor(R.color.cardview_shadow_start_color); + mShadowEndColor = 0x03000000; + dm=resources.getDisplayMetrics(); + + //resources.getColor(R.color.cardview_shadow_end_color); + mInsetShadow = (int)dp(1); + //resources.getDimensionPixelSize(R.dimen.cardview_compat_inset_shadow); + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + mPaint.setColor(backgroundColor); + mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + mCornerShadowPaint.setStyle(Paint.Style.FILL); + mCornerRadius = (int) (radius + .5f); + mCardBounds = new RectF(); + mEdgeShadowPaint = new Paint(mCornerShadowPaint); + mEdgeShadowPaint.setAntiAlias(false); + setShadowSize(shadowSize, maxShadowSize); + } + + private float dp(float n) { + // TODO: Implement this method + return TypedValue.applyDimension(1,n,dm); + } + + /** + * Casts the value to an even integer. + */ + private int toEven(float value) { + int i = (int) (value + .5f); + if (i % 2 == 1) { + return i - 1; + } + return i; + } + + public void setAddPaddingForCorners(boolean addPaddingForCorners) { + mAddPaddingForCorners = addPaddingForCorners; + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + mCornerShadowPaint.setAlpha(alpha); + mEdgeShadowPaint.setAlpha(alpha); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + mDirty = true; + } + + void setShadowSize(float shadowSize, float maxShadowSize) { + if (shadowSize < 0 || maxShadowSize < 0) { + throw new IllegalArgumentException("invalid shadow size"); + } + shadowSize = toEven(shadowSize); + maxShadowSize = toEven(maxShadowSize); + if (shadowSize > maxShadowSize) { + shadowSize = maxShadowSize; + if (!mPrintedShadowClipWarning) { + mPrintedShadowClipWarning = true; + } + } + if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) { + return; + } + mRawShadowSize = shadowSize; + mRawMaxShadowSize = maxShadowSize; + mShadowSize = (int)(shadowSize * SHADOW_MULTIPLIER + mInsetShadow + .5f); + mMaxShadowSize = maxShadowSize + mInsetShadow; + mDirty = true; + invalidateSelf(); + } + + @Override + public boolean getPadding(Rect padding) { + int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius, + mAddPaddingForCorners)); + int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius, + mAddPaddingForCorners)); + padding.set(hOffset, vOffset, hOffset, vOffset); + return true; + } + + static float calculateVerticalPadding(float maxShadowSize, float cornerRadius, + boolean addPaddingForCorners) { + if (addPaddingForCorners) { + return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius); + } else { + return maxShadowSize * SHADOW_MULTIPLIER; + } + } + + static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius, + boolean addPaddingForCorners) { + if (addPaddingForCorners) { + return (float) (maxShadowSize + (1 - COS_45) * cornerRadius); + } else { + return maxShadowSize; + } + } + + @Override + public void setColorFilter(ColorFilter cf) { + mPaint.setColorFilter(cf); + mCornerShadowPaint.setColorFilter(cf); + mEdgeShadowPaint.setColorFilter(cf); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + void setCornerRadius(float radius) { + radius = (int) (radius + .5f); + if (mCornerRadius == radius) { + return; + } + mCornerRadius = radius; + mDirty = true; + invalidateSelf(); + } + + @Override + public void draw(Canvas canvas) { + if (mDirty) { + buildComponents(getBounds()); + mDirty = false; + } + canvas.translate(0, mRawShadowSize / 2); + drawShadow(canvas); + canvas.translate(0, -mRawShadowSize / 2); + sRoundRectHelper.drawRoundRect(canvas, mCardBounds, mCornerRadius, mPaint); + } + + private void drawShadow(Canvas canvas) { + final float edgeShadowTop = -mCornerRadius - mShadowSize; + final float inset = mCornerRadius + mInsetShadow + mRawShadowSize / 2; + final boolean drawHorizontalEdges = mCardBounds.width() - 2 * inset > 0; + final boolean drawVerticalEdges = mCardBounds.height() - 2 * inset > 0; + // LT + int saved = canvas.save(); + canvas.translate(mCardBounds.left + inset, mCardBounds.top + inset); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawHorizontalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.width() - 2 * inset, -mCornerRadius, + mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + // RB + saved = canvas.save(); + canvas.translate(mCardBounds.right - inset, mCardBounds.bottom - inset); + canvas.rotate(180f); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawHorizontalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.width() - 2 * inset, -mCornerRadius + mShadowSize, + mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + // LB + saved = canvas.save(); + canvas.translate(mCardBounds.left + inset, mCardBounds.bottom - inset); + canvas.rotate(270f); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawVerticalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + // RT + saved = canvas.save(); + canvas.translate(mCardBounds.right - inset, mCardBounds.top + inset); + canvas.rotate(90f); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawVerticalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + } + + private void buildShadowCorners() { + RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius); + RectF outerBounds = new RectF(innerBounds); + outerBounds.inset(-mShadowSize, -mShadowSize); + + if (mCornerShadowPath == null) { + mCornerShadowPath = new Path(); + } else { + mCornerShadowPath.reset(); + } + mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD); + mCornerShadowPath.moveTo(-mCornerRadius, 0); + mCornerShadowPath.rLineTo(-mShadowSize, 0); + // outer arc + mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false); + // inner arc + mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false); + mCornerShadowPath.close(); + float startRatio = mCornerRadius / (mCornerRadius + mShadowSize); + mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize, + new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, + new float[]{0f, startRatio, 1f} + , Shader.TileMode.CLAMP)); + + // we offset the content shadowSize/2 pixels up to make it more realistic. + // this is why edge shadow shader has some extra space + // When drawing bottom edge shadow, we use that extra space. + mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0, + -mCornerRadius - mShadowSize, + new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, + new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP)); + mEdgeShadowPaint.setAntiAlias(false); + } + + private void buildComponents(Rect bounds) { + // Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift. + // We could have different top-bottom offsets to avoid extra gap above but in that case + // center aligning Views inside the CardView would be problematic. + final float verticalOffset = mRawMaxShadowSize * SHADOW_MULTIPLIER; + mCardBounds.set(bounds.left + mRawMaxShadowSize, bounds.top + verticalOffset, + bounds.right - mRawMaxShadowSize, bounds.bottom - verticalOffset); + buildShadowCorners(); + } + + float getCornerRadius() { + return mCornerRadius; + } + + void getMaxShadowAndCornerPadding(Rect into) { + getPadding(into); + } + + void setShadowSize(float size) { + setShadowSize(size, mRawMaxShadowSize); + } + + void setMaxShadowSize(float size) { + setShadowSize(mRawShadowSize, size); + } + + float getShadowSize() { + return mRawShadowSize; + } + + float getMaxShadowSize() { + return mRawMaxShadowSize; + } + + float getMinWidth() { + final float content = 2 * + Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize / 2); + return content + (mRawMaxShadowSize + mInsetShadow) * 2; + } + + float getMinHeight() { + final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + + mRawMaxShadowSize * SHADOW_MULTIPLIER / 2); + return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER + mInsetShadow) * 2; + } + + public void setColor(int color) { + mPaint.setColor(color); + invalidateSelf(); + } + + static interface RoundRectHelper { + void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint); + } +} diff --git a/app/src/main/java/android/widget/SlidingLayout.java b/app/src/main/java/android/widget/SlidingLayout.java new file mode 100644 index 0000000..8c46209 --- /dev/null +++ b/app/src/main/java/android/widget/SlidingLayout.java @@ -0,0 +1,261 @@ +package android.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.view.*; +import android.view.ViewGroup.*; + + +public class SlidingLayout extends HorizontalScrollView +{ + /** + * 屏幕宽度 + */ + private int mScreenWidth; + /** + * 可以打开菜单的滑动范围 + */ + private int mTouchScale = 0; + /** + * 菜单的宽度 + */ + private int mMenuWidth = 0; + private int mHalfMenuWidth = 0; + + private boolean once; + + private boolean isOpen; + + private LinearLayout wrapper; + + private OnMenuOpenedListener mOnMenuOpenedListener; + + private OnMenuClosedListener mOnMenuClosedListener; + + private OnMenuStateChangeListener mOnMenuStateChangeListener; + + private boolean isSlidinged; + + public SlidingLayout(Context context) + { + super(context); + init(context); + } + + public SlidingLayout(Context context, AttributeSet attrs) + { + super(context, attrs); + init(context); + } + + public void setOnMenuStateChangeListener(OnMenuStateChangeListener mOnMenuStateChangeListener) + { + this.mOnMenuStateChangeListener = mOnMenuStateChangeListener; + } + + public void setOnMenuClosedListener(OnMenuClosedListener onMenuClosedListener) + { + mOnMenuClosedListener = onMenuClosedListener; + } + + public void setOnMenuOpenedListener(OnMenuOpenedListener onMenuOpenedListener) + { + mOnMenuOpenedListener = onMenuOpenedListener; + } + + public void setTouchScale(int touchScale) + { + this.mTouchScale = touchScale; + } + + public int getTouchScale() + { + return mTouchScale; + } + + public void setMenuWidth(int menuWidth) + { + this.mMenuWidth = menuWidth; + } + + public int getMenuWidth() + { + return mMenuWidth; + } + + private void init(Context context) + { + setHorizontalScrollBarEnabled(false); + mScreenWidth = context.getResources().getDisplayMetrics().widthPixels; + + //默认左侧滑动范围为屏幕宽度的10% + mTouchScale = mScreenWidth / 10; + wrapper = new LinearLayout(context); + super.addView(wrapper); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) + { + /** + * 设置菜单宽度 + */ + if (!once) + { + View menu = wrapper.getChildAt(0); + View content = wrapper.getChildAt(1); + + ViewGroup.LayoutParams lp=menu.getLayoutParams(); + + //如果没有指定菜单宽度,盲人使用屏幕宽度的80% + if (mMenuWidth == 0 && lp.width < 0) + lp.width = (int)(mScreenWidth * 0.8); + mMenuWidth = lp.width; + mHalfMenuWidth = lp.width / 2; + content.getLayoutParams().width = mScreenWidth; + wrapper.getLayoutParams().width=mScreenWidth+mMenuWidth; + } + if(isOpen) + openMenu(); + else + closeMenu(); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) + { + super.onLayout(changed, l, t, r, b); + if (changed) + { + // 将菜单隐藏 + if(!once) + this.scrollTo(mMenuWidth, 0); + else + closeMenu(); + once = true; + } + + } + + @Override + public void addView(View child, ViewGroup.LayoutParams params) + { + // TODO: Implement this method + wrapper.addView(child, params); + } + + @Override + public void addView(View child) + { + // TODO: Implement this method + wrapper.addView(child); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) + { + //菜单显示或者触摸在范围则拦截触摸操作 + if (isOpen || ev.getX() < mTouchScale) + { + return super.onInterceptTouchEvent(ev); + } + else + { + return false; + } + } + + + @Override + public boolean onTouchEvent(MotionEvent ev) + { + int action = ev.getAction(); + switch (action) + { + case MotionEvent.ACTION_MOVE: + if (!isSlidinged && mOnMenuStateChangeListener != null) + mOnMenuStateChangeListener.onMenuStateChange(this, isOpen); + isSlidinged = true; + break; + // Up时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏 + case MotionEvent.ACTION_UP: + int scrollX = getScrollX(); + if (isOpen) + { + if (scrollX > mHalfMenuWidth / 2) + closeMenu(); + else + openMenu(); + } + else + { + if (scrollX > mHalfMenuWidth * 1.5) + closeMenu(); + else + openMenu(); + } + isSlidinged = false; + return true; + } + return super.onTouchEvent(ev); + } + + /** + * 打开菜单 + */ + public void openMenu() + { + this.smoothScrollTo(0, 0); + if (!isOpen && mOnMenuOpenedListener != null) + mOnMenuOpenedListener.onMenuOpened(this); + isOpen = true; + } + + /** + * 关闭菜单 + */ + public void closeMenu() + { + this.smoothScrollTo(mMenuWidth, 0); + if (isOpen && mOnMenuClosedListener != null) + mOnMenuClosedListener.onMenuClosed(this); + isOpen = false; + } + + /** + * 切换菜单状态 + */ + public void toggle() + { + if (isOpen) + { + closeMenu(); + } + else + { + openMenu(); + } + } + + public static interface OnMenuOpenedListener + { + public void onMenuOpened(View v); + } + + public static interface OnMenuClosedListener + { + public void onMenuClosed(View v); + } + + public static interface OnMenuStateChangeListener + { + public void onMenuStateChange(View v, boolean isOpen); + } +} diff --git a/app/src/main/java/android/widget/ToolBar.java b/app/src/main/java/android/widget/ToolBar.java new file mode 100644 index 0000000..47caaad --- /dev/null +++ b/app/src/main/java/android/widget/ToolBar.java @@ -0,0 +1,240 @@ +package android.widget; +import android.content.*; +import android.graphics.*; +import android.graphics.drawable.*; +import android.util.*; +import android.view.*; +import com.androlua.util.*; +import android.view.ViewGroup.*; +import com.androlua.*; +import com.osfans.trime.pro.R; + +import android.widget.ImageView.*; + +public class ToolBar extends LinearLayout { + + private TextView mTitle; + + private TextView mSubTitle; + + private ImageView mNavi; + + private ImageView mLogo; + + private ImageView mMore; + + private LinearLayout wrapper; + + private PopupMenu mMenu; + + private OnLogoClickListener mOnLogoCilck; + private OnNaviClickListener mOnNaviCilck; + private OnMenuItemClickListener mOnMenuItemClick; + + private DisplayMetrics dm; + + private int mHeight; + + public ToolBar(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + // TODO: Implement this method + dm = context.getResources().getDisplayMetrics(); + mHeight = dp(48); + LinearLayout.LayoutParams lp = new LayoutParams(mHeight, mHeight); + setMinimumHeight(mHeight); + mNavi = new ImageView(context); + mNavi.setScaleType(ScaleType.FIT_CENTER); + mNavi.setVisibility(GONE); + super.addView(mNavi, lp); + + mLogo = new ImageView(context); + mLogo.setScaleType(ScaleType.FIT_CENTER); + mLogo.setImageResource(R.drawable.icon); + mLogo.setVisibility(GONE); + super.addView(mLogo, lp); + + LinearLayout titleLayout=new LinearLayout(context); + int p=dp(1); + titleLayout.setPadding(p * 4, p, p, p); + titleLayout.setOrientation(LinearLayout.VERTICAL); + titleLayout.setGravity(Gravity.CENTER); + super.addView(titleLayout, new LayoutParams(LayoutParams.MATCH_PARENT, mHeight, 1)); + + mTitle = new TextView(context); + mTitle.setTextSize(1, 20); + mTitle.setSingleLine(true); + mTitle.setTypeface(Typeface.DEFAULT_BOLD); + titleLayout.addView(mTitle, new LayoutParams(LayoutParams.MATCH_PARENT, dp(26))); + mSubTitle = new TextView(context); + mSubTitle.setTextSize(1, 14); + mSubTitle.setSingleLine(true); + mSubTitle.setVisibility(GONE); + titleLayout.addView(mSubTitle, new LayoutParams(LayoutParams.MATCH_PARENT, dp(20))); + + wrapper=new LinearLayout(context); + super.addView(wrapper, new LayoutParams(LayoutParams.WRAP_CONTENT, mHeight)); + + mMore = new ImageView(context); + mMore.setScaleType(ScaleType.FIT_CENTER); + mMore.setVisibility(GONE); + super.addView(mMore, lp); + + new RippleHelper(mNavi); + new RippleHelper(mMore); + + Paint paint=new Paint(); + paint.setColor(0xff888888); + + Bitmap nb=Bitmap.createBitmap(mHeight, mHeight, Bitmap.Config.ARGB_4444); + Canvas nc=new Canvas(nb); + double h=mHeight; + double w=h; + nc.drawRect((int)(w / 4), (int)(h / 32 * 10), (int)(w / 4 * 3), (int)(h / 32 * 12), paint); + nc.drawRect((int)(w / 4), (int)(h / 32 * 15), (int)(w / 4 * 3), (int)(h / 32 * 17), paint); + nc.drawRect((int)(w / 4), (int)(h / 32 * 20), (int)(w / 4 * 3), (int)(h / 32 * 22), paint); + mNavi.setImageBitmap(nb); + + Bitmap mb=Bitmap.createBitmap(mHeight, mHeight, Bitmap.Config.ARGB_4444); + Canvas mc=new Canvas(mb); + mc.drawCircle((int)(w / 2), (int)(h / 3), (int)(w / 16), paint); + mc.drawCircle((int)(w / 2), (int)(h / 2), (int)(w / 16), paint); + mc.drawCircle((int)(w / 2), (int)(h / 3 * 2), (int)(w / 16), paint); + mMore.setImageBitmap(mb); + + mNavi.setOnClickListener(new OnClickListener(){ + + @Override + public void onClick(View p1) { + // TODO: Implement this method + if (mOnNaviCilck != null) + mOnNaviCilck.onNaviClick(p1); + } + }); + + mLogo.setOnClickListener(new OnClickListener(){ + + @Override + public void onClick(View p1) { + // TODO: Implement this method + if (mOnLogoCilck != null) + mOnLogoCilck.onLogoClick(p1); + } + }); + + mMore.setOnClickListener(new OnClickListener(){ + + @Override + public void onClick(View p1) { + // TODO: Implement this method + if (mMenu != null) + mMenu.show(); + } + }); + + mMenu = new PopupMenu(getContext(), mMore); + mMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ + + @Override + public boolean onMenuItemClick(MenuItem p1) { + // TODO: Implement this method + if (mOnMenuItemClick != null) + return mOnMenuItemClick.onMenuItemClick(p1); + return false; + } + }); + } + + private int dp(float n) { + // TODO: Implement this method + return (int)TypedValue.applyDimension(1, n, dm); + } + + @Override + public void addView(View child) { + // TODO: Implement this method + wrapper.addView(child); + } + + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + // TODO: Implement this method + wrapper.addView(child, params); + } + + + + + public void setLogo(Drawable logo) { + mLogo.setImageDrawable(logo); + } + + public void setNaviEnabled(boolean enabled) { + mNavi.setVisibility(enabled ?VISIBLE: GONE); + } + + public void setLogoEnabled(boolean enabled) { + mLogo.setVisibility(enabled ?VISIBLE: GONE); + } + + public void setMenuEnabled(boolean enabled) { + mMore.setVisibility(enabled ?VISIBLE: GONE); + } + + public void setNaviIcon(Drawable icon) { + mNavi.setImageDrawable(icon); + } + + public void setTitle(CharSequence title) { + mTitle.setText(title); + } + + public void setTitleColor(int color) { + mTitle.setTextColor(color); + } + + public void setSubtitle(CharSequence title) { + if (title == null || title.length() == 0) + mSubTitle.setVisibility(GONE); + else + mSubTitle.setVisibility(VISIBLE); + mSubTitle.setText(title); + } + + public void setSubtitleColor(int color) { + mSubTitle.setTextColor(color); + } + + public void setOnLogoClickListener(OnLogoClickListener l) { + mOnLogoCilck = l; + } + + public void setOnNaviClickListener(OnNaviClickListener l) { + mOnNaviCilck = l; + } + + public void setOnMenuItemClickListener(OnMenuItemClickListener listener) { + mOnMenuItemClick = listener; + } + + public Menu getMenu() { + setMenuEnabled(true); + return mMenu.getMenu(); + } + + public static interface OnLogoClickListener { + public void onLogoClick(View view); + } + + public static interface OnNaviClickListener { + public void onNaviClick(View view); + } + + public static interface OnMenuItemClickListener { + public boolean onMenuItemClick(android.view.MenuItem item); + } + +} diff --git a/app/src/main/java/android/widget/ViewDragHelper.java b/app/src/main/java/android/widget/ViewDragHelper.java new file mode 100644 index 0000000..e986bb4 --- /dev/null +++ b/app/src/main/java/android/widget/ViewDragHelper.java @@ -0,0 +1,1475 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.widget; + +import android.content.*; +import android.view.*; +import android.view.animation.*; +import android.widget.*; +import java.util.*; + +/** + * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number + * of useful operations and state tracking for allowing a user to drag and reposition + * views within their parent ViewGroup. + */ +public class ViewDragHelper { + private static final String TAG = "ViewDragHelper"; + + /** + * A null/invalid pointer ID. + */ + public static final int INVALID_POINTER = -1; + + /** + * A view is not currently being dragged or animating as a result of a fling/snap. + */ + public static final int STATE_IDLE = 0; + + /** + * A view is currently being dragged. The position is currently changing as a result + * of user input or simulated user input. + */ + public static final int STATE_DRAGGING = 1; + + /** + * A view is currently settling into place as a result of a fling or + * predefined non-interactive motion. + */ + public static final int STATE_SETTLING = 2; + + /** + * Edge flag indicating that the left edge should be affected. + */ + public static final int EDGE_LEFT = 1 << 0; + + /** + * Edge flag indicating that the right edge should be affected. + */ + public static final int EDGE_RIGHT = 1 << 1; + + /** + * Edge flag indicating that the top edge should be affected. + */ + public static final int EDGE_TOP = 1 << 2; + + /** + * Edge flag indicating that the bottom edge should be affected. + */ + public static final int EDGE_BOTTOM = 1 << 3; + + /** + * Edge flag set indicating all edges should be affected. + */ + public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM; + + /** + * Indicates that a check should occur along the horizontal axis + */ + public static final int DIRECTION_HORIZONTAL = 1 << 0; + + /** + * Indicates that a check should occur along the vertical axis + */ + public static final int DIRECTION_VERTICAL = 1 << 1; + + /** + * Indicates that a check should occur along all axes + */ + public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; + + private static final int EDGE_SIZE = 20; // dp + + private static final int BASE_SETTLE_DURATION = 256; // ms + private static final int MAX_SETTLE_DURATION = 600; // ms + + // Current drag state; idle, dragging or settling + private int mDragState; + + // Distance to travel before a drag may begin + private int mTouchSlop; + + // Last known position/pointer tracking + private int mActivePointerId = INVALID_POINTER; + private float[] mInitialMotionX; + private float[] mInitialMotionY; + private float[] mLastMotionX; + private float[] mLastMotionY; + private int[] mInitialEdgesTouched; + private int[] mEdgeDragsInProgress; + private int[] mEdgeDragsLocked; + private int mPointersDown; + + private VelocityTracker mVelocityTracker; + private float mMaxVelocity; + private float mMinVelocity; + + private int mEdgeSize; + private int mTrackingEdges; + + private Scroller mScroller; + + private final Callback mCallback; + + private View mCapturedView; + private boolean mReleaseInProgress; + + private final ViewGroup mParentView; + + /** + * A Callback is used as a communication channel with the ViewDragHelper back to the + * parent view using it. on*methods are invoked on siginficant events and several + * accessor methods are expected to provide the ViewDragHelper with more information + * about the state of the parent view upon request. The callback also makes decisions + * governing the range and draggability of child views. + */ + public static abstract class Callback { + /** + * Called when the drag state changes. See the STATE_* constants + * for more information. + * + * @param state The new drag state + * + * @see #STATE_IDLE + * @see #STATE_DRAGGING + * @see #STATE_SETTLING + */ + public void onViewDragStateChanged(int state) {} + + /** + * Called when the captured view's position changes as the result of a drag or settle. + * + * @param changedView View whose position changed + * @param left New X coordinate of the left edge of the view + * @param top New Y coordinate of the top edge of the view + * @param dx Change in X position from the last call + * @param dy Change in Y position from the last call + */ + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {} + + /** + * Called when a child view is captured for dragging or settling. The ID of the pointer + * currently dragging the captured view is supplied. If activePointerId is + * identified as {@link #INVALID_POINTER} the capture is programmatic instead of + * pointer-initiated. + * + * @param capturedChild Child view that was captured + * @param activePointerId Pointer id tracking the child capture + */ + public void onViewCaptured(View capturedChild, int activePointerId) {} + + /** + * Called when the child view is no longer being actively dragged. + * The fling velocity is also supplied, if relevant. The velocity values may + * be clamped to system minimums or maximums. + * + *

Calling code may decide to fling or otherwise release the view to let it + * settle into place. It should do so using {@link #settleCapturedViewAt(int, int)} + * or {@link #flingCapturedView(int, int, int, int)}. If the Callback invokes + * one of these methods, the ViewDragHelper will enter {@link #STATE_SETTLING} + * and the view capture will not fully end until it comes to a complete stop. + * If neither of these methods is invoked before onViewReleased returns, + * the view will stop in place and the ViewDragHelper will return to + * {@link #STATE_IDLE}.

+ * + * @param releasedChild The captured child view now being released + * @param xvel X velocity of the pointer as it left the screen in pixels per second. + * @param yvel Y velocity of the pointer as it left the screen in pixels per second. + */ + public void onViewReleased(View releasedChild, float xvel, float yvel) {} + + /** + * Called when one of the subscribed edges in the parent view has been touched + * by the user while no child view is currently captured. + * + * @param edgeFlags A combination of edge flags describing the edge(s) currently touched + * @param pointerId ID of the pointer touching the described edge(s) + * @see #EDGE_LEFT + * @see #EDGE_TOP + * @see #EDGE_RIGHT + * @see #EDGE_BOTTOM + */ + public void onEdgeTouched(int edgeFlags, int pointerId) {} + + /** + * Called when the given edge may become locked. This can happen if an edge drag + * was preliminarily rejected before beginning, but after {@link #onEdgeTouched(int, int)} + * was called. This method should return true to lock this edge or false to leave it + * unlocked. The default behavior is to leave edges unlocked. + * + * @param edgeFlags A combination of edge flags describing the edge(s) locked + * @return true to lock the edge, false to leave it unlocked + */ + public boolean onEdgeLock(int edgeFlags) { + return false; + } + + /** + * Called when the user has started a deliberate drag away from one + * of the subscribed edges in the parent view while no child view is currently captured. + * + * @param edgeFlags A combination of edge flags describing the edge(s) dragged + * @param pointerId ID of the pointer touching the described edge(s) + * @see #EDGE_LEFT + * @see #EDGE_TOP + * @see #EDGE_RIGHT + * @see #EDGE_BOTTOM + */ + public void onEdgeDragStarted(int edgeFlags, int pointerId) {} + + /** + * Called to determine the Z-order of child views. + * + * @param index the ordered position to query for + * @return index of the view that should be ordered at position index + */ + public int getOrderedChildIndex(int index) { + return index; + } + + /** + * Return the magnitude of a draggable child view's horizontal range of motion in pixels. + * This method should return 0 for views that cannot move horizontally. + * + * @param child Child view to check + * @return range of horizontal motion in pixels + */ + public int getViewHorizontalDragRange(View child) { + return 0; + } + + /** + * Return the magnitude of a draggable child view's vertical range of motion in pixels. + * This method should return 0 for views that cannot move vertically. + * + * @param child Child view to check + * @return range of vertical motion in pixels + */ + public int getViewVerticalDragRange(View child) { + return 0; + } + + /** + * Called when the user's input indicates that they want to capture the given child view + * with the pointer indicated by pointerId. The callback should return true if the user + * is permitted to drag the given view with the indicated pointer. + * + *

ViewDragHelper may call this method multiple times for the same view even if + * the view is already captured; this indicates that a new pointer is trying to take + * control of the view.

+ * + *

If this method returns true, a call to {@link #onViewCaptured(android.view.View, int)} + * will follow if the capture is successful.

+ * + * @param child Child the user is attempting to capture + * @param pointerId ID of the pointer attempting the capture + * @return true if capture should be allowed, false otherwise + */ + public abstract boolean tryCaptureView(View child, int pointerId); + + /** + * Restrict the motion of the dragged child view along the horizontal axis. + * The default implementation does not allow horizontal motion; the extending + * class must override this method and provide the desired clamping. + * + * + * @param child Child view being dragged + * @param left Attempted motion along the X axis + * @param dx Proposed change in position for left + * @return The new clamped position for left + */ + public int clampViewPositionHorizontal(View child, int left, int dx) { + return 0; + } + + /** + * Restrict the motion of the dragged child view along the vertical axis. + * The default implementation does not allow vertical motion; the extending + * class must override this method and provide the desired clamping. + * + * + * @param child Child view being dragged + * @param top Attempted motion along the Y axis + * @param dy Proposed change in position for top + * @return The new clamped position for top + */ + public int clampViewPositionVertical(View child, int top, int dy) { + return 0; + } + } + + /** + * Interpolator defining the animation curve for mScroller + */ + private static final Interpolator sInterpolator = new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + + private final Runnable mSetIdleRunnable = new Runnable() { + public void run() { + setDragState(STATE_IDLE); + } + }; + + /** + * Factory method to create a new ViewDragHelper. + * + * @param forParent Parent view to monitor + * @param cb Callback to provide information and receive events + * @return a new ViewDragHelper instance + */ + public static ViewDragHelper create(ViewGroup forParent, Callback cb) { + return new ViewDragHelper(forParent.getContext(), forParent, cb); + } + + /** + * Factory method to create a new ViewDragHelper. + * + * @param forParent Parent view to monitor + * @param sensitivity Multiplier for how sensitive the helper should be about detecting + * the start of a drag. Larger values are more sensitive. 1.0f is normal. + * @param cb Callback to provide information and receive events + * @return a new ViewDragHelper instance + */ + public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) { + final ViewDragHelper helper = create(forParent, cb); + helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity)); + return helper; + } + + /** + * Apps should use ViewDragHelper.create() to get a new instance. + * This will allow VDH to use internal compatibility implementations for different + * platform versions. + * + * @param context Context to initialize config-dependent params from + * @param forParent Parent view to monitor + */ + private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) { + if (forParent == null) { + throw new IllegalArgumentException("Parent view may not be null"); + } + if (cb == null) { + throw new IllegalArgumentException("Callback may not be null"); + } + + mParentView = forParent; + mCallback = cb; + + final ViewConfiguration vc = ViewConfiguration.get(context); + final float density = context.getResources().getDisplayMetrics().density; + mEdgeSize = (int) (EDGE_SIZE * density + 0.5f); + + mTouchSlop = vc.getScaledTouchSlop(); + mMaxVelocity = vc.getScaledMaximumFlingVelocity(); + mMinVelocity = vc.getScaledMinimumFlingVelocity(); + mScroller = new Scroller(context, sInterpolator); + } + + /** + * Set the minimum velocity that will be detected as having a magnitude greater than zero + * in pixels per second. Callback methods accepting a velocity will be clamped appropriately. + * + * @param minVel Minimum velocity to detect + */ + public void setMinVelocity(float minVel) { + mMinVelocity = minVel; + } + + /** + * Return the currently configured minimum velocity. Any flings with a magnitude less + * than this value in pixels per second. Callback methods accepting a velocity will receive + * zero as a velocity value if the real detected velocity was below this threshold. + * + * @return the minimum velocity that will be detected + */ + public float getMinVelocity() { + return mMinVelocity; + } + + /** + * Retrieve the current drag state of this helper. This will return one of + * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}. + * @return The current drag state + */ + public int getViewDragState() { + return mDragState; + } + + /** + * Enable edge tracking for the selected edges of the parent view. + * The callback's {@link Callback#onEdgeTouched(int, int)} and + * {@link Callback#onEdgeDragStarted(int, int)} methods will only be invoked + * for edges for which edge tracking has been enabled. + * + * @param edgeFlags Combination of edge flags describing the edges to watch + * @see #EDGE_LEFT + * @see #EDGE_TOP + * @see #EDGE_RIGHT + * @see #EDGE_BOTTOM + */ + public void setEdgeTrackingEnabled(int edgeFlags) { + mTrackingEdges = edgeFlags; + } + + /** + * Return the size of an edge. This is the range in pixels along the edges of this view + * that will actively detect edge touches or drags if edge tracking is enabled. + * + * @return The size of an edge in pixels + * @see #setEdgeTrackingEnabled(int) + */ + public int getEdgeSize() { + return mEdgeSize; + } + + /** + * Capture a specific child view for dragging within the parent. The callback will be notified + * but {@link Callback#tryCaptureView(android.view.View, int)} will not be asked permission to + * capture this view. + * + * @param childView Child view to capture + * @param activePointerId ID of the pointer that is dragging the captured child view + */ + public void captureChildView(View childView, int activePointerId) { + if (childView.getParent() != mParentView) { + throw new IllegalArgumentException("captureChildView: parameter must be a descendant " + + "of the ViewDragHelper's tracked parent view (" + mParentView + ")"); + } + + mCapturedView = childView; + mActivePointerId = activePointerId; + mCallback.onViewCaptured(childView, activePointerId); + setDragState(STATE_DRAGGING); + } + + /** + * @return The currently captured view, or null if no view has been captured. + */ + public View getCapturedView() { + return mCapturedView; + } + + /** + * @return The ID of the pointer currently dragging the captured view, + * or {@link #INVALID_POINTER}. + */ + public int getActivePointerId() { + return mActivePointerId; + } + + /** + * @return The minimum distance in pixels that the user must travel to initiate a drag + */ + public int getTouchSlop() { + return mTouchSlop; + } + + /** + * The result of a call to this method is equivalent to + * {@link #processTouchEvent(android.view.MotionEvent)} receiving an ACTION_CANCEL event. + */ + public void cancel() { + mActivePointerId = INVALID_POINTER; + clearMotionHistory(); + + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + /** + * {@link #cancel()}, but also abort all motion in progress and snap to the end of any + * animation. + */ + public void abort() { + cancel(); + if (mDragState == STATE_SETTLING) { + final int oldX = mScroller.getCurrX(); + final int oldY = mScroller.getCurrY(); + mScroller.abortAnimation(); + final int newX = mScroller.getCurrX(); + final int newY = mScroller.getCurrY(); + mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY); + } + setDragState(STATE_IDLE); + } + + /** + * Animate the view child to the given (left, top) position. + * If this method returns true, the caller should invoke {@link #continueSettling(boolean)} + * on each subsequent frame to continue the motion until it returns false. If this method + * returns false there is no further work to do to complete the movement. + * + *

This operation does not count as a capture event, though {@link #getCapturedView()} + * will still report the sliding view while the slide is in progress.

+ * + * @param child Child view to capture and animate + * @param finalLeft Final left position of child + * @param finalTop Final top position of child + * @return true if animation should continue through {@link #continueSettling(boolean)} calls + */ + public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) { + mCapturedView = child; + mActivePointerId = INVALID_POINTER; + + boolean continueSliding = forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0); + if (!continueSliding && mDragState == STATE_IDLE && mCapturedView != null) { + // If we're in an IDLE state to begin with and aren't moving anywhere, we + // end up having a non-null capturedView with an IDLE dragState + mCapturedView = null; + } + + return continueSliding; + } + + /** + * Settle the captured view at the given (left, top) position. + * The appropriate velocity from prior motion will be taken into account. + * If this method returns true, the caller should invoke {@link #continueSettling(boolean)} + * on each subsequent frame to continue the motion until it returns false. If this method + * returns false there is no further work to do to complete the movement. + * + * @param finalLeft Settled left edge position for the captured view + * @param finalTop Settled top edge position for the captured view + * @return true if animation should continue through {@link #continueSettling(boolean)} calls + */ + public boolean settleCapturedViewAt(int finalLeft, int finalTop) { + if (!mReleaseInProgress) { + throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to " + + "Callback#onViewReleased"); + } + + return forceSettleCapturedViewAt(finalLeft, finalTop, + (int) mVelocityTracker.getXVelocity(mActivePointerId), + (int) mVelocityTracker.getYVelocity(mActivePointerId)); + } + + /** + * Settle the captured view at the given (left, top) position. + * + * @param finalLeft Target left position for the captured view + * @param finalTop Target top position for the captured view + * @param xvel Horizontal velocity + * @param yvel Vertical velocity + * @return true if animation should continue through {@link #continueSettling(boolean)} calls + */ + private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) { + final int startLeft = mCapturedView.getLeft(); + final int startTop = mCapturedView.getTop(); + final int dx = finalLeft - startLeft; + final int dy = finalTop - startTop; + + if (dx == 0 && dy == 0) { + // Nothing to do. Send callbacks, be done. + mScroller.abortAnimation(); + setDragState(STATE_IDLE); + return false; + } + + final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel); + mScroller.startScroll(startLeft, startTop, dx, dy, duration); + + setDragState(STATE_SETTLING); + return true; + } + + private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) { + xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity); + yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity); + final int absDx = Math.abs(dx); + final int absDy = Math.abs(dy); + final int absXVel = Math.abs(xvel); + final int absYVel = Math.abs(yvel); + final int addedVel = absXVel + absYVel; + final int addedDistance = absDx + absDy; + + final float xweight = xvel != 0 ? (float) absXVel / addedVel : + (float) absDx / addedDistance; + final float yweight = yvel != 0 ? (float) absYVel / addedVel : + (float) absDy / addedDistance; + + int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child)); + int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child)); + + return (int) (xduration * xweight + yduration * yweight); + } + + private int computeAxisDuration(int delta, int velocity, int motionRange) { + if (delta == 0) { + return 0; + } + + final int width = mParentView.getWidth(); + final int halfWidth = width / 2; + final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width); + final float distance = halfWidth + halfWidth * + distanceInfluenceForSnapDuration(distanceRatio); + + int duration; + velocity = Math.abs(velocity); + if (velocity > 0) { + duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); + } else { + final float range = (float) Math.abs(delta) / motionRange; + duration = (int) ((range + 1) * BASE_SETTLE_DURATION); + } + return Math.min(duration, MAX_SETTLE_DURATION); + } + + /** + * Clamp the magnitude of value for absMin and absMax. + * If the value is below the minimum, it will be clamped to zero. + * If the value is above the maximum, it will be clamped to the maximum. + * + * @param value Value to clamp + * @param absMin Absolute value of the minimum significant value to return + * @param absMax Absolute value of the maximum value to return + * @return The clamped value with the same sign as value + */ + private int clampMag(int value, int absMin, int absMax) { + final int absValue = Math.abs(value); + if (absValue < absMin) return 0; + if (absValue > absMax) return value > 0 ? absMax : -absMax; + return value; + } + + /** + * Clamp the magnitude of value for absMin and absMax. + * If the value is below the minimum, it will be clamped to zero. + * If the value is above the maximum, it will be clamped to the maximum. + * + * @param value Value to clamp + * @param absMin Absolute value of the minimum significant value to return + * @param absMax Absolute value of the maximum value to return + * @return The clamped value with the same sign as value + */ + private float clampMag(float value, float absMin, float absMax) { + final float absValue = Math.abs(value); + if (absValue < absMin) return 0; + if (absValue > absMax) return value > 0 ? absMax : -absMax; + return value; + } + + private float distanceInfluenceForSnapDuration(float f) { + f -= 0.5f; // center the values about 0. + f *= 0.3f * Math.PI / 2.0f; + return (float) Math.sin(f); + } + + /** + * Settle the captured view based on standard free-moving fling behavior. + * The caller should invoke {@link #continueSettling(boolean)} on each subsequent frame + * to continue the motion until it returns false. + * + * @param minLeft Minimum X position for the view's left edge + * @param minTop Minimum Y position for the view's top edge + * @param maxLeft Maximum X position for the view's left edge + * @param maxTop Maximum Y position for the view's top edge + */ + public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) { + if (!mReleaseInProgress) { + throw new IllegalStateException("Cannot flingCapturedView outside of a call to " + + "Callback#onViewReleased"); + } + + mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(), + (int) mVelocityTracker.getXVelocity(mActivePointerId), + (int) mVelocityTracker.getYVelocity(mActivePointerId), + minLeft, maxLeft, minTop, maxTop); + + setDragState(STATE_SETTLING); + } + + /** + * Move the captured settling view by the appropriate amount for the current time. + * If continueSettling returns true, the caller should call it again + * on the next frame to continue. + * + * @param deferCallbacks true if state callbacks should be deferred via posted message. + * Set this to true if you are calling this method from + * {@link android.view.View#computeScroll()} or similar methods + * invoked as part of layout or drawing. + * @return true if settle is still in progress + */ + public boolean continueSettling(boolean deferCallbacks) { + if (mDragState == STATE_SETTLING) { + boolean keepGoing = mScroller.computeScrollOffset(); + final int x = mScroller.getCurrX(); + final int y = mScroller.getCurrY(); + final int dx = x - mCapturedView.getLeft(); + final int dy = y - mCapturedView.getTop(); + + if (dx != 0) { + mCapturedView.offsetLeftAndRight(dx); + } + if (dy != 0) { + mCapturedView.offsetTopAndBottom(dy); + } + + if (dx != 0 || dy != 0) { + mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy); + } + + if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) { + // Close enough. The interpolator/scroller might think we're still moving + // but the user sure doesn't. + mScroller.abortAnimation(); + keepGoing = false; + } + + if (!keepGoing) { + if (deferCallbacks) { + mParentView.post(mSetIdleRunnable); + } else { + setDragState(STATE_IDLE); + } + } + } + + return mDragState == STATE_SETTLING; + } + + /** + * Like all callback events this must happen on the UI thread, but release + * involves some extra semantics. During a release (mReleaseInProgress) + * is the only time it is valid to call {@link #settleCapturedViewAt(int, int)} + * or {@link #flingCapturedView(int, int, int, int)}. + */ + private void dispatchViewReleased(float xvel, float yvel) { + mReleaseInProgress = true; + mCallback.onViewReleased(mCapturedView, xvel, yvel); + mReleaseInProgress = false; + + if (mDragState == STATE_DRAGGING) { + // onViewReleased didn't call a method that would have changed this. Go idle. + setDragState(STATE_IDLE); + } + } + + private void clearMotionHistory() { + if (mInitialMotionX == null) { + return; + } + Arrays.fill(mInitialMotionX, 0); + Arrays.fill(mInitialMotionY, 0); + Arrays.fill(mLastMotionX, 0); + Arrays.fill(mLastMotionY, 0); + Arrays.fill(mInitialEdgesTouched, 0); + Arrays.fill(mEdgeDragsInProgress, 0); + Arrays.fill(mEdgeDragsLocked, 0); + mPointersDown = 0; + } + + private void clearMotionHistory(int pointerId) { + if (mInitialMotionX == null) { + return; + } + mInitialMotionX[pointerId] = 0; + mInitialMotionY[pointerId] = 0; + mLastMotionX[pointerId] = 0; + mLastMotionY[pointerId] = 0; + mInitialEdgesTouched[pointerId] = 0; + mEdgeDragsInProgress[pointerId] = 0; + mEdgeDragsLocked[pointerId] = 0; + mPointersDown &= ~(1 << pointerId); + } + + private void ensureMotionHistorySizeForId(int pointerId) { + if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) { + float[] imx = new float[pointerId + 1]; + float[] imy = new float[pointerId + 1]; + float[] lmx = new float[pointerId + 1]; + float[] lmy = new float[pointerId + 1]; + int[] iit = new int[pointerId + 1]; + int[] edip = new int[pointerId + 1]; + int[] edl = new int[pointerId + 1]; + + if (mInitialMotionX != null) { + System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length); + System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length); + System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length); + System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length); + System.arraycopy(mInitialEdgesTouched, 0, iit, 0, mInitialEdgesTouched.length); + System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length); + System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length); + } + + mInitialMotionX = imx; + mInitialMotionY = imy; + mLastMotionX = lmx; + mLastMotionY = lmy; + mInitialEdgesTouched = iit; + mEdgeDragsInProgress = edip; + mEdgeDragsLocked = edl; + } + } + + private void saveInitialMotion(float x, float y, int pointerId) { + ensureMotionHistorySizeForId(pointerId); + mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x; + mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y; + mInitialEdgesTouched[pointerId] = getEdgesTouched((int) x, (int) y); + mPointersDown |= 1 << pointerId; + } + + private void saveLastMotion(MotionEvent ev) { + final int pointerCount = ev.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = ev.getPointerId(i); + final float x = ev.getX(i); + final float y = ev.getY(i); + mLastMotionX[pointerId] = x; + mLastMotionY[pointerId] = y; + } + } + + /** + * Check if the given pointer ID represents a pointer that is currently down (to the best + * of the ViewDragHelper's knowledge). + * + *

The state used to report this information is populated by the methods + * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or + * {@link #processTouchEvent(android.view.MotionEvent)}. If one of these methods has not + * been called for all relevant MotionEvents to track, the information reported + * by this method may be stale or incorrect.

+ * + * @param pointerId pointer ID to check; corresponds to IDs provided by MotionEvent + * @return true if the pointer with the given ID is still down + */ + public boolean isPointerDown(int pointerId) { + return (mPointersDown & 1 << pointerId) != 0; + } + + void setDragState(int state) { + mParentView.removeCallbacks(mSetIdleRunnable); + if (mDragState != state) { + mDragState = state; + mCallback.onViewDragStateChanged(state); + if (mDragState == STATE_IDLE) { + mCapturedView = null; + } + } + } + + /** + * Attempt to capture the view with the given pointer ID. The callback will be involved. + * This will put us into the "dragging" state. If we've already captured this view with + * this pointer this method will immediately return true without consulting the callback. + * + * @param toCapture View to capture + * @param pointerId Pointer to capture with + * @return true if capture was successful + */ + boolean tryCaptureViewForDrag(View toCapture, int pointerId) { + if (toCapture == mCapturedView && mActivePointerId == pointerId) { + // Already done! + return true; + } + if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) { + mActivePointerId = pointerId; + captureChildView(toCapture, pointerId); + return true; + } + return false; + } + + /** + * Tests scrollability within child views of v given a delta of dx. + * + * @param v View to test for horizontal scrollability + * @param checkV Whether the view v passed should itself be checked for scrollability (true), + * or just its children (false). + * @param dx Delta scrolled in pixels along the X axis + * @param dy Delta scrolled in pixels along the Y axis + * @param x X coordinate of the active touch point + * @param y Y coordinate of the active touch point + * @return true if child views of v can be scrolled by delta of dx. + */ + protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) { + if (v instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) v; + final int scrollX = v.getScrollX(); + final int scrollY = v.getScrollY(); + final int count = group.getChildCount(); + // Count backwards - let topmost views consume scroll distance first. + for (int i = count - 1; i >= 0; i--) { + // TODO: Add versioned support here for transformed views. + // This will not work for transformed views in Honeycomb+ + final View child = group.getChildAt(i); + if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && + y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && + canScroll(child, true, dx, dy, x + scrollX - child.getLeft(), + y + scrollY - child.getTop())) { + return true; + } + } + } + + return checkV && (v.canScrollHorizontally(-dx) || + v.canScrollVertically(-dy)); + } + + /** + * Check if this event as provided to the parent view's onInterceptTouchEvent should + * cause the parent to intercept the touch event stream. + * + * @param ev MotionEvent provided to onInterceptTouchEvent + * @return true if the parent view should return true from onInterceptTouchEvent + */ + public boolean shouldInterceptTouchEvent(MotionEvent ev) { + final int action = ev.getActionMasked(); + final int actionIndex = ev.getActionIndex(); + + if (action == MotionEvent.ACTION_DOWN) { + // Reset things for a new event stream, just in case we didn't get + // the whole previous stream. + cancel(); + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + final int pointerId = ev.getPointerId(0); + saveInitialMotion(x, y, pointerId); + + final View toCapture = findTopChildUnder((int) x, (int) y); + + // Catch a settling view if possible. + if (toCapture == mCapturedView && mDragState == STATE_SETTLING) { + tryCaptureViewForDrag(toCapture, pointerId); + } + + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + break; + } + + case MotionEvent.ACTION_POINTER_DOWN: { + final int pointerId = ev.getPointerId(actionIndex); + final float x = ev.getX(actionIndex); + final float y = ev.getY(actionIndex); + + saveInitialMotion(x, y, pointerId); + + // A ViewDragHelper can only manipulate one view at a time. + if (mDragState == STATE_IDLE) { + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + } else if (mDragState == STATE_SETTLING) { + // Catch a settling view if possible. + final View toCapture = findTopChildUnder((int) x, (int) y); + if (toCapture == mCapturedView) { + tryCaptureViewForDrag(toCapture, pointerId); + } + } + break; + } + + case MotionEvent.ACTION_MOVE: { + if (mInitialMotionX == null || mInitialMotionY == null) break; + + // First to cross a touch slop over a draggable view wins. Also report edge drags. + final int pointerCount = ev.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = ev.getPointerId(i); + final float x = ev.getX(i); + final float y = ev.getY(i); + final float dx = x - mInitialMotionX[pointerId]; + final float dy = y - mInitialMotionY[pointerId]; + + final View toCapture = findTopChildUnder((int) x, (int) y); + final boolean pastSlop = toCapture != null && checkTouchSlop(toCapture, dx, dy); + if (pastSlop) { + // check the callback's + // getView[Horizontal|Vertical]DragRange methods to know + // if you can move at all along an axis, then see if it + // would clamp to the same value. If you can't move at + // all in every dimension with a nonzero range, bail. + final int oldLeft = toCapture.getLeft(); + final int targetLeft = oldLeft + (int) dx; + final int newLeft = mCallback.clampViewPositionHorizontal(toCapture, + targetLeft, (int) dx); + final int oldTop = toCapture.getTop(); + final int targetTop = oldTop + (int) dy; + final int newTop = mCallback.clampViewPositionVertical(toCapture, targetTop, + (int) dy); + final int horizontalDragRange = mCallback.getViewHorizontalDragRange( + toCapture); + final int verticalDragRange = mCallback.getViewVerticalDragRange(toCapture); + if ((horizontalDragRange == 0 || horizontalDragRange > 0 + && newLeft == oldLeft) && (verticalDragRange == 0 + || verticalDragRange > 0 && newTop == oldTop)) { + break; + } + } + reportNewEdgeDrags(dx, dy, pointerId); + if (mDragState == STATE_DRAGGING) { + // Callback might have started an edge drag + break; + } + + if (pastSlop && tryCaptureViewForDrag(toCapture, pointerId)) { + break; + } + } + saveLastMotion(ev); + break; + } + + case MotionEvent.ACTION_POINTER_UP: { + final int pointerId = ev.getPointerId(actionIndex); + clearMotionHistory(pointerId); + break; + } + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + cancel(); + break; + } + } + + return mDragState == STATE_DRAGGING; + } + + /** + * Process a touch event received by the parent view. This method will dispatch callback events + * as needed before returning. The parent view's onTouchEvent implementation should call this. + * + * @param ev The touch event received by the parent view + */ + public void processTouchEvent(MotionEvent ev) { + final int action = ev.getActionMasked(); + final int actionIndex = ev.getActionIndex(); + + if (action == MotionEvent.ACTION_DOWN) { + // Reset things for a new event stream, just in case we didn't get + // the whole previous stream. + cancel(); + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + final int pointerId = ev.getPointerId(0); + final View toCapture = findTopChildUnder((int) x, (int) y); + + saveInitialMotion(x, y, pointerId); + + // Since the parent is already directly processing this touch event, + // there is no reason to delay for a slop before dragging. + // Start immediately if possible. + tryCaptureViewForDrag(toCapture, pointerId); + + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + break; + } + + case MotionEvent.ACTION_POINTER_DOWN: { + final int pointerId = ev.getPointerId(actionIndex); + final float x = ev.getX(actionIndex); + final float y = ev.getY(actionIndex); + + saveInitialMotion(x, y, pointerId); + + // A ViewDragHelper can only manipulate one view at a time. + if (mDragState == STATE_IDLE) { + // If we're idle we can do anything! Treat it like a normal down event. + + final View toCapture = findTopChildUnder((int) x, (int) y); + tryCaptureViewForDrag(toCapture, pointerId); + + final int edgesTouched = mInitialEdgesTouched[pointerId]; + if ((edgesTouched & mTrackingEdges) != 0) { + mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + } + } else if (isCapturedViewUnder((int) x, (int) y)) { + // We're still tracking a captured view. If the same view is under this + // point, we'll swap to controlling it with this pointer instead. + // (This will still work if we're "catching" a settling view.) + + tryCaptureViewForDrag(mCapturedView, pointerId); + } + break; + } + + case MotionEvent.ACTION_MOVE: { + if (mDragState == STATE_DRAGGING) { + final int index = ev.findPointerIndex(mActivePointerId); + final float x = ev.getX(index); + final float y = ev.getY(index); + final int idx = (int) (x - mLastMotionX[mActivePointerId]); + final int idy = (int) (y - mLastMotionY[mActivePointerId]); + + dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy); + + saveLastMotion(ev); + } else { + // Check to see if any pointer is now over a draggable view. + final int pointerCount = ev.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = ev.getPointerId(i); + final float x = ev.getX(i); + final float y = ev.getY(i); + final float dx = x - mInitialMotionX[pointerId]; + final float dy = y - mInitialMotionY[pointerId]; + + reportNewEdgeDrags(dx, dy, pointerId); + if (mDragState == STATE_DRAGGING) { + // Callback might have started an edge drag. + break; + } + + final View toCapture = findTopChildUnder((int) x, (int) y); + if (checkTouchSlop(toCapture, dx, dy) && + tryCaptureViewForDrag(toCapture, pointerId)) { + break; + } + } + saveLastMotion(ev); + } + break; + } + + case MotionEvent.ACTION_POINTER_UP: { + final int pointerId = ev.getPointerId(actionIndex); + if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) { + // Try to find another pointer that's still holding on to the captured view. + int newActivePointer = INVALID_POINTER; + final int pointerCount = ev.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + final int id = ev.getPointerId(i); + if (id == mActivePointerId) { + // This one's going away, skip. + continue; + } + + final float x = ev.getX(i); + final float y = ev.getY(i); + if (findTopChildUnder((int) x, (int) y) == mCapturedView && + tryCaptureViewForDrag(mCapturedView, id)) { + newActivePointer = mActivePointerId; + break; + } + } + + if (newActivePointer == INVALID_POINTER) { + // We didn't find another pointer still touching the view, release it. + releaseViewForPointerUp(); + } + } + clearMotionHistory(pointerId); + break; + } + + case MotionEvent.ACTION_UP: { + if (mDragState == STATE_DRAGGING) { + releaseViewForPointerUp(); + } + cancel(); + break; + } + + case MotionEvent.ACTION_CANCEL: { + if (mDragState == STATE_DRAGGING) { + dispatchViewReleased(0, 0); + } + cancel(); + break; + } + } + } + + private void reportNewEdgeDrags(float dx, float dy, int pointerId) { + int dragsStarted = 0; + if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) { + dragsStarted |= EDGE_LEFT; + } + if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) { + dragsStarted |= EDGE_TOP; + } + if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) { + dragsStarted |= EDGE_RIGHT; + } + if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) { + dragsStarted |= EDGE_BOTTOM; + } + + if (dragsStarted != 0) { + mEdgeDragsInProgress[pointerId] |= dragsStarted; + mCallback.onEdgeDragStarted(dragsStarted, pointerId); + } + } + + private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) { + final float absDelta = Math.abs(delta); + final float absODelta = Math.abs(odelta); + + if ((mInitialEdgesTouched[pointerId] & edge) != edge || (mTrackingEdges & edge) == 0 || + (mEdgeDragsLocked[pointerId] & edge) == edge || + (mEdgeDragsInProgress[pointerId] & edge) == edge || + (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) { + return false; + } + if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) { + mEdgeDragsLocked[pointerId] |= edge; + return false; + } + return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop; + } + + /** + * Check if we've crossed a reasonable touch slop for the given child view. + * If the child cannot be dragged along the horizontal or vertical axis, motion + * along that axis will not count toward the slop check. + * + * @param child Child to check + * @param dx Motion since initial position along X axis + * @param dy Motion since initial position along Y axis + * @return true if the touch slop has been crossed + */ + private boolean checkTouchSlop(View child, float dx, float dy) { + if (child == null) { + return false; + } + final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0; + final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0; + + if (checkHorizontal && checkVertical) { + return dx * dx + dy * dy > mTouchSlop * mTouchSlop; + } else if (checkHorizontal) { + return Math.abs(dx) > mTouchSlop; + } else if (checkVertical) { + return Math.abs(dy) > mTouchSlop; + } + return false; + } + + /** + * Check if any pointer tracked in the current gesture has crossed + * the required slop threshold. + * + *

This depends on internal state populated by + * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or + * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on + * the results of this method after all currently available touch data + * has been provided to one of these two methods.

+ * + * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL}, + * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL} + * @return true if the slop threshold has been crossed, false otherwise + */ + public boolean checkTouchSlop(int directions) { + final int count = mInitialMotionX.length; + for (int i = 0; i < count; i++) { + if (checkTouchSlop(directions, i)) { + return true; + } + } + return false; + } + + /** + * Check if the specified pointer tracked in the current gesture has crossed + * the required slop threshold. + * + *

This depends on internal state populated by + * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or + * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on + * the results of this method after all currently available touch data + * has been provided to one of these two methods.

+ * + * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL}, + * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL} + * @param pointerId ID of the pointer to slop check as specified by MotionEvent + * @return true if the slop threshold has been crossed, false otherwise + */ + public boolean checkTouchSlop(int directions, int pointerId) { + if (!isPointerDown(pointerId)) { + return false; + } + + final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL; + final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL; + + final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId]; + final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId]; + + if (checkHorizontal && checkVertical) { + return dx * dx + dy * dy > mTouchSlop * mTouchSlop; + } else if (checkHorizontal) { + return Math.abs(dx) > mTouchSlop; + } else if (checkVertical) { + return Math.abs(dy) > mTouchSlop; + } + return false; + } + + /** + * Check if any of the edges specified were initially touched in the currently active gesture. + * If there is no currently active gesture this method will return false. + * + * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT}, + * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and + * {@link #EDGE_ALL} + * @return true if any of the edges specified were initially touched in the current gesture + */ + public boolean isEdgeTouched(int edges) { + final int count = mInitialEdgesTouched.length; + for (int i = 0; i < count; i++) { + if (isEdgeTouched(edges, i)) { + return true; + } + } + return false; + } + + /** + * Check if any of the edges specified were initially touched by the pointer with + * the specified ID. If there is no currently active gesture or if there is no pointer with + * the given ID currently down this method will return false. + * + * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT}, + * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and + * {@link #EDGE_ALL} + * @return true if any of the edges specified were initially touched in the current gesture + */ + public boolean isEdgeTouched(int edges, int pointerId) { + return isPointerDown(pointerId) && (mInitialEdgesTouched[pointerId] & edges) != 0; + } + + private void releaseViewForPointerUp() { + mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); + final float xvel = clampMag( + mVelocityTracker.getXVelocity(mActivePointerId), + mMinVelocity, mMaxVelocity); + final float yvel = clampMag( + mVelocityTracker.getYVelocity(mActivePointerId), + mMinVelocity, mMaxVelocity); + dispatchViewReleased(xvel, yvel); + } + + private void dragTo(int left, int top, int dx, int dy) { + int clampedX = left; + int clampedY = top; + final int oldLeft = mCapturedView.getLeft(); + final int oldTop = mCapturedView.getTop(); + if (dx != 0) { + clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx); + mCapturedView.offsetLeftAndRight(clampedX - oldLeft); + } + if (dy != 0) { + clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy); + mCapturedView.offsetTopAndBottom(clampedY - oldTop); + } + + if (dx != 0 || dy != 0) { + final int clampedDx = clampedX - oldLeft; + final int clampedDy = clampedY - oldTop; + mCallback.onViewPositionChanged(mCapturedView, clampedX, clampedY, + clampedDx, clampedDy); + } + } + + /** + * Determine if the currently captured view is under the given point in the + * parent view's coordinate system. If there is no captured view this method + * will return false. + * + * @param x X position to test in the parent's coordinate system + * @param y Y position to test in the parent's coordinate system + * @return true if the captured view is under the given point, false otherwise + */ + public boolean isCapturedViewUnder(int x, int y) { + return isViewUnder(mCapturedView, x, y); + } + + /** + * Determine if the supplied view is under the given point in the + * parent view's coordinate system. + * + * @param view Child view of the parent to hit test + * @param x X position to test in the parent's coordinate system + * @param y Y position to test in the parent's coordinate system + * @return true if the supplied view is under the given point, false otherwise + */ + public boolean isViewUnder(View view, int x, int y) { + if (view == null) { + return false; + } + return x >= view.getLeft() && + x < view.getRight() && + y >= view.getTop() && + y < view.getBottom(); + } + + /** + * Find the topmost child under the given point within the parent view's coordinate system. + * The child order is determined using {@link Callback#getOrderedChildIndex(int)}. + * + * @param x X position to test in the parent's coordinate system + * @param y Y position to test in the parent's coordinate system + * @return The topmost child view under (x, y) or null if none found. + */ + public View findTopChildUnder(int x, int y) { + final int childCount = mParentView.getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i)); + if (x >= child.getLeft() && x < child.getRight() && + y >= child.getTop() && y < child.getBottom()) { + return child; + } + } + return null; + } + + private int getEdgesTouched(int x, int y) { + int result = 0; + + if (x < mParentView.getLeft() + mEdgeSize) result |= EDGE_LEFT; + if (y < mParentView.getTop() + mEdgeSize) result |= EDGE_TOP; + if (x > mParentView.getRight() - mEdgeSize) result |= EDGE_RIGHT; + if (y > mParentView.getBottom() - mEdgeSize) result |= EDGE_BOTTOM; + + return result; + } +} diff --git a/app/src/main/java/com/android/cglib/dx/AppDataDirGuesser.java b/app/src/main/java/com/android/cglib/dx/AppDataDirGuesser.java new file mode 100644 index 0000000..b9ece9d --- /dev/null +++ b/app/src/main/java/com/android/cglib/dx/AppDataDirGuesser.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.cglib.dx; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * Uses heuristics to guess the application's private data directory. + */ +class AppDataDirGuesser { + public File guess() { + try { + ClassLoader classLoader = guessSuitableClassLoader(); + // Check that we have an instance of the PathClassLoader. + Class clazz = Class.forName("dalvik.system.PathClassLoader"); + clazz.cast(classLoader); + // Use the toString() method to calculate the data directory. + String pathFromThisClassLoader = getPathFromThisClassLoader(classLoader, clazz); + File[] results = guessPath(pathFromThisClassLoader); + if (results.length > 0) { + return results[0]; + } + } catch (ClassCastException ignored) { + } catch (ClassNotFoundException ignored) { + } + return null; + } + + private ClassLoader guessSuitableClassLoader() { + return AppDataDirGuesser.class.getClassLoader(); + } + + private String getPathFromThisClassLoader(ClassLoader classLoader, + Class pathClassLoaderClass) { + // Prior to ICS, we can simply read the "path" field of the + // PathClassLoader. + try { + Field pathField = pathClassLoaderClass.getDeclaredField("path"); + pathField.setAccessible(true); + return (String) pathField.get(classLoader); + } catch (NoSuchFieldException ignored) { + } catch (IllegalAccessException ignored) { + } catch (ClassCastException ignored) { + } + + // Parsing toString() method: yuck. But no other way to get the path. + String result = classLoader.toString(); + return processClassLoaderString(result); + } + + /** + * Given the result of a ClassLoader.toString() call, process the result so that guessPath + * can use it. There are currently two variants. For Android 4.3 and later, the string + * "DexPathList" should be recognized and the array of dex path elements is parsed. for + * earlier versions, the last nested array ('[' ... ']') is enclosing the string we are + * interested in. + */ + static String processClassLoaderString(String input) { + if (input.contains("DexPathList")) { + return processClassLoaderString43OrLater(input); + } else { + return processClassLoaderString42OrEarlier(input); + } + } + + private static String processClassLoaderString42OrEarlier(String input) { + /* The toString output looks like this: + * dalvik.system.PathClassLoader[dexPath=path/to/apk,libraryPath=path/to/libs] + */ + int index = input.lastIndexOf('['); + input = (index == -1) ? input : input.substring(index + 1); + index = input.indexOf(']'); + input = (index == -1) ? input : input.substring(0, index); + return input; + } + + private static String processClassLoaderString43OrLater(String input) { + /* The toString output looks like this: + * dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/{NAME}", ...], nativeLibraryDirectories=[...]]] + */ + int start = input.indexOf("DexPathList") + "DexPathList".length(); + if (input.length() > start + 4) { // [[ + ]] + String trimmed = input.substring(start); + int end = trimmed.indexOf(']'); + if (trimmed.charAt(0) == '[' && trimmed.charAt(1) == '[' && end >= 0) { + trimmed = trimmed.substring(2, end); + // Comma-separated list, Arrays.toString output. + String split[] = trimmed.split(","); + + // Clean up parts. Each path element is the type of the element plus the path in + // quotes. + for (int i = 0; i < split.length; i++) { + int quoteStart = split[i].indexOf('"'); + int quoteEnd = split[i].lastIndexOf('"'); + if (quoteStart > 0 && quoteStart < quoteEnd) { + split[i] = split[i].substring(quoteStart + 1, quoteEnd); + } + } + + // Need to rejoin components. + StringBuilder sb = new StringBuilder(); + for (String s : split) { + if (sb.length() > 0) { + sb.append(':'); + } + sb.append(s); + } + return sb.toString(); + } + } + + // This is technically a parsing failure. Return the original string, maybe a later + // stage can still salvage this. + return input; + } + + File[] guessPath(String input) { + List results = new ArrayList(); + for (String potential : splitPathList(input)) { + if (!potential.startsWith("/data/app/")) { + continue; + } + int start = "/data/app/".length(); + int end = potential.lastIndexOf(".apk"); + if (end != potential.length() - 4) { + continue; + } + int dash = potential.indexOf("-"); + if (dash != -1) { + end = dash; + } + String packageName = potential.substring(start, end); + File dataDir = new File("/data/data/" + packageName); + if (isWriteableDirectory(dataDir)) { + File cacheDir = new File(dataDir, "cache"); + // The cache directory might not exist -- create if necessary + if (fileOrDirExists(cacheDir) || cacheDir.mkdir()) { + if (isWriteableDirectory(cacheDir)) { + results.add(cacheDir); + } + } + } + } + return results.toArray(new File[results.size()]); + } + + static String[] splitPathList(String input) { + String trimmed = input; + if (input.startsWith("dexPath=")) { + int start = "dexPath=".length(); + int end = input.indexOf(','); + + trimmed = (end == -1) ? input.substring(start) : input.substring(start, end); + } + + return trimmed.split(":"); + } + + boolean fileOrDirExists(File file) { + return file.exists(); + } + + boolean isWriteableDirectory(File file) { + return file.isDirectory() && file.canWrite(); + } +} diff --git a/app/src/main/java/com/android/cglib/dx/BinaryOp.java b/app/src/main/java/com/android/cglib/dx/BinaryOp.java new file mode 100644 index 0000000..87f5e47 --- /dev/null +++ b/app/src/main/java/com/android/cglib/dx/BinaryOp.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.cglib.dx; + +import com.android.cglib.dx.rop.code.Rop; +import com.android.cglib.dx.rop.code.Rops; +import com.android.cglib.dx.rop.type.TypeList; + +/** + * An operation on two values of the same type. + * + *

Math operations ({@link #ADD}, {@link #SUBTRACT}, {@link #MULTIPLY}, + * {@link #DIVIDE}, and {@link #REMAINDER}) support ints, longs, floats and + * doubles. + * + *

Bit operations ({@link #AND}, {@link #OR}, {@link #XOR}, {@link + * #SHIFT_LEFT}, {@link #SHIFT_RIGHT}, {@link #UNSIGNED_SHIFT_RIGHT}) support + * ints and longs. + * + *

Division by zero behaves differently depending on the operand type. + * For int and long operands, {@link #DIVIDE} and {@link #REMAINDER} throw + * {@link ArithmeticException} if {@code b == 0}. For float and double operands, + * the operations return {@code NaN}. + */ +public enum BinaryOp { + /** {@code a + b} */ + ADD() { + @Override Rop rop(TypeList types) { + return Rops.opAdd(types); + } + }, + + /** {@code a - b} */ + SUBTRACT() { + @Override Rop rop(TypeList types) { + return Rops.opSub(types); + } + }, + + /** {@code a * b} */ + MULTIPLY() { + @Override Rop rop(TypeList types) { + return Rops.opMul(types); + } + }, + + /** {@code a / b} */ + DIVIDE() { + @Override Rop rop(TypeList types) { + return Rops.opDiv(types); + } + }, + + /** {@code a % b} */ + REMAINDER() { + @Override Rop rop(TypeList types) { + return Rops.opRem(types); + } + }, + + /** {@code a & b} */ + AND() { + @Override Rop rop(TypeList types) { + return Rops.opAnd(types); + } + }, + + /** {@code a | b} */ + OR() { + @Override Rop rop(TypeList types) { + return Rops.opOr(types); + } + }, + + /** {@code a ^ b} */ + XOR() { + @Override Rop rop(TypeList types) { + return Rops.opXor(types); + } + }, + + /** {@code a << b} */ + SHIFT_LEFT() { + @Override Rop rop(TypeList types) { + return Rops.opShl(types); + } + }, + + /** {@code a >> b} */ + SHIFT_RIGHT() { + @Override Rop rop(TypeList types) { + return Rops.opShr(types); + } + }, + + /** {@code a >>> b} */ + UNSIGNED_SHIFT_RIGHT() { + @Override Rop rop(TypeList types) { + return Rops.opUshr(types); + } + }; + + abstract Rop rop(com.android.cglib.dx.rop.type.TypeList types); +} diff --git a/app/src/main/java/com/android/cglib/dx/Code.java b/app/src/main/java/com/android/cglib/dx/Code.java new file mode 100644 index 0000000..e6b2178 --- /dev/null +++ b/app/src/main/java/com/android/cglib/dx/Code.java @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.cglib.dx; + +import static com.android.cglib.dx.rop.code.Rop.BRANCH_GOTO; +import static com.android.cglib.dx.rop.code.Rop.BRANCH_NONE; +import static com.android.cglib.dx.rop.code.Rop.BRANCH_RETURN; +import static com.android.cglib.dx.rop.type.Type.BT_BYTE; +import static com.android.cglib.dx.rop.type.Type.BT_CHAR; +import static com.android.cglib.dx.rop.type.Type.BT_INT; +import static com.android.cglib.dx.rop.type.Type.BT_SHORT; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import com.android.cglib.dx.rop.code.BasicBlockList; +import com.android.cglib.dx.rop.code.Insn; +import com.android.cglib.dx.rop.code.PlainCstInsn; +import com.android.cglib.dx.rop.code.PlainInsn; +import com.android.cglib.dx.rop.code.RegisterSpecList; +import com.android.cglib.dx.rop.code.Rop; +import com.android.cglib.dx.rop.code.Rops; +import com.android.cglib.dx.rop.code.SourcePosition; +import com.android.cglib.dx.rop.code.ThrowingCstInsn; +import com.android.cglib.dx.rop.code.ThrowingInsn; +import com.android.cglib.dx.rop.cst.CstInteger; +import com.android.cglib.dx.rop.type.StdTypeList; + +/** + * Builds a sequence of instructions. + * + *

Locals

+ * All data manipulation takes place in local variables. Each parameter gets its + * own local by default; access these using {@link #getParameter + * getParameter()}. Non-static methods and constructors also have a {@code this} + * parameter; it's available as {@link #getThis getThis()}. Allocate a new local + * variable using {@link #newLocal newLocal()}, and assign a default value to it + * with {@link #loadConstant loadConstant()}. Copy a value from one local to + * another with {@link #move move()}. + * + *

Every local variable has a fixed type. This is either a primitive type (of + * any size) or a reference type. This class emits instructions appropriate to + * the types they operate on. Not all operations are local on all types; + * attempting to emit such an operation will fail with an unchecked exception. + * + *

Math and Bit Operations

+ * Transform a single value into another related value using {@link + * #op(UnaryOp,Local,Local) op(UnaryOp, Local, Local)}. Transform two values + * into a third value using {@link #op(BinaryOp,Local,Local,Local) op(BinaryOp, + * Local, Local, Local)}. In either overload the first {@code Local} parameter + * is where the result will be sent; the other {@code Local} parameters are the + * inputs. + * + *

Comparisons

+ * There are three different comparison operations each with different + * constraints: + *
    + *
  • {@link #compareLongs compareLongs()} compares two locals each + * containing a {@code long} primitive. This is the only operation that + * can compare longs. The result of the comparison is written to another + * {@code int} local.
  • + *
  • {@link #compareFloatingPoint compareFloatingPoint()} compares two + * locals; both {@code float} primitives or both {@code double} + * primitives. This is the only operation that can compare floating + * point values. This comparison takes an extra parameter that sets + * the desired result if either parameter is {@code NaN}. The result of + * the comparison is wrtten to another {@code int} local. + *
  • {@link #compare compare()} compares two locals. The {@link + * Comparison#EQ} and {@link Comparison#NE} options compare either + * {@code int} primitives or references. The other options compare only + * {@code int} primitives. This comparison takes a {@link Label} that + * will be jumped to if the comparison is true. If the comparison is + * false the next instruction in sequence will be executed. + *
+ * There's no single operation to compare longs and jump, or to compare ints and + * store the result in a local. Accomplish these goals by chaining multiple + * operations together. + * + *

Branches, Labels and Returns

+ * Basic control flow is expressed using jumps and labels. Each label must be + * marked exactly once and may be jumped to any number of times. Create a label + * using its constructor: {@code new Label()}, and mark it using {@link #mark + * mark(Label)}. All jumps to a label will execute instructions starting from + * that label. You can jump to a label that hasn't yet been marked (jumping + * forward) or to a label that has already been marked (jumping backward). Jump + * unconditionally with {@link #jump jump(Label)} or conditionally based on a + * comparison using {@link #compare compare()}. + * + *

Most methods should contain a return instruction. Void methods + * should use {@link #returnVoid()}; non-void methods should use {@link + * #returnValue returnValue()} with a local whose return type matches the + * method's return type. Constructors are considered void methods and should + * call {@link #returnVoid()}. Methods may make multiple returns. Methods + * containing no return statements must either loop infinitely or throw + * unconditionally; it is not legal to end a sequence of instructions without a + * jump, return or throw. + * + *

Throwing and Catching

+ * This API uses labels to handle thrown exceptions, errors and throwables. Call + * {@link #addCatchClause addCatchClause()} to register the target label and + * throwable class. All statements that follow will jump to that catch clause if + * they throw a {@link Throwable} assignable to that type. Use {@link + * #removeCatchClause removeCatchClause()} to unregister the throwable class. + * + *

Throw an throwable by first assigning it to a local and then calling + * {@link #throwValue throwValue()}. Control flow will jump to the nearest label + * assigned to a type assignable to the thrown type. In this context, "nearest" + * means the label requiring the fewest stack frames to be popped. + * + *

Calling methods

+ * A method's caller must know its return type, name, parameters, and invoke + * kind. Lookup a method on a type using {@link TypeId#getMethod + * TypeId.getMethod()}. This is more onerous than Java language invokes, which + * can infer the target method using the target object and parameters. There are + * four invoke kinds: + *
    + *
  • {@link #invokeStatic invokeStatic()} is used for static methods.
  • + *
  • {@link #invokeDirect invokeDirect()} is used for private instance + * methods and for constructors to call their superclass's + * constructor.
  • + *
  • {@link #invokeInterface invokeInterface()} is used to invoke a method + * whose declaring type is an interface.
  • + *
  • {@link #invokeVirtual invokeVirtual()} is used to invoke any other + * method. The target must not be static, private, a constructor, or an + * interface method.
  • + *
  • {@link #invokeSuper invokeSuper()} is used to invoke the closest + * superclass's virtual method. The target must not be static, private, + * a constructor method, or an interface method.
  • + *
  • {@link #newInstance newInstance()} is used to invoke a + * constructor.
  • + *
+ * All invoke methods take a local for the return value. For void methods this + * local is unused and may be null. + * + *

Field Access

+ * Read static fields using {@link #sget sget()}; write them using {@link + * #sput sput()}. For instance values you'll need to specify the declaring + * instance; use {@link #getThis getThis()} in an instance method to use {@code + * this}. Read instance values using {@link #iget iget()} and write them with + * {@link #iput iput()}. + * + *

Array Access

+ * Allocate an array using {@link #newArray newArray()}. Read an array's length + * with {@link #arrayLength arrayLength()} and its elements with {@link #aget + * aget()}. Write an array's elements with {@link #aput aput()}. + * + *

Types

+ * Use {@link #cast cast()} to perform either a numeric cast or + * a type cast. Interrogate the type of a value in a local + * using {@link #instanceOfType instanceOfType()}. + * + *

Synchronization

+ * Acquire a monitor using {@link #monitorEnter monitorEnter()}; release it with + * {@link #monitorExit monitorExit()}. It is the caller's responsibility to + * guarantee that enter and exit calls are balanced, even in the presence of + * exceptions thrown. + * + * Warning: Even if a method has the {@code synchronized} flag, + * dex requires instructions to acquire and release monitors manually. A method + * declared with {@link java.lang.reflect.Modifier#SYNCHRONIZED SYNCHRONIZED} + * but without manual calls to {@code monitorEnter()} and {@code monitorExit()} + * will not be synchronized when executed. + */ +public final class Code { + private final MethodId method; + /** + * All allocated labels. Although the order of the labels in this list + * shouldn't impact behavior, it is used to determine basic block indices. + */ + private final List