diff --git a/1.6ChineseGuide.md b/1.6ChineseGuide.md new file mode 100644 index 00000000..8b99e167 --- /dev/null +++ b/1.6ChineseGuide.md @@ -0,0 +1,142 @@ + +## 起源 + + 前段时间鸿洋推送的一篇[《推荐3个有用的开源项目》](https://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650826138&idx=1&sn=eeaed05fbd58a71fead6ea8b2d245ff9&chksm=80b7b104b7c03812e8876897c1d1ae2ee9c349674667dac660520815277fdf4021750cfa1cb2&mpshare=1&scene=23&srcid=1014SmKcBFEpROGevZvWA5HR#rd)文章中,推荐了一篇github上的[ADB 用法大全](https://github.com/mzlogin/awesome-adb) ,非常的全面,正如大全中提到的: "ADB,即 [Android Debug Bridge](https://developer.android.com/studio/command-line/adb.html),它是 Android 开发/测试人员不可替代的强大工具,也是 Android 设备玩家的好玩具."相信做安卓开发的肯定都会用到.它的功能是非常强大的.但是强大一般也意味着复杂.我除了少数经常使用到的命令外,其他的都不甚了解.使用上也不是非常的方便,比如安装一个apk文件到手机,我一般是先打开这个apk所在的目录,右键Git Bash Here,然后键入:`adb install -r ./apkFile.apk`,虽然很有逼格,但是有没有更方便一点的实现方式呢?鸿洋的文章中也说道了一个现有的ADB整合插件[adb-idea](https://github.com/pbreault/adb-idea),这个插件我一直都有在用,特别是调试的时候.举个栗子:假如想在启动流程的代码中添加添加一个断点,(比如App启动的第一个Activity的onCreate()中),以前只能打了断点之后点击Debug 'app'按钮,重新走一遍编译流程才能进入断点.可是有时候是什么代码都没有改的.这一个编译流程完全没有必要.但是有了这个插件以后.只需要打好断点.Ctrl+Alt+Shift+A,选择ADB Restart App With Debugger,就可以跳过编译流程,直接启动进入断点了,非常的方便.鸿洋的文章中也提到希望有人能结合这2个优秀的项目做一个较为完备的提示插件.最近项目也比较轻松,私活也接不到,闲得时候都在鼓捣一些开发的辅助工具.正好我在插件這方面有一点点经验,站在巨人的肩膀上这种事我是喜欢干的.我fork[adb-idea](https://github.com/pbreault/adb-idea)这个项目参照[ADB 用法大全](https://github.com/mzlogin/awesome-adb),经过断断续续的开发,在原有的功能上做了一些画蛇添足的扩展,做出来一看感觉和"提示插件"搭不上太大的关系,算是辅助插件吧.不尽完美,好歹还有点作用,现在推荐给大家,对使用姿势做一个简单的说明. + +## 特性和使用 + +### 扩展功能 + +#### 应用管理 + +- 查看应用列表 + - [所有应用](https://github.com/mzlogin/awesome-adb#%E6%89%80%E6%9C%89%E5%BA%94%E7%94%A8) + - [系统应用](https://github.com/mzlogin/awesome-adb#%E7%B3%BB%E7%BB%9F%E5%BA%94%E7%94%A8) + - [第三方应用](https://github.com/mzlogin/awesome-adb#%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8) + - [包名包含某字符串的应用](https://github.com/mzlogin/awesome-adb#%E5%8C%85%E5%90%8D%E5%8C%85%E5%90%AB%E6%9F%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%BA%94%E7%94%A8) +- [卸载应用](https://github.com/mzlogin/awesome-adb#%E5%8D%B8%E8%BD%BD%E5%BA%94%E7%94%A8) +- [清除应用数据与缓存](https://github.com/mzlogin/awesome-adb#%E6%B8%85%E9%99%A4%E5%BA%94%E7%94%A8%E6%95%B0%E6%8D%AE%E4%B8%8E%E7%BC%93%E5%AD%98) +- [查看前台 Activity](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E5%89%8D%E5%8F%B0-activity) +- [查看正在运行的 Services](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84-services) +- [查看应用详细信息](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E5%BA%94%E7%94%A8%E8%AF%A6%E7%BB%86%E4%BF%A1%E6%81%AF) +- [查看应用安装路径](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E5%BA%94%E7%94%A8%E5%AE%89%E8%A3%85%E8%B7%AF%E5%BE%84) +- [强制停止应用](https://github.com/mzlogin/awesome-adb#%E5%BC%BA%E5%88%B6%E5%81%9C%E6%AD%A2%E5%BA%94%E7%94%A8) +- [使用 Monkey 进行压力测试](https://github.com/mzlogin/awesome-adb#%E4%BD%BF%E7%94%A8-monkey-%E8%BF%9B%E8%A1%8C%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95),这个建议直接在命令行中使用,可以查看到实时输出信息,我的插件还不能.😅 + +以上功能都整合到:Application management中 + +![](website/appManagement.png) + +主要是看输出信息,不记得命令也没关系,报名也不用输了,点一点OK,输出的信息,选中后Ctrl+C可以复制,右键可以清屏.除了Foreground Activity和Monkey Test外,都需要选中目标APP. + +#### 与应用交互 + +- [启动应用/ 调起 Activity](https://github.com/mzlogin/awesome-adb#%E5%90%AF%E5%8A%A8%E5%BA%94%E7%94%A8-%E8%B0%83%E8%B5%B7-activity) + + ![](website/startActivity.png) + +- [调起 Service](https://github.com/mzlogin/awesome-adb#%E8%B0%83%E8%B5%B7-service) + + ![](website/startService.png) + +- [发送广播](https://github.com/mzlogin/awesome-adb#%E5%8F%91%E9%80%81%E5%B9%BF%E6%92%AD) + + ![](website/sendBroadcast.png) + + 发送广播在我的8.1的真机上提示安全问题,不能正常发送,6.0好像是可以的. + +以上功能都整合到:Application Interacting中. + +#### 查看设备信息 + +- [型号](https://github.com/mzlogin/awesome-adb#%E5%9E%8B%E5%8F%B7) + +- [电池状况](https://github.com/mzlogin/awesome-adb#%E7%94%B5%E6%B1%A0%E7%8A%B6%E5%86%B5) + +- [屏幕分辨率](https://github.com/mzlogin/awesome-adb#%E5%B1%8F%E5%B9%95%E5%88%86%E8%BE%A8%E7%8E%87) + +- [屏幕密度](https://github.com/mzlogin/awesome-adb#%E5%B1%8F%E5%B9%95%E5%AF%86%E5%BA%A6) + +- [显示屏参数](https://github.com/mzlogin/awesome-adb#%E6%98%BE%E7%A4%BA%E5%B1%8F%E5%8F%82%E6%95%B0) + +- [android_id](https://github.com/mzlogin/awesome-adb#android_id) + +- [IMEI](https://github.com/mzlogin/awesome-adb#imei) + +- [Android 系统版本](https://github.com/mzlogin/awesome-adb#android-%E7%B3%BB%E7%BB%9F%E7%89%88%E6%9C%AC) + +- [IP 地址](https://github.com/mzlogin/awesome-adb#ip-%E5%9C%B0%E5%9D%80) + +- [Mac 地址](https://github.com/mzlogin/awesome-adb#mac-%E5%9C%B0%E5%9D%80) + +- [CPU 信息](https://github.com/mzlogin/awesome-adb#cpu-%E4%BF%A1%E6%81%AF) + +- [内存信息](https://github.com/mzlogin/awesome-adb#%E5%86%85%E5%AD%98%E4%BF%A1%E6%81%AF) + +- [更多硬件与系统属性](https://github.com/mzlogin/awesome-adb#%E6%9B%B4%E5%A4%9A%E7%A1%AC%E4%BB%B6%E4%B8%8E%E7%B3%BB%E7%BB%9F%E5%B1%9E%E6%80%A7) + + 以上功能都整合到:Device information中: + + ![](website/deviceInfo.png) + + 在8.1上部分信息获取失败,提示权限拒绝.同样是Ctrl+C复制,右键清屏. + +#### 实用功能 + +- [安装 APK](https://github.com/mzlogin/awesome-adb#%E5%AE%89%E8%A3%85-apk) + + ![](website/installApk.png) + + 选中apk文件,点击ok安装到手机,支持多选,支持覆盖安装. + +- [输入文本](https://github.com/mzlogin/awesome-adb#%E8%BE%93%E5%85%A5%E6%96%87%E6%9C%AC) + + ![](website/putString.png) + + 首先在手机上让目标EditText获取焦点,让后ok就能推过去了,遗憾的是不支持汉字,空格会被去掉.需要注意的是在部分输入法状态下,并不会直接输入,还需要点一下. + + ![](website/simpleString.png) + +- [屏幕截图](https://github.com/mzlogin/awesome-adb#%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE) + + 选择要保存到的文件夹: + + ![](website/capture1.png) + + 点击OK,会自动打开保存到的文件夹,还方便吧?感觉超实用的. + + ![](website/capture2.png) + +- [录制屏幕](https://github.com/mzlogin/awesome-adb#%E5%BD%95%E5%88%B6%E5%B1%8F%E5%B9%95) + + 1. 点击start开始录制,Windows和Linux都是自动开始的,但是macOS不能自动开始录制,需要把已经放到剪贴板的命令粘贴到命令行中回车开始.昨天整整研究一天也没有发现macOS能从Runtime或者ProcessBuilder启动命令行然后执行一个命令的方法,如果你知道的话请告诉我,谢谢.按Ctrl+C停止录制. + + ![](website/record2.png) + + ![](website/record4.png) + + 2. 录制完成后点击Pull to local->选择保存路径,拉取到本地,视频默认保存在手机的/sdcard中,勾选delete会删除sdcard中的视频: + + ![](website/record1.png) + + 3. 拉取完成后会自动打开保存目录: + + + ![](website/record3.png) + + 录制的视频存在的问题是有一丢丢延迟....😅应该的adb的原因. + +## 下载 + +- 下载[`最新发布的插件包`](https://github.com/longforus/adb-idea/releases) > File >Preferences(Settings) > Plugins > Install plugin from disk... + +## 致谢 + +排名不分先后,都是一样的666 + +- 感谢 [ADB Usage Complete / ADB 用法大全](https://github.com/mzlogin/awesome-adb) 仓库贡献者的收集整理 +- 感谢 [pbreault/**adb-idea**](https://github.com/pbreault/adb-idea) 的优秀开源插件 +- 感谢鸿洋大神的试用测试和修改建议.开发之初因为偷懒和自己也一直都在Windows平台开发,就没有太多的关注其他平台,导致1.6版本的部分功能在其他平台上失效.周末抽时间搭建虚拟机进行了Linux和macOS的测试适配.因为这2个平台了解都不深入,要是这2个平台的用户在使用中遇到什么问题,请联系我. + + +欢迎大家试用,star,issue.你的star是我的动力.谢谢. \ No newline at end of file diff --git a/1.6EnglishGuide.md b/1.6EnglishGuide.md new file mode 100644 index 00000000..1e2bac6f --- /dev/null +++ b/1.6EnglishGuide.md @@ -0,0 +1,128 @@ + +## Features and use + +#### application management + +- view the application list + - [all applications ](https://github.com/mzlogin/awesome-adb#%E6%89%80%E6%9C%89%E5%BA%94%E7%94%A8) + - [system Application](https://github.com/mzlogin/awesome-adb#%E7%B3%BB%E7%BB%9F%E5%BA%94%E7%94%A8) + - [third party applications ](https://github.com/mzlogin/awesome-adb#%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8) + - [package name contains a string of application](https://github.com/mzlogin/awesome-adb#%E5%8C%85%E5%90%8D%E5%8C%85%E5%90%AB%E6%9F%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%BA%94%E7%94%A8) +- [uninstall application](https://github.com/mzlogin/awesome-adb#%E5%8D%B8%E8%BD%BD%E5%BA%94%E7%94%A8) +- [Clear application data and the cache](https://github.com/mzlogin/awesome-adb#%E6%B8%85%E9%99%A4%E5%BA%94%E7%94%A8%E6%95%B0%E6%8D%AE%E4%B8%8E%E7%BC%93%E5%AD%98) +- [see the foreground Activity](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E5%89%8D%E5%8F%B0-activity) +- [see the running Services](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84-services) +- [view application detailed information](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E5%BA%94%E7%94%A8%E8%AF%A6%E7%BB%86%E4%BF%A1%E6%81%AF) +- [view application installation path](https://github.com/mzlogin/awesome-adb#%E6%9F%A5%E7%9C%8B%E5%BA%94%E7%94%A8%E5%AE%89%E8%A3%85%E8%B7%AF%E5%BE%84) +- [Enforced stop application](https://github.com/mzlogin/awesome-adb#%E5%BC%BA%E5%88%B6%E5%81%9C%E6%AD%A2%E5%BA%94%E7%94%A8) +- [ Monkey test](https://github.com/mzlogin/awesome-adb#%E4%BD%BF%E7%94%A8-monkey-%E8%BF%9B%E8%A1%8C%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95),This recommendation is used directly from the command line to view real-time output information, which my plug-in does not yet.😅 + +The above functions are integrated into :Application management + +![](website/appManagement.png) + +Mainly is to look at the output information, do not remember the command also it doesn't matter, don't have to lose, signing up is OK, the output of information, Ctrl + C to copy after selected, right-click can clear screen. In addition to the Foreground Activity and Monkey Test, will need to select the target APP. +#### Interacting with the application + +- [start the application/tuning up the Activity](https://github.com/mzlogin/awesome-adb#%E5%90%AF%E5%8A%A8%E5%BA%94%E7%94%A8-%E8%B0%83%E8%B5%B7-activity) + + ![](website/startActivity.png) + +- [tuning up Service](https://github.com/mzlogin/awesome-adb#%E8%B0%83%E8%B5%B7-service) + + ![](website/startService.png) + +- [send broadcast](https://github.com/mzlogin/awesome-adb#%E5%8F%91%E9%80%81%E5%B9%BF%E6%92%AD) + + ![](website/sendBroadcast.png) + + Send the broadcast on my 8.1 real machine to prompt the security problem, cannot send normally,6.0 seems to be ok. + +The above functions are integrated into: Application in Interacting. + +#### View device information + +- [model](https://github.com/mzlogin/awesome-adb#%E5%9E%8B%E5%8F%B7) + +- [battery status](https://github.com/mzlogin/awesome-adb#%E7%94%B5%E6%B1%A0%E7%8A%B6%E5%86%B5) + +- [screen resolution](https://github.com/mzlogin/awesome-adb#%E5%B1%8F%E5%B9%95%E5%88%86%E8%BE%A8%E7%8E%87) + +- [screen density](https://github.com/mzlogin/awesome-adb#%E5%B1%8F%E5%B9%95%E5%AF%86%E5%BA%A6) + +- [display parameters](https://github.com/mzlogin/awesome-adb#%E6%98%BE%E7%A4%BA%E5%B1%8F%E5%8F%82%E6%95%B0) + +- [android_id](https://github.com/mzlogin/awesome-adb#android_id) + +- [IMEI](https://github.com/mzlogin/awesome-adb#imei) + +- [Android version ](https://github.com/mzlogin/awesome-adb#android-%E7%B3%BB%E7%BB%9F%E7%89%88%E6%9C%AC) + +- [IP](https://github.com/mzlogin/awesome-adb#ip-%E5%9C%B0%E5%9D%80) + +- [Mac](https://github.com/mzlogin/awesome-adb#mac-%E5%9C%B0%E5%9D%80) + +- [CPU](https://github.com/mzlogin/awesome-adb#cpu-%E4%BF%A1%E6%81%AF) + +- [Memory ](https://github.com/mzlogin/awesome-adb#%E5%86%85%E5%AD%98%E4%BF%A1%E6%81%AF) + +- [more hardware and system property](https://github.com/mzlogin/awesome-adb#%E6%9B%B4%E5%A4%9A%E7%A1%AC%E4%BB%B6%E4%B8%8E%E7%B3%BB%E7%BB%9F%E5%B1%9E%E6%80%A7) + + The above functions are integrated into :Device information: + + ![](website/deviceInfo.png) + + Some information failed to get on 8.1, and the permission was rejected. Again, Ctrl+C copy and right click clear. + +#### Useful features + +- [insatll APK](https://github.com/mzlogin/awesome-adb#%E5%AE%89%E8%A3%85-apk) + + ![](website/installApk.png) + + Select the apk file and click ok to install it to the device. + +- [put string](https://github.com/mzlogin/awesome-adb#%E8%BE%93%E5%85%A5%E6%96%87%E6%9C%AC) + + ![](website/putString.png) + + First, make the target EditText the focus on the phone, and then ok can be pushed over. Unfortunately, Chinese characters are not supported and Spaces are removed. + +- [Screenshots ](https://github.com/mzlogin/awesome-adb#%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE) + + Select the folder to save to: + + ![](website/capture1.png) + + Click OK, and the folder you saved will be opened automatically. Is that still convenient?It feels super practical. + + ![](website/capture2.png) + +- [recording screen](https://github.com/mzlogin/awesome-adb#%E5%BD%95%E5%88%B6%E5%B1%8F%E5%B9%95) + + 1. Click start to start recording, Windows and Linux are started automatically, but macOS doesn't automatically start recording, need to have in the clipboard command affixed to the command line, press enter to start. Yesterday, the entire day also didn't find macOS can start from the Runtime or ProcessBuilder method of command line and then execute a command, if you know please tell me, thank you. Press Ctrl + C to stop recording. + + ![](website/record2.png) + + ![](website/record4.png) + + 2. After recording, click Pull to local-> to select the saving path and Pull to local. Video is saved by default in the /sdcard/ of the phone. Tick delete to delete video in sdcard: + + ![](website/record1.png) + + 3. The save directory will be opened automatically after pulling and fetching: + + + ![](website/record3.png) + +## download + +- download[`Newly released plug-in packages`](https://github.com/longforus/adb-idea/releases) > File >Preferences(Settings) > Plugins > Install plugin from disk... + +## thanks + +- thanks [ADB Usage Complete / ADB 用法大全](https://github.com/mzlogin/awesome-adb) warehouse contributors to collect +- thanks [pbreault/**adb-idea**](https://github.com/pbreault/adb-idea) the excellent open source plugin + + +Welcome to try out,star,issue. Your star is my motivation. Thanks. \ No newline at end of file diff --git a/README.md b/README.md index 4902f690..fec70285 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,38 @@ A plugin for Android Studio and Intellij IDEA that speeds up your day to day and The following commands are provided: * Uninstall App + * Kill App + * Start App + * Restart App + * Clear App Data + * Clear App Data and Restart + Since 1.6: + +* Application management + +* Application Interacting + +* Show Device information + +* Install apk files on your computer to your device + +* Put simple string on your computer to your device + +* Record device screen save to computer + +* Capture device screen save to computer + + + [1.6 English Guide](./1.6EnglishGuide.md) + + [1.6 中文指引](./1.6ChineseGuide.md) + Usage ===== @@ -46,17 +72,19 @@ Download and install *ADB Idea* directly from Intellij / Android Studio: Alternatively, you can [download the plugin](http://plugins.jetbrains.com/plugin/7380?pr=idea) from the jetbrains plugin site and install it manually in: `Preferences/Settings->Plugins->Install plugin from disk` +[Click here](https://github.com/longforus/adb-idea/releases) to download the enhanced version and manually install it using the above method. + License ======= Copyright 2017 Philippe Breault - + 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. diff --git a/build.gradle b/build.gradle index d528915c..0ffe9473 100644 --- a/build.gradle +++ b/build.gradle @@ -1,18 +1,14 @@ -buildscript { - - ext.kotlin_version = '1.3.72' - - repositories { - mavenCentral() - jcenter() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } +plugins { + id "org.jetbrains.kotlin.jvm" version "1.5.21" + id "org.jetbrains.intellij" version "1.2.0" } -plugins { - id "org.jetbrains.intellij" version "0.4.16" +repositories { + maven { url 'https://maven.aliyun.com/repository/public' } + maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } + maven { url 'https://maven.aliyun.com/repository/google' } + mavenCentral() + jcenter() } sourceCompatibility = 1.8 @@ -20,21 +16,11 @@ targetCompatibility = 1.8 -apply plugin: 'java' -apply plugin: 'kotlin' - - -repositories { - mavenCentral() - jcenter() -} sourceSets { main { resources { - exclude 'website/adb_operations_popup.png' - exclude 'website/find_actions.png' - exclude 'website/debug_howto.png' + exclude 'website/*.png' } } } @@ -44,25 +30,32 @@ if (!hasProperty('StudioCompilePath')) { } intellij { - pluginName 'adb_idea' - updateSinceUntilBuild false + pluginName = 'adb_idea' + updateSinceUntilBuild = false + localPath = project.hasProperty("StudioRunPath") ? StudioRunPath : StudioCompilePath + instrumentCode { + compilerVersion = "212.4746.92" + } + instrumentTestCode { + compilerVersion = "212.4746.92" + } - intellij.localPath = project.hasProperty("StudioRunPath") ? StudioRunPath : StudioCompilePath } + group 'com.developerphil.intellij.plugin.adbidea' dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" - compile "org.jooq:joor-java-8:0.9.7" + implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.5.21' + implementation 'org.jooq:joor-java-8:0.9.14' compileOnly fileTree(dir: "$StudioCompilePath/plugins/android/lib", include: ['*.jar']) compileOnly fileTree(dir: "$StudioCompilePath/lib", include: ['*.jar']) - testCompile 'junit:junit:4.12' - testCompile fileTree(dir: "$StudioCompilePath/plugins/android/lib", include: ['*.jar']) - testCompile fileTree(dir: "$StudioCompilePath/lib", include: ['*.jar']) - testCompile "org.mockito:mockito-core:1.+" - testCompile "com.google.truth:truth:1.0.1" + testImplementation 'junit:junit:4.13.2' + testImplementation fileTree(dir: "$StudioCompilePath/plugins/android/lib", include: ['*.jar']) + testImplementation fileTree(dir: "$StudioCompilePath/lib", include: ['*.jar']) + testImplementation "org.mockito:mockito-core:1.+" + testImplementation 'com.google.truth:truth:1.1.3' } @@ -78,3 +71,4 @@ task(verifySetup) { compileJava.dependsOn verifySetup +buildSearchableOptions.enabled = false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c..e708b1c0 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1b16c34a..3c4101c3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7d..4f906e0c 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac 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 @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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 diff --git a/gradlew.bat b/gradlew.bat index 24467a14..ac1b06f9 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @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="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_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=%* - :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% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.form b/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.form new file mode 100644 index 00000000..80460abd --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.form @@ -0,0 +1,315 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.java b/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.java new file mode 100644 index 00000000..13429aca --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.java @@ -0,0 +1,507 @@ +package com.developerphil.adbidea.ui; + +import com.developerphil.adbidea.HelperMethodsKt; +import com.developerphil.adbidea.SearchHelper; +import com.developerphil.adbidea.adb.AdbFacade; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileChooser.ex.FileChooserDialogImpl; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.JBColor; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.jgoodies.forms.layout.CellConstraints; +import com.jgoodies.forms.layout.FormLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Toolkit; +import java.awt.event.MouseEvent; +import java.io.File; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JTextPane; +import javax.swing.SwingUtilities; +import javax.swing.event.MouseInputAdapter; +import org.jetbrains.annotations.Nullable; + +/** + * Created by XQ Yang on 8/28/2018 4:13 PM. + * Description : + */ + +public class ApplicationManagementFrame extends JFrame { + private MyApplistModel mModel; + private List mList; + private JRadioButton mAllStatusRadioButton; + private JRadioButton mDisabledRadioButton; + private JRadioButton mEnabledRadioButton; + private JRadioButton mAllTypeRadioButton; + private JRadioButton mSystemRadioButton; + private JRadioButton mThirdPartyRadioButton; + private JCheckBox mShowApkFileCheckBox; + private JCheckBox mShowInstallersCheckBox; + private JCheckBox mContainsUninstalledCheckBox; + private JButton mQueryButton; + private JTextField tv_keyword; + private JList mJList; + private JButton mRunningServicesButton; + private JPanel mPanel; + private JScrollPane sp; + private JTextPane tp; + private JScrollPane sp_tp; + private JButton mForegroundActivityButton; + private JButton mMonkeyTestButton; + private JTextField tv_search; + private JButton btn_search; + private final Project mProject; + private final JPopupMenu mPopupMenu; + private final JPopupMenu mListPopupMenu; + + private static final String PARAMETER_DISABLED = "-d "; + private static final String PARAMETER_ENABLED = "-e "; + private static final String PARAMETER_SYSTEM = "-s "; + private static final String PARAMETER_THIRD_PARTY = "-3 "; + private static final String PARAMETER_INSTALLER = "-i "; + private static final String PARAMETER_UNINSTALLED = "-u "; + private static final String PARAMETER_RELEVANCE_FILE = "-f "; + + + private SearchHelper mSearchHelper; + + + public ApplicationManagementFrame(@Nullable Project project) { + setResizable(true); + Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize(); + int x = (int) screensize.getWidth() / 2 - mPanel.getPreferredSize().width / 2; + int y = (int) screensize.getHeight() / 2 - mPanel.getPreferredSize().height / 2; + setTitle("Adb Application Management"); + URL filename = getClass().getResource("/icon.png"); + ImageIcon icon = new ImageIcon(filename); + setIconImage(icon.getImage()); + setLocation(x, y); + mProject = project; + mPopupMenu = new JPopupMenu(); + JMenuItem clear = mPopupMenu.add(new JMenuItem("clear")); + clear.addActionListener(e -> tp.setText("")); + tp.addMouseListener(new MouseInputAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + mPopupMenu.show(tp, e.getX(), e.getY()); + } + } + }); + mListPopupMenu = new JPopupMenu(); + JMenuItem pullApk = mListPopupMenu.add(new JMenuItem("pull apk file to ...")); + pullApk.addActionListener(e -> { + List selectedValuesList = mJList.getSelectedValuesList(); + if (!selectedValuesList.isEmpty()) { + FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false); + descriptor.setTitle("Select apk file save to ... "); + VirtualFile[] choose = new FileChooserDialogImpl(descriptor, project).choose(project); + if (choose.length > 0 && choose[0] != null) { + VirtualFile selectedFile = choose[0]; + for (String sv : selectedValuesList) { + String name = getRealPackageName(sv); + AdbFacade.INSTANCE.getPackagePath(mProject, name, s -> { + String realPath = s.replace("package:", "").replace("\n", "").replace("\r", ""); + NotificationHelper.INSTANCE.info(String.format("%s package path = %s", name, realPath)); + String fileName = name + ".apk"; + NotificationHelper.INSTANCE.info(String.format("start pull %s to %s", fileName, selectedFile.getCanonicalPath())); + SwingUtilities.invokeLater(() -> { + File file = new File(selectedFile.getCanonicalPath(), fileName); + AdbFacade.INSTANCE.pullFile(project, realPath, file, false); + NotificationHelper.INSTANCE.info(String.format("pull %s success ", fileName)); + }); + return null; + }); + } + } + } + }); + JMenuItem jiUninstall = mListPopupMenu.add(new JMenuItem("uninstall")); + jiUninstall.addActionListener(e -> { + int[] selectedIndices = mJList.getSelectedIndices(); + String[] selected = new String[selectedIndices.length]; + for (int i = 0; i < selectedIndices.length; i++) { + String packageName = mList.get(selectedIndices[i]); + AdbFacade.INSTANCE.uninstall(mProject, getRealPackageName(packageName)); + selected[i] = packageName; + } + for (String s : selected) { + mModel.delete(s); + } + }); + JMenuItem jiClear = mListPopupMenu.add(new JMenuItem("clear data and cache")); + jiClear.addActionListener(e -> { + List selectedValuesList = mJList.getSelectedValuesList(); + for (String packageName : selectedValuesList) { + AdbFacade.INSTANCE.clearData(mProject, getRealPackageName(packageName)); + } + }); + JMenuItem jiDetail = mListPopupMenu.add(new JMenuItem("view detail")); + jiDetail.addActionListener(e -> { + List selectedValuesList = mJList.getSelectedValuesList(); + for (String packageName : selectedValuesList) { + String name = getRealPackageName(packageName); + Utils.Companion.append2TextPane("View " + name + " detail : \n", JBColor.BLUE, tp); + AdbFacade.INSTANCE.getPackageDetail(mProject, name, s -> { + Utils.Companion.append2TextPane(s, tp); + return null; + }); + } + }); + JMenuItem jiPath = mListPopupMenu.add(new JMenuItem("view apk path")); + jiPath.addActionListener(e -> { + List selectedValuesList = mJList.getSelectedValuesList(); + for (String packageName : selectedValuesList) { + String name = getRealPackageName(packageName); + Utils.Companion.append2TextPane("View " + name + " apk Path : \n", JBColor.BLUE, tp); + AdbFacade.INSTANCE.getPackagePath(mProject, name, s -> { + Utils.Companion.append2TextPane(s, tp); + return null; + }); + } + }); + JMenuItem jiStop = mListPopupMenu.add(new JMenuItem("force stop")); + jiStop.addActionListener(e -> { + List selectedValuesList = mJList.getSelectedValuesList(); + for (String packageName : selectedValuesList) { + String name = getRealPackageName(packageName); + Utils.Companion.append2TextPane("Force-stop : " + name + "\n", JBColor.BLUE, tp); + AdbFacade.INSTANCE.forceStop(mProject, name); + } + }); + + mJList.addMouseListener(new MouseInputAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + //mJList.clearSelection(); + mListPopupMenu.show(mJList, e.getX(), e.getY()); + } + } + }); + mQueryButton.addActionListener(e -> { + StringBuilder sb = new StringBuilder(); + if (mDisabledRadioButton.isSelected()) { + sb.append(PARAMETER_DISABLED); + } else if (mEnabledRadioButton.isSelected()) { + sb.append(PARAMETER_ENABLED); + } + if (mSystemRadioButton.isSelected()) { + sb.append(PARAMETER_SYSTEM); + } else if (mThirdPartyRadioButton.isSelected()) { + sb.append(PARAMETER_THIRD_PARTY); + } + if (mShowApkFileCheckBox.isSelected()) { + sb.append(PARAMETER_RELEVANCE_FILE); + } + if (mShowInstallersCheckBox.isSelected()) { + sb.append(PARAMETER_INSTALLER); + } + if (mContainsUninstalledCheckBox.isSelected()) { + sb.append(PARAMETER_UNINSTALLED); + } + String keywordText = tv_keyword.getText(); + if (!Utils.Companion.isEmpty(keywordText)) { + sb.append(keywordText); + } + AdbFacade.INSTANCE.getAllApplicationList(mProject, sb.toString(), strings -> { + Collections.sort(strings); + mList = strings; + mModel = new MyApplistModel(mList); + mJList.setModel(mModel); + return null; + }); + }); + + mRunningServicesButton.addActionListener(e -> { + List selectedValuesList = mJList.getSelectedValuesList(); + if (selectedValuesList.isEmpty()) { + String keywordText = tv_keyword.getText(); + if (!Utils.Companion.isEmpty(keywordText)) { + Utils.Companion.append2TextPane("View running services related with " + keywordText + " : \n", JBColor.BLUE, tp); + AdbFacade.INSTANCE.getActivityService(mProject, keywordText, s -> { + Utils.Companion.append2TextPane(s, tp); + return null; + }); + } else { + Utils.Companion.append2TextPane("View all running services : \n", JBColor.BLUE, tp); + AdbFacade.INSTANCE.getActivityService(mProject, "", s -> { + Utils.Companion.append2TextPane(s, tp); + return null; + }); + } + } + for (String packageName : selectedValuesList) { + String name = getRealPackageName(packageName); + Utils.Companion.append2TextPane("View running services related with " + name + " : \n", JBColor.BLUE, tp); + AdbFacade.INSTANCE.getActivityService(mProject, name, s -> { + Utils.Companion.append2TextPane(s, tp); + return null; + }); + } + }); + + mForegroundActivityButton.addActionListener(e -> { + Utils.Companion.append2TextPane("Foreground Activity : \n", JBColor.BLUE, tp); + AdbFacade.INSTANCE.showForegroundActivity(mProject, s -> { + if (Utils.Companion.isEmpty(s)) { + Utils.Companion.append2TextPaneNewLine("get foreground Activity failure", JBColor.RED, tp); + } else { + Utils.Companion.append2TextPaneNewLine(s, tp); + } + return null; + }); + }); + mMonkeyTestButton.addActionListener(e -> { + List selectedValuesList = mJList.getSelectedValuesList(); + String name = ""; + if (!selectedValuesList.isEmpty()) { + name = getRealPackageName(selectedValuesList.get(0)); + Utils.Companion.append2TextPane("Monkey test of " + name + " :\n", JBColor.BLUE, tp); + } + String countStr = JOptionPane.showInputDialog("Enter test count(only integers):"); + if (countStr == null || countStr.isEmpty()) { + HelperMethodsKt.showErrorMsg("count can not empty"); + return; + } + int count = 0; + try { + count = Integer.parseInt(countStr); + } catch (NumberFormatException e1) { + HelperMethodsKt.showErrorMsg("parse count error,You can only enter integers"); + return; + } + if (count > 0) { + AdbFacade.INSTANCE.monkeyTest(mProject, name, count, s -> { + Utils.Companion.append2TextPane(s, tp); + return null; + }); + } + }); + mSearchHelper = new SearchHelper(tv_search,tp); + btn_search.addActionListener(e -> { + mSearchHelper.doSearch(); + }); + + setContentPane($$$getRootComponent$$$()); + } + + + + private String getRealPackageName(String packageName) { + if (mShowApkFileCheckBox.isSelected() && mShowInstallersCheckBox.isSelected()) { + String[] split = packageName.split("="); + return split[1].split(" ")[0]; + } + if (mShowApkFileCheckBox.isSelected()) { + String[] split = packageName.split("="); + return split[1]; + } + if (mShowInstallersCheckBox.isSelected()) { + String[] split = packageName.split(":"); + return split[1].split(" ")[0]; + } + String[] strings = packageName.split(":"); + return strings[1]; + } + + public static void main(String... args) { + ApplicationManagementFrame frame = new ApplicationManagementFrame(null); + frame.pack(); + frame.setVisible(true); + } + + { + // GUI initializer generated by IntelliJ IDEA GUI Designer + // >>> IMPORTANT!! <<< + // DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + mPanel = new JPanel(); + mPanel.setLayout(new FormLayout("fill:341px:noGrow,fill:d:grow,fill:d:noGrow,fill:d:noGrow", + "center:max(d;4px):noGrow,center:44px:noGrow,center:32px:noGrow,center:d:noGrow,center:p:noGrow,center:d:grow,top:4dlu:noGrow,center:max(d;4px):noGrow")); + mPanel.setMinimumSize(new Dimension(590, 280)); + mPanel.setName(""); + mPanel.setPreferredSize(new Dimension(800, 620)); + mPanel.setBorder(BorderFactory.createTitledBorder("All Application")); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridBagLayout()); + CellConstraints cc = new CellConstraints(); + mPanel.add(panel1, cc.xyw(1, 2, 4)); + panel1.setBorder(BorderFactory.createTitledBorder("Other")); + mShowApkFileCheckBox = new JCheckBox(); + mShowApkFileCheckBox.setText("Show Apk File"); + GridBagConstraints gbc; + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel1.add(mShowApkFileCheckBox, gbc); + mShowInstallersCheckBox = new JCheckBox(); + mShowInstallersCheckBox.setText("Show installers"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel1.add(mShowInstallersCheckBox, gbc); + mContainsUninstalledCheckBox = new JCheckBox(); + mContainsUninstalledCheckBox.setText("Contains uninstalled"); + gbc = new GridBagConstraints(); + gbc.gridx = 2; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel1.add(mContainsUninstalledCheckBox, gbc); + mQueryButton = new JButton(); + mQueryButton.setText("Query"); + mPanel.add(mQueryButton, cc.xy(4, 3)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); + mPanel.add(panel2, cc.xyw(1, 3, 3)); + final JLabel label1 = new JLabel(); + label1.setText("Name Filter :"); + panel2.add(label1, + new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, + null, 0, false)); + tv_keyword = new JTextField(); + panel2.add(tv_keyword, + new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, + null, new Dimension(150, -1), null, 0, false)); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new FormLayout("fill:170px:grow,fill:d:grow,fill:153px:grow,fill:d:grow,fill:d:grow,fill:d:grow", "center:30px:grow,center:max(d;4px):noGrow")); + mPanel.add(panel3, cc.xyw(1, 5, 4)); + mForegroundActivityButton = new JButton(); + mForegroundActivityButton.setText("Foreground Activity"); + panel3.add(mForegroundActivityButton, cc.xy(1, 2)); + sp = new JScrollPane(); + sp.setMinimumSize(new Dimension(0, 100)); + mPanel.add(sp, cc.xyw(1, 4, 4, CellConstraints.FILL, CellConstraints.FILL)); + mJList = new JList(); + mJList.setMinimumSize(new Dimension(0, 100)); + sp.setViewportView(mJList); + final JPanel panel4 = new JPanel(); + panel4.setLayout(new GridBagLayout()); + mPanel.add(panel4, cc.xy(1, 1)); + panel4.setBorder(BorderFactory.createTitledBorder("Type")); + mAllTypeRadioButton = new JRadioButton(); + mAllTypeRadioButton.setSelected(true); + mAllTypeRadioButton.setText("All"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel4.add(mAllTypeRadioButton, gbc); + mSystemRadioButton = new JRadioButton(); + mSystemRadioButton.setText("System"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel4.add(mSystemRadioButton, gbc); + mThirdPartyRadioButton = new JRadioButton(); + mThirdPartyRadioButton.setText("Third-party"); + gbc = new GridBagConstraints(); + gbc.gridx = 2; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel4.add(mThirdPartyRadioButton, gbc); + final JPanel panel5 = new JPanel(); + panel5.setLayout(new GridBagLayout()); + panel5.setToolTipText("status"); + mPanel.add(panel5, cc.xyw(2, 1, 3)); + panel5.setBorder(BorderFactory.createTitledBorder("Status")); + mAllStatusRadioButton = new JRadioButton(); + mAllStatusRadioButton.setSelected(true); + mAllStatusRadioButton.setText("All"); + gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel5.add(mAllStatusRadioButton, gbc); + mEnabledRadioButton = new JRadioButton(); + mEnabledRadioButton.setText("enabled"); + gbc = new GridBagConstraints(); + gbc.gridx = 2; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel5.add(mEnabledRadioButton, gbc); + mDisabledRadioButton = new JRadioButton(); + mDisabledRadioButton.setText("disabled"); + gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.anchor = GridBagConstraints.WEST; + panel5.add(mDisabledRadioButton, gbc); + sp_tp = new JScrollPane(); + sp_tp.setPreferredSize(new Dimension(590, 200)); + sp_tp.setVisible(true); + sp_tp.setWheelScrollingEnabled(true); + mPanel.add(sp_tp, cc.xyw(1, 6, 4, CellConstraints.FILL, CellConstraints.FILL)); + tp = new JTextPane(); + tp.setPreferredSize(new Dimension(590, 200)); + tp.setVisible(true); + sp_tp.setViewportView(tp); + ButtonGroup buttonGroup; + buttonGroup = new ButtonGroup(); + buttonGroup.add(mDisabledRadioButton); + buttonGroup.add(mAllStatusRadioButton); + buttonGroup.add(mEnabledRadioButton); + buttonGroup = new ButtonGroup(); + buttonGroup.add(mAllTypeRadioButton); + buttonGroup.add(mSystemRadioButton); + buttonGroup.add(mThirdPartyRadioButton); + } + + /** @noinspection ALL */ + public JComponent $$$getRootComponent$$$() { + return mPanel; + } +} diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/DeviceChooserDialog.form b/src/main/java/com/developerphil/adbidea/ui/DeviceChooserDialog.form similarity index 100% rename from src/main/kotlin/com/developerphil/adbidea/ui/DeviceChooserDialog.form rename to src/main/java/com/developerphil/adbidea/ui/DeviceChooserDialog.form diff --git a/src/main/java/com/developerphil/adbidea/ui/DeviceInfoFrame.form b/src/main/java/com/developerphil/adbidea/ui/DeviceInfoFrame.form new file mode 100644 index 00000000..86805061 --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/DeviceInfoFrame.form @@ -0,0 +1,161 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/developerphil/adbidea/ui/DeviceInfoFrame.java b/src/main/java/com/developerphil/adbidea/ui/DeviceInfoFrame.java new file mode 100644 index 00000000..a935843d --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/DeviceInfoFrame.java @@ -0,0 +1,177 @@ +package com.developerphil.adbidea.ui; + +import com.android.ddmlib.IDevice; +import com.developerphil.adbidea.SearchHelper; +import com.developerphil.adbidea.adb.AdbFacade; +import com.intellij.openapi.project.Project; +import com.intellij.ui.JBColor; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.MouseEvent; +import java.net.URL; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JTextField; +import javax.swing.JTextPane; +import javax.swing.SwingUtilities; +import javax.swing.event.MouseInputAdapter; +import org.jetbrains.annotations.Nullable; + +/** + * Created by XQ Yang on 10/11/2018 11:45 AM. + * Description : show some device information + */ + +public class DeviceInfoFrame extends JFrame { + private final Project mProject; + private final JPopupMenu mPopupMenu; + private JPanel mPanel; + private JTextPane mTextPane; + private JButton mDisplaysInfoButton; + private JButton mCPUInfoButton; + private JButton mMemoryInfoButton; + private JButton mScreenInfoButton; + private JButton mBatteryInfoButton; + private JButton mSystemButton; + private JButton mNetworkButton; + private JButton mMoreButton; + private JTextField tf_search; + private JButton btn_search; + + private String androidVersion = ""; + private IDevice mDevice; + + + private SearchHelper mSearchHelper; + + + public DeviceInfoFrame(@Nullable Project project) { + setResizable(true); + Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize(); + int x = (int) screensize.getWidth() / 2 - mPanel.getPreferredSize().width / 2; + int y = (int) screensize.getHeight() / 2 - mPanel.getPreferredSize().height / 2; + setTitle("Adb Device information"); + setLocation(x, y); + URL filename = getClass().getResource("/icon.png"); + ImageIcon icon = new ImageIcon(filename); + setIconImage(icon.getImage()); + mProject = project; + mPopupMenu = new JPopupMenu(); + JMenuItem clear = mPopupMenu.add(new JMenuItem("clear")); + clear.addActionListener(e -> mTextPane.setText("")); + mTextPane.addMouseListener(new MouseInputAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + mPopupMenu.show(mTextPane, e.getX(), e.getY()); + } + } + }); + + AdbFacade.INSTANCE.getSimpleInfo(mProject, "getprop ro.product.brand", "get Device brand ", (s,d) -> { + mDevice = d; + setTitle("Adb Device information on " + mDevice.getSerialNumber()); + Utils.Companion.append2TextPaneNewLine("Device brand:", JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPane(s, mTextPane); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + AdbFacade.INSTANCE.getSimpleInfo(mProject, "getprop ro.product.model", "get Device model ", mDevice, (s, d) -> { + Utils.Companion.append2TextPaneNewLine("Device model:", JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPane(s, mTextPane); + return null; + }); + AdbFacade.INSTANCE.getSimpleInfo(mProject, "getprop ro.product.name", "get Device name ", mDevice, (s, d) -> { + Utils.Companion.append2TextPaneNewLine("Device name:", JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPaneNewLine(s, mTextPane); + return null; + }); + AdbFacade.INSTANCE.getSimpleInfo(mProject, "getprop ro.build.version.release", "get Android Version ", mDevice, (s, d) -> { + androidVersion = s.trim(); + return null; + }); + } + }); + return null; + }); + + mDisplaysInfoButton.addActionListener(e -> getInfo2Show("Displays Info:", "dumpsys window displays", "get Displays Info ")); + mCPUInfoButton.addActionListener(e -> { + getInfo2Show("CPU Info:", "cat /proc/cpuinfo", "get CPU Info "); + getInfo2Show("Support ABI list:", "getprop ro.product.cpu.abilist", "Support ABI list "); + }); + mMemoryInfoButton.addActionListener(e -> { + getInfo2Show("Memory Info:", "cat /proc/meminfo", "get Memory Info "); + getInfo2Show("Support heap size:", "getprop dalvik.vm.heapsize", "get Support heap "); + }); + mScreenInfoButton.addActionListener(e -> { + getInfo2Show("Screen Size:", "wm size", "get Screen Size "); + getInfo2Show("Screen density:", "wm density", "get Screen density "); + }); + mBatteryInfoButton.addActionListener(e -> { + getInfo2Show("Battery Service state:", "dumpsys battery", "get Battery Service state "); + }); + mMoreButton.addActionListener(e -> { + getInfo2Show("More system and hardware information:", "cat /system/build.prop", "get System and hardware information "); + }); + mSystemButton.addActionListener(e -> { + getInfo2Show("Android id:", "settings get secure android_id", "get Android id "); + AdbFacade.INSTANCE.getSimpleInfo(mProject, "getprop ro.build.version.sdk", "get Android sdk ", mDevice,(s,d) -> { + Utils.Companion.append2TextPaneNewLine("Android SDK:", JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPane(s, mTextPane); + return null; + }); + if (!Utils.Companion.isEmpty(androidVersion)) { + Utils.Companion.append2TextPaneNewLine("Android Version:", JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPaneNewLine(androidVersion, mTextPane); + } + + }); + mNetworkButton.addActionListener(e -> { + getInfo2Show("Android id:", "settings get secure android_id", "get Android id "); + if (!Utils.Companion.isEmpty(androidVersion)) { + try { + int version = Integer.parseInt(androidVersion.substring(0, 1)); + if (version >= 5) { + //cannot work + //getInfo2Show("IMEI 1 :", "service call iphonesubinfo 1 | awk -F \"'\" '{print $2}' | sed '1 d' | tr -d '.' | awk '{print}' ORS=", "get IMEI 1 "); + Utils.Companion.append2TextPaneNewLine("Can not get IMEI", JBColor.red, mTextPane); + } else { + getInfo2Show("IMEI 1 :", "dumpsys iphonesubinfo", "get IMEI 1 "); + } + } catch (NumberFormatException e1) { + e1.printStackTrace(); + Utils.Companion.append2TextPaneNewLine("Can not get IMEI", JBColor.red, mTextPane); + } + } + AdbFacade.INSTANCE.getSimpleInfo(mProject, "ifconfig | grep Mask", "get IP Address ", mDevice,(s,d) -> { + Utils.Companion.append2TextPaneNewLine("ifconfig :", JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPaneNewLine(s, mTextPane); + return null; + }); + AdbFacade.INSTANCE.getSimpleInfo(mProject, "ifconfig wlan0", "get IP Address ", mDevice,(s,d) -> { + Utils.Companion.append2TextPaneNewLine("wlan0 :", JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPaneNewLine(s, mTextPane); + return null; + }); + getInfo2Show("Mac Address:", "cat /sys/class/net/wlan0/address", "get Mac Address "); + }); + + mSearchHelper = new SearchHelper(tf_search,mTextPane); + btn_search.addActionListener(e -> mSearchHelper.doSearch()); + + setContentPane(mPanel); + } + + public void getInfo2Show(String item, String command, String desc) { + AdbFacade.INSTANCE.getSimpleInfo(mProject, command, desc, mDevice,(s,d) -> { + Utils.Companion.append2TextPaneNewLine(item, JBColor.BLUE, mTextPane); + Utils.Companion.append2TextPaneNewLine(s, mTextPane); + return null; + }); + } +} diff --git a/src/main/java/com/developerphil/adbidea/ui/InteractingFrame.form b/src/main/java/com/developerphil/adbidea/ui/InteractingFrame.form new file mode 100644 index 00000000..f1cac1e8 --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/InteractingFrame.form @@ -0,0 +1,253 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/developerphil/adbidea/ui/InteractingFrame.java b/src/main/java/com/developerphil/adbidea/ui/InteractingFrame.java new file mode 100644 index 00000000..8bcc0ce1 --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/InteractingFrame.java @@ -0,0 +1,124 @@ +package com.developerphil.adbidea.ui; + +import com.developerphil.adbidea.ConstKt; +import com.developerphil.adbidea.HelperMethodsKt; +import com.developerphil.adbidea.adb.AdbFacade; +import com.developerphil.adbidea.bean.BoundItemBean; +import com.intellij.openapi.project.Project; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import javax.swing.DefaultComboBoxModel; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import org.jetbrains.annotations.Nullable; + +/** + * Created by XQ Yang on 10/10/2018 11:25 AM. + * Description : + */ + +public class InteractingFrame extends JFrame { + + private final Project mProject; + private JPanel mPanel; + private JRadioButton mStartActivityRadioButton; + private JRadioButton mStartServiceRadioButton; + private JRadioButton mSendBroadcastRadioButton; + private JComboBox mCbAction; + private JComboBox mCbCategory; + private JComboBox mCbComponent; + private BoundTypeJTable mTable; + private JButton mGoButton; + private JButton mAddRowButton; + private JButton mDeleteRowButton; + private JButton mClearButton; + private BoundTableModel mModel; + + public InteractingFrame(@Nullable Project project) { + setResizable(true); + Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize(); + int x = (int) screensize.getWidth() / 2 - mPanel.getPreferredSize().width / 2; + int y = (int) screensize.getHeight() / 2 - mPanel.getPreferredSize().height / 2; + setTitle("Adb Interacting with applications"); + URL filename = getClass().getResource("/icon.png"); + ImageIcon icon = new ImageIcon(filename); + setIconImage(icon.getImage()); + setLocation(x, y); + mProject = project; + + mCbAction.setModel(new DefaultComboBoxModel(ConstKt.getStartActivityActions())); + mCbCategory.setModel(new DefaultComboBoxModel(ConstKt.getCategorys())); + + mStartActivityRadioButton.addActionListener(e -> mCbAction.setModel(new DefaultComboBoxModel(ConstKt.getStartActivityActions()))); + mSendBroadcastRadioButton.addActionListener(e -> mCbAction.setModel(new DefaultComboBoxModel(ConstKt.getBroadCastActions()))); + + boundInit(); + mGoButton.addActionListener(e -> { + Object selectedItem = mCbComponent.getSelectedItem(); + String name = selectedItem != null ? selectedItem.toString() : ""; + if (!mSendBroadcastRadioButton.isSelected() && Utils.Companion.isEmpty(name)) { + HelperMethodsKt.showErrorMsg("Component name cannot be empty"); + return; + } + selectedItem = mCbAction.getSelectedItem(); + String action = selectedItem != null ? selectedItem.toString() : ""; + selectedItem = mCbCategory.getSelectedItem(); + String category = selectedItem != null ? selectedItem.toString() : ""; + List boundData = mModel.getData(); + int type = mStartActivityRadioButton.isSelected() ? 0 : (mStartServiceRadioButton.isSelected() ? 1 : 2); + AdbFacade.INSTANCE.interacting(mProject, type, action, category, name, boundData); + }); + + setContentPane(mPanel); + } + + public void boundInit() { + mModel = new BoundTableModel(); + mTable.setModel(mModel); + mTable.getColumnModel().getColumn(0).setPreferredWidth(50); + mTable.getColumnModel().getColumn(1).setPreferredWidth(120); + mTable.getColumnModel().getColumn(2).setPreferredWidth(250); + mTable.getColumnModel().getColumn(3).setPreferredWidth(70); + mTable.setRowHeight(25); + mTable.addKeyListener(new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { + + } + + @Override + public void keyPressed(KeyEvent e) { + + } + + @Override + public void keyReleased(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_DELETE) { + mModel.removeRow(mTable.getSelectedRow()); + } + } + }); + mAddRowButton.addActionListener(e -> { + mModel.addEmptyRow(); + mTable.requestFocus(); + int index = mModel.getRowCount() - 1; + mTable.setRowSelectionInterval(index, index); + mTable.editCellAt(index, 1); + }); + mDeleteRowButton.addActionListener(e -> mModel.removeRow(mTable.getSelectedRow())); + mClearButton.addActionListener(e -> mModel.setData(new ArrayList<>())); + } + + private void createUIComponents() { + mTable = new BoundTypeJTable(); + } +} diff --git a/src/main/java/com/developerphil/adbidea/ui/RecordOptionDialog.form b/src/main/java/com/developerphil/adbidea/ui/RecordOptionDialog.form new file mode 100644 index 00000000..8fd7df05 --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/RecordOptionDialog.form @@ -0,0 +1,121 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/developerphil/adbidea/ui/RecordOptionDialog.java b/src/main/java/com/developerphil/adbidea/ui/RecordOptionDialog.java new file mode 100644 index 00000000..8a27c4fc --- /dev/null +++ b/src/main/java/com/developerphil/adbidea/ui/RecordOptionDialog.java @@ -0,0 +1,88 @@ +package com.developerphil.adbidea.ui; + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextPane; +import javax.swing.KeyStroke; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; +import org.jetbrains.annotations.NotNull; +/** + * @describe + * @author Void Young + * @date 2018-10-13 16:48:56 + */ +public class RecordOptionDialog extends JDialog { + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JButton mStartButton; + private JTextPane clickStartAndTheTextPane; + private JCheckBox mDeleteCheckBox; + @NotNull + public Function1 okListener; + @NotNull + public Function1 onStartListener; + + public RecordOptionDialog(@NotNull Function1 okListener) { + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + this.okListener = okListener; + Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize(); + int x = (int) screensize.getWidth() / 2 - contentPane.getPreferredSize().width / 2; + int y = (int) screensize.getHeight() / 2 - contentPane.getPreferredSize().height / 2; + setTitle("Adb record option"); + setLocation(x, y); + + buttonOK.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onOK(); + } + }); + + buttonCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }); + + mStartButton.addActionListener(e -> onStartListener.invoke(null)); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + } + + private void onOK() { + okListener.invoke(mDeleteCheckBox.isSelected()); + dispose(); + } + + private void onCancel() { + // add your code here if necessary + dispose(); + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/Application.kt b/src/main/kotlin/com/developerphil/adbidea/Application.kt index fcac65c1..c905bbed 100644 --- a/src/main/kotlin/com/developerphil/adbidea/Application.kt +++ b/src/main/kotlin/com/developerphil/adbidea/Application.kt @@ -1,7 +1,7 @@ package com.developerphil.adbidea -import com.developerphil.adbidea.preference.accessor.PreferenceAccessorImpl import com.developerphil.adbidea.preference.ApplicationPreferences +import com.developerphil.adbidea.preference.accessor.PreferenceAccessorImpl import com.developerphil.adbidea.ui.NotificationHelper import com.intellij.ide.plugins.PluginManager import com.intellij.ide.util.PropertiesComponent diff --git a/src/main/kotlin/com/developerphil/adbidea/Const.kt b/src/main/kotlin/com/developerphil/adbidea/Const.kt new file mode 100644 index 00000000..da6b33bb --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/Const.kt @@ -0,0 +1,115 @@ +package com.developerphil.adbidea + +/** + * Created by XQ Yang on 10/10/2018 3:28 PM. + * Description : some actions form android.content.Intent + */ + +const val ACTION_MAIN = "android.intent.action.MAIN" +const val ACTION_VIEW = "android.intent.action.VIEW" +const val ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA" +const val ACTION_EDIT = "android.intent.action.EDIT" +const val ACTION_PICK = "android.intent.action.PICK" +const val ACTION_CHOOSER = "android.intent.action.CHOOSER" +const val ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT" +const val ACTION_DIAL = "android.intent.action.DIAL" +const val ACTION_CALL = "android.intent.action.CALL" +const val ACTION_SEND = "android.intent.action.SEND" +const val ACTION_SENDTO = "android.intent.action.SENDTO" +const val ACTION_ANSWER = "android.intent.action.ANSWER" +const val ACTION_INSERT = "android.intent.action.INSERT" +const val ACTION_DELETE = "android.intent.action.DELETE" +const val ACTION_RUN = "android.intent.action.RUN" +const val ACTION_SYNC = "android.intent.action.SYNC" +const val ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY" +const val ACTION_SEARCH = "android.intent.action.SEARCH" +const val ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH" +const val ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST" + + +val StartActivityActions = arrayOf("", ACTION_MAIN, + ACTION_VIEW, + ACTION_ATTACH_DATA, + ACTION_EDIT, + ACTION_PICK, + ACTION_CHOOSER, + ACTION_GET_CONTENT, + ACTION_DIAL, + ACTION_CALL, + ACTION_SEND, + ACTION_SENDTO, + ACTION_ANSWER, + ACTION_INSERT, + ACTION_DELETE, + ACTION_RUN, + ACTION_SYNC, + ACTION_PICK_ACTIVITY, + ACTION_SEARCH, + ACTION_WEB_SEARCH, + ACTION_FACTORY_TEST +) + + +const val CATEGORY_DEFAULT = "android.intent.category.DEFAULT" +const val CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE" +const val CATEGORY_TAB = "android.intent.category.TAB" +const val CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE" +const val CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE" +const val CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER" +const val CATEGORY_INFO = "android.intent.category.INFO" +const val CATEGORY_HOME = "android.intent.category.HOME" +const val CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE" +const val CATEGORY_TEST = "android.intent.category.TEST" +const val CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK" +const val CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK" +const val CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK" +const val CATEGORY_HE_DESK_DOCK = "android.intent.category.HE_DESK_DOCK" +const val CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE" +const val CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET" +const val CATEGORY_VR_HOME = "android.intent.category.VR_HOME" + + +val Categorys = arrayOf("", + CATEGORY_DEFAULT, + CATEGORY_BROWSABLE, + CATEGORY_TAB, + CATEGORY_ALTERNATIVE, + CATEGORY_SELECTED_ALTERNATIVE, + CATEGORY_LAUNCHER, + CATEGORY_INFO, + CATEGORY_HOME, + CATEGORY_PREFERENCE, + CATEGORY_TEST, + CATEGORY_CAR_DOCK, + CATEGORY_DESK_DOCK, + CATEGORY_LE_DESK_DOCK, + CATEGORY_HE_DESK_DOCK, + CATEGORY_CAR_MODE, + CATEGORY_APP_MARKET, + CATEGORY_VR_HOME +) + +val BroadCastActions = arrayOf("", + "android.net.conn.CONNECTIVITY_CHANGE",//网络连接发生变化 + "android.intent.action.SCREEN_ON",//屏幕点亮 + "android.intent.action.SCREEN_OFF",//屏幕熄灭 + "android.intent.action.BATTERY_LOW",//电量低,会弹出电量低提示框 + "android.intent.action.BATTERY_OKAY",//电量恢复了 + "android.intent.action.BOOT_COMPLETED",//设备启动完毕 + "android.intent.action.DEVICE_STORAGE_LOW",//存储空间过低 + "android.intent.action.DEVICE_STORAGE_OK",//存储空间恢复 + "android.intent.action.PACKAGE_ADDED",//安装了新的应用 + "android.net.wifi.STATE_CHANGE",//WiFi连接状态发生变化 + "android.net.wifi.WIFI_STATE_CHANGED",//WiFi状态变为启用/关闭/正在启动/正在关闭/未知 + "android.intent.action.BATTERY_CHANGED",//电池电量发生变化 + "android.intent.action.INPUT_METHOD_CHANGED",//系统输入法发生变化 + "android.intent.action.ACTION_POWER_CONNECTED",//外部电源连接 + "android.intent.action.ACTION_POWER_DISCONNECTED",//外部电源断开连接 + "android.intent.action.DREAMING_STARTED",//系统开始休眠 + "android.intent.action.DREAMING_STOPPED",//系统停止休眠 + "android.intent.action.WALLPAPER_CHANGED",//壁纸发生变化 + "android.intent.action.HEADSET_PLUG",//插入耳机 + "android.intent.action.MEDIA_UNMOUNTED",//卸载外部介质 + "android.intent.action.MEDIA_MOUNTED",//挂载外部介质 + "android.os.action.POWER_SAVE_MODE_CHANGED"//省电模式开启 +) \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/HelperMethods.kt b/src/main/kotlin/com/developerphil/adbidea/HelperMethods.kt index 2cd9c309..746cec04 100644 --- a/src/main/kotlin/com/developerphil/adbidea/HelperMethods.kt +++ b/src/main/kotlin/com/developerphil/adbidea/HelperMethods.kt @@ -1,6 +1,8 @@ package com.developerphil.adbidea import com.intellij.openapi.application.ApplicationManager +import org.jdesktop.swingx.util.OS +import javax.swing.JOptionPane fun waitUntil(timeoutMillis: Long = 30000L, step: Long = 100L, condition: () -> Boolean) { val endTime = System.currentTimeMillis() + timeoutMillis @@ -14,4 +16,17 @@ fun waitUntil(timeoutMillis: Long = 30000L, step: Long = 100L, condition: () -> fun invokeLater(runnable: () -> Unit) { ApplicationManager.getApplication().invokeLater(runnable) +} + +fun showErrorMsg(msg:String){ + JOptionPane.showMessageDialog(null, msg,"Error", JOptionPane.ERROR_MESSAGE) +} + + +fun openFileExplorer(path: String){ + when { + OS.isWindows() -> Runtime.getRuntime().exec(arrayOf("cmd", "/C", "start $path")) + OS.isMacOSX() -> ProcessBuilder("open",path).start() + OS.isLinux() -> Runtime.getRuntime().exec("nautilus $path") + } } \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt b/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt index 15e47ba3..fdc8a8e2 100644 --- a/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt +++ b/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt @@ -1,10 +1,10 @@ package com.developerphil.adbidea -import com.developerphil.adbidea.preference.accessor.PreferenceAccessorImpl import com.developerphil.adbidea.adb.BridgeImpl import com.developerphil.adbidea.adb.DeviceResultFetcher import com.developerphil.adbidea.adb.UseSameDevicesHelper import com.developerphil.adbidea.preference.ProjectPreferences +import com.developerphil.adbidea.preference.accessor.PreferenceAccessorImpl import com.intellij.ide.util.PropertiesComponent import com.intellij.openapi.components.ProjectComponent import com.intellij.openapi.project.Project @@ -28,4 +28,8 @@ class ObjectGraph(private val project: Project) : ProjectComponent { override fun initComponent() = Unit override fun disposeComponent() = Unit override fun getComponentName(): String = "InjectionObjectGraph" + + fun clearSelectedDevice(){ + useSameDevicesHelper.clearSelectedDevice() + } } diff --git a/src/main/kotlin/com/developerphil/adbidea/SearchHelper.kt b/src/main/kotlin/com/developerphil/adbidea/SearchHelper.kt new file mode 100644 index 00000000..8bf0d1e0 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/SearchHelper.kt @@ -0,0 +1,42 @@ +package com.developerphil.adbidea + +import com.developerphil.adbidea.ui.Utils.Companion.isEmpty +import com.developerphil.adbidea.ui.Utils.Companion.searchAndSelection +import javax.swing.JTextField +import javax.swing.JTextPane +import javax.swing.text.BadLocationException + +/** + * @describe + * @author longforus + * @date 2022/1/12 17:01 + */ +class SearchHelper(private val tv_search: JTextField,private val tp: JTextPane) { + + private var lastSearchContent: String? = null + private var lastSearchSeg = 0 + private var lastSearchEnd = -1 + + fun doSearch() { + val document = tv_search.document + try { + val text = document.getText(0, document.length) + if (!isEmpty(text)) { + if (text != lastSearchContent) { + lastSearchSeg = 0 + lastSearchEnd = -1 + } + val (first, second) = searchAndSelection(text, tp, lastSearchSeg, lastSearchEnd) + lastSearchSeg = first + lastSearchEnd = second + lastSearchContent = text + } else { + lastSearchContent = null + lastSearchEnd = -1 + lastSearchSeg = 0 + } + } catch (badLocationException: BadLocationException) { + badLocationException.printStackTrace() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/action/QuickListAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/QuickListAction.kt index e42b900d..aa6b52f3 100644 --- a/src/main/kotlin/com/developerphil/adbidea/action/QuickListAction.kt +++ b/src/main/kotlin/com/developerphil/adbidea/action/QuickListAction.kt @@ -28,6 +28,8 @@ class QuickListAction : QuickSwitchSchemeAction(), DumbAware { addAction("com.developerphil.adbidea.action.StartWithDebuggerAction", group) addAction("com.developerphil.adbidea.action.RestartWithDebuggerAction", group) } + group.addSeparator() + addAction("com.developerphil.adbidea.action.QuickListSupplementaryAction", group) } diff --git a/src/main/kotlin/com/developerphil/adbidea/action/QuickListSupplementaryAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/QuickListSupplementaryAction.kt new file mode 100644 index 00000000..b8d571ef --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/QuickListSupplementaryAction.kt @@ -0,0 +1,45 @@ +package com.developerphil.adbidea.action + +import com.intellij.ide.actions.QuickSwitchSchemeAction +import com.intellij.openapi.actionSystem.ActionManager +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project + +class QuickListSupplementaryAction : QuickSwitchSchemeAction(), DumbAware { + override fun fillActions(project: Project?, + group: DefaultActionGroup, + dataContext: DataContext) { + + if (project == null) { + return + } + addAction("com.developerphil.adbidea.action.extend.ApplicationManagementPopupAction", group) + addAction("com.developerphil.adbidea.action.extend.InteractingAction", group) + addAction("com.developerphil.adbidea.action.extend.ShowDeviceInfoAction", group) + addAction("com.developerphil.adbidea.action.extend.InstallApkAction", group) + addAction("com.developerphil.adbidea.action.extend.PutStringAction", group) + addAction("com.developerphil.adbidea.action.extend.ScreenRecordAction", group) + addAction("com.developerphil.adbidea.action.extend.ScreenCaptureAction", group) + } + + override fun isEnabled(): Boolean { + return true + } + + private fun addAction(actionId: String, toGroup: DefaultActionGroup) { + val action = ActionManager.getInstance().getAction(actionId) + + // add action to group if it is available + if (action != null) { + toGroup.add(action) + } + } + + override fun getPopupTitle(e: AnActionEvent): String { + return "ADB Supplementary Operations Popup" + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/ApplicationManagementPopupAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/ApplicationManagementPopupAction.kt new file mode 100644 index 00000000..830be95f --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/ApplicationManagementPopupAction.kt @@ -0,0 +1,21 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.ui.ApplicationManagementFrame +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +/** + * Created by XQ Yang on 8/28/2018 2:53 PM. + * Description : + */ +class ApplicationManagementPopupAction:AdbAction(){ + override fun actionPerformed(e: AnActionEvent, project: Project) { + val form = ApplicationManagementFrame(project) + form.pack() + form.isVisible = true + } + + + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/ClearCurrentRememberDeviceAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/ClearCurrentRememberDeviceAction.kt new file mode 100644 index 00000000..35f37734 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/ClearCurrentRememberDeviceAction.kt @@ -0,0 +1,22 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.ObjectGraph +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.ui.NotificationHelper +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +/** + * @describe + * @author longforus + * @date 10/29/2018 4:21 PM + */ +class ClearCurrentRememberDeviceAction : AdbAction() { + + override fun actionPerformed(e: AnActionEvent, project: Project) { + project.getComponent(ObjectGraph::class.java) + .clearSelectedDevice() + NotificationHelper.info("clear success") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/InstallApkAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/InstallApkAction.kt new file mode 100644 index 00000000..8fcd9f4a --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/InstallApkAction.kt @@ -0,0 +1,35 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.fileChooser.FileChooserDescriptor +import com.intellij.openapi.fileChooser.ex.FileChooserDialogImpl +import com.intellij.openapi.project.Project +import org.jdesktop.swingx.util.OS +import java.io.File + + +/** + * Created by XQ Yang on 8/28/2018 2:53 PM. + * Description : + */ +class InstallApkAction : AdbAction() { + override fun actionPerformed(e: AnActionEvent, project: Project) { + // Set 'chooseFolders' depend on OS, because macOS application represents a directory. + apkChooserDescriptor = FileChooserDescriptor(true, OS.isMacOSX(), false, false, false, true) + apkChooserDescriptor.title = "selected apk file to install,support multiple choose" + apkChooserDescriptor.withFileFilter { + it.extension == "apk" + } + val apks = FileChooserDialogImpl(apkChooserDescriptor, project) + .choose(project) + if (apks.isNotEmpty()) { + AdbFacade.installApk(project, apks.map { File(it.canonicalPath) }.toList()) + } + } + + + private lateinit var apkChooserDescriptor: FileChooserDescriptor + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/InteractingAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/InteractingAction.kt new file mode 100644 index 00000000..70a45bc9 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/InteractingAction.kt @@ -0,0 +1,22 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.ui.InteractingFrame +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + + +/** + * Created by XQ Yang on 8/28/2018 2:53 PM. + * Description : input simple string to device + */ +class InteractingAction : AdbAction() { + + + override fun actionPerformed(e: AnActionEvent, project: Project) { + val form = InteractingFrame(project) + form.pack() + form.isVisible = true + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/PutStringAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/PutStringAction.kt new file mode 100644 index 00000000..9b76998f --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/PutStringAction.kt @@ -0,0 +1,25 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project +import javax.swing.JOptionPane + + +/** + * Created by XQ Yang on 8/28/2018 2:53 PM. + * Description : input simple string to device + */ +class PutStringAction : AdbAction() { + + + override fun actionPerformed(e: AnActionEvent, project: Project) { + var result = JOptionPane.showInputDialog("Input simple string(ASCII) put to device,need open USB debugging(Security settings)") + if (!result.isNullOrEmpty()) { + result = result.replace(" ","") + AdbFacade.putStringToDevice(project,result) + } + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenCaptureAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenCaptureAction.kt new file mode 100644 index 00000000..a13dd65d --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenCaptureAction.kt @@ -0,0 +1,46 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.fileChooser.FileChooserDescriptor +import com.intellij.openapi.fileChooser.ex.FileChooserDialogImpl +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import java.io.File +import java.text.SimpleDateFormat +import java.util.* + + +/** + * Created by XQ Yang on 8/28/2018 2:53 PM. + * Description : capture device screen via adb + */ +class ScreenCaptureAction : AdbAction() { + var deviceName = "" + init { + saveDirChooserDescriptor.title = "Select capture .png file save to..." + } + + + override fun actionPerformed(e: AnActionEvent, project: Project) { + AdbFacade.getDeviceModel(project){model:String-> + deviceName = model + } + val choose = FileChooserDialogImpl(saveDirChooserDescriptor, project) + .choose(project, selectedFile) + if (choose.isNotEmpty()) { + selectedFile = choose[0] + val fileName = "${deviceName}_${dateFormat.format(Date())}.png" + AdbFacade.captureScreen(project, File(selectedFile?.canonicalPath),fileName) + } + } + + companion object { + private var selectedFile: VirtualFile? = null + private var saveDirChooserDescriptor: FileChooserDescriptor = FileChooserDescriptor(false, true, false, false, false, false) + private var dateFormat = SimpleDateFormat("yyyyMMddHHmmss") + + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenRecordAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenRecordAction.kt new file mode 100644 index 00000000..dad8d522 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenRecordAction.kt @@ -0,0 +1,77 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.adb.AdbFacade +import com.developerphil.adbidea.ui.RecordOptionDialog +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.fileChooser.FileChooserDescriptor +import com.intellij.openapi.fileChooser.ex.FileChooserDialogImpl +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import org.jdesktop.swingx.util.OS +import org.jetbrains.android.sdk.AndroidSdkUtils +import java.awt.Toolkit +import java.awt.datatransfer.StringSelection +import java.io.File +import java.text.SimpleDateFormat +import java.util.* + + +/** + * Created by XQ Yang on 8/28/2018 2:53 PM. + * Description : record device screen via adb + */ +class ScreenRecordAction : AdbAction() { + private var deviceName = "" + + val videoName: String by lazy { "${deviceName}_${dateFormat.format(Date())}.mp4" } + val remotePath: String by lazy { "/sdcard/$videoName" } + var getFiled = false + override fun actionPerformed(e: AnActionEvent, project: Project) { + AdbFacade.getDeviceModel(project) { model: String -> + deviceName = model + } + val dialog = RecordOptionDialog { deleteRemoteFile -> + saveDirChooserDescriptor.title = "Select $videoName save to..." + val chooserDialogImpl = FileChooserDialogImpl(saveDirChooserDescriptor, project) + val choose = if (selectedFile != null) { + chooserDialogImpl + .choose(project, selectedFile!!) + } else { + chooserDialogImpl + .choose(project) + } + if (choose.isNotEmpty()) { + selectedFile = choose[0] + AdbFacade.pullFile(project, remotePath, File(selectedFile?.canonicalPath, videoName), deleteRemoteFile) + } + } + dialog.onStartListener = { + if (OS.isLinux()) { + val adb = AndroidSdkUtils.getAdb(project) + if (adb==null){ + getFiled = true + throw RuntimeException("Adb is null") + }else{ + Runtime.getRuntime().exec("gnome-terminal --window --title=Press_Ctrl+C_stop_adb_screenrecord -- ${adb.absolutePath} shell screenrecord $remotePath") + } + } else if(OS.isWindows()) { + ProcessBuilder("cmd", "/c", "start", "cmd", "/K","adb shell screenrecord $remotePath").start() + }else if(OS.isMacOSX()){ + Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection("adb shell screenrecord $remotePath"), null) + Runtime.getRuntime().exec("open /Users -a Terminal") + } + } + dialog.pack() + dialog.isVisible = true + } + + companion object { + private var selectedFile: VirtualFile? = null + private var saveDirChooserDescriptor: FileChooserDescriptor = FileChooserDescriptor(false, true, false, false, false, false) + private var dateFormat = SimpleDateFormat("yyyyMMddHHmmss") + + } + + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/SetDefaultModuleAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/SetDefaultModuleAction.kt new file mode 100644 index 00000000..aa0f5c9e --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/SetDefaultModuleAction.kt @@ -0,0 +1,22 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.ObjectGraph +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.ui.ModuleChooserDialogHelper +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project +import org.jetbrains.android.util.AndroidUtils + +/** + * @describe + * @author longforus + * @date 10/29/2018 4:21 PM + */ +class SetDefaultModuleAction : AdbAction() { + + override fun actionPerformed(e: AnActionEvent, project: Project) { + val facets = AndroidUtils.getApplicationFacets(project) + ModuleChooserDialogHelper.showDialogForFacets(project, facets, true) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/ShowDeviceInfoAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/ShowDeviceInfoAction.kt new file mode 100644 index 00000000..8d1e3e11 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/ShowDeviceInfoAction.kt @@ -0,0 +1,22 @@ +package com.developerphil.adbidea.action.extend + +import com.developerphil.adbidea.action.AdbAction +import com.developerphil.adbidea.ui.DeviceInfoFrame +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + + +/** + * Created by XQ Yang on 8/28/2018 2:53 PM. + * Description : input simple string to device + */ +class ShowDeviceInfoAction : AdbAction() { + + + override fun actionPerformed(e: AnActionEvent, project: Project) { + val form = DeviceInfoFrame(project) + form.pack() + form.isVisible = true + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt b/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt index e9a506f3..4f19c03a 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt @@ -1,18 +1,24 @@ package com.developerphil.adbidea.adb +import com.android.ddmlib.IDevice import com.developerphil.adbidea.ObjectGraph import com.developerphil.adbidea.adb.command.* -import com.developerphil.adbidea.adb.command.SvcCommand.MOBILE -import com.developerphil.adbidea.adb.command.SvcCommand.WIFI +import com.developerphil.adbidea.bean.BoundItemBean import com.developerphil.adbidea.ui.NotificationHelper import com.google.common.util.concurrent.ThreadFactoryBuilder import com.intellij.openapi.project.Project +import org.eclipse.xtext.xbase.lib.Functions +import java.io.File import java.util.concurrent.Executors object AdbFacade { - private val EXECUTOR = Executors.newCachedThreadPool(ThreadFactoryBuilder().setNameFormat("AdbIdea-%d").build()) + internal val EXECUTOR = Executors.newCachedThreadPool(ThreadFactoryBuilder().setNameFormat("AdbIdea-%d").build()) fun uninstall(project: Project) = executeOnDevice(project, UninstallCommand()) + fun uninstall(project: Project, packageName: String) { + executeOnDevice(project, UninstallCommand(packageName)) + } + fun kill(project: Project) = executeOnDevice(project, KillCommand()) fun grantPermissions(project: Project) = executeOnDevice(project, GrantPermissionsCommand()) fun revokePermissions(project: Project) = executeOnDevice(project, RevokePermissionsCommand()) @@ -23,21 +29,57 @@ object AdbFacade { fun restartDefaultActivityWithDebugger(project: Project) = executeOnDevice(project, CommandList(KillCommand(), StartDefaultActivityCommand(true))) fun clearData(project: Project) = executeOnDevice(project, ClearDataCommand()) fun clearDataAndRestart(project: Project) = executeOnDevice(project, ClearDataAndRestartCommand()) - fun clearDataAndRestartWithDebugger(project: Project) = executeOnDevice(project, ClearDataAndRestartWithDebuggerCommand()) - fun enableWifi(project: Project) = executeOnDevice(project, ToggleSvcCommand(WIFI, true)) - fun disableWifi(project: Project) = executeOnDevice(project, ToggleSvcCommand(WIFI, false)) - fun enableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(MOBILE, true)) - fun disableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(MOBILE, false)) - private fun executeOnDevice(project: Project, runnable: Command) { + + + + fun installApk(project: Project, apks: List) { + executeOnDevice(project, InstallApkCommand(apks)) + } + + + + fun getPackageDetail(project: Project, packageName: String, callback: Function1) { + executeOnDevice(project, PackageDetailCommand(packageName, callback)) + } + + fun forceStop(project: Project, packageName: String) { + executeOnDevice(project, ForceStopCommand(packageName)) + } + + fun getPackagePath(project: Project, packageName: String, callback: Function1) { + executeOnDevice(project, PackagePathCommand(packageName, callback)) + } + + fun getActivityService(project: Project, packageName: String, callback: Function1) { + executeOnDevice(project, ActivityServiceCommand(packageName, callback)) + } + + + + fun getAllApplicationList(project: Project, parameter: String, callback: Function1, Unit>) { + executeOnDevice(project, GetApplicationListCommand(parameter, callback)) + } + + + fun clearDataAndRestartWithDebugger(project: Project) = executeOnDevice(project, ClearDataAndRestartWithDebuggerCommand()) + fun enableWifi(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.WIFI, true)) + fun disableWifi(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.WIFI, false)) + fun enableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.MOBILE, true)) + fun disableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.MOBILE, false)) + + + + private fun executeOnDevice(project: Project, runnable: Command,dev: IDevice? = null) { if (AdbUtil.isGradleSyncInProgress(project)) { NotificationHelper.error("Gradle sync is in progress") return } + val result = project.getComponent(ObjectGraph::class.java) .deviceResultFetcher - .fetch() + .fetch(dev) if (result != null) { for (device in result.devices) { @@ -47,4 +89,56 @@ object AdbFacade { NotificationHelper.error("No Device found") } } -} + + fun clearData(project: Project, realPackageName: String) { + executeOnDevice(project, ClearDataCommand(realPackageName)) + } + + fun showForegroundActivity(project: Project, callback: Function1) { + executeOnDevice(project, ForegroundActivityCommand(callback)) + } + + fun monkeyTest(project: Project, packageName: String, count: Int, callback: Function1) { + executeOnDevice(project, MonkeyTestCommand(packageName, count, callback)) + } + + fun putStringToDevice(project: Project?, str: String) { + executeOnDevice(project!!, PutStringToDeviceCommand(str)) + } + + fun interacting(project: Project, type: Int, action: String, category: String, name: String, boundData: MutableList) { + executeOnDevice(project, getInteractingCommand(type, action, category, name, boundData)) + } + + @JvmOverloads + fun getSimpleInfo(project: Project?, command: String, desc: String,dev: IDevice? = null, callback: Function2) { + executeOnDevice(project!!, CommonStringResultCommand(command, desc, callback),dev) + } + + fun captureScreen(project: Project?, localDir: File, fileName: String) { + executeOnDevice(project!!, CaptureScreenCommand(localDir, fileName)) + } + + /** + * "bad result" + * @param project + * @param localFile + * @param videoName + * @param length + * @param showTouches + */ + @Deprecated("") + fun recordScreen(project: Project?, localFile: File, videoName: String, length: Int, showTouches: Boolean) { + executeOnDevice(project!!, ScreenRecordCommand(localFile, videoName, length, showTouches)) + } + + fun pullFile(project: Project?, remotePath: String, localFile: File, deleteRemoteFile: Boolean) { + executeOnDevice(project!!, PullFileCommand(remotePath, localFile, deleteRemoteFile)) + } + + fun getDeviceModel(project: Project?, function: Function1) { + getSimpleInfo(project, "getprop ro.product.model", "get Device model ") { s,d -> + function.invoke(s.replace("\n", "").replace("\r", "").replace(" ", "")) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/AdbUtil.kt b/src/main/kotlin/com/developerphil/adbidea/adb/AdbUtil.kt index 9b2069b4..46a14a7c 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/AdbUtil.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/AdbUtil.kt @@ -1,17 +1,16 @@ package com.developerphil.adbidea.adb -import com.android.ddmlib.AdbCommandRejectedException -import com.android.ddmlib.IDevice -import com.android.ddmlib.ShellCommandUnresponsiveException -import com.android.ddmlib.TimeoutException +import com.android.ddmlib.* import com.android.tools.idea.gradle.project.sync.GradleSyncState import com.developerphil.adbidea.adb.command.receiver.GenericReceiver import com.developerphil.adbidea.ui.NotificationHelper.info import com.intellij.openapi.project.Project import org.joor.Reflect +import java.io.File import java.io.IOException import java.util.concurrent.TimeUnit + object AdbUtil { @Throws(TimeoutException::class, AdbCommandRejectedException::class, ShellCommandUnresponsiveException::class, IOException::class) fun isAppInstalled(device: IDevice, packageName: String): Boolean { @@ -43,4 +42,32 @@ object AdbUtil { false } } + + + @Throws(IOException::class, AdbCommandRejectedException::class, com.android.ddmlib.TimeoutException::class, SyncException::class) + fun pullFile(device: IDevice, remote: String, local: String, monitor: SyncService.ISyncProgressMonitor) { + var sync: SyncService? = null + try { + val targetFileName = File(remote).getName() + Log.d(targetFileName, String.format("Downloading %1\$s from device '%2\$s'", targetFileName, device.serialNumber)) + sync = device.syncService + if (sync == null) { + throw IOException("Unable to open sync connection!") + } + val message = String.format("Downloading file from device '%1\$s'", device.serialNumber) + Log.d("Device", message) + sync.pullFile(remote, local, monitor) + } catch (var11: com.android.ddmlib.TimeoutException) { + Log.e("Device", "Error during Sync: timeout.") + throw var11 + } catch (var12: SyncException) { + Log.e("Device", String.format("Error during Sync: %1\$s", var12.message)) + throw var12 + } catch (var13: IOException) { + Log.e("Device", String.format("Error during Sync: %1\$s", var13.message)) + throw var13 + } finally { + sync?.close() + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/Bridge.kt b/src/main/kotlin/com/developerphil/adbidea/adb/Bridge.kt index c3cad2a3..52c51f5c 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/Bridge.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/Bridge.kt @@ -1,5 +1,6 @@ package com.developerphil.adbidea.adb +import com.android.ddmlib.AndroidDebugBridge import com.android.ddmlib.IDevice import com.intellij.openapi.project.Project import org.jetbrains.android.sdk.AndroidSdkUtils @@ -10,19 +11,16 @@ interface Bridge { } -class BridgeImpl(project: Project) : Bridge { +class BridgeImpl(private val project: Project) : Bridge { - val androidBridge = AndroidSdkUtils.getDebugBridge(project) + private val androidBridge: AndroidDebugBridge? + get() = AndroidSdkUtils.getDebugBridge(project) - override fun isReady(): Boolean { - if (androidBridge == null) { - return false - } - - return androidBridge.isConnected && androidBridge.hasInitialDeviceList() - } + override fun isReady() = androidBridge?.let { + it.isConnected && it.hasInitialDeviceList() + } ?: false override fun connectedDevices(): List { return androidBridge?.devices?.asList() ?: emptyList() } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/DeviceResultFetcher.kt b/src/main/kotlin/com/developerphil/adbidea/adb/DeviceResultFetcher.kt index 8ac5eab4..64cd57e7 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/DeviceResultFetcher.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/DeviceResultFetcher.kt @@ -13,7 +13,7 @@ import org.jetbrains.android.util.AndroidUtils class DeviceResultFetcher constructor(private val project: Project, private val useSameDevicesHelper: UseSameDevicesHelper, private val bridge: Bridge) { - fun fetch(): DeviceResult? { + fun fetch(dev: IDevice? = null): DeviceResult? { val facets = AndroidUtils.getApplicationFacets(project) if (facets.isNotEmpty()) { val facet = getFacet(facets) ?: return null @@ -24,18 +24,20 @@ class DeviceResultFetcher constructor(private val project: Project, private val return null } + if (dev != null) { + return DeviceResult(listOf(dev), facet, packageName) + } + val rememberedDevices = useSameDevicesHelper.getRememberedDevices() if (rememberedDevices.isNotEmpty()) { return DeviceResult(rememberedDevices, facet, packageName) } val devices = bridge.connectedDevices() - if (devices.size == 1) { - return DeviceResult(devices, facet, packageName) - } else if (devices.size > 1) { - return showDeviceChooserDialog(facet, packageName) - } else { - return null + return when { + devices.size == 1 -> DeviceResult(devices, facet, packageName) + devices.size > 1 -> showDeviceChooserDialog(facet, packageName) + else -> null } } return null @@ -44,17 +46,17 @@ class DeviceResultFetcher constructor(private val project: Project, private val private fun getFacet(facets: List): AndroidFacet? { val facet: AndroidFacet? if (facets.size > 1) { - facet = ModuleChooserDialogHelper.showDialogForFacets(project, facets) + facet = ModuleChooserDialogHelper.showDialogForFacets(project, facets, false) if (facet == null) { return null } } else { facet = facets[0] } - return facet } + private fun showDeviceChooserDialog(facet: AndroidFacet, packageName: String): DeviceResult? { val chooser = DeviceChooserDialog(facet) chooser.show() @@ -76,6 +78,8 @@ class DeviceResultFetcher constructor(private val project: Project, private val return DeviceResult(selectedDevices.asList(), facet, packageName) } + + } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt b/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt index 279e9293..095c5f06 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt @@ -24,4 +24,7 @@ class UseSameDevicesHelper constructor(private val projectPreferences: ProjectPr fun rememberDevices() { previouslyConnectedDevices = bridge.connectedDevices() } + fun clearSelectedDevice() { + previouslyConnectedDevices = null + } } \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ActivityServiceCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ActivityServiceCommand.kt new file mode 100644 index 00000000..65b610ed --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ActivityServiceCommand.kt @@ -0,0 +1,38 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.AdbUtil.isAppInstalled +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit +/** + * @describe + * @author Void Young + * @date 2018-10-13 16:48:56 + */ + +class ActivityServiceCommand(private val mPackageName: String,private val callback:(String)->Unit) : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + if (mPackageName.isNotEmpty()&&!isAppInstalled(device, mPackageName)) { + error(String.format("%s is not installed on %s", mPackageName, device.name)) + } + val receiver = PrintReceiver() + device.executeShellCommand("dumpsys activity services $mPackageName", receiver, 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format("%s get activity service on %s", mPackageName, device.name)) + val string = receiver.toString() + callback.invoke(string) + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } catch (e1: Exception) { + error("get activity service... " + e1.message) + } + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/CaptureScreenCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/CaptureScreenCommand.kt new file mode 100644 index 00000000..a65881c1 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/CaptureScreenCommand.kt @@ -0,0 +1,39 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.AdbFacade +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.intellij.notification.NotificationType +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.io.File +import java.util.concurrent.TimeUnit + +/** + * Created by XQ Yang on 10/10/2018 10:56 AM. + * Description : + */ +class CaptureScreenCommand(val localDir: File, val fileName: String) : Command { + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + val remotePath = "/sdcard/$fileName" + val receiver = PrintReceiver() + device.executeShellCommand("screencap -p > $remotePath", receiver, 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format("Capture screen on %s", device.name)) + val string = receiver.toString() + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NotificationHelper.NOOP_LISTENER) + notification.notify(project) + Thread.sleep(1000L) + ApplicationManager.getApplication().invokeLater { + AdbFacade.pullFile(project, remotePath, File(localDir,fileName), true) + } + return true + } catch (e1: Exception) { + NotificationHelper.error("Capture Screen ... " + e1.message) + } + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt index 86580cf2..5e8fb7c7 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt @@ -8,19 +8,25 @@ import com.intellij.openapi.project.Project import org.jetbrains.android.facet.AndroidFacet import java.util.concurrent.TimeUnit -class ClearDataCommand : Command { +class ClearDataCommand(val realPackageName:String = "") : Command { override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + var pn = packageName + if (realPackageName.isNotEmpty()) { + pn = realPackageName + } try { - if (AdbUtil.isAppInstalled(device, packageName)) { - device.executeShellCommand("pm clear $packageName", GenericReceiver(), 15L, TimeUnit.SECONDS) - NotificationHelper.info(String.format("%s cleared data for app on %s", packageName, device.name)) + if (AdbUtil.isAppInstalled(device, pn)) { + device.executeShellCommand("pm clear $pn", GenericReceiver(), 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format("%s cleared data for app on %s", pn, device.name)) return true } else { - NotificationHelper.error(String.format("%s is not installed on %s", packageName, device.name)) + NotificationHelper.error(String.format("%s is not installed on %s", pn, device.name)) } } catch (e1: Exception) { NotificationHelper.error("Clear data failed... " + e1.message) } + return false } + } \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/CommonStringResultCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/CommonStringResultCommand.kt new file mode 100644 index 00000000..6c88e179 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/CommonStringResultCommand.kt @@ -0,0 +1,37 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit +/** + * @describe + * @author Void Young + * @date 2018-10-13 16:48:56 + */ + +class CommonStringResultCommand(private val commandStr:String,private val operationDesc:String,private val callback:((String,IDevice)->Unit)? = null) : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + val receiver = PrintReceiver() + device.executeShellCommand(commandStr, receiver, 15L, TimeUnit.SECONDS) + if (callback==null) { + NotificationHelper.info("$operationDesc on ${device.name}\n") + val string = receiver.toString() + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + } else { + callback.invoke(receiver.toString(),device) + } + return true + } catch (e1: Exception) { + error("$operationDesc... " + e1.message) + } + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ForceStopCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForceStopCommand.kt new file mode 100644 index 00000000..a3e10ddc --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForceStopCommand.kt @@ -0,0 +1,38 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.AdbUtil.isAppInstalled +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +/** + * Created by XQ Yang on 2018-10-9 15:00:43 + * Description : + */ + +class ForceStopCommand(private val mPackageName: String) : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + if (isAppInstalled(device, mPackageName)) { + val receiver = PrintReceiver() + device.executeShellCommand("am force-stop $mPackageName", receiver, 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format("ForceStop %s on %s", mPackageName, device.name)) + val string = receiver.toString() + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } else { + error(String.format("%s is not installed on %s", mPackageName, device.name)) + } + } catch (e1: Exception) { + error("Force Stop... " + e1.message) + } + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ForegroundActivityCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForegroundActivityCommand.kt new file mode 100644 index 00000000..adad2ad4 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForegroundActivityCommand.kt @@ -0,0 +1,34 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit +/** + * @describe + * @author Void Young + * @date 2018-10-13 16:48:56 + */ + +class ForegroundActivityCommand(private val callback:(String)->Unit) : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + val receiver = PrintReceiver() + device.executeShellCommand("dumpsys activity activities | grep mFocusedActivity", receiver, 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format(" get foreground Activity on %s",device.name)) + val string = receiver.toString() + callback.invoke(string) + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } catch (e1: Exception) { + error("Get foreground Activity... " + e1.message) + } + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/GetApplicationListCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/GetApplicationListCommand.kt new file mode 100644 index 00000000..d888a177 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/GetApplicationListCommand.kt @@ -0,0 +1,29 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.command.receiver.GenericReceiver +import com.developerphil.adbidea.ui.NotificationHelper.error +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +/** + * Created by XQ Yang on 8/28/2018 3:33 PM. + * Description : + */ + +class GetApplicationListCommand(private val mParameter: String,private val callback:(List)->Unit) : Command { + + private val genericReceiver = GenericReceiver() + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + device.executeShellCommand("pm list packages $mParameter", genericReceiver, 10L, TimeUnit.SECONDS) + callback.invoke(genericReceiver.adbOutputLines) + return true + } catch (e1: Exception) { + error(String.format("get Application list failure on %s",device.name)) + } + return false + } +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/InstallApkCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/InstallApkCommand.kt new file mode 100644 index 00000000..bb4a2d82 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/InstallApkCommand.kt @@ -0,0 +1,30 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.android.ddmlib.InstallException +import com.developerphil.adbidea.ui.NotificationHelper.error +import com.developerphil.adbidea.ui.NotificationHelper.info +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.io.File +import java.util.concurrent.TimeUnit + +/** + * Created by XQ Yang on 2018-10-9 15:01:03 + * Description : + */ + +class InstallApkCommand(val apks: List) : Command { + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + device.installPackages(apks, true, listOf(), 15, TimeUnit.SECONDS) + info(String.format("Install %d apk file to %s", apks.size, device.name)) + return true + } catch (e1: InstallException) { + error("Install fail... " + e1.message) + } + return false + } + + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/InteractingCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/InteractingCommand.kt new file mode 100644 index 00000000..3fa17608 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/InteractingCommand.kt @@ -0,0 +1,39 @@ +package com.developerphil.adbidea.adb.command + +import com.developerphil.adbidea.bean.BoundItemBean + +/** + * Created by XQ Yang on 10/10/2018 4:53 PM. + * Description : + */ + +fun getInteractingCommand(type: Int, action: String, category: String, name: String, + boundData: MutableList): CommonStringResultCommand { + + var desc = "StartActivity" + val sb = StringBuilder(when (type) { + 0 -> "am start " + 1 -> { + desc = "StartService" + "am startservice " + } + 2 -> { + desc = "SendBroadCast" + "am broadcast " + } + else -> "am start " + }) + if (action.isNotEmpty()) { + sb.append("-a $action ") + } + if (category.isNotEmpty()) { + sb.append("-c $category ") + } + if (name.isNotEmpty()) { + sb.append("-n $name ") + } + boundData.forEach { + sb.append(it.toString()) + } + return CommonStringResultCommand(sb.toString(), desc) +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/MonkeyTestCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/MonkeyTestCommand.kt new file mode 100644 index 00000000..4cf94bda --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/MonkeyTestCommand.kt @@ -0,0 +1,36 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +class MonkeyTestCommand(private val mPackageName: String, private val count: Int, private val callback: (String) -> Unit) : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + val receiver = PrintReceiver() + val sb = StringBuilder("monkey ") + if (mPackageName.isNotEmpty()) { + sb.append("-p $mPackageName ") + }else if (packageName.isNotEmpty()) { + sb.append("-p $packageName ") + } + sb.append("-v $count") + device.executeShellCommand(sb.toString(), receiver, 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format(" start monkey test on %s", device.name)) + val string = receiver.toString() + callback.invoke(string) + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } catch (e1: Exception) { + error("Start monkey test... " + e1.message) + } + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/PackageDetailCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackageDetailCommand.kt new file mode 100644 index 00000000..cd8f85f9 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackageDetailCommand.kt @@ -0,0 +1,41 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.AdbUtil.isAppInstalled +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +/** + * @describe + * @author Void Young + * @date 2018-10-13 16:48:56 + */ + +class PackageDetailCommand(private val mPackageName: String,private val callback:(String)->Unit) : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + if (isAppInstalled(device, mPackageName)) { + val receiver = PrintReceiver() + device.executeShellCommand("dumpsys package $mPackageName", receiver, 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format("%s get package detail on %s", mPackageName, device.name)) + val string = receiver.toString() + callback.invoke(string) + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } else { + error(String.format("%s is not installed on %s", mPackageName, device.name)) + } + } catch (e1: Exception) { + error("Get package detail... " + e1.message) + } + + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/PackagePathCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackagePathCommand.kt new file mode 100644 index 00000000..062d6a16 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackagePathCommand.kt @@ -0,0 +1,40 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.AdbUtil.isAppInstalled +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +/** + * @describe + * @author Void Young + * @date 2018-10-13 16:48:56 + */ + +class PackagePathCommand(private val mPackageName: String,private val callback:(String)->Unit) : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + if (isAppInstalled(device, mPackageName)) { + val receiver = PrintReceiver() + device.executeShellCommand("pm path $mPackageName", receiver, 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format("%s get package path on %s", mPackageName, device.name)) + val string = receiver.toString() + callback.invoke(string) + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } else { + error(String.format("%s is not installed on %s", mPackageName, device.name)) + } + } catch (e1: Exception) { + error("Get package path... " + e1.message) + } + } + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/PullFileCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/PullFileCommand.kt new file mode 100644 index 00000000..45109778 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/PullFileCommand.kt @@ -0,0 +1,63 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.android.ddmlib.SyncService +import com.developerphil.adbidea.adb.AdbUtil +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.openFileExplorer +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.developerphil.adbidea.ui.NotificationHelper.error +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.io.File +import java.util.concurrent.TimeUnit + +/** + * Created by XQ Yang on 2018-10-9 15:00:43 + * Description : pull file to computer + */ + +class PullFileCommand(private val remotePath: String,val localFile: File, val deleteRemoteFile:Boolean) : Command { + + lateinit var mDevice: IDevice + val receiver = PrintReceiver() + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + mDevice = device + try { + AdbUtil.pullFile(device,remotePath,localFile.absolutePath,object : SyncService.ISyncProgressMonitor{ + override fun startSubTask(p0: String?) { + + } + override fun start(p0: Int) { + + } + + override fun stop() { + openFileExplorer(localFile.parentFile.absolutePath) + if (deleteRemoteFile) { + device.executeShellCommand("rm $remotePath",receiver,10L,TimeUnit.SECONDS) + } + } + + override fun isCanceled(): Boolean = false + + override fun advance(p0: Int) { + + } + + }) + val string = receiver.toString() + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } catch (e1: Exception) { + error("Pull File... " + e1.message) + } + return false + } + + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/PutStringToDeviceCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/PutStringToDeviceCommand.kt new file mode 100644 index 00000000..1a799589 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/PutStringToDeviceCommand.kt @@ -0,0 +1,29 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.ui.NotificationHelper +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +/** + * Created by XQ Yang on 10/10/2018 10:56 AM. + * Description : + */ +class PutStringToDeviceCommand(val str:String):Command{ + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + val receiver = PrintReceiver() + device?.executeShellCommand("input text $str", receiver, 15L, TimeUnit.SECONDS) + if (!receiver.toString().isNullOrEmpty()) { + NotificationHelper.error("Put String to device :\n $receiver") + } + return true + } catch (e1: Exception) { + NotificationHelper.error("Put String to device... " + e1.message) + } + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ScreenRecordCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ScreenRecordCommand.kt new file mode 100644 index 00000000..3b36fd4a --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ScreenRecordCommand.kt @@ -0,0 +1,72 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.android.ddmlib.ScreenRecorderOptions +import com.android.ddmlib.SyncService +import com.developerphil.adbidea.adb.AdbUtil +import com.developerphil.adbidea.adb.command.receiver.PrintReceiver +import com.developerphil.adbidea.openFileExplorer +import com.developerphil.adbidea.ui.NotificationHelper +import com.developerphil.adbidea.ui.NotificationHelper.NOOP_LISTENER +import com.developerphil.adbidea.ui.NotificationHelper.error +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.io.File +import java.util.* +import java.util.concurrent.TimeUnit + +/** + * Created by XQ Yang on 2018-10-9 15:00:43 + * Description : record screen to computer + */ + +@Deprecated("bad result") +class ScreenRecordCommand(private val localPath: File, videoName: String, val length: Int, val showTouches:Boolean) : Command { + + lateinit var mDevice: IDevice + val receiver = PrintReceiver() + private val remotePath = "/sdcard/$videoName" + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + mDevice = device + try { + val options = ScreenRecorderOptions.Builder().setTimeLimit(length.toLong(), TimeUnit.SECONDS).setShowTouches(showTouches).build() + device.startScreenRecorder(remotePath, options, receiver) + val timer = Timer() + timer.schedule(object : TimerTask() { + override fun run() { + AdbUtil.pullFile(device,remotePath,localPath.absolutePath,object : SyncService.ISyncProgressMonitor{ + override fun startSubTask(p0: String?) { + + } + override fun start(p0: Int) { + + } + + override fun stop() { + openFileExplorer(localPath.parentFile.absolutePath) + device.executeShellCommand("rm $remotePath",receiver,10L,TimeUnit.SECONDS) + } + + override fun isCanceled(): Boolean = false + + override fun advance(p0: Int) { + + } + + }) + } + }, (length + 1) * 1000L) + val string = receiver.toString() + val notification = NotificationHelper.INFO.createNotification("ADB IDEA", string, NotificationType.INFORMATION, NOOP_LISTENER) + notification.notify(project) + return true + } catch (e1: Exception) { + error("Record Screen... " + e1.message) + } + return false + } + + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/UninstallCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/UninstallCommand.kt index 5e160422..79d6b75d 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/UninstallCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/UninstallCommand.kt @@ -2,14 +2,17 @@ package com.developerphil.adbidea.adb.command import com.android.ddmlib.IDevice import com.android.ddmlib.InstallException -import com.developerphil.adbidea.ui.NotificationHelper import com.developerphil.adbidea.ui.NotificationHelper.error import com.developerphil.adbidea.ui.NotificationHelper.info import com.intellij.openapi.project.Project import org.jetbrains.android.facet.AndroidFacet -class UninstallCommand : Command { +class UninstallCommand(val mPackageName:String = "") : Command { override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + var packageName = packageName + if (mPackageName.isNotEmpty()) { + packageName = mPackageName + } try { val errorCode = device.uninstallPackage(packageName) if (errorCode == null) { @@ -21,6 +24,7 @@ class UninstallCommand : Command { } catch (e1: InstallException) { error("Uninstall fail... " + e1.message) } + return false } } \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt index c0f06632..cdd1eb12 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt @@ -1,12 +1,11 @@ package com.developerphil.adbidea.adb.command.receiver import com.android.ddmlib.MultiLineReceiver -import java.util.* import java.util.regex.Pattern class GenericReceiver : MultiLineReceiver() { - val adbOutputLines: MutableList = ArrayList() + val adbOutputLines= arrayListOf() private var errorMessage: String? = null override fun processNewLines(lines: Array) { diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/PrintReceiver.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/PrintReceiver.kt new file mode 100644 index 00000000..5bcb32e6 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/PrintReceiver.kt @@ -0,0 +1,23 @@ +package com.developerphil.adbidea.adb.command.receiver + +import com.android.ddmlib.IShellOutputReceiver +import com.developerphil.adbidea.ui.Utils.Companion.isEmpty +import com.google.common.base.Charsets + +class PrintReceiver : IShellOutputReceiver { + private var mString: String? = null + override fun addOutput(data: ByteArray, offset: Int, length: Int) { + if (!this.isCancelled) { + mString = String(data, offset, length, Charsets.UTF_8) + "\r\n" + } + } + + override fun flush() {} + override fun isCancelled(): Boolean { + return false + } + + override fun toString(): String { + return if (isEmpty(mString)) "" else mString!! + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/bean/BoundItemBean.kt b/src/main/kotlin/com/developerphil/adbidea/bean/BoundItemBean.kt new file mode 100644 index 00000000..da062574 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/bean/BoundItemBean.kt @@ -0,0 +1,32 @@ +package com.developerphil.adbidea.bean + +/** + * Created by XQ Yang on 9/4/2018 2:41 PM. + * Description : + */ + +data class BoundItemBean(var selected: Boolean, var key: String, var value: String,var dataType:BoundDataType = BoundDataType.STRING){ + override fun toString(): String { + if (selected&&key.isNotEmpty()) { + if (dataType == BoundDataType.NULL) { + return "${dataType.prefix} \"$key\" " + } + return "${dataType.prefix} \"$key\" \"$value\" " + } + return "" + } +} + + +enum class BoundDataType(val prefix:String){ + STRING("--es"), + BOOLEAN("--ez"), + INTEGER("--ei"), + LONG ("--el"), + FLOAT ("--ef"), + URI("--eu"), + COMPONENT_NAME("--ecn"), + INTEGER_ARRAY("--eia"), + LONG_ARRAY("--ela"), + NULL("--esn") +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt b/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt index 5cf76ee9..3bf4ac58 100644 --- a/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt +++ b/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt @@ -4,49 +4,35 @@ import com.android.ddmlib.Client import com.android.ddmlib.IDevice import com.android.tools.idea.run.AndroidProcessHandler import com.android.tools.idea.run.editor.AndroidDebugger -import com.developerphil.adbidea.compatibility.BackwardCompatibleGetter import com.developerphil.adbidea.invokeLater -import com.developerphil.adbidea.on import com.developerphil.adbidea.waitUntil import com.intellij.execution.ExecutionManager -import com.intellij.execution.process.ProcessHandler import com.intellij.execution.process.ProcessOutputTypes import com.intellij.openapi.project.Project -import org.joor.Reflect.on class Debugger(private val project: Project, private val device: IDevice, private val packageName: String) { fun attach() { - var client: Client? = null - waitUntil { - client = device.getClient(packageName) - AndroidDebugger.EP_NAME.extensions.isNotEmpty() && client != null - } + waitUntil { debuggerCanBeAttached() } for (androidDebugger in AndroidDebugger.EP_NAME.extensions) { if (androidDebugger.supportsProject(project)) { - invokeLater { closeOldSessionAndRun(androidDebugger, device.getClient(packageName) ?: client!!) } + invokeLater { closeOldSessionAndRun(androidDebugger, device.getClient(packageName)) } break } } } + private fun debuggerCanBeAttached() = AndroidDebugger.EP_NAME.extensions.isNotEmpty() && device.getClient(packageName) != null + private fun closeOldSessionAndRun(androidDebugger: AndroidDebugger<*>, client: Client) { terminateRunSessions(client) - AttachToClient(androidDebugger, project, client).get() + androidDebugger.attachToClient(project, client,null) } // Disconnect any active run sessions to the same client private fun terminateRunSessions(selectedClient: Client) { - TerminateRunSession(selectedClient, project).get() - } -} - -class TerminateRunSession( - private val selectedClient: Client, - private val project: Project -) : BackwardCompatibleGetter() { - override fun getCurrentImplementation() { val pid = selectedClient.clientData.pid + // find if there are any active run sessions to the same client, and terminate them if so for (handler in ExecutionManager.getInstance(project).getRunningProcesses()) { if (handler is AndroidProcessHandler) { @@ -60,46 +46,5 @@ class TerminateRunSession( } } - override fun getPreviousImplementation() { - val pid = pidFrom(selectedClient) - // find if there are any active run sessions to the same client, and terminate them if so - for (handler in RunningProcessesGetter(project).get()) { - if (handler is AndroidProcessHandler) { - val device = on(selectedClient).call("getDevice").get() - val client = handler.getClient(device) - if (client != null && pidFrom(client) == pid) { - handler.detachProcess() - handler.notifyTextAvailable("Disconnecting run session: a new debug session will be established.\n", ProcessOutputTypes.STDOUT) - break - } - } - } - - } - - private fun pidFrom(client: Client) = on(client).call("getClientData").call("getPid").get()!! -} - -class AttachToClient(private val androidDebugger: AndroidDebugger<*>, - private val project: Project, - private val client: Client) : BackwardCompatibleGetter() { - override fun getCurrentImplementation() { - androidDebugger.attachToClient(project, client, null) - } - override fun getPreviousImplementation() { - on(androidDebugger).call("attachToClient", project, client) - } -} - -private class RunningProcessesGetter( - val project: Project -) : BackwardCompatibleGetter>() { - override fun getCurrentImplementation(): Array { - return ExecutionManager.getInstance(project).getRunningProcesses() - } - - override fun getPreviousImplementation(): Array { - return on().call("getInstance", project).call("getRunningProcesses").get>() - } } diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/BoundTableModel.kt b/src/main/kotlin/com/developerphil/adbidea/ui/BoundTableModel.kt new file mode 100644 index 00000000..cc80e87b --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/ui/BoundTableModel.kt @@ -0,0 +1,91 @@ +package com.developerphil.adbidea.ui + +import com.developerphil.adbidea.bean.BoundDataType +import com.developerphil.adbidea.bean.BoundItemBean +import java.util.* +import javax.swing.table.AbstractTableModel + +class BoundTableModel : AbstractTableModel() { + private val cellType = arrayOf>(Boolean::class.java, String::class.java, String::class.java, BoundDataType::class.java) + private val title = arrayOf("select", "key", "value", "type") + + private val data = ArrayList() + + + fun getData(): List { + return data.filter { it.selected&& it.key.isNotEmpty()} + } + + fun setData(data: List) { + this.data.clear() + this.data.addAll(data) + fireTableDataChanged() + } + + fun clear() { + val size = this.data.size + this.data.clear() + fireTableRowsDeleted(0, size) + } + + fun addEmptyRow() { + data.add(BoundItemBean(true, "", "", BoundDataType.STRING)) + fireTableRowsInserted(data.size - 1, data.size - 1) + } + + fun removeRow(row: Int) { + if (row > -1 && row < data.size) { + data.removeAt(row) + } + fireTableRowsDeleted(row, row) + } + + override fun getColumnClass(arg0: Int): Class<*> { + return cellType[arg0] + } + + override fun getColumnName(arg0: Int): String { + return title[arg0] + } + + override fun getColumnCount(): Int { + return title.size + } + + override fun getRowCount(): Int { + return data.size + } + + override fun getValueAt(rowIndex: Int, columnIndex: Int): Any? { + if (rowIndex < data.size) { + when (columnIndex) { + 0 -> return data[rowIndex].selected + 1 -> return data[rowIndex].key + 2 -> return data[rowIndex].value + 3 -> return data[rowIndex].dataType + } + } + return null + } + + //重写isCellEditable方法 + + override fun isCellEditable(rowIndex: Int, columnIndex: Int): Boolean { + return true + } + + //重写setValueAt方法 + override fun setValueAt(aValue: Any?, rowIndex: Int, columnIndex: Int) { + if (rowIndex < data.size) { + when (columnIndex) { + 0 -> data[rowIndex].selected = aValue as Boolean + 1 -> data[rowIndex].key = aValue as String + 2 -> data[rowIndex].value = aValue as String + 3 -> data[rowIndex].dataType = aValue as BoundDataType + } + } + this.fireTableCellUpdated(rowIndex, columnIndex) + } + + +} diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/BoundTypeCellEditor.kt b/src/main/kotlin/com/developerphil/adbidea/ui/BoundTypeCellEditor.kt new file mode 100644 index 00000000..bd16496d --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/ui/BoundTypeCellEditor.kt @@ -0,0 +1,12 @@ +package com.developerphil.adbidea.ui + +import com.developerphil.adbidea.bean.BoundDataType +import javax.swing.DefaultCellEditor +import javax.swing.JComboBox + +/** + * Created by XQ Yang on 10/10/2018 2:12 PM. + * Description : + */ + +class BoundTypeCellEditor : DefaultCellEditor(JComboBox(BoundDataType.values())) diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/BoundTypeJTable.kt b/src/main/kotlin/com/developerphil/adbidea/ui/BoundTypeJTable.kt new file mode 100644 index 00000000..ba159e4f --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/ui/BoundTypeJTable.kt @@ -0,0 +1,21 @@ +package com.developerphil.adbidea.ui + +import javax.swing.JTable +import javax.swing.table.TableCellEditor + +/** + * Created by XQ Yang on 10/10/2018 2:08 PM. + * Description : + */ + +class BoundTypeJTable : JTable() { + + private val mBoundTypeCellEditor = BoundTypeCellEditor() + + override fun getCellEditor(row: Int, column: Int): TableCellEditor { + return if (column == 3) { + mBoundTypeCellEditor + } else super.getCellEditor(row, column) + } +} + diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/ModuleChooserDialogHelper.kt b/src/main/kotlin/com/developerphil/adbidea/ui/ModuleChooserDialogHelper.kt index e3065b2b..ed785689 100644 --- a/src/main/kotlin/com/developerphil/adbidea/ui/ModuleChooserDialogHelper.kt +++ b/src/main/kotlin/com/developerphil/adbidea/ui/ModuleChooserDialogHelper.kt @@ -1,43 +1,99 @@ package com.developerphil.adbidea.ui +import com.google.common.collect.Lists import com.intellij.ide.util.PropertiesComponent import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleType import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.ui.configuration.ChooseModulesDialog import org.jetbrains.android.facet.AndroidFacet + object ModuleChooserDialogHelper { - fun showDialogForFacets(project: Project, facets: List): AndroidFacet? { - val modules = facets.map { it.module } - val previousModuleName = getSavedModuleName(project) - val previousSelectedModule = modules.firstOrNull { it.name == previousModuleName } + val SELECTED_MODULE_PROPERTY = ModuleChooserDialogHelper::class.java.canonicalName + "-SELECTED_MODULE" + val DEFAULT_MODULE_PROPERTY = ModuleChooserDialogHelper::class.java.canonicalName + "-DEFAULT_MODULE" - val selectedModule = showDialog(project, modules, previousSelectedModule) ?: return null - saveModuleName(project, selectedModule.name) - return facets[modules.indexOf(selectedModule)] - } + val DO_NOT_SELECT_THE_DEFAULT_MODULE = "Do not select the default module" + + fun showDialogForFacets(project: Project, facets: List, isSetDefault: Boolean): AndroidFacet? { + val modules = Lists.newArrayList() + val modulesName = Lists.newArrayList() + val previousModuleName = getPreviousModuleName(project) + val defaultModuleName = getDefaultModuleName(project) + var previousSelectedModule: List? = null + for (facet in facets) { + val module = facet.module + val name = module.name + if (!isSetDefault && name == defaultModuleName) { + return facet + } + modules.add(module) + modulesName.add(name) + if (name == previousModuleName) { + previousSelectedModule = Lists.newArrayList(name) + } else if (isSetDefault && name == defaultModuleName) { + previousSelectedModule = Lists.newArrayList(name) + } + } + + if (isSetDefault && previousSelectedModule == null) { + previousSelectedModule = Lists.newArrayList(DO_NOT_SELECT_THE_DEFAULT_MODULE) + } - private fun showDialog(project: Project, modules: List, previousSelectedModule: Module?): Module? { - with(ChooseModulesDialog(project, modules, "Choose Module", "")) { - setSingleSelectionMode() - previousSelectedModule?.let { selectElements(listOf(it)) } - show() - return if (chosenElements.isEmpty()) { - null + if (isSetDefault) { + modulesName.add(DO_NOT_SELECT_THE_DEFAULT_MODULE) + } + var titleSelectDefault = "Choose Default Module" + if (!Utils.isEmpty(defaultModuleName)) { + titleSelectDefault += ",Current module is :" + defaultModuleName!! + } + val dialog = MyChooseModulesDialog(project, modulesName, if (isSetDefault) titleSelectDefault else "Choose Module", + if (isSetDefault) "Set the default module for each operation" else "", ModuleType.get(modules[0]).icon) + dialog.setSingleSelectionMode() + if (previousSelectedModule != null) { + dialog.selectElements(previousSelectedModule) + } + dialog.show() + + val chosenElements = dialog.chosenElements + if (chosenElements.isEmpty()) { + return null + } + + val chosenModule = chosenElements[0] + if (isSetDefault) { + if (chosenModule == DO_NOT_SELECT_THE_DEFAULT_MODULE) { + saveDefaultModuleName(project, "") + return null } else { - chosenElements[0] + saveDefaultModuleName(project, chosenModule) } + } else { + saveModuleName(project, chosenModule) } + val chosenModuleIndex = modulesName.indexOf(chosenModule) + return facets[chosenModuleIndex] + } + + private fun saveDefaultModuleName(project: Project, moduleName: String) { + val properties = PropertiesComponent.getInstance(project) + properties.setValue(DEFAULT_MODULE_PROPERTY, moduleName) } private fun saveModuleName(project: Project, moduleName: String) { - PropertiesComponent.getInstance(project).setValue(SELECTED_MODULE_PROPERTY, moduleName) + val properties = PropertiesComponent.getInstance(project) + properties.setValue(SELECTED_MODULE_PROPERTY, moduleName) + } + + private fun getPreviousModuleName(project: Project): String? { + val properties = PropertiesComponent.getInstance(project) + return properties.getValue(SELECTED_MODULE_PROPERTY) } - private fun getSavedModuleName(project: Project): String? { - return PropertiesComponent.getInstance(project).getValue(SELECTED_MODULE_PROPERTY) + private fun getDefaultModuleName(project: Project): String? { + val properties = PropertiesComponent.getInstance(project) + return properties.getValue(DEFAULT_MODULE_PROPERTY) } -} -private val SELECTED_MODULE_PROPERTY = ModuleChooserDialogHelper::class.java.canonicalName + "-SELECTED_MODULE" \ No newline at end of file + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/MyApplistModel.kt b/src/main/kotlin/com/developerphil/adbidea/ui/MyApplistModel.kt new file mode 100644 index 00000000..893606e8 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/ui/MyApplistModel.kt @@ -0,0 +1,27 @@ +package com.developerphil.adbidea.ui + +import javax.swing.AbstractListModel + +/** + * Created by XQ Yang on 10/8/2018 5:41 PM. + * Description : + */ + +internal class MyApplistModel(private val mList: MutableList) : AbstractListModel() { + + override fun getSize(): Int { + return mList.size + } + + override fun getElementAt(index: Int): String { + return mList[index] + } + + fun delete(s: String) { + val index = mList.indexOf(s) + if (index != -1) { + mList.removeAt(index) + fireIntervalRemoved(this, index, index) + } + } +} diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/MyChooseModulesDialog.kt b/src/main/kotlin/com/developerphil/adbidea/ui/MyChooseModulesDialog.kt new file mode 100644 index 00000000..edf2ad3d --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/ui/MyChooseModulesDialog.kt @@ -0,0 +1,22 @@ +package com.developerphil.adbidea.ui + +import com.intellij.icons.AllIcons +import com.intellij.ide.util.ChooseElementsDialog +import com.intellij.openapi.project.Project +import javax.swing.Icon + +class MyChooseModulesDialog(project: Project, items: List, title: String, description: String, private val mIcon: Icon) : ChooseElementsDialog(project, items, + title, description, false) { + + fun setSingleSelectionMode() { + this.myChooser.setSingleSelectionMode() + } + + override fun getItemText(s: String): String { + return s + } + + override fun getItemIcon(s: String): Icon? { + return if (s == ModuleChooserDialogHelper.DO_NOT_SELECT_THE_DEFAULT_MODULE) AllIcons.Actions.Close else mIcon + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt b/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt index bc368288..cdac589b 100755 --- a/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt +++ b/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt @@ -18,7 +18,6 @@ package com.developerphil.adbidea.ui import com.android.ddmlib.AndroidDebugBridge import com.android.ddmlib.IDevice import com.android.ddmlib.IDevice.HardwareFeature -import com.android.sdklib.IAndroidTarget import com.android.tools.idea.run.ConnectedAndroidDevice import com.android.tools.idea.run.LaunchCompatibility import com.android.tools.idea.run.LaunchCompatibilityCheckerImpl @@ -273,7 +272,7 @@ class MyDeviceChooser(multipleSelection: Boolean, DEVICE_NAME_COLUMN_INDEX -> return generateDeviceName(device) SERIAL_COLUMN_INDEX -> return device.serialNumber DEVICE_STATE_COLUMN_INDEX -> return getDeviceState(device) - COMPATIBILITY_COLUMN_INDEX -> return LaunchCompatibilityCheckerImpl.create(myFacet, null, null).validate(ConnectedAndroidDevice(device, null)) + COMPATIBILITY_COLUMN_INDEX -> return LaunchCompatibilityCheckerImpl.create(myFacet, null, null)?.validate(ConnectedAndroidDevice(device, null)) } return null } @@ -299,24 +298,28 @@ class MyDeviceChooser(multipleSelection: Boolean, private class LaunchCompatibilityRenderer : ColoredTableCellRenderer() { override fun customizeCellRenderer(table: JTable, value: Any?, selected: Boolean, hasFocus: Boolean, row: Int, column: Int) { - if (value !is LaunchCompatibility) { - return - } - val compatibility = value - val compatible = compatibility.isCompatible - if (compatible == ThreeState.YES) { - append("Yes") - } else { - if (compatible == ThreeState.NO) { - append("No", SimpleTextAttributes.ERROR_ATTRIBUTES) - } else { - append("Maybe") + try { + if (value !is LaunchCompatibility) { + return } - val reason = compatibility.reason - if (reason != null) { - append(", ") - append(reason) + val compatible = value.state + if (compatible == LaunchCompatibility.State.OK) { + append("Yes") + } else { + if (compatible == LaunchCompatibility.State.ERROR) { + append("No", SimpleTextAttributes.ERROR_ATTRIBUTES) + } else { + append("Maybe") + } + val reason = value.reason + if (reason != null) { + append(", ") + append(reason) + } } + } catch (e: Error) { + // Expected on Intellij 2021.2. + // Should be removed once the android plugin is upgraded to 7.0 } } } diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/NotificationHelper.kt b/src/main/kotlin/com/developerphil/adbidea/ui/NotificationHelper.kt index 5b3492b8..4ec7278d 100644 --- a/src/main/kotlin/com/developerphil/adbidea/ui/NotificationHelper.kt +++ b/src/main/kotlin/com/developerphil/adbidea/ui/NotificationHelper.kt @@ -1,19 +1,22 @@ package com.developerphil.adbidea.ui -import com.intellij.notification.NotificationDisplayType +import com.intellij.notification.Notification import com.intellij.notification.NotificationGroup +import com.intellij.notification.NotificationListener import com.intellij.notification.NotificationType +import javax.swing.event.HyperlinkEvent object NotificationHelper { - private val INFO = NotificationGroup("ADB Idea (Logging)", NotificationDisplayType.NONE, true, null, null) - private val ERRORS = NotificationGroup("ADB Idea (Errors)", NotificationDisplayType.BALLOON, true, null, null) + val INFO = NotificationGroup.logOnlyGroup("ADB Idea (Logging)") + val ERRORS = NotificationGroup.balloonGroup("ADB Idea (Errors)") + val NOOP_LISTENER = NotificationListener { _: Notification?, _: HyperlinkEvent? -> } fun info(message: String) = sendNotification(message, NotificationType.INFORMATION, INFO) fun error(message: String) = sendNotification(message, NotificationType.ERROR, ERRORS) private fun sendNotification(message: String, notificationType: NotificationType, notificationGroup: NotificationGroup) { - notificationGroup.createNotification("ADB IDEA", escapeString(message), notificationType, null).notify(null) + notificationGroup.createNotification("ADB IDEA", escapeString(message), notificationType, NOOP_LISTENER).notify(null) } private fun escapeString(string: String) = string.replace("\n".toRegex(), "\n
") diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/Utils.kt b/src/main/kotlin/com/developerphil/adbidea/ui/Utils.kt new file mode 100644 index 00000000..6303c3f6 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/ui/Utils.kt @@ -0,0 +1,86 @@ +package com.developerphil.adbidea.ui + +import java.awt.Color +import javax.swing.JTextPane +import javax.swing.text.BadLocationException +import javax.swing.text.MutableAttributeSet +import javax.swing.text.SimpleAttributeSet +import javax.swing.text.StyleConstants + + +/** + * Created by XQ Yang on 2018/6/25 18:14. + * Description : + */ + +class Utils { + companion object { + + fun isEmpty(str: CharSequence?): Boolean { + return str == null || str.isEmpty() + } + + + @Synchronized + fun append2TextPane(str: String, color: Color?, textPane: JTextPane) { + val doc = textPane.document + if (doc != null) { + try { + var attr: MutableAttributeSet? = null + if (color != null) { + attr = SimpleAttributeSet() + StyleConstants.setForeground(attr, color) + StyleConstants.setBold(attr, true) + } + doc.insertString(doc.length, str, attr) + } catch (e: BadLocationException) { + } + + } + } + + fun searchAndSelection(str: String,textPane: JTextPane,segIndex:Int = 0,thisStartIndex:Int = -1):Pair{ + val doc = textPane.document + val root = doc.getDefaultRootElement() + var nowSeg = segIndex + //对每一个段落进行搜索 + if (nowSeg < root.getElementCount()) { + var seg = root.getElement(nowSeg) + try { + var line: String = doc.getText(seg.getStartOffset(), seg.getEndOffset() - seg.getStartOffset()) + var start = line.indexOf(str) + while (-1 == start||start+seg.getStartOffset()+ str.length<=thisStartIndex) { + nowSeg++ + if (nowSeg >= root.getElementCount()) { + //搜索完毕 + return 0 to -1 + } + seg = root.getElement(nowSeg) + line = doc.getText(seg.getStartOffset(), seg.getEndOffset() - seg.getStartOffset()) + start = line.indexOf(str) + } + textPane.requestFocus() + val st= seg.getStartOffset() + start + val end = st + str.length + textPane.select(st, end) + return nowSeg to end + } catch (e1: BadLocationException) { + e1.printStackTrace() + } + } + return 0 to -1 + } + + fun append2TextPane(str: String, textPane: JTextPane) { + append2TextPane(str, null, textPane) + } + + fun append2TextPaneNewLine(str: String, color: Color, textPane: JTextPane) { + append2TextPane(str + "\n", color, textPane) + } + + fun append2TextPaneNewLine(str: String, textPane: JTextPane) { + append2TextPane(str + "\n", null, textPane) + } + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index d2d871d6..c3a7f50a 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,10 +1,10 @@ - - com.developerphil.adbidea - ADB Idea - 1.6.2 - Philippe Breault + + com.developerphil.adbidea + ADB Idea + + 1.6.8 + Philippe Breault & Void Young -
  • ADB Uninstall App
  • @@ -18,39 +18,72 @@
  • ADB Grant/Revoke Permissions
  • ADB Enable/Disable Wi-Fi
  • ADB Enable/Disable Mobile Data
  • +
  • ADB Application management
  • +
  • ADB Application Interacting
  • +
  • ADB Device information
  • +
  • ADB Install Apk file
  • +
  • ADB Put simple string to device
  • +
  • ADB Record device screen
  • +
  • ADB Capture device screen

There are two basic ways to invoke a command:
  • Through the Tools->Android->ADB Idea menu
  • -
  • By searching for "ADB" in "Find Actions" (osx: cmd+shift+a, windows/linux: ctrl+shift+a)
  • +
  • By searching for "ADB" in "Find Actions" (osx: cmd+shift+a, windows/linux: ctrl+shift+a)
]]>
- 1.6.2 -
    -
  • BUGFIX: Notifications don't show up on Studio 4.0
  • -
  • BUGFIX: Debugger sometime fails to attach on Studio 4.0
  • + 1.6.8 +
      +
    • FEATURE: Add simple search function in DeviceInfo and App Management. Add clear current remembered device function. +
    • BUGFIX: DeviceInfoFrame need repeat select device bug
    - 1.6.1 -
      -
    • BUGFIX: Can't attach a debugger on Android Studio 3.6
    • + 1.6.7 +
        +
      • FEATURE: Application Management panel now can pull apk file to pc, by right click application item
      • +
      • OPTIMIZE:Application Management panel function change to right click menu
      • +
      • Update to origin repertory:
      • +
      • BUGFIX: Compatibility with Android Studio 7.0
      • +
      • BUGFIX: Notifications don't show up on Studio 4.0
      • +
      • BUGFIX: Debugger sometime fails to attach on Studio 4.0
      - 1.6.0 -
        + 1.6.6 +
          +
        • Update to origin repertory:
        • +
        • BUGFIX: Notifications don't show up on Studio 4.0
        • +
        • BUGFIX: Debugger sometime fails to attach on Studio 4.0
        • 1.6.4 +
        • BUGFIX: Can't attach a debugger on Android Studio 3.6
        • FEATURE: Enable/Disable Wi-Fi
        • FEATURE: Enable/Disable Mobile Data
        • BUGFIX: Compatibility with Android Studio 4.1-alpha07+
        • +
        • BUGFIX: The result of multi-module selection is inconsistent with the actual selection
        - 1.5.4 -
          -
        • BUGFIX: Compatibility with Android Studio 3.6-alpha12+
        • + 1.6.3 +
            +
          • update to origin : BUGFIX: Show all connected devices on Android Studio 3.4+
          - 1.5.3 + 1.6.2 +
            +
          • add set default module function, After setting the default module under the same project, all operations will use the default module, and no longer pop up the module selection dialog
          • +
          + 1.6.1 +
            +
          • add linux and macOS support,The test passed in Ubuntu 18.10 and macOSx 10.13
          • +
          + 1.6.0
            -
          • BUGFIX: Show all connected devices on Android Studio 3.4+
          • +
          • Add some simple function
          • +
              +
            • ADB Application management
            • +
            • ADB Application Interacting
            • +
            • ADB Device information
            • +
            • ADB Install Apk file
            • +
            • ADB Put simple string to device
            • +
            • ADB Record device screen
            • +
            • ADB Capture device screen
            1.5.2
              @@ -140,9 +173,9 @@ ]]> - + - + com.intellij.modules.platform org.jetbrains.android @@ -156,6 +189,10 @@ + + - - - - - + + - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png new file mode 100644 index 00000000..e37a2347 Binary files /dev/null and b/src/main/resources/icon.png differ diff --git a/src/test/kotlin/com/developerphil/adbidea/TempTest.kt b/src/test/kotlin/com/developerphil/adbidea/TempTest.kt new file mode 100644 index 00000000..3721a6ff --- /dev/null +++ b/src/test/kotlin/com/developerphil/adbidea/TempTest.kt @@ -0,0 +1,12 @@ +package com.developerphil.adbidea + +import javax.swing.JOptionPane + +/** + * Created by XQ Yang on 10/10/2018 10:46 AM. + * Description : + */ +fun main(args: Array) { + val reslut = JOptionPane.showInputDialog("Input simple string to device") + println(reslut) +} \ No newline at end of file diff --git a/src/test/kotlin/com/developerphil/adbidea/adb/FakeDevice.kt b/src/test/kotlin/com/developerphil/adbidea/adb/FakeDevice.kt index eda723ef..62e4318e 100644 --- a/src/test/kotlin/com/developerphil/adbidea/adb/FakeDevice.kt +++ b/src/test/kotlin/com/developerphil/adbidea/adb/FakeDevice.kt @@ -4,256 +4,17 @@ import com.android.ddmlib.* import com.android.ddmlib.log.LogReceiver import com.android.sdklib.AndroidVersion import java.io.File +import java.lang.reflect.Proxy import java.util.concurrent.Future import java.util.concurrent.TimeUnit -data class FakeDevice(private val serialNumber: String) : IDevice { - +data class FakeDevice(private val serialNumber: String) : IDevice by stub() { override fun getSerialNumber(): String { return serialNumber } +} - // --------------- - // NOT IMPLEMENTED - // --------------- - - override fun installRemotePackage(p0: String?, p1: Boolean, p2: InstallReceiver?, vararg p3: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun installRemotePackage(p0: String?, p1: Boolean, p2: InstallReceiver?, p3: Long, p4: Long, p5: TimeUnit?, vararg p6: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun installPackage(p0: String?, p1: Boolean, p2: InstallReceiver?, vararg p3: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun installPackage(p0: String?, p1: Boolean, p2: InstallReceiver?, p3: Long, p4: Long, p5: TimeUnit?, vararg p6: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun executeShellCommand(p0: String?, p1: IShellOutputReceiver?, p2: Long, p3: Long, p4: TimeUnit?) { - throw UnsupportedOperationException("not implemented") - } - - override fun isOffline(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun startScreenRecorder(p0: String?, p1: ScreenRecorderOptions?, p2: IShellOutputReceiver?) { - throw UnsupportedOperationException("not implemented") - } - - override fun reboot(p0: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun getMountPoint(p0: String?): String { - throw UnsupportedOperationException("not implemented") - } - - override fun getClients(): Array { - throw UnsupportedOperationException("not implemented") - } - - override fun runLogService(p0: String?, p1: LogReceiver?) { - throw UnsupportedOperationException("not implemented") - } - - override fun installRemotePackage(p0: String?, p1: Boolean, vararg p2: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun getVersion(): AndroidVersion { - throw UnsupportedOperationException("not implemented") - } - - override fun getClientName(p0: Int): String { - throw UnsupportedOperationException("not implemented") - } - - override fun isOnline(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun runEventLogService(p0: LogReceiver?) { - throw UnsupportedOperationException("not implemented") - } - - override fun getLanguage(): String { - throw UnsupportedOperationException("not implemented") - } - - override fun root(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun isBootLoader(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun getSystemProperty(p0: String?): Future { - throw UnsupportedOperationException("not implemented") - } - - override fun isEmulator(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun getFileListingService(): FileListingService { - throw UnsupportedOperationException("not implemented") - } - - override fun isRoot(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun removeForward(p0: Int, p1: Int) { - throw UnsupportedOperationException("not implemented") - } - - override fun removeForward(p0: Int, p1: String?, p2: IDevice.DeviceUnixSocketNamespace?) { - throw UnsupportedOperationException("not implemented") - } - - override fun createForward(p0: Int, p1: Int) { - throw UnsupportedOperationException("not implemented") - } - - override fun createForward(p0: Int, p1: String?, p2: IDevice.DeviceUnixSocketNamespace?) { - throw UnsupportedOperationException("not implemented") - } - - override fun getAbis(): MutableList { - throw UnsupportedOperationException("not implemented") - } - - override fun pushFile(p0: String?, p1: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun removeRemotePackage(p0: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun getName(): String { - throw UnsupportedOperationException("not implemented") - } - - override fun getClient(p0: String?): Client { - throw UnsupportedOperationException("not implemented") - } - - override fun getBattery(): Future { - throw UnsupportedOperationException("not implemented") - } - - override fun getBattery(p0: Long, p1: TimeUnit?): Future { - throw UnsupportedOperationException("not implemented") - } - - override fun executeShellCommand(p0: String?, p1: IShellOutputReceiver?, p2: Int) { - throw UnsupportedOperationException("not implemented") - } - - override fun executeShellCommand(p0: String?, p1: IShellOutputReceiver?) { - throw UnsupportedOperationException("not implemented") - } - - override fun executeShellCommand(p0: String?, p1: IShellOutputReceiver?, p2: Long, p3: TimeUnit?) { - throw UnsupportedOperationException("not implemented") - } - - override fun hasClients(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun getPropertySync(p0: String?): String { - throw UnsupportedOperationException("not implemented") - } - - override fun getProperties(): MutableMap { - throw UnsupportedOperationException("not implemented") - } - - override fun getProperty(p0: String?): String { - throw UnsupportedOperationException("not implemented") - } - - override fun getAvdName(): String { - throw UnsupportedOperationException("not implemented") - } - - override fun getRegion(): String { - throw UnsupportedOperationException("not implemented") - } - - override fun getState(): IDevice.DeviceState { - throw UnsupportedOperationException("not implemented") - } - - override fun getPropertyCacheOrSync(p0: String?): String { - throw UnsupportedOperationException("not implemented") - } - - override fun installPackages(p0: MutableList?, p1: Boolean, p2: MutableList?, p3: Long, p4: TimeUnit?) { - throw UnsupportedOperationException("not implemented") - } - - override fun pullFile(p0: String?, p1: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun getDensity(): Int { - throw UnsupportedOperationException("not implemented") - } - - override fun uninstallPackage(p0: String?): String { - throw UnsupportedOperationException("not implemented") - } - - override fun getSyncService(): SyncService { - throw UnsupportedOperationException("not implemented") - } - - override fun installPackage(p0: String?, p1: Boolean, vararg p2: String?) { - throw UnsupportedOperationException("not implemented") - } - - override fun syncPackageToDevice(p0: String?): String { - throw UnsupportedOperationException("not implemented") - } - - override fun arePropertiesSet(): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun supportsFeature(p0: IDevice.Feature?): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun supportsFeature(p0: IDevice.HardwareFeature?): Boolean { - throw UnsupportedOperationException("not implemented") - } - - override fun getScreenshot(): RawImage { - throw UnsupportedOperationException("not implemented") - } - - override fun getScreenshot(p0: Long, p1: TimeUnit?): RawImage { - throw UnsupportedOperationException("not implemented") - } - - override fun getBatteryLevel(): Int { - throw UnsupportedOperationException("not implemented") - } - - override fun getBatteryLevel(p0: Long): Int { - throw UnsupportedOperationException("not implemented") - } - - override fun getPropertyCount(): Int { - throw UnsupportedOperationException("not implemented") - } -} \ No newline at end of file +inline fun stub(): T = Proxy.newProxyInstance( + T::class.java.classLoader, + arrayOf(T::class.java) +) { _, _, _ -> throw NotImplementedError() } as T \ No newline at end of file diff --git a/website/appManagement.png b/website/appManagement.png new file mode 100644 index 00000000..a1b14f06 Binary files /dev/null and b/website/appManagement.png differ diff --git a/website/capture1.png b/website/capture1.png new file mode 100644 index 00000000..045a1c95 Binary files /dev/null and b/website/capture1.png differ diff --git a/website/capture2.png b/website/capture2.png new file mode 100644 index 00000000..b706fddd Binary files /dev/null and b/website/capture2.png differ diff --git a/website/deviceInfo.png b/website/deviceInfo.png new file mode 100644 index 00000000..6f2d9e7d Binary files /dev/null and b/website/deviceInfo.png differ diff --git a/website/installApk.png b/website/installApk.png new file mode 100644 index 00000000..99350e7a Binary files /dev/null and b/website/installApk.png differ diff --git a/website/putString.png b/website/putString.png new file mode 100644 index 00000000..88ad7878 Binary files /dev/null and b/website/putString.png differ diff --git a/website/record1.png b/website/record1.png new file mode 100644 index 00000000..7a179f97 Binary files /dev/null and b/website/record1.png differ diff --git a/website/record2.png b/website/record2.png new file mode 100644 index 00000000..f35e2916 Binary files /dev/null and b/website/record2.png differ diff --git a/website/record3.png b/website/record3.png new file mode 100644 index 00000000..2d842ad0 Binary files /dev/null and b/website/record3.png differ diff --git a/website/record4.png b/website/record4.png new file mode 100644 index 00000000..790809d5 Binary files /dev/null and b/website/record4.png differ diff --git a/website/sendBroadcast.png b/website/sendBroadcast.png new file mode 100644 index 00000000..55c73ed7 Binary files /dev/null and b/website/sendBroadcast.png differ diff --git a/website/simpleString.png b/website/simpleString.png new file mode 100644 index 00000000..51e58788 Binary files /dev/null and b/website/simpleString.png differ diff --git a/website/startActivity.png b/website/startActivity.png new file mode 100644 index 00000000..5030464e Binary files /dev/null and b/website/startActivity.png differ diff --git a/website/startService.png b/website/startService.png new file mode 100644 index 00000000..4276b51b Binary files /dev/null and b/website/startService.png differ