├── .gitignore ├── README.md ├── imgs └── bg.png ├── lib ├── chimpchat.jar ├── ddmlib.jar ├── guavalib.jar ├── monkeyrunner.jar └── sdklib.jar ├── src └── com │ ├── android │ └── chimpchat │ │ ├── ChimpChat.java │ │ └── ChimpManager.java │ └── lenovo │ ├── Form │ ├── App.form │ ├── App.java │ ├── ControlPage.form │ ├── ControlPage.java │ ├── ImageThread.java │ └── ZxMouseListener.java │ ├── ScreenCapture │ ├── MainWindow.java │ ├── MyChimpChat.java │ └── OperateAndroid.java │ └── test │ ├── ServerThread.java │ ├── SocketClient.java │ ├── SocketTest.java │ ├── TestClient.java │ └── TestServer.java └── weiqunkong.iml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | bin 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 暂停研发说明 2 | >由于工作需要,目前没有时间去研究开发该功能,暂时搁置。 3 | 4 | # weiqunkong 5 | 微群控, 电脑统一控制多台Android设备 6 | 7 | 8 | ## 实现进度 9 | 1. 把用USB连接到电脑上的设备,都展示在应用程序上 10 | 2. 添加打开微信功能,打开QQ, 打开微博,打开摄像头功能 11 | 3. 添加单独在PC端控制Android设备的功能,操作之后可以群控所有手机 12 | 4. 添加设备列表 13 | 5. 选择某一个设备,群控所有连接到电脑的设备 14 | 6. 录制脚本功能 15 | 7. 【TODO】BUG冲突解决(broken pipe , monkey --port 12345 这两个主要BUG) 16 | 17 | ## 注意 18 | >如果设备使用USB连接到电脑后,adb devices 没有显示出设备, 则需要在手机上打开 USB调试功能。 19 | 20 | 21 | ### 比较耗时的操作 22 | ```java 23 | //创建这个对象,比较耗时,大概需要2s,因此默认只刚开始创建改对象,然后保存起来,不一直创建 24 | IChimpDevice chimpDevice = new AdbChimpDevice(dev); 25 | ``` 26 | 27 | ```java 28 | //这个截屏的操作也比较耗时,大概需要 1~3s, 不固定 29 | RawImage rawImage = device.getScreenshot(); 30 | ``` 31 | 32 | 33 | ## 使用说明 34 | 一、下载代码 35 | ```shell 36 | git clone https://github.com/zhongxia245/weiqunkong.git 37 | ``` 38 | 39 | 二、使用IDEA或者 Eclipse 打开【本人使用 IDEA】 40 | 41 | 三、src下的 App.java 和 MainWindow.java 是包含main函数 42 | 43 | ## 说明 44 | MainWindow 可以在 手机屏幕截图上,直接进行操作 45 | App 上可以投射多个设备的屏幕截图,但是目前操作功能,只实现了 HOME,BACK,MENU 三个按键 46 | 47 | 48 | 手机屏幕投射原理: 49 | 根据adb获取手机屏幕的截图,然后替换PC应用上显示的图片,由于获取屏幕截图需要1~3s,因此存在延迟。 需要寻找更好的解决方案。 50 | 可以去调研下 toal control 是如何解决的。 51 | 52 | ## 想要最终实现的效果图 53 | >最终想要实现的效果图大概是这样的。 54 | 55 | 图片来源于 通路云 56 | ![](http://ww2.sinaimg.cn/large/801b780agw1f93s7ar9iaj20tp0fegp1.jpg) 57 | 58 | ## 目前效果图 59 | 2016-10-26 14:42:45 60 | 新增设备列表,单独操作设备的窗口 61 | 62 | 63 | 2016-10-24 14:42:49 64 | ![](http://ww3.sinaimg.cn/large/801b780agw1f93rxty21sg20mn0gt49u.gif) 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /imgs/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongxia245/weiqunkong/fe8a426d7450e6da1fb36a35f40bcfcb7ef9d91f/imgs/bg.png -------------------------------------------------------------------------------- /lib/chimpchat.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongxia245/weiqunkong/fe8a426d7450e6da1fb36a35f40bcfcb7ef9d91f/lib/chimpchat.jar -------------------------------------------------------------------------------- /lib/ddmlib.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongxia245/weiqunkong/fe8a426d7450e6da1fb36a35f40bcfcb7ef9d91f/lib/ddmlib.jar -------------------------------------------------------------------------------- /lib/guavalib.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongxia245/weiqunkong/fe8a426d7450e6da1fb36a35f40bcfcb7ef9d91f/lib/guavalib.jar -------------------------------------------------------------------------------- /lib/monkeyrunner.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongxia245/weiqunkong/fe8a426d7450e6da1fb36a35f40bcfcb7ef9d91f/lib/monkeyrunner.jar -------------------------------------------------------------------------------- /lib/sdklib.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongxia245/weiqunkong/fe8a426d7450e6da1fb36a35f40bcfcb7ef9d91f/lib/sdklib.jar -------------------------------------------------------------------------------- /src/com/android/chimpchat/ChimpChat.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2011 The Android Open Source Project 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.android.chimpchat; 19 | 20 | import com.android.chimpchat.adb.AdbBackend; 21 | import com.android.chimpchat.core.IChimpBackend; 22 | import com.android.chimpchat.core.IChimpDevice; 23 | 24 | import java.util.Map; 25 | import java.util.TreeMap; 26 | 27 | /** 28 | * ChimpChat is a host-side library that provides an API for communication with 29 | * an instance of Monkey on a device. This class provides an entry point to 30 | * setting up communication with a device. Currently it only supports communciation 31 | * over ADB, however. 32 | */ 33 | public class ChimpChat { 34 | private final IChimpBackend mBackend; 35 | private static String sAdbLocation; 36 | 37 | private ChimpChat(IChimpBackend backend) { 38 | this.mBackend = backend; 39 | } 40 | 41 | /** 42 | * Generates a new instance of ChimpChat based on the options passed. 43 | * 44 | * @param options a map of settings for the new ChimpChat instance 45 | * @return a new instance of ChimpChat or null if errors occur during creation 46 | */ 47 | public static ChimpChat getInstance(Map options) { 48 | sAdbLocation = options.get("adbLocation"); 49 | IChimpBackend backend = createBackendByName(options.get("backend")); 50 | if (backend == null) { 51 | return null; 52 | } 53 | ChimpChat chimpchat = new ChimpChat(backend); 54 | return chimpchat; 55 | } 56 | 57 | /** 58 | * Generates a new instance of ChimpChat using default settings 59 | * 60 | * @return a new instance of ChimpChat or null if errors occur during creation 61 | */ 62 | public static ChimpChat getInstance() { 63 | Map options = new TreeMap(); 64 | options.put("backend", "adb"); 65 | return ChimpChat.getInstance(options); 66 | } 67 | 68 | 69 | /** 70 | * Creates a specific backend by name. 71 | * 72 | * @param backendName the name of the backend to create 73 | * @return the new backend, or null if none were found. 74 | */ 75 | 76 | private static IChimpBackend createBackendByName(String backendName) { 77 | if ("adb".equals(backendName)) { 78 | if (sAdbLocation == null) { 79 | return new AdbBackend(); 80 | } else { 81 | return new AdbBackend(sAdbLocation); 82 | } 83 | } else { 84 | return null; 85 | } 86 | } 87 | 88 | /** 89 | * Retrieves an instance of the device from the backend 90 | * 91 | * @param timeoutMs length of time to wait before timing out 92 | * @param deviceId the id of the device you want to connect to 93 | * @return an instance of the device 94 | */ 95 | public IChimpDevice waitForConnection(long timeoutMs, String deviceId) { 96 | return mBackend.waitForConnection(timeoutMs, deviceId); 97 | } 98 | 99 | /** 100 | * Retrieves an instance of the device from the backend. 101 | * Defaults to the longest possible wait time and any available device. 102 | * 103 | * @return an instance of the device 104 | */ 105 | public IChimpDevice waitForConnection() { 106 | return mBackend.waitForConnection(Integer.MAX_VALUE, ".*"); 107 | } 108 | 109 | /** 110 | * Shutdown and clean up chimpchat. 111 | */ 112 | public void shutdown() { 113 | mBackend.shutdown(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/com/android/chimpchat/ChimpManager.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2011 The Android Open Source Project 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.android.chimpchat; 18 | 19 | import com.google.common.collect.Lists; 20 | 21 | import com.android.chimpchat.core.PhysicalButton; 22 | 23 | import java.io.BufferedReader; 24 | import java.io.BufferedWriter; 25 | import java.io.IOException; 26 | import java.io.InputStreamReader; 27 | import java.io.OutputStreamWriter; 28 | import java.net.Socket; 29 | import java.util.Collection; 30 | import java.util.Collections; 31 | import java.util.StringTokenizer; 32 | import java.util.logging.Level; 33 | import java.util.logging.Logger; 34 | 35 | /** 36 | * Provides a nicer interface to interacting with the low-level network access protocol for talking 37 | * to the monkey. 38 | *

39 | * This class is thread-safe and can handle being called from multiple threads. 40 | */ 41 | public class ChimpManager { 42 | private static Logger LOG = Logger.getLogger(ChimpManager.class.getName()); 43 | 44 | private Socket monkeySocket; 45 | private BufferedWriter monkeyWriter; 46 | private BufferedReader monkeyReader; 47 | 48 | /** 49 | * Create a new ChimpMananger to talk to the specified device. 50 | * 51 | * @param monkeySocket the already connected socket on which to send protocol messages. 52 | * @throws IOException if there is an issue setting up the sockets 53 | */ 54 | public ChimpManager(Socket monkeySocket) throws IOException { 55 | this.monkeySocket = monkeySocket; 56 | monkeyWriter = 57 | new BufferedWriter(new OutputStreamWriter(monkeySocket.getOutputStream())); 58 | monkeyReader = new BufferedReader(new InputStreamReader(monkeySocket.getInputStream())); 59 | } 60 | 61 | /** 62 | * Send a touch down event at the specified location. 63 | * 64 | * @param x the x coordinate of where to click 65 | * @param y the y coordinate of where to click 66 | * @return success or not 67 | * @throws IOException on error communicating with the device 68 | */ 69 | public boolean touchDown(int x, int y) throws IOException { 70 | return sendMonkeyEvent("touch down " + x + " " + y); 71 | } 72 | 73 | /** 74 | * Send a touch down event at the specified location. 75 | * 76 | * @param x the x coordinate of where to click 77 | * @param y the y coordinate of where to click 78 | * @return success or not 79 | * @throws IOException on error communicating with the device 80 | */ 81 | public boolean touchUp(int x, int y) throws IOException { 82 | return sendMonkeyEvent("touch up " + x + " " + y); 83 | } 84 | 85 | /** 86 | * Send a touch move event at the specified location. 87 | * 88 | * @param x the x coordinate of where to click 89 | * @param y the y coordinate of where to click 90 | * @return success or not 91 | * @throws IOException on error communicating with the device 92 | */ 93 | public boolean touchMove(int x, int y) throws IOException { 94 | return sendMonkeyEvent("touch move " + x + " " + y); 95 | } 96 | 97 | /** 98 | * Send a touch (down and then up) event at the specified location. 99 | * 100 | * @param x the x coordinate of where to click 101 | * @param y the y coordinate of where to click 102 | * @return success or not 103 | * @throws IOException on error communicating with the device 104 | */ 105 | public boolean touch(int x, int y) throws IOException { 106 | return sendMonkeyEvent("tap " + x + " " + y); 107 | } 108 | 109 | /** 110 | * Press a physical button on the device. 111 | * 112 | * @param name the name of the button (As specified in the protocol) 113 | * @return success or not 114 | * @throws IOException on error communicating with the device 115 | */ 116 | public boolean press(String name) throws IOException { 117 | return sendMonkeyEvent("press " + name); 118 | } 119 | 120 | /** 121 | * Send a Key Down event for the specified button. 122 | * 123 | * @param name the name of the button (As specified in the protocol) 124 | * @return success or not 125 | * @throws IOException on error communicating with the device 126 | */ 127 | public boolean keyDown(String name) throws IOException { 128 | return sendMonkeyEvent("key down " + name); 129 | } 130 | 131 | /** 132 | * Send a Key Up event for the specified button. 133 | * 134 | * @param name the name of the button (As specified in the protocol) 135 | * @return success or not 136 | * @throws IOException on error communicating with the device 137 | */ 138 | public boolean keyUp(String name) throws IOException { 139 | return sendMonkeyEvent("key up " + name); 140 | } 141 | 142 | /** 143 | * Press a physical button on the device. 144 | * 145 | * @param button the button to press 146 | * @return success or not 147 | * @throws IOException on error communicating with the device 148 | */ 149 | public boolean press(PhysicalButton button) throws IOException { 150 | return press(button.getKeyName()); 151 | } 152 | 153 | /** 154 | * This function allows the communication bridge between the host and the device 155 | * to be invisible to the script for internal needs. 156 | * It splits a command into monkey events and waits for responses for each over an adb tcp socket. 157 | * Returns on an error, else continues and sets up last response. 158 | * 159 | * @param command the monkey command to send to the device 160 | * @return the (unparsed) response returned from the monkey. 161 | */ 162 | private String sendMonkeyEventAndGetResponse(String command) throws IOException { 163 | command = command.trim(); 164 | LOG.info("Monkey Command: " + command + "."); 165 | 166 | // send a single command and get the response 167 | monkeyWriter.write(command + "\n"); 168 | monkeyWriter.flush(); 169 | return monkeyReader.readLine(); 170 | } 171 | 172 | /** 173 | * Parse a monkey response string to see if the command succeeded or not. 174 | * 175 | * @param monkeyResponse the response 176 | * @return true if response code indicated success. 177 | */ 178 | private boolean parseResponseForSuccess(String monkeyResponse) { 179 | if (monkeyResponse == null) { 180 | return false; 181 | } 182 | // return on ok 183 | if (monkeyResponse.startsWith("OK")) { 184 | return true; 185 | } 186 | 187 | return false; 188 | } 189 | 190 | /** 191 | * Parse a monkey response string to get the extra data returned. 192 | * 193 | * @param monkeyResponse the response 194 | * @return any extra data that was returned, or empty string if there was nothing. 195 | */ 196 | private String parseResponseForExtra(String monkeyResponse) { 197 | int offset = monkeyResponse.indexOf(':'); 198 | if (offset < 0) { 199 | return ""; 200 | } 201 | return monkeyResponse.substring(offset + 1); 202 | } 203 | 204 | /** 205 | * This function allows the communication bridge between the host and the device 206 | * to be invisible to the script for internal needs. 207 | * It splits a command into monkey events and waits for responses for each over an 208 | * adb tcp socket. 209 | * 210 | * @param command the monkey command to send to the device 211 | * @return true on success. 212 | */ 213 | public boolean sendMonkeyEvent(String command) throws IOException { 214 | synchronized (this) { 215 | String monkeyResponse = sendMonkeyEventAndGetResponse(command); 216 | return parseResponseForSuccess(monkeyResponse); 217 | } 218 | } 219 | 220 | /** 221 | * Close all open resources related to this device. 222 | */ 223 | public void close() { 224 | try { 225 | monkeySocket.close(); 226 | } catch (IOException e) { 227 | LOG.log(Level.SEVERE, "Unable to close monkeySocket", e); 228 | } 229 | try { 230 | monkeyReader.close(); 231 | } catch (IOException e) { 232 | LOG.log(Level.SEVERE, "Unable to close monkeyReader", e); 233 | } 234 | try { 235 | monkeyWriter.close(); 236 | } catch (IOException e) { 237 | LOG.log(Level.SEVERE, "Unable to close monkeyWriter", e); 238 | } 239 | } 240 | 241 | /** 242 | * Function to get a static variable from the device. 243 | * 244 | * @param name name of static variable to get 245 | * @return the value of the variable, or null if there was an error 246 | */ 247 | public String getVariable(String name) throws IOException { 248 | synchronized (this) { 249 | String response = sendMonkeyEventAndGetResponse("getvar " + name); 250 | if (!parseResponseForSuccess(response)) { 251 | return null; 252 | } 253 | return parseResponseForExtra(response); 254 | } 255 | } 256 | 257 | /** 258 | * Function to get the list of static variables from the device. 259 | */ 260 | public Collection listVariable() throws IOException { 261 | synchronized (this) { 262 | String response = sendMonkeyEventAndGetResponse("listvar"); 263 | if (!parseResponseForSuccess(response)) { 264 | Collections.emptyList(); 265 | } 266 | String extras = parseResponseForExtra(response); 267 | return Lists.newArrayList(extras.split(" ")); 268 | } 269 | } 270 | 271 | /** 272 | * Tells the monkey that we are done for this session. 273 | * 274 | * @throws IOException 275 | */ 276 | public void done() throws IOException { 277 | // this command just drops the connection, so handle it here 278 | synchronized (this) { 279 | sendMonkeyEventAndGetResponse("done"); 280 | } 281 | } 282 | 283 | /** 284 | * Tells the monkey that we are done forever. 285 | * 286 | * @throws IOException 287 | */ 288 | public void quit() throws IOException { 289 | // this command drops the connection, so handle it here 290 | synchronized (this) { 291 | sendMonkeyEventAndGetResponse("quit"); 292 | } 293 | } 294 | 295 | /** 296 | * Send a tap event at the specified location. 297 | * 298 | * @param x the x coordinate of where to click 299 | * @param y the y coordinate of where to click 300 | * @return success or not 301 | * @throws IOException 302 | * @throws IOException on error communicating with the device 303 | */ 304 | public boolean tap(int x, int y) throws IOException { 305 | return sendMonkeyEvent("tap " + x + " " + y); 306 | } 307 | 308 | /** 309 | * Type the following string to the monkey. 310 | * 311 | * @param text the string to type 312 | * @return success 313 | * @throws IOException 314 | */ 315 | public boolean type(String text) throws IOException { 316 | // The network protocol can't handle embedded line breaks, so we have to handle it 317 | // here instead 318 | StringTokenizer tok = new StringTokenizer(text, "\n", true); 319 | while (tok.hasMoreTokens()) { 320 | String line = tok.nextToken(); 321 | if ("\n".equals(line)) { 322 | boolean success = press(PhysicalButton.ENTER); 323 | if (!success) { 324 | return false; 325 | } 326 | } else { 327 | boolean success = sendMonkeyEvent("type " + line); 328 | if (!success) { 329 | return false; 330 | } 331 | } 332 | } 333 | return true; 334 | } 335 | 336 | /** 337 | * Type the character to the monkey. 338 | * 339 | * @param keyChar the character to type. 340 | * @return success 341 | * @throws IOException 342 | */ 343 | public boolean type(char keyChar) throws IOException { 344 | return type(Character.toString(keyChar)); 345 | } 346 | 347 | /** 348 | * Wake the device up from sleep. 349 | * 350 | * @throws IOException 351 | */ 352 | public void wake() throws IOException { 353 | sendMonkeyEvent("wake"); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/com/lenovo/Form/App.form: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
104 | -------------------------------------------------------------------------------- /src/com/lenovo/Form/App.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.Form; 2 | 3 | import com.android.ddmlib.AndroidDebugBridge; 4 | import com.android.ddmlib.IDevice; 5 | import com.lenovo.ScreenCapture.OperateAndroid; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.MouseEvent; 9 | import java.awt.event.WindowAdapter; 10 | import java.awt.event.WindowEvent; 11 | import java.io.File; 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Created by zhongxia on 10/24/16. 16 | */ 17 | public class App { 18 | private JPanel pApp; 19 | private JButton btnWX; 20 | private JButton btnConnect; 21 | private JButton btnHome; 22 | private JButton btnBack; 23 | private JButton btnMenu; 24 | private JPanel panelDevices; 25 | private JPanel pTop; 26 | private JScrollPane spMain; 27 | private JButton btnControl; 28 | private JPanel panelTable; 29 | private JButton btnCommand; 30 | private JTextField txtCommand; 31 | 32 | private static IDevice[] devices = null; //所有的设备数组 33 | private static ArrayList oas = null; //保存所有的Android操作对象[创建这个对象挺耗时间,因此只创建一次] 34 | private ControlPage cp = null; 35 | 36 | //设备屏幕截图的宽高 37 | final int imgWidth = 270; 38 | final int imgHeight = 480; 39 | 40 | 41 | public static void main(String[] args) { 42 | JFrame frame = new JFrame("App"); 43 | frame.setContentPane(new App().pApp); 44 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 45 | frame.pack(); 46 | frame.setSize(800, 600); 47 | frame.setVisible(true); 48 | } 49 | 50 | /** 51 | * 构造函数 52 | */ 53 | public App() { 54 | bindEvent(); 55 | devices = getDevices(); 56 | oas = getOperateAndroid(devices); 57 | initList(devices); 58 | } 59 | 60 | /** 61 | * 初始化设备列表 62 | */ 63 | public void initList(IDevice[] devices) { 64 | if (devices != null) { 65 | ArrayList listData = new ArrayList<>(); 66 | for (int i = 0; i < devices.length; i++) { 67 | listData.add(devices[i].getName()); 68 | } 69 | JList list = new JList<>(); 70 | list.setListData(listData.toArray()); 71 | panelTable.add(list); 72 | } 73 | } 74 | 75 | /** 76 | * 绑定事件 77 | */ 78 | public void bindEvent() { 79 | //打开微信 80 | btnCommand.addMouseListener(new ZxMouseListener() { 81 | @Override 82 | public void mousePressed(MouseEvent e) { 83 | String shell = txtCommand.getText(); 84 | for (OperateAndroid oa : oas) { 85 | oa.shell(shell.trim()); 86 | } 87 | } 88 | }); 89 | 90 | //打开微信 91 | btnWX.addMouseListener(new ZxMouseListener() { 92 | @Override 93 | public void mousePressed(MouseEvent e) { 94 | for (OperateAndroid oa : oas) { 95 | oa.openWeiXin(); 96 | } 97 | } 98 | }); 99 | 100 | //群控微信,弹出操作面板 101 | btnControl.addMouseListener(new ZxMouseListener() { 102 | @Override 103 | public void mousePressed(MouseEvent e) { 104 | if (cp == null) { 105 | JFrame frame = new JFrame("操作页面"); 106 | cp = new ControlPage(devices[0], oas.get(0)); 107 | frame.setContentPane(cp.panel1); 108 | frame.setSize(cp.lblImage.getWidth() + 300, cp.lblImage.getHeight() + 20); 109 | frame.setVisible(true); 110 | frame.addWindowListener(new WindowAdapter() { 111 | public void windowClosing(WindowEvent e) { 112 | System.out.println("关闭操作设备的窗口"); 113 | cp.stopThread(); 114 | cp = null; 115 | } 116 | }); 117 | } 118 | } 119 | }); 120 | 121 | //显示屏幕 122 | btnConnect.addMouseListener(new ZxMouseListener() { 123 | @Override 124 | public void mousePressed(MouseEvent e) { 125 | btnConnect.setEnabled(false); 126 | if (devices != null) { 127 | if (devices.length > 0) { 128 | initDevices(devices); 129 | } else { 130 | JOptionPane.showMessageDialog(pApp, "没有检测到设备连接该电脑"); 131 | } 132 | } 133 | } 134 | }); 135 | 136 | //返回首页 137 | btnHome.addMouseListener(new ZxMouseListener() { 138 | @Override 139 | public void mousePressed(MouseEvent e) { 140 | for (OperateAndroid oa : oas) { 141 | oa.press(OperateAndroid.HOME); 142 | } 143 | } 144 | }); 145 | 146 | //返回键 147 | btnBack.addMouseListener(new ZxMouseListener() { 148 | @Override 149 | public void mousePressed(MouseEvent e) { 150 | for (OperateAndroid oa : oas) { 151 | oa.press(OperateAndroid.BACK); 152 | } 153 | } 154 | }); 155 | 156 | //菜单键 157 | btnMenu.addMouseListener(new ZxMouseListener() { 158 | @Override 159 | public void mousePressed(MouseEvent e) { 160 | for (OperateAndroid oa : oas) { 161 | oa.press(OperateAndroid.MENU); 162 | } 163 | } 164 | }); 165 | } 166 | 167 | /** 168 | * 获取设备列表 169 | * 170 | * @return 171 | */ 172 | public IDevice[] getDevices() { 173 | String adbLocation = System.getProperty("com.android.screenshot.bindir"); 174 | 175 | if (adbLocation != null && adbLocation.length() != 0) { 176 | adbLocation += File.separator + "adb"; 177 | } else { 178 | adbLocation = "adb"; 179 | } 180 | 181 | AndroidDebugBridge.init(false); 182 | AndroidDebugBridge bridge = AndroidDebugBridge.createBridge(adbLocation, true); 183 | 184 | int count = 0; 185 | 186 | /** 187 | * 循环100次,每次间隔0.1s, 去获取是否有设备连接到电脑上 188 | */ 189 | while (bridge.hasInitialDeviceList() == false) { 190 | try { 191 | Thread.sleep(100); 192 | count++; 193 | } catch (InterruptedException e) { 194 | 195 | } 196 | 197 | if (count > 100) { 198 | System.err.println("获取设备超时,请检查是否把设备用USB连接到PC上"); 199 | JOptionPane.showMessageDialog(pApp, "获取设备超时,请检查是否把设备用USB连接到PC上"); 200 | break; 201 | } 202 | } 203 | //android机器列表 204 | IDevice[] devices = bridge.getDevices(); 205 | return devices; 206 | } 207 | 208 | /** 209 | * 把设备列表的设备展示到面板上 210 | * 211 | * @param devices 212 | */ 213 | public void initDevices(IDevice[] devices) { 214 | //获取连接的设备列表,然后动态生成到设备列表中 215 | for (IDevice d : devices) { 216 | JLabel label = new JLabel(); 217 | label.setSize(imgWidth, imgHeight); 218 | label.setToolTipText(d.getName()); 219 | 220 | panelDevices.add(label); 221 | initDeviceImage(label, d); 222 | } 223 | } 224 | 225 | /** 226 | * 初始化设备屏幕截图到应用上 227 | * 228 | * @param label 放置屏幕截图的组件 229 | * @param device 设备对象 230 | */ 231 | public void initDeviceImage(JLabel label, IDevice device) { 232 | ImageThread it = new ImageThread(label, device); 233 | if (!it.isAlive()) { 234 | it.start(); 235 | } 236 | } 237 | 238 | /** 239 | * 获取操作Android设备的对象 240 | * 241 | * @param devices 242 | * @return 243 | */ 244 | public ArrayList getOperateAndroid(IDevice[] devices) { 245 | long start = System.currentTimeMillis(); 246 | ArrayList oas = new ArrayList<>(); 247 | for (IDevice d : devices) { 248 | oas.add(new OperateAndroid(d)); 249 | } 250 | long end = System.currentTimeMillis(); 251 | System.out.println("构建OperatorAndroid对象耗时:" + (end - start) + "毫秒"); 252 | return oas; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/com/lenovo/Form/ControlPage.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | -------------------------------------------------------------------------------- /src/com/lenovo/Form/ControlPage.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.Form; 2 | 3 | import com.android.ddmlib.IDevice; 4 | import com.lenovo.ScreenCapture.OperateAndroid; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.event.*; 9 | 10 | /** 11 | * Created by zhongxia on 10/25/16. 12 | */ 13 | public class ControlPage extends JFrame { 14 | public JPanel panel1; 15 | public JLabel lblImage; 16 | private JTextPane tpCommand; 17 | private JButton btnExec; 18 | private IDevice _device = null; 19 | private OperateAndroid oa = null; 20 | private double zoom = 2.5; 21 | private int width = (int) (1080 / zoom); 22 | private int height = (int) (1920 / zoom); 23 | private ImageThread it = null; 24 | private Boolean recordFlag = false; //是否录制脚本 25 | private String command = ""; //命令 26 | 27 | 28 | public ControlPage(IDevice device, OperateAndroid _oa) throws HeadlessException { 29 | _device = device; 30 | oa = _oa; 31 | lblImage.setSize(width, height); 32 | initEvent(); 33 | 34 | it = new ImageThread(lblImage, device, width, height); 35 | 36 | if (!it.isAlive()) { 37 | it.start(); 38 | } 39 | } 40 | 41 | /** 42 | * 停止线程 43 | */ 44 | public void stopThread() { 45 | if (it != null && it.isAlive()) { 46 | it.stop(); 47 | System.out.println("中断操作设备的线程!"); 48 | } 49 | } 50 | 51 | /** 52 | * 初始化操作事件 53 | */ 54 | public void initEvent() { 55 | lblImage.addMouseListener(new ZxMouseListener() { 56 | @Override 57 | public void mouseReleased(MouseEvent e) { 58 | try { 59 | int x = (int) (e.getX() * zoom); 60 | int y = (int) (e.getY() * zoom); 61 | oa.touchUp((int) (e.getX() * zoom), (int) (e.getY() * zoom)); 62 | command += "touch up " + x + " " + y + "\n"; 63 | setCommandText(); 64 | } catch (Exception e1) { 65 | e1.printStackTrace(); 66 | } 67 | } 68 | 69 | @Override 70 | public void mousePressed(MouseEvent e) { 71 | try { 72 | int x = (int) (e.getX() * zoom); 73 | int y = (int) (e.getY() * zoom); 74 | oa.touchDown(x, y); 75 | command += "touch down " + x + " " + y + "\n"; 76 | setCommandText(); 77 | } catch (Exception e1) { 78 | e1.printStackTrace(); 79 | } 80 | } 81 | }); 82 | 83 | lblImage.addMouseMotionListener(new MouseMotionListener() { 84 | 85 | @Override 86 | public void mouseMoved(MouseEvent e) { 87 | } 88 | 89 | @Override 90 | public void mouseDragged(MouseEvent e) { 91 | try { 92 | oa.touchMove((int) (e.getX() * zoom), (int) (e.getY() * zoom)); 93 | System.out.println("move"); 94 | } catch (Exception ex) { 95 | ex.printStackTrace(); 96 | } 97 | } 98 | }); 99 | 100 | lblImage.addMouseWheelListener(new MouseWheelListener() { 101 | 102 | @Override 103 | public void mouseWheelMoved(MouseWheelEvent e) { 104 | if (e.getWheelRotation() == 1) { 105 | oa.press("KEYCODE_DPAD_DOWN"); 106 | command += "press KEYCODE_DPAD_DOWN \n"; 107 | } else if (e.getWheelRotation() == -1) { 108 | oa.press("KEYCODE_DPAD_UP"); 109 | command += "press KEYCODE_DPAD_UP \n"; 110 | } 111 | } 112 | }); 113 | 114 | this.addKeyListener(new KeyListener() { 115 | @Override 116 | public void keyTyped(KeyEvent e) { 117 | } 118 | 119 | @Override 120 | public void keyReleased(KeyEvent e) { 121 | } 122 | 123 | @Override 124 | public void keyPressed(KeyEvent e) { 125 | int code = e.getKeyCode(); 126 | switch (code) { 127 | case KeyEvent.VK_BACK_SPACE: 128 | oa.press("KEYCODE_DEL"); 129 | break; 130 | case KeyEvent.VK_SPACE: 131 | oa.press("KEYCODE_SPACE"); 132 | break; 133 | case KeyEvent.VK_DELETE: 134 | oa.press("KEYCODE_FORWARD_DEL"); 135 | break; 136 | case KeyEvent.VK_UP: 137 | oa.press("KEYCODE_DPAD_UP"); 138 | break; 139 | case KeyEvent.VK_DOWN: 140 | oa.press("KEYCODE_DPAD_DOWN"); 141 | break; 142 | case KeyEvent.VK_LEFT: 143 | oa.press("KEYCODE_DPAD_LEFT"); 144 | break; 145 | case KeyEvent.VK_RIGHT: 146 | oa.press("KEYCODE_DPAD_RIGHT"); 147 | break; 148 | case KeyEvent.VK_ENTER: 149 | oa.press("KEYCODE_ENTER"); 150 | break; 151 | case KeyEvent.VK_CONTROL: 152 | break; 153 | case KeyEvent.VK_ALT: 154 | break; 155 | case KeyEvent.VK_SHIFT: 156 | break; 157 | default: 158 | oa.type(e.getKeyChar()); 159 | } 160 | 161 | } 162 | }); 163 | 164 | /** 165 | * 执行录制的操作 166 | * */ 167 | btnExec.addMouseListener(new ZxMouseListener() { 168 | @Override 169 | public void mousePressed(MouseEvent e) { 170 | String[] commands = command.split("\n"); 171 | for (int i = 0; i < commands.length; i++) { 172 | try { 173 | oa.shell(commands[i]); 174 | /** 175 | * touch down 和 touch up 两个步骤和在一起,才是一个完整的操作 176 | * 每一个操作之间间隔2s 177 | */ 178 | if (commands[i].contains("touch up")) { 179 | Thread.sleep(2000); 180 | } 181 | 182 | } catch (InterruptedException ev) { 183 | 184 | } 185 | } 186 | } 187 | }); 188 | } 189 | 190 | /** 191 | * 设置文本域显示命令 192 | */ 193 | public void setCommandText() { 194 | tpCommand.setText(command); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/com/lenovo/Form/ImageThread.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.Form; 2 | 3 | import com.android.ddmlib.IDevice; 4 | import com.android.ddmlib.RawImage; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.image.BufferedImage; 9 | 10 | /** 11 | * Created by zhongxia on 10/24/16. 12 | */ 13 | public class ImageThread extends Thread { 14 | private JLabel _label = null; 15 | private IDevice _device = null; 16 | private int _width = 270; 17 | private int _height = 480; 18 | 19 | /** 20 | * 构造函数 21 | * 22 | * @param label 标签组件 23 | * @param device 设备对象 24 | */ 25 | public ImageThread(JLabel label, IDevice device) { 26 | _label = label; 27 | _device = device; 28 | } 29 | 30 | /** 31 | * 构造函数 32 | * 33 | * @param label 标签组件 34 | * @param device 设备对象 35 | * @param width 宽 36 | * @param height 高 37 | */ 38 | public ImageThread(JLabel label, IDevice device, int width, int height) { 39 | _label = label; 40 | _device = device; 41 | _width = width; 42 | _height = height; 43 | } 44 | 45 | 46 | @Override 47 | public void run() { 48 | super.run(); 49 | ImageIcon image = null; 50 | try { 51 | while (true) { 52 | image = new ImageIcon("no.gif"); 53 | image.setImage(getImageIcon(_device).getImage().getScaledInstance(_width, _height, Image.SCALE_SMOOTH)); 54 | _label.setIcon(image); 55 | } 56 | } catch (Exception e) { 57 | System.out.println("中断线程"); 58 | } 59 | 60 | } 61 | 62 | /** 63 | * 获取屏幕截图 64 | * 65 | * @param device 设备 66 | * @return 67 | */ 68 | public static ImageIcon getImageIcon(IDevice device) { 69 | try { 70 | long start = System.currentTimeMillis(); 71 | 72 | RawImage rawImage = device.getScreenshot(); 73 | 74 | long end = System.currentTimeMillis(); 75 | 76 | // System.out.println("获取设备屏幕的时间:" + device.getName() + "=>" + (end - start) + "毫秒"); 77 | 78 | BufferedImage image = new BufferedImage(rawImage.width, rawImage.height, BufferedImage.SCALE_SMOOTH); 79 | 80 | int index = 0; 81 | int IndexInc = rawImage.bpp >> 3; 82 | for (int y = 0; y < rawImage.height; y++) { 83 | for (int x = 0; x < rawImage.width; x++) { 84 | int value = rawImage.getARGB(index); 85 | index += IndexInc; 86 | image.setRGB(x, y, value); 87 | } 88 | } 89 | return new ImageIcon(image); 90 | 91 | } catch (Exception e) { 92 | System.out.println("获取屏幕截图异常!设备名称:" + device.getName() + ",可能情况,中断了线程!"); 93 | } 94 | return null; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/com/lenovo/Form/ZxMouseListener.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.Form; 2 | 3 | import java.awt.event.MouseEvent; 4 | import java.awt.event.MouseListener; 5 | 6 | /** 7 | * Created by zhongxia on 10/24/16. 8 | */ 9 | public class ZxMouseListener implements MouseListener { 10 | 11 | @Override 12 | public void mouseClicked(MouseEvent e) { 13 | 14 | } 15 | 16 | @Override 17 | public void mousePressed(MouseEvent e) { 18 | 19 | } 20 | 21 | @Override 22 | public void mouseReleased(MouseEvent e) { 23 | 24 | } 25 | 26 | @Override 27 | public void mouseEntered(MouseEvent e) { 28 | 29 | } 30 | 31 | @Override 32 | public void mouseExited(MouseEvent e) { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/com/lenovo/ScreenCapture/MainWindow.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.ScreenCapture; 2 | 3 | import java.awt.Image; 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.ActionListener; 6 | import java.awt.event.KeyEvent; 7 | import java.awt.event.KeyListener; 8 | import java.awt.event.MouseEvent; 9 | import java.awt.event.MouseListener; 10 | import java.awt.event.MouseMotionListener; 11 | import java.awt.event.MouseWheelEvent; 12 | import java.awt.event.MouseWheelListener; 13 | import java.awt.image.BufferedImage; 14 | import java.io.File; 15 | 16 | import javax.swing.ImageIcon; 17 | import javax.swing.JFrame; 18 | import javax.swing.JLabel; 19 | import javax.swing.JMenu; 20 | import javax.swing.JMenuBar; 21 | import javax.swing.JMenuItem; 22 | import javax.swing.SwingConstants; 23 | 24 | import com.android.ddmlib.AndroidDebugBridge; 25 | import com.android.ddmlib.IDevice; 26 | import com.android.ddmlib.RawImage; 27 | 28 | /** 29 | * 主页面,手机屏幕实时投射到PC端,PC端通过adb控制手机【反向控制】 30 | */ 31 | @SuppressWarnings("serial") 32 | public class MainWindow extends JFrame { 33 | 34 | public static void main(String[] args) { 35 | new MainWindow(); 36 | } 37 | 38 | /** 39 | * PC端应用页面 40 | */ 41 | public MainWindow() { 42 | super(); 43 | initWindow(); 44 | 45 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 46 | setSize(200, 200); 47 | 48 | setVisible(true); 49 | setResizable(true); 50 | } 51 | 52 | JLabel label; //用来放置屏幕截图的组件 53 | public static String targetNum = null; 54 | public static IDevice device = null; 55 | public Thread th = null; 56 | public OperateAndroid oa = null; 57 | public int width, height; 58 | public double zoom = 1; 59 | 60 | 61 | /** 62 | * 初始化窗口 63 | * 根据ADB获取链接到设备上的设备列表,展示在设备列表的菜单下 64 | */ 65 | public void initWindow() { 66 | // final MyChimpChat mych = new MyChimpChat(); 67 | 68 | label = new JLabel(); 69 | add(label); 70 | label.setHorizontalAlignment(SwingConstants.CENTER); 71 | 72 | String adbLocation = System.getProperty("com.android.screenshot.bindir"); 73 | 74 | if (adbLocation != null && adbLocation.length() != 0) { 75 | adbLocation += File.separator + "adb"; 76 | } else { 77 | adbLocation = "adb"; 78 | } 79 | 80 | AndroidDebugBridge.init(false); 81 | AndroidDebugBridge bridge = AndroidDebugBridge.createBridge(adbLocation, true); 82 | int count = 0; 83 | 84 | System.out.println("是否存在设备:" + bridge.hasInitialDeviceList()); 85 | 86 | /** 87 | * 循环100次,每次间隔0.1s, 去获取是否有设备连接到电脑上 88 | */ 89 | while (bridge.hasInitialDeviceList() == false) { 90 | try { 91 | Thread.sleep(100); 92 | count++; 93 | } catch (InterruptedException e) { 94 | } 95 | 96 | if (count > 100) { 97 | System.err.println("获取设备超时,请检查是否把设备用USB连接到PC上"); 98 | return; 99 | } 100 | } 101 | 102 | //android机器列表 103 | final IDevice[] devices = bridge.getDevices(); 104 | 105 | JMenu fileMenu = new JMenu("设备列表"); 106 | JMenu functionMenu = new JMenu("功能键"); 107 | JMenu functionZoom = new JMenu("缩放"); 108 | 109 | JMenuItem ItemHome = new JMenuItem("HOME"); 110 | JMenuItem ItemBack = new JMenuItem("BACK"); 111 | JMenuItem ItemMenu = new JMenuItem("MENU"); 112 | //JMenuItem ItemPower = new JMenuItem("POWER"); 113 | 114 | functionMenu.add(ItemHome); 115 | functionMenu.add(ItemBack); 116 | functionMenu.add(ItemMenu); 117 | //functionMenu.add(ItemPower); 118 | 119 | JMenuItem Item100 = new JMenuItem("100%"); 120 | JMenuItem Item80 = new JMenuItem("80%"); 121 | JMenuItem Item50 = new JMenuItem("50%"); 122 | 123 | functionZoom.add(Item100); 124 | functionZoom.add(Item80); 125 | functionZoom.add(Item50); 126 | 127 | JMenuBar menuBar = new JMenuBar(); 128 | menuBar.add(fileMenu); 129 | menuBar.add(functionMenu); 130 | menuBar.add(functionZoom); 131 | 132 | JMenuItem newMenuItem = null; 133 | 134 | //获取连接的设备列表,然后动态生成到设备列表中 135 | for (IDevice d : devices) { 136 | newMenuItem = new JMenuItem(d.getName()); 137 | newMenuItem.addActionListener(new ActionListener() { 138 | 139 | @Override 140 | public void actionPerformed(ActionEvent arg0) { 141 | System.out.println(arg0.getActionCommand()); 142 | 143 | targetNum = arg0.getActionCommand(); 144 | targetNum = targetNum.substring(targetNum.lastIndexOf("-") + 1); 145 | 146 | for (IDevice d : devices) { 147 | if (d.getSerialNumber().equals(targetNum)) { 148 | 149 | device = d; 150 | oa = new OperateAndroid(device); 151 | 152 | //System.out.printf("width:%d,height:%d", oa.getScreenWidth(), oa.getScreenHeight()); 153 | // oa = OperateAndroid.getOperateAndroid(device); 154 | initResolution(); 155 | 156 | setSize(width, (height + 60)); 157 | 158 | if (!th.isAlive()) { 159 | th.start(); 160 | } 161 | } 162 | } 163 | } 164 | }); 165 | fileMenu.add(newMenuItem); 166 | } 167 | 168 | if (devices.length < 1) { 169 | fileMenu.setText("没有设备"); 170 | fileMenu.setEnabled(false); 171 | functionMenu.setEnabled(false); 172 | } 173 | 174 | ItemHome.addActionListener(new ActionListener() { 175 | 176 | @Override 177 | public void actionPerformed(ActionEvent arg0) { 178 | oa.press(OperateAndroid.HOME); 179 | } 180 | }); 181 | ItemBack.addActionListener(new ActionListener() { 182 | 183 | @Override 184 | public void actionPerformed(ActionEvent arg0) { 185 | oa.press(OperateAndroid.BACK); 186 | } 187 | }); 188 | ItemMenu.addActionListener(new ActionListener() { 189 | 190 | @Override 191 | public void actionPerformed(ActionEvent arg0) { 192 | oa.press(OperateAndroid.MENU); 193 | } 194 | }); 195 | 196 | // ItemPower.addActionListener(new ActionListener() { 197 | // 198 | // @Override 199 | // public void actionPerformed(ActionEvent arg0) { 200 | // oa.press(OperateAndroid.POWER); 201 | // } 202 | // }); 203 | 204 | Item100.addActionListener(new ActionListener() { 205 | 206 | @Override 207 | public void actionPerformed(ActionEvent arg0) { 208 | zoom = 1; 209 | initResolution(); 210 | width = (int) (width * zoom); 211 | height = (int) (height * zoom); 212 | setSize(width, height + 60); 213 | } 214 | }); 215 | 216 | Item80.addActionListener(new ActionListener() { 217 | 218 | @Override 219 | public void actionPerformed(ActionEvent arg0) { 220 | zoom = 0.8; 221 | initResolution(); 222 | width = (int) (width * zoom); 223 | height = (int) (height * zoom); 224 | setSize(width, height + 60); 225 | } 226 | }); 227 | Item50.addActionListener(new ActionListener() { 228 | 229 | @Override 230 | public void actionPerformed(ActionEvent arg0) { 231 | zoom = 0.5; 232 | initResolution(); 233 | width = (int) (width * zoom); 234 | height = (int) (height * zoom); 235 | setSize(width, height + 60); 236 | } 237 | }); 238 | 239 | setJMenuBar(menuBar); 240 | 241 | th = new Thread(new Runnable() { 242 | 243 | @Override 244 | public void run() { 245 | ImageIcon image = null; 246 | while (true) { 247 | 248 | image = new ImageIcon("no.gif"); 249 | 250 | image.setImage(getImageIcon(targetNum).getImage() 251 | .getScaledInstance(width, height, Image.SCALE_DEFAULT)); 252 | 253 | label.setIcon(image); 254 | } 255 | } 256 | }); 257 | 258 | label.addMouseListener(new MouseListener() { 259 | 260 | @Override 261 | public void mouseReleased(MouseEvent e) { 262 | try { 263 | oa.touchUp((int) (e.getX() / zoom), (int) (e.getY() / zoom)); 264 | System.out.printf("mouseReleased,x=%d,y=%d", e.getX(), e.getY()); 265 | } catch (Exception e1) { 266 | e1.printStackTrace(); 267 | } 268 | } 269 | 270 | @Override 271 | public void mousePressed(MouseEvent e) { 272 | try { 273 | oa.touchDown((int) (e.getX() / zoom), (int) (e.getY() / zoom)); 274 | System.out.printf("mousePressed,x=%d,y=%d", e.getX(), e.getY()); 275 | } catch (Exception e1) { 276 | e1.printStackTrace(); 277 | } 278 | } 279 | 280 | @Override 281 | public void mouseExited(MouseEvent e) { 282 | } 283 | 284 | @Override 285 | public void mouseEntered(MouseEvent e) { 286 | } 287 | 288 | @Override 289 | public void mouseClicked(MouseEvent e) { 290 | } 291 | }); 292 | 293 | label.addMouseMotionListener(new MouseMotionListener() { 294 | 295 | @Override 296 | public void mouseMoved(MouseEvent e) { 297 | } 298 | 299 | @Override 300 | public void mouseDragged(MouseEvent e) { 301 | try { 302 | oa.touchMove((int) (e.getX() / zoom), 303 | (int) (e.getY() / zoom)); 304 | } catch (Exception ex) { 305 | ex.printStackTrace(); 306 | } 307 | } 308 | }); 309 | 310 | label.addMouseWheelListener(new MouseWheelListener() { 311 | 312 | @Override 313 | public void mouseWheelMoved(MouseWheelEvent e) { 314 | if (e.getWheelRotation() == 1) { 315 | oa.press("KEYCODE_DPAD_DOWN"); 316 | } else if (e.getWheelRotation() == -1) { 317 | oa.press("KEYCODE_DPAD_UP"); 318 | } 319 | } 320 | }); 321 | 322 | this.addKeyListener(new KeyListener() { 323 | 324 | @Override 325 | public void keyTyped(KeyEvent e) { 326 | 327 | } 328 | 329 | @Override 330 | public void keyReleased(KeyEvent e) { 331 | } 332 | 333 | @Override 334 | public void keyPressed(KeyEvent e) { 335 | int code = e.getKeyCode(); 336 | switch (code) { 337 | 338 | case KeyEvent.VK_BACK_SPACE: 339 | oa.press("KEYCODE_DEL"); 340 | break; 341 | case KeyEvent.VK_SPACE: 342 | oa.press("KEYCODE_SPACE"); 343 | break; 344 | case KeyEvent.VK_DELETE: 345 | oa.press("KEYCODE_FORWARD_DEL"); 346 | break; 347 | case KeyEvent.VK_UP: 348 | oa.press("KEYCODE_DPAD_UP"); 349 | break; 350 | case KeyEvent.VK_DOWN: 351 | oa.press("KEYCODE_DPAD_DOWN"); 352 | break; 353 | case KeyEvent.VK_LEFT: 354 | oa.press("KEYCODE_DPAD_LEFT"); 355 | break; 356 | case KeyEvent.VK_RIGHT: 357 | oa.press("KEYCODE_DPAD_RIGHT"); 358 | break; 359 | case KeyEvent.VK_ENTER: 360 | oa.press("KEYCODE_ENTER"); 361 | break; 362 | case KeyEvent.VK_CONTROL: 363 | break; 364 | case KeyEvent.VK_ALT: 365 | break; 366 | case KeyEvent.VK_SHIFT: 367 | break; 368 | default: 369 | oa.type(e.getKeyChar()); 370 | } 371 | 372 | } 373 | }); 374 | } 375 | 376 | /** 377 | * PC端展示设备屏幕截图的容器大小 378 | */ 379 | public void initResolution() { 380 | width = 480; // oa.getScreenWidth(); 381 | height = 800; // oa.getScreenHeight(); 382 | //width = oa.getScreenWidth() / scale; 383 | //height = oa.getScreenHeight() / scale; 384 | } 385 | 386 | /** 387 | * 获取屏幕截图 388 | * 389 | * @param targetNum 当前设备所在下标 390 | * @return 391 | */ 392 | public ImageIcon getImageIcon(String targetNum) { 393 | try { 394 | long start = System.currentTimeMillis(); 395 | RawImage rawImage = device.getScreenshot(); 396 | long end = System.currentTimeMillis(); 397 | System.out.println("获取设备屏幕的时间" + (end - start) + "毫秒"); 398 | 399 | BufferedImage image = new BufferedImage(rawImage.width, rawImage.height, BufferedImage.TYPE_INT_RGB); 400 | 401 | int index = 0; 402 | int IndexInc = rawImage.bpp >> 3; 403 | for (int y = 0; y < rawImage.height; y++) { 404 | for (int x = 0; x < rawImage.width; x++) { 405 | int value = rawImage.getARGB(index); 406 | index += IndexInc; 407 | image.setRGB(x, y, value); 408 | } 409 | } 410 | return new ImageIcon(image); 411 | 412 | } catch (Exception e) { 413 | e.printStackTrace(); 414 | } 415 | return null; 416 | } 417 | 418 | } 419 | -------------------------------------------------------------------------------- /src/com/lenovo/ScreenCapture/MyChimpChat.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.ScreenCapture; 2 | 3 | import java.net.Socket; 4 | 5 | public class MyChimpChat { 6 | 7 | public Socket socket; 8 | 9 | public MyChimpChat() { 10 | 11 | Thread th = new Thread(new Runnable() { 12 | 13 | @Override 14 | public void run() { 15 | try { 16 | Runtime.getRuntime() 17 | .exec("adb forward tcp:12345 tcp:12345"); 18 | Runtime.getRuntime().exec("adb shell monkey --port 12345"); 19 | } catch (Exception e) { 20 | e.printStackTrace(); 21 | } 22 | 23 | } 24 | }); 25 | th.start(); 26 | 27 | try { 28 | Thread.sleep(1000); 29 | socket = new Socket("127.0.0.1", 12345); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | public void touchDown(int x, int y) { 36 | try { 37 | socket.getOutputStream().write( 38 | new String("touch down " + x + " " + y + "\n").getBytes()); 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | public void touchUp(int x, int y) { 45 | try { 46 | socket.getOutputStream().write( 47 | new String("touch up " + x + " " + y + "\n").getBytes()); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | 53 | public void Press() { 54 | try { 55 | socket.getOutputStream().write( 56 | new String("press KEYCODE_HOME\n").getBytes()); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | } 61 | 62 | public void touchMove(int x, int y) { 63 | try { 64 | socket.getOutputStream().write( 65 | new String("touch move " + x + " " + y + "\n").getBytes()); 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/com/lenovo/ScreenCapture/OperateAndroid.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.ScreenCapture; 2 | 3 | import com.android.chimpchat.ChimpManager; 4 | import com.android.chimpchat.adb.AdbChimpDevice; 5 | import com.android.chimpchat.core.IChimpDevice; 6 | import com.android.chimpchat.core.TouchPressType; 7 | import com.android.ddmlib.IDevice; 8 | 9 | import java.io.IOException; 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.HashMap; 13 | 14 | /** 15 | * 操作Android手机的方法封装 16 | * 1、提供 HOME,BACK,MENU,POWER 四个按键的功能 17 | * 2、提供 点击事件,滑动事件 18 | */ 19 | public class OperateAndroid { 20 | private AdbChimpDevice device; //adb移动设备 21 | private ChimpManager manager; //移动设备管理对象 22 | private static OperateAndroid oa; //操作移动设备的类 23 | 24 | public static String HOME = "KEYCODE_HOME"; 25 | public static String BACK = "KEYCODE_BACK"; 26 | public static String MENU = "KEYCODE_MENU"; 27 | public static String POWER = "KEYCODE_POWER"; 28 | 29 | /** 30 | * 初始化操作类 31 | * 32 | * @param dev 通过adb返回的device对象 33 | */ 34 | public OperateAndroid(IDevice dev) { 35 | long start = System.currentTimeMillis(); 36 | if (device == null) { 37 | IChimpDevice chimpDevice = new AdbChimpDevice(dev); 38 | device = (AdbChimpDevice) chimpDevice; 39 | manager = device.getManager(); 40 | } 41 | long end = System.currentTimeMillis(); 42 | } 43 | 44 | /** 45 | * 获取OA对象 46 | * 如果已经存在,则支持返回,不存在则生成 47 | * 48 | * @param dev 49 | * @return 50 | */ 51 | public static OperateAndroid getOperateAndroid(IDevice dev) { 52 | if (oa == null) { 53 | oa = new OperateAndroid(dev); 54 | } 55 | return oa; 56 | } 57 | 58 | /** 59 | * 执行命令 60 | * 61 | * @param str 62 | */ 63 | public void shell(String str) { 64 | try { 65 | manager.sendMonkeyEvent(str); 66 | } catch (IOException e) { 67 | System.out.println("执行命令:" + str + " ,异常!"); 68 | } 69 | 70 | } 71 | 72 | /** 73 | * Android touch 事件 74 | * 75 | * @param x 坐标 76 | * @param y 坐标 77 | */ 78 | public void touch(int x, int y) { 79 | device.touch(x, y, com.android.chimpchat.core.TouchPressType.DOWN_AND_UP); 80 | } 81 | 82 | /** 83 | * Android touch 事件 84 | * 85 | * @param x 坐标 86 | * @param y 坐标 87 | * @param type touch 类型 88 | */ 89 | public void touch(int x, int y, TouchPressType type) { 90 | device.touch(x, y, type); 91 | } 92 | 93 | /** 94 | * press 触摸事件 95 | * 96 | * @param str 97 | */ 98 | public void press(String str) { 99 | device.press(str, com.android.chimpchat.core.TouchPressType.DOWN_AND_UP); 100 | } 101 | 102 | /** 103 | * press 触摸按下事件 104 | * 105 | * @param str 106 | */ 107 | public void press_DOWN(String str) { 108 | device.press(str, com.android.chimpchat.core.TouchPressType.DOWN); 109 | } 110 | 111 | /** 112 | * press 触摸放开事件 113 | * 114 | * @param str 115 | */ 116 | public void press_UP(String str) { 117 | device.press(str, com.android.chimpchat.core.TouchPressType.UP); 118 | } 119 | 120 | /** 121 | * 移动 事件 122 | * 123 | * @param startX 开始位置X 124 | * @param startY 开始位置Y 125 | * @param endX 结束位置X 126 | * @param endY 结束位置Y 127 | * @param time 时间 128 | * @param step 步骤 129 | */ 130 | public void drag(int startX, int startY, int endX, int endY, int time, int step) { 131 | device.drag(startX, startY, endX, endY, time, step); 132 | } 133 | 134 | /** 135 | * 输入字符 136 | * 137 | * @param c 字符 138 | */ 139 | public void type(char c) { 140 | device.type(Character.toString(c)); 141 | } 142 | 143 | /** 144 | * touch按下 145 | * 146 | * @param x 坐标 147 | * @param y 坐标 148 | * @throws Exception 149 | */ 150 | public void touchDown(int x, int y) throws Exception { 151 | manager.touchDown(x, y); 152 | } 153 | 154 | /** 155 | * touch 放开 156 | * 157 | * @param x 坐标 158 | * @param y 坐标 159 | * @throws Exception 160 | */ 161 | public void touchUp(int x, int y) throws Exception { 162 | manager.touchUp(x, y); 163 | } 164 | 165 | /** 166 | * touch 移动 167 | * 168 | * @param x 坐标 169 | * @param y 坐标 170 | * @throws Exception 171 | */ 172 | public void touchMove(int x, int y) throws Exception { 173 | manager.touchMove(x, y); 174 | } 175 | 176 | /** 177 | * 获取屏幕宽度 178 | * 179 | * @return 180 | */ 181 | public int getScreenWidth() { 182 | return Integer.parseInt(device.getProperty("display.width")); 183 | } 184 | 185 | /** 186 | * 获取屏幕高度 187 | * 188 | * @return 189 | */ 190 | public int getScreenHeight() { 191 | return Integer.parseInt(device.getProperty("display.height")); 192 | } 193 | 194 | /** 195 | * 安装软件 196 | * 197 | * @param path 198 | */ 199 | public void installPackage(String path) { 200 | device.installPackage(path); 201 | } 202 | 203 | /** 204 | * 打开应用 205 | * 206 | * @param activityPath apk包名/主界面 eg: cn.com.fetion/.android.ui.activities.StartActivity 207 | */ 208 | public void startActivity(String activityPath) { 209 | String action = "android.intent.action.MAIN"; 210 | Collection categories = new ArrayList(); 211 | categories.add("android.intent.category.LAUNCHER"); 212 | try { 213 | device.startActivity(null, action, null, null, categories, new HashMap(), activityPath, 0); 214 | } catch (Exception e) { 215 | e.printStackTrace(); 216 | } 217 | } 218 | 219 | /** 220 | * 打开微信 221 | */ 222 | public void openWeiXin() { 223 | startActivity("com.tencent.mm/com.tencent.mm.ui.LauncherUI"); 224 | } 225 | 226 | /** 227 | * 打开QQ 228 | */ 229 | public void openQQ() { 230 | startActivity("com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity"); 231 | } 232 | 233 | /** 234 | * 打开摄像头 235 | */ 236 | public void openCamera() { 237 | startActivity("com.android.camera/com.android.camera.Camera"); 238 | } 239 | 240 | /** 241 | * 打开微博 242 | */ 243 | public void openWeiBo() { 244 | startActivity("com.sina.weibo/com.sina.weibo.SplashActivity"); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /src/com/lenovo/test/ServerThread.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.test; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStream; 5 | import java.io.InputStreamReader; 6 | import java.io.OutputStream; 7 | import java.io.PrintStream; 8 | import java.net.Socket; 9 | 10 | public class ServerThread extends Thread { 11 | private Socket so; 12 | 13 | public ServerThread(Socket so) { 14 | this.so = so; 15 | } 16 | 17 | public void run() { 18 | try { 19 | InputStream is = so.getInputStream(); 20 | OutputStream os = so.getOutputStream(); 21 | BufferedReader br = new BufferedReader(new InputStreamReader(is)); 22 | PrintStream ps = new PrintStream(os); 23 | while (true) { 24 | String temp = br.readLine();// �ͻ�Ҫ��println 25 | ps.println("from server:" + temp);// ������ 26 | 27 | // if (temp.equals("bye")) { 28 | // break; 29 | // } 30 | } 31 | // ps.close(); 32 | // br.close(); 33 | // so.close(); 34 | } catch (Exception rr) { 35 | rr.printStackTrace(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/com/lenovo/test/SocketClient.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.test; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.net.InetSocketAddress; 7 | import java.net.Socket; 8 | 9 | public class SocketClient { 10 | 11 | public static void main(String[] args) { 12 | Socket socket = new Socket(); 13 | InetSocketAddress inetSocketAddress = new InetSocketAddress( 14 | "127.0.0.1", 12345); 15 | try { 16 | Runtime.getRuntime().exec("adb forward tcp:12345 tcp:12345"); 17 | socket.connect(inetSocketAddress, 3000); 18 | 19 | OutputStream outputStream = socket.getOutputStream(); 20 | outputStream.write("$1".getBytes()); 21 | 22 | InputStream inputStream = socket.getInputStream(); 23 | byte[] b = new byte[10]; 24 | int read = inputStream.read(b); 25 | if (read > 0) { 26 | System.out.println(new String(b)); 27 | } 28 | socket.close(); 29 | } catch (IOException e) { 30 | e.printStackTrace(); 31 | } 32 | System.exit(0); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/lenovo/test/SocketTest.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.test; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.net.ServerSocket; 6 | import java.net.Socket; 7 | import java.net.UnknownHostException; 8 | 9 | public class SocketTest { 10 | 11 | public static void main(String[] args) throws UnknownHostException, 12 | IOException { 13 | ServerSocket ss = new ServerSocket(6666); 14 | while (true) { 15 | Socket accept = ss.accept(); 16 | InputStream inputStream = accept.getInputStream(); 17 | byte[] b = new byte[2]; 18 | inputStream.read(b); 19 | 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/com/lenovo/test/TestClient.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongxia245/weiqunkong/fe8a426d7450e6da1fb36a35f40bcfcb7ef9d91f/src/com/lenovo/test/TestClient.java -------------------------------------------------------------------------------- /src/com/lenovo/test/TestServer.java: -------------------------------------------------------------------------------- 1 | package com.lenovo.test; 2 | 3 | import java.net.ServerSocket; 4 | import java.net.Socket; 5 | import java.io.*; 6 | 7 | public class TestServer extends Thread { 8 | private ServerSocket ss = null; 9 | 10 | public TestServer() { 11 | try { 12 | ss = new ServerSocket(7456); 13 | } catch (IOException e) { 14 | e.printStackTrace(); 15 | } 16 | } 17 | 18 | public void run() { 19 | while (true) { 20 | try { 21 | Socket so = ss.accept(); 22 | ServerThread st = new ServerThread(so); 23 | st.start(); 24 | } catch (IOException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | } 29 | 30 | public static void main(String[] args) { 31 | new TestServer().start(); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /weiqunkong.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | --------------------------------------------------------------------------------