├── .bowerrc ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── change_version.py ├── karma.conf.js ├── package.json ├── src ├── assets │ ├── BrickLogo2011.png │ ├── ChromeADBLogo.png │ ├── chromeadb_screenshot.png │ ├── github.png │ ├── icon_016.png │ ├── icon_032.png │ ├── icon_048.png │ ├── icon_128.png │ ├── icon_256.png │ └── icon_512.png ├── index.html ├── manifest.json ├── scripts │ ├── background.js │ ├── chrome.js │ ├── chromeadb.js │ ├── controllers.js │ ├── parser.js │ ├── services.js │ └── utils.js ├── styles │ └── chromeadb.css └── views │ ├── controller.html │ ├── diskspace.html │ ├── meminfo.html │ ├── packages.html │ └── processes.html └── test └── parserSpec.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/bower_components/ 2 | dist/ 3 | node_modules/ 4 | package/ 5 | .idea/ 6 | *.iml 7 | .*.swp 8 | .swp 9 | .DS_Store 10 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "$": true, 23 | "$routeProvider": true, 24 | "$locationProvider": true, 25 | "parseInt": true, 26 | "parseProcessList": true, 27 | "parseDeviceInfoList": true, 28 | "parsePackageList": true, 29 | "makeCommand": true, 30 | "parseMemInfo": true, 31 | "parsePackageMemInfo": true, 32 | "parseDiskSpace": true, 33 | "parseResolution": true, 34 | "arrayBufferToString": true, 35 | "arrayBufferToBinaryString": true, 36 | "stringToArrayBuffer": true, 37 | "newZeroArray": true, 38 | "getChartId": true, 39 | "integerToArrayBuffer": true, 40 | "angular": true, 41 | "it": true, 42 | "expect": true, 43 | "describe": true, 44 | "beforeEach": true, 45 | "afterEach": true, 46 | "chrome": true 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | before_install: 5 | - "npm install -g grunt-cli" 6 | - "npm install -g bower" 7 | - "bower install" 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | # v 0.4.2 5 | - Improved mousepad 6 | - replaced apk install link to button that sends intent to a device 7 | - added retry input command when failed to tab or swipe 8 | 9 | # v 0.4.0 10 | - Mousepad in Controller 11 | - Support: Tab, Swipe (depends on your device) 12 | 13 | # v 0.3.0 14 | - Install an apk file 15 | - Update app icon 16 | 17 | # v 0.2.0 18 | - Add real-time graph for a process 19 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt) { 4 | require('load-grunt-tasks')(grunt); 5 | require('time-grunt')(grunt); 6 | 7 | grunt.initConfig({ 8 | pkg: grunt.file.readJSON('package.json'), 9 | compress: { 10 | dist: { 11 | options: { 12 | archive: 'package/<%= pkg.name %>_<%= pkg.version %>.zip' 13 | }, 14 | files: [ 15 | { 16 | expand: true, 17 | cwd: 'dist/src/', 18 | src: ['**'], 19 | dest: '' 20 | } 21 | ] 22 | } 23 | }, 24 | 25 | watch: { 26 | js: { 27 | files: ['Gruntfile.js', 'src/scripts/{,*/}*.js'], 28 | tasks: ['jshint'], 29 | options: { 30 | livereload: true 31 | } 32 | }, 33 | views: { 34 | files: ['src/index.html', 'src/views/{,*/}*.html'], 35 | options: { 36 | livereload: true 37 | } 38 | }, 39 | styles: { 40 | files: ['src/styles/{,*/}*.css'], 41 | tasks: [], 42 | options: { 43 | livereload: true 44 | } 45 | }, 46 | livereload: { 47 | options: { 48 | livereload: '<%= connect.options.livereload %>' 49 | }, 50 | files: [ 51 | 'src/views/**/*.html', 52 | 'src/assets/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', 53 | 'src/manifest.json' 54 | ] 55 | } 56 | }, 57 | 58 | jshint: { 59 | options: { 60 | jshintrc: '.jshintrc' 61 | }, 62 | all: [ 63 | 'Gruntfile.js', 64 | 'karma.conf.js', 65 | 'src/scripts/**/*.js', 66 | 'test/**/*.js' 67 | ] 68 | }, 69 | 70 | connect: { 71 | options: { 72 | port: 9000, 73 | livereload: 35729, 74 | hostname: 'localhost', 75 | open: true 76 | }, 77 | chrome: { 78 | options: { 79 | base: ['src'] 80 | } 81 | } 82 | }, 83 | 84 | clean: { 85 | dist: { 86 | files: [ 87 | { 88 | dot: true, 89 | src: ['dist/*', 'package/*.zip'] 90 | } 91 | ] 92 | } 93 | }, 94 | 95 | karma: { 96 | unit: { 97 | configFile: 'karma.conf.js', 98 | singleRun: true, 99 | browsers: ['PhantomJS'] 100 | } 101 | }, 102 | 103 | copy: { 104 | dist: { 105 | files: [ 106 | { 107 | cwd: '.', 108 | dot: false, 109 | dest: 'dist/', 110 | src: [ 111 | 'src/manifest.json', 112 | 'src/index.html', 113 | 'src/scripts/*', 114 | 'src/styles/*', 115 | 'src/assets/*', 116 | 'src/views/*', 117 | 'src/bower_components/bootstrap/dist/css/bootstrap.min.css', 118 | 'src/bower_components/bootstrap/dist/js/bootstrap.min.js', 119 | 'src/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot', 120 | 'src/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg', 121 | 'src/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf', 122 | 'src/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff', 123 | 'src/bower_components/bootstrap/dist/js/bootstrap.min.css', 124 | 'src/bower_components/jquery/dist/jquery.min.js', 125 | 'src/bower_components/angular/angular.min.js', 126 | 'src/bower_components/angular-route/angular-route.min.js', 127 | 'src/bower_components/angular-sanitize/angular-sanitize.min.js', 128 | 'src/bower_components/jqplot/jquery.jqplot.min.css', 129 | 'src/bower_components/jqplot/jquery.jqplot.min.js', 130 | 'src/bower_components/jqplot/plugins/jqplot.canvasTextRenderer.min.js', 131 | 'src/bower_components/jqplot/plugins/jqplot.canvasAxisLabelRenderer.min.js' 132 | ] 133 | } 134 | ] 135 | } 136 | } 137 | }); 138 | 139 | grunt.registerTask('default', [ 140 | 'build' 141 | ]); 142 | 143 | grunt.registerTask('build', [ 144 | 'build:dist' 145 | ]); 146 | 147 | grunt.registerTask('debug', function (platform) { 148 | var watch = grunt.config('watch'); 149 | platform = platform || 'chrome'; 150 | 151 | // Configure updated watch task 152 | grunt.config('watch', watch); 153 | grunt.task.run(['connect:' + platform, 'watch']); 154 | }); 155 | 156 | grunt.registerTask('build:dist', [ 157 | 'clean:dist', 158 | 'copy:dist', 159 | 'compress:dist' 160 | ]); 161 | 162 | grunt.registerTask('test', [ 163 | 'jshint', 164 | 'karma' 165 | ]); 166 | }; 167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BrickSimple Public License 1.0 (Based on the Mozilla Public License Version 2.0) 2 | ================================================================================ 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | BrickSimple LLC is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the BrickSimple Public 359 | License, v. 1.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://bricksimple.com/bpl10.txt. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the BrickSimple Public License, v. 1.0. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ChromeADB 2 | ========= 3 | 4 | [![Build Status](https://travis-ci.org/importre/chromeadb.svg?branch=master)](https://travis-ci.org/importre/chromeadb) 5 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-ChromeADB-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/863) 6 | 7 | **ChromeADB** is a Chrome ADB (Android Debug Bridge) client. 8 | 9 | When launched, you can see all devices connected to your machine if the ADB connection is successful. 10 | Click a device that you want to control or monitor. And enjoy! 11 | 12 | ![screenshot](https://raw.github.com/importre/chromeadb/master/src/assets/chromeadb_screenshot.png) 13 | 14 | 15 | 16 | How to install 17 | -------------- 18 | 19 | - Install [node.js][0] 20 | - `$ npm install -g bower` 21 | - `$ bower install` 22 | - Open `chrome://extensions` in your Chrome. 23 | - Check `Developer mode` 24 | - Select `Load unpacked extensions...` 25 | - Open `$CHROMEADB_HOME/src` 26 | 27 | 28 | 29 | How to build 30 | ------------ 31 | 32 | - `$ npm install -g grunt-cli` 33 | - `$ npm install` 34 | - `$ grunt` 35 | - Check a zip file in `$CHROMEADB_HOME/package` 36 | 37 | 38 | 39 | Pre-requirements 40 | ---------------- 41 | 42 | - ADB included in [Android SDK][1] 43 | - Start ADB daemon 44 | - `$ adb start-server` 45 | - ChromeADB for Android (Optional) 46 | - for Mousepad 47 | - Go to [Github][github] or [PlayStore][chromeadb_for_android] 48 | 49 | 50 | 51 | How to use 52 | ---------- 53 | 54 | Are you an Android developer? 55 | No description needed anymore :) 56 | 57 | 58 | 59 | Chrome Store 60 | ------------ 61 | 62 | [![chrome_store](https://developer.chrome.com/webstore/images/ChromeWebStore_Badge_v2_496x150.png)][2] 63 | 64 | 65 | 66 | References 67 | ---------- 68 | 69 | - [ADB OVERVIEW.txt][3] 70 | - [ADB SERVICES.txt][4] 71 | 72 | 73 | 74 | License 75 | ------- 76 | 77 | BrickSimple Public License 1.0 (Based on the Mozilla Public License Version 2.0). See the `LICENSE` file. 78 | 79 | 80 | 81 | 82 | [0]: http://www.nodejs.org/ "node.js" 83 | [1]: http://developer.android.com/sdk/index.html "android sdk" 84 | [2]: https://chrome.google.com/webstore/detail/chrome-adb/fhdoijgfljahinnpbolfdimpcfoicmnm "chrome store" 85 | [3]: https://github.com/android/platform_system_core/blob/master/adb/OVERVIEW.TXT "adb overview" 86 | [4]: https://github.com/android/platform_system_core/blob/master/adb/SERVICES.TXT "adb services" 87 | 88 | [chromeadb_for_android]: https://play.google.com/store/apps/details?id=io.github.importre.android.chromeadb 89 | [github]: https://github.com/importre/chromeadb_for_android 90 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "importre" 4 | ], 5 | "dependencies": { 6 | "angular": "~1.2.16", 7 | "angular-route": "~1.2.16", 8 | "angular-sanitize": "~1.2.16", 9 | "bootstrap": "~3.0.2", 10 | "jqplot": "*" 11 | }, 12 | "description": "Chrome ADB(Android Debug Bridge) Client", 13 | "homepage": "https://github.com/importre/chromeadb", 14 | "license": "BSD", 15 | "name": "ChromeADB", 16 | "version": "0.4.2", 17 | "devDependencies": { 18 | "angular-mocks": "~1.2.17" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /change_version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __author__ = 'importre' 4 | 5 | import argparse 6 | import json 7 | import re 8 | import sys 9 | 10 | json_files = ('package.json', 'bower.json', 'src/manifest.json',) 11 | 12 | def get_argparser(): 13 | parser = argparse.ArgumentParser(description='Modify ChromeADB version.') 14 | parser.add_argument('-n', help='new version. ex) 1.0.0') 15 | return parser 16 | 17 | def is_valid_version(ver): 18 | if not ver or not re.match('^(\d+\.){2}\d+$', ver.strip()): 19 | return False 20 | return True 21 | 22 | if __name__ == '__main__': 23 | parser = get_argparser() 24 | ver = parser.parse_args().n 25 | 26 | if not is_valid_version(ver): 27 | parser.print_help() 28 | sys.exit(1) 29 | 30 | json_data = [] 31 | try: 32 | ver 33 | for json_file in json_files: 34 | with open(json_file) as fin: 35 | data = json.load(fin, 'utf_8') 36 | data['version'] = ver 37 | json_data.append(data) 38 | except Exception as why: 39 | print why 40 | sys.exit(1) 41 | 42 | for name, data in zip(json_files, json_data): 43 | with open(name, 'w') as fout: 44 | json.dump(data, fout, indent=4, separators=(',', ': ',), sort_keys=True) 45 | pass 46 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(config) { 4 | config.set({ 5 | frameworks: ['jasmine'], 6 | autoWatch : true, 7 | files : [ 8 | 'src/bower_components/angular/angular.js', 9 | 'src/bower_components/angular-mocks/angular-mocks.js', 10 | 'src/scripts/**/*.js', 11 | 'test/**/*.js' 12 | ], 13 | exclude: [ 14 | 'src/scripts/background.js' 15 | ] 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "importre & BrickSimple", 3 | "dependencies": {}, 4 | "description": "Chrome ADB (Android Debug Bridge) Client", 5 | "devDependencies": { 6 | "grunt": "~0.4.1", 7 | "grunt-contrib-clean": "~0.5.0", 8 | "grunt-contrib-compress": "~0.5.2", 9 | "grunt-contrib-copy": "~0.4.1", 10 | "load-grunt-tasks": "~0.2.0", 11 | "grunt-contrib-watch": "^0.6.1", 12 | "grunt-contrib-connect": "^0.7.1", 13 | "time-grunt": "^0.3.2", 14 | "grunt-contrib-jshint": "^0.10.0", 15 | "karma": "^0.12.16", 16 | "karma-jasmine": "^0.1.5", 17 | "grunt-karma": "^0.8.3", 18 | "karma-phantomjs-launcher": "^0.1.4" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/importre/chromeadb" 23 | }, 24 | "name": "ChromeADB", 25 | "scripts": { 26 | "test": "grunt test" 27 | }, 28 | "version": "0.4.2" 29 | } 30 | -------------------------------------------------------------------------------- /src/assets/BrickLogo2011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/BrickLogo2011.png -------------------------------------------------------------------------------- /src/assets/ChromeADBLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/ChromeADBLogo.png -------------------------------------------------------------------------------- /src/assets/chromeadb_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/chromeadb_screenshot.png -------------------------------------------------------------------------------- /src/assets/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/github.png -------------------------------------------------------------------------------- /src/assets/icon_016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/icon_016.png -------------------------------------------------------------------------------- /src/assets/icon_032.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/icon_032.png -------------------------------------------------------------------------------- /src/assets/icon_048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/icon_048.png -------------------------------------------------------------------------------- /src/assets/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/icon_128.png -------------------------------------------------------------------------------- /src/assets/icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/icon_256.png -------------------------------------------------------------------------------- /src/assets/icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/importre/chromeadb/de2d4f0205b6819135cb2064babf87e8a8313b87/src/assets/icon_512.png -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ChromeADB 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 55 | 56 | 57 |
58 |
59 | 60 | 61 |
62 |
63 |
64 |

65 | Device List {{ numOfDevices }} 66 |

67 |
68 | 79 |
80 | 81 |
82 | 83 |
84 |
Device Info
85 | 86 |
87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
INFO
STATE{{ devInfo.state }}
USB{{ devInfo.usb }}
PRODUCT{{ devInfo.product }}
DEVICE{{ devInfo.device }}
113 |
114 |
115 | 116 |
117 | 118 |
119 |
Log Message
120 | 121 |
122 |

{{ logMessage.cmd }}

123 | 124 |

{{ logMessage.res }}

125 |
126 |
127 |
128 | 129 | 130 |
131 | 132 | 133 |
134 | 156 |
157 | 158 |
159 | 160 | 161 |
162 |
163 |
164 |
165 |
166 | 167 | 168 | 169 | 183 |
184 | 185 | 186 | 187 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "background": { 4 | "scripts": [ 5 | "scripts/background.js" 6 | ] 7 | } 8 | }, 9 | "description": "Chrome ADB (Android Debug Bridge) Client", 10 | "icons": { 11 | "128": "assets/icon_128.png", 12 | "16": "assets/icon_016.png", 13 | "48": "assets/icon_048.png" 14 | }, 15 | "manifest_version": 2, 16 | "minimum_chrome_version": "24", 17 | "name": "ChromeADB", 18 | "permissions": [ 19 | "fileSystem", 20 | { 21 | "socket": [ 22 | "tcp-connect" 23 | ] 24 | } 25 | ], 26 | "version": "0.4.2" 27 | } -------------------------------------------------------------------------------- /src/scripts/background.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, importre. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | 7 | chrome.app.runtime.onLaunched.addListener(function () { 8 | chrome.app.window.create('../index.html', { 9 | minWidth: 800, 10 | minHeight: 600, 11 | width: 1280, 12 | height: 800 13 | }); 14 | }); 15 | 16 | -------------------------------------------------------------------------------- /src/scripts/chrome.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* jshint unused:false */ 3 | 4 | var timeoutDelay = 10; 5 | var curCmd; 6 | var cmdToResp; 7 | 8 | function initCmdToResp() { 9 | cmdToResp = { 10 | '000ehost:devices-l': ['OKAY', '005B', 11 | '048233d1d151e3cc device usb:1A120000 product:aosp_mako ' + 12 | 'model:AOSP_on_Mako device:mako'], 13 | '001fhost:transport:048233d1d151e3cc': ['OKAY'], 14 | '0016shell:pm list packages': ['OKAY', 15 | 'package:com.android.settings\npackage:com.android.musicfx'], 16 | '0015shell:dumpsys meminfo': ['OKAY', 'OKAY', 17 | 'Applications Memory Usage (kB):\n' + 18 | 'Uptime: 95848872 Realtime: 211090246\n\nTotal PSS by process:\n' + 19 | '71959 kB: com.google.android.googlequicksearchbox (pid 892 / activities)\n' + 20 | '71580 kB: com.android.chrome (pid 7876 / activities)'] 21 | }; 22 | } 23 | 24 | function initChromeSocket(chrome) { 25 | if (chrome.socket) { 26 | return; 27 | } 28 | 29 | chrome.socket = { 30 | create: function (type, options, callback) { 31 | var createInfo = { 32 | 'socketId': 10 33 | }; 34 | 35 | window.setTimeout(function () { 36 | callback(createInfo); 37 | }, timeoutDelay); 38 | }, 39 | 40 | destroy: function (socketId) { 41 | }, 42 | 43 | connect: function (socketId, hostname, port, callback) { 44 | var result = 1; 45 | window.setTimeout(function () { 46 | callback(result); 47 | }, timeoutDelay); 48 | }, 49 | 50 | read: function (socketId, bufferSize, callback) { 51 | window.setTimeout(function () { 52 | var resp = cmdToResp[curCmd]; 53 | if (resp) { 54 | resp = cmdToResp[curCmd].splice(0, 1)[0]; 55 | } 56 | if (typeof resp === 'undefined') { 57 | initCmdToResp(); 58 | } 59 | stringToArrayBuffer(resp, function (bytes) { 60 | var readInfo = { 61 | 'resultCode': resp ? 1 : 0, 62 | 'data': bytes 63 | }; 64 | callback(readInfo); 65 | }); 66 | }, timeoutDelay); 67 | }, 68 | 69 | write: function (socketId, data, callback) { 70 | curCmd = data; 71 | var writeInfo = { 72 | bytesWritten: data.length 73 | }; 74 | window.setTimeout(function () { 75 | callback(writeInfo); 76 | }, timeoutDelay); 77 | } 78 | }; 79 | 80 | window.arrayBufferToString = function (buf, callback) { 81 | callback(buf); 82 | }; 83 | 84 | window.stringToArrayBuffer = function (str, callback) { 85 | callback(str); 86 | }; 87 | } 88 | 89 | function initChromeRuntime(chrome) { 90 | if (!chrome.runtime) { 91 | return; 92 | } 93 | 94 | if (!chrome.runtime.getURL) { 95 | chrome.runtime.getURL = function (url) { 96 | return url; 97 | }; 98 | } 99 | } 100 | 101 | (function (window) { 102 | var chrome = window.chrome; 103 | if (typeof chrome === 'undefined' || typeof chrome !== 'object') { 104 | chrome = window.chrome = {}; 105 | } 106 | 107 | initCmdToResp(); 108 | initChromeSocket(chrome); 109 | initChromeRuntime(chrome); 110 | 111 | return chrome; 112 | }(window)); 113 | -------------------------------------------------------------------------------- /src/scripts/chromeadb.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, importre. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | 7 | var adb = angular.module('chromeADB', ['ngRoute', 'ngSanitize']); 8 | 9 | adb.config(function ($routeProvider) { 10 | $routeProvider 11 | .when('/', { 12 | redirectTo: '/packages' 13 | }) 14 | .when('/packages', { 15 | templateUrl: chrome.runtime.getURL('../views/packages.html') 16 | }) 17 | .when('/controller', { 18 | templateUrl: chrome.runtime.getURL('../views/controller.html') 19 | }) 20 | .when('/processes', { 21 | templateUrl: chrome.runtime.getURL('../views/processes.html') 22 | }) 23 | .when('/meminfo', { 24 | templateUrl: chrome.runtime.getURL('../views/meminfo.html') 25 | }) 26 | .when('/diskspace', { 27 | templateUrl: chrome.runtime.getURL('../views/diskspace.html') 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/scripts/controllers.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, importre. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | /* jshint unused:false */ 7 | /* exported parseProcessList */ 8 | /* exported parseDeviceInfoList */ 9 | /* exported parsePackageList */ 10 | /* exported makeCommand */ 11 | /* exported parseMemInfo */ 12 | /* exported parsePackageMemInfo */ 13 | /* exported parseDiskSpace */ 14 | /* exported parseResolution */ 15 | 16 | var adb = angular.module('chromeADB'); 17 | 18 | adb.controller('controller', ['$scope', '$q', 'socketService', '$sce', function ($scope, $q, socketService, $sce) { 19 | $scope.host = '127.0.0.1'; 20 | $scope.port = 5037; 21 | $scope.numOfXAxis = 15; 22 | 23 | $scope.initVariables = function () { 24 | $scope.devInfo = null; 25 | $scope.deviceInfoList = null; 26 | $scope.numOfDevices = null; 27 | $scope.initDeviceData(); 28 | }; 29 | 30 | $scope.clearIntervalOfHeapInfo = function () { 31 | var intervalId = $scope.intervalIdOfHeapInfo; 32 | if (intervalId) { 33 | window.clearInterval(intervalId); 34 | $scope.intervalIdOfHeapInfo = null; 35 | } 36 | 37 | if ($scope.heapChartList) { 38 | for (var i = 0; i < $scope.heapChartList.length; i++) { 39 | if ($scope.heapChartList[i]) { 40 | $scope.heapChartList[i].destroy(); 41 | } 42 | } 43 | } 44 | 45 | $scope.heapSize = [newZeroArray($scope.numOfXAxis), newZeroArray($scope.numOfXAxis)]; 46 | $scope.heapAlloc = [newZeroArray($scope.numOfXAxis), newZeroArray($scope.numOfXAxis)]; 47 | }; 48 | 49 | $scope.initDeviceData = function () { 50 | $scope.packages = null; 51 | $scope.text = null; 52 | $scope.processList = null; 53 | $scope.memInfo = null; 54 | $scope.diskSpace = null; 55 | $scope.logMessage = null; 56 | $scope.mousepadEnabled = false; 57 | $scope.notInstalledApk = false; 58 | $scope.clearIntervalOfHeapInfo(); 59 | }; 60 | 61 | $scope.initVariables(); 62 | 63 | $scope.getNewCommandPromise = function (cmd) { 64 | return socketService.create() 65 | .then(function (createInfo) { 66 | return socketService.connect(createInfo, $scope.host, $scope.port); 67 | }) 68 | .then(function (createInfo) { 69 | var cmdWidthLength = makeCommand(cmd); 70 | // console.log('command:', cmdWidthLength); 71 | return socketService.write(createInfo, cmdWidthLength); 72 | }) 73 | .then(function (param) { 74 | return socketService.read(param.createInfo, 4); 75 | }) 76 | .catch(function (param) { 77 | $scope.initVariables(); 78 | $scope.logMessage = { 79 | cmd: 'Connection Error', 80 | res: 'run \"$ adb start-server\"' 81 | }; 82 | }); 83 | }; 84 | 85 | $scope.getCommandPromise = function (cmd, createInfo) { 86 | var cmdWidthLength = makeCommand(cmd); 87 | // console.log('command:', cmdWidthLength); 88 | return socketService.write(createInfo, cmdWidthLength) 89 | .then(function (param) { 90 | return socketService.read(param.createInfo, 4); 91 | }); 92 | }; 93 | 94 | $scope.getByteCommandPromise = function (cmd, createInfo) { 95 | return socketService.writeBytes(createInfo, cmd) 96 | .then(function (param) { 97 | return socketService.read(param.createInfo, 4); 98 | }); 99 | }; 100 | 101 | $scope.getReadAllPromise = function (cmd1, cmd2) { 102 | return $scope.getNewCommandPromise(cmd1) 103 | .then(function (param) { 104 | // console.log(param); 105 | if (param.data === 'OKAY') { 106 | return $scope.getCommandPromise(cmd2, param.createInfo); 107 | } 108 | }) 109 | .then(function (param) { 110 | // console.log(param); 111 | if (param && param.data === 'OKAY') { 112 | return socketService.readAll(param.createInfo, arrayBufferToString); 113 | } 114 | }) 115 | .catch(function (param) { 116 | $scope.initVariables(); 117 | $scope.logMessage = { 118 | cmd: 'Connection Error', 119 | res: 'Cannot find any devices' 120 | }; 121 | }); 122 | }; 123 | 124 | /** 125 | * Sets connected devices, a number of devices to $scope.deviceInfoList, $scope.numOfDevices respectively. 126 | * 127 | * $ adb devices -l 128 | */ 129 | $scope.loadDevices = function () { 130 | $scope.initVariables(); 131 | 132 | $scope.getNewCommandPromise('host:devices-l') 133 | .then(function (param) { 134 | if (param.data === 'OKAY') { 135 | return socketService.read(param.createInfo, 4); 136 | } 137 | }) 138 | .then(function (param) { 139 | var size = parseInt(param.data, 16); 140 | return socketService.read(param.createInfo, size); 141 | }) 142 | .then(function (param) { 143 | chrome.socket.destroy(param.createInfo.socketId); 144 | 145 | if (!param.data || param.data.length === 0) { 146 | return; 147 | } 148 | 149 | var res = parseDeviceInfoList(param.data); 150 | var firstSerial = res.firstSerial; 151 | $scope.deviceInfoList = res.deviceInfoList; 152 | $scope.numOfDevices = res.numOfDevices; 153 | 154 | if (firstSerial) { 155 | $scope.loadDeviceInfo(firstSerial); 156 | } 157 | }); 158 | }; 159 | 160 | /** 161 | * Sets the device info to $scope.devInfo. 162 | * It'll be invoked if $scope.loadDevices is successful. 163 | * 164 | * @param serial A specific device. 165 | */ 166 | $scope.loadDeviceInfo = function (serial) { 167 | $scope.initDeviceData(); 168 | $scope.devInfo = $scope.deviceInfoList[serial]; 169 | $scope.loadPackages(serial); 170 | 171 | // show packages tab 172 | $(function () { 173 | $('#mytab a:first').tab('show'); 174 | }); 175 | }; 176 | 177 | /** 178 | * Sets the package list to $scope.packages. 179 | * 180 | * $ adb shell pm list packages 181 | * 182 | * @param serial A specific device. 183 | */ 184 | $scope.loadPackages = function (serial) { 185 | var cmd1 = 'host:transport:' + serial; 186 | var cmd2 = 'shell:pm list packages'; 187 | 188 | $scope.logMessage = { 189 | cmd: 'Load packages', 190 | res: 'Loading ...' 191 | }; 192 | 193 | $scope.getReadAllPromise(cmd1, cmd2) 194 | .then(function (param) { 195 | if (param) { 196 | $scope.packages = parsePackageList(param.data); 197 | $scope.logMessage.res = 'Done'; 198 | } 199 | }); 200 | }; 201 | 202 | /** 203 | * Handles a click event. 204 | * 205 | * $ adb shell input keyevent 206 | * 207 | * @param serial A specific device. 208 | * @param keyCode See http://goo.gl/ANf7J 209 | */ 210 | $scope.onClickButton = function (serial, keyCode) { 211 | var cmd1 = 'host:transport:' + serial; 212 | var cmd2 = 'shell:input keyevent ' + keyCode; 213 | 214 | $scope.getReadAllPromise(cmd1, cmd2) 215 | .then(function (param) { 216 | // do nothing... 217 | }); 218 | }; 219 | 220 | /** 221 | * Removes all data of the package. 222 | * 223 | * $ adb shell pm clear 224 | * 225 | * @param serial A specific device. 226 | * @param packageName The package that you're going to clear 227 | */ 228 | $scope.clearData = function (serial, packageName) { 229 | var cmd1 = 'host:transport:' + serial; 230 | var cmd2 = 'shell:pm clear ' + packageName; 231 | 232 | $scope.logMessage = { 233 | cmd: 'Clear Data', 234 | res: null 235 | }; 236 | 237 | $scope.getReadAllPromise(cmd1, cmd2) 238 | .then(function (param) { 239 | $scope.logMessage.res = param.data.trim(); 240 | }); 241 | }; 242 | 243 | $scope.pushFile = function (serial, fileEntry, filePath) { 244 | fileEntry.file(function (file) { 245 | var reader = new FileReader(); 246 | reader.onerror = function (e) { 247 | $scope.logMessage = { 248 | cmd: 'File Error', 249 | res: e.target.error.message 250 | }; 251 | $scope.$apply(); 252 | }; 253 | reader.onloadend = function (e) { 254 | if (!e.target.error) { 255 | $scope.pushFileCommands(e, serial, filePath); 256 | } 257 | }; 258 | reader.readAsArrayBuffer(file); 259 | }); 260 | }; 261 | 262 | $scope.pushFileCommands = function (e, serial, filePath) { 263 | var fileName = filePath.replace(/^.*[\\\/]/, ''); 264 | var cmd1 = 'host:transport:' + serial; 265 | var cmd2 = 'sync:'; 266 | var sendCmd1 = 'SEND'; 267 | var packagePath = '/data/local/tmp/' + fileName; 268 | var sendCmd3 = packagePath + ',33206'; 269 | var sendCmd2 = integerToArrayBuffer(sendCmd3.length); 270 | var dataCmd1 = 'DATA'; 271 | var doneCmd = 'DONE'; 272 | 273 | $scope.logMessage = { 274 | cmd: 'Install Package', 275 | res: 'Installing...' 276 | }; 277 | 278 | $scope.getNewCommandPromise(cmd1) 279 | .then(function (param) { 280 | if (param.data === 'OKAY') { 281 | return $scope.getCommandPromise(cmd2, param.createInfo); 282 | } 283 | }) 284 | .then(function (param) { 285 | if (param.data === 'OKAY') { 286 | return socketService.write(param.createInfo, sendCmd1); 287 | } 288 | }) 289 | .then(function (param) { 290 | return socketService.writeBytes(param.createInfo, sendCmd2.buffer); 291 | }) 292 | .then(function (param) { 293 | return socketService.write(param.createInfo, sendCmd3); 294 | }) 295 | .then(function (param) { 296 | var defer = $q.defer(); 297 | var promise = defer.promise; 298 | var file = e.target.result; 299 | var maxChunkSize = 64 * 1024; 300 | var chunkFunc = function (i, chunkSize) { 301 | var fileSlice = file.slice(i, i + chunkSize); 302 | promise = promise.then(function (param) { 303 | return socketService.write(param.createInfo, dataCmd1); 304 | }) 305 | .then(function (param) { 306 | var chunkSizeInBytes = integerToArrayBuffer(chunkSize); 307 | return socketService.writeBytes(param.createInfo, chunkSizeInBytes.buffer); 308 | }) 309 | .then(function (param) { 310 | return socketService.writeBytes(param.createInfo, fileSlice); 311 | }); 312 | }; 313 | 314 | for (var i = 0; i < file.byteLength; i += maxChunkSize) { 315 | var chunkSize = maxChunkSize; 316 | //check if on last chunk 317 | if (i + maxChunkSize > file.byteLength) { 318 | chunkSize = file.byteLength - i; 319 | } 320 | chunkFunc(i, chunkSize); 321 | } 322 | 323 | promise.then(function (param) { 324 | return socketService.write(param.createInfo, doneCmd); 325 | }) 326 | .then(function (param) { 327 | return socketService.write(param.createInfo, integerToArrayBuffer(0)); 328 | }) 329 | .then(function (param) { 330 | $scope.installPackage(serial, packagePath); 331 | }); 332 | 333 | defer.resolve(param); 334 | 335 | return promise; 336 | }) 337 | .catch(function (param) { 338 | $scope.initVariables(); 339 | $scope.logMessage = { 340 | cmd: 'Connection Error', 341 | res: 'Cannot find any devices' 342 | }; 343 | }); 344 | }; 345 | 346 | /** 347 | * Installs a package. 348 | * 349 | * $ adb shell pm install 350 | * 351 | * @param serial 352 | * @param packageName 353 | */ 354 | $scope.installPackage = function (serial, packagePath) { 355 | var cmd1 = 'host:transport:' + serial; 356 | var cmd2 = 'shell:pm install -r ' + packagePath; 357 | 358 | $scope.logMessage = { 359 | cmd: 'Install Package', 360 | res: 'Installing...' 361 | }; 362 | 363 | $scope.getReadAllPromise(cmd1, cmd2) 364 | .then(function (param) { 365 | $scope.logMessage.res = param.data.trim(); 366 | if ($scope.logMessage.res.length === 0) { 367 | $scope.logMessage.res = 'Done'; 368 | } 369 | $scope.loadPackages(serial); 370 | $scope.removeApkFile(serial, packagePath); 371 | }); 372 | }; 373 | 374 | /** 375 | * Uninstalls a package. 376 | * 377 | * $ adb shell pm uninstall 378 | * 379 | * @param serial 380 | * @param packageName 381 | */ 382 | $scope.uninstallPackage = function (serial, packageName) { 383 | var cmd1 = 'host:transport:' + serial; 384 | var cmd2 = 'shell:pm uninstall ' + packageName; 385 | 386 | $scope.logMessage = { 387 | cmd: 'Uninstall', 388 | res: 'Uninstalling...' 389 | }; 390 | 391 | $scope.getReadAllPromise(cmd1, cmd2) 392 | .then(function (param) { 393 | $scope.logMessage.res = param.data.trim(); 394 | if ($scope.logMessage.res.length === 0) { 395 | $scope.logMessage.res = 'Done'; 396 | } 397 | $scope.loadPackages(serial); 398 | }); 399 | }; 400 | 401 | $scope.removeApkFile = function (serial, packagePath) { 402 | var cmd1 = 'host:transport:' + serial; 403 | var cmd2 = 'shell:rm -rf ' + packagePath; 404 | 405 | $scope.getReadAllPromise(cmd1, cmd2) 406 | .then(function (param) { 407 | }); 408 | }; 409 | 410 | $scope.stopPackage = function (serial, packageName) { 411 | var cmd1 = 'host:transport:' + serial; 412 | var cmd2 = 'shell:am force-stop ' + packageName; 413 | 414 | $scope.logMessage = { 415 | cmd: 'Force-stop', 416 | res: null 417 | }; 418 | 419 | console.log(serial, packageName); 420 | $scope.getReadAllPromise(cmd1, cmd2) 421 | .then(function (param) { 422 | console.log(serial, packageName); 423 | }); 424 | }; 425 | 426 | /** 427 | * Sends the text. 428 | * 429 | * $ adb shell input text 430 | * 431 | * @param serial 432 | * @param text 433 | */ 434 | $scope.sendText = function (serial, text) { 435 | var cmd1 = 'host:transport:' + serial; 436 | var cmd2 = 'shell:input text ' + text; 437 | 438 | $scope.getReadAllPromise(cmd1, cmd2) 439 | .then(function (param) { 440 | // console.log(param); 441 | $scope.text = null; 442 | }); 443 | }; 444 | 445 | /** 446 | * Sets the process list to $scope.processList 447 | * 448 | * $ adb shell ps 449 | * 450 | * @param serial 451 | */ 452 | $scope.loadProcessList = function (serial) { 453 | var cmd1 = 'host:transport:' + serial; 454 | var cmd2 = 'shell:ps'; 455 | 456 | $scope.logMessage = { 457 | cmd: 'Load process list', 458 | res: 'Loading ...' 459 | }; 460 | 461 | $scope.getReadAllPromise(cmd1, cmd2) 462 | .then(function (param) { 463 | if (param) { 464 | var lines = parseProcessList(param.data); 465 | var body = lines.splice(1); 466 | var head = lines[0]; 467 | 468 | $scope.logMessage.res = 'Done'; 469 | $scope.processList = { 470 | head: head, 471 | processes: body 472 | }; 473 | } 474 | }); 475 | }; 476 | 477 | /** 478 | * Sets the meminfo to $scope.memInfo 479 | * 480 | * $ adb shell dumpsys meminfo 481 | * 482 | * @param serial 483 | * @param procName 484 | */ 485 | $scope.loadMemInfo = function (serial, procName) { 486 | var cmd1 = 'host:transport:' + serial; 487 | var cmd2 = 'shell:dumpsys meminfo'; 488 | 489 | if (procName) { 490 | cmd2 += (' ' + procName); 491 | } 492 | 493 | $scope.logMessage = { 494 | cmd: 'Load memory info', 495 | res: 'Loading ...' 496 | }; 497 | 498 | $scope.getReadAllPromise(cmd1, cmd2) 499 | .then(function (param) { 500 | if (param) { 501 | var data; 502 | if (!procName) { 503 | data = parseMemInfo(param.data); 504 | $scope.memInfo = data; 505 | $scope.logMessage.res = 'Done'; 506 | } else { 507 | data = parsePackageMemInfo(param.data); 508 | drawHeapGraph(data); 509 | } 510 | } 511 | }); 512 | }; 513 | 514 | /** 515 | * Sets the disk space info to $scope.diskSpace 516 | * 517 | * $ adb shell cat /proc/meminfo 518 | * 519 | * @param serial 520 | */ 521 | $scope.loadDiskSpace = function (serial) { 522 | var cmd1 = 'host:transport:' + serial; 523 | var cmd2 = 'shell:df'; 524 | 525 | $scope.logMessage = { 526 | cmd: 'Load disk space', 527 | res: 'Loading ...' 528 | }; 529 | 530 | $scope.getReadAllPromise(cmd1, cmd2) 531 | .then(function (param) { 532 | if (param) { 533 | $scope.diskSpace = parseDiskSpace(param.data); 534 | $scope.logMessage.res = 'Done'; 535 | } 536 | }); 537 | }; 538 | 539 | /** 540 | * Assigns temporary variables for clear data, uninstall or stop a package. 541 | * 542 | * @param cmd 0: clear data, 1: uninstall, 2: stop 543 | * @param serial 544 | * @param packageName 545 | */ 546 | $scope.setPackageCommandInfo = function (cmd, serial, packageName) { 547 | var func = null; 548 | var msg = ''; 549 | switch (cmd) { 550 | case 0: 551 | func = $scope.clearData; 552 | msg = 'CLEAR DATA'; 553 | break; 554 | case 1: 555 | func = $scope.uninstallPackage; 556 | msg = 'UNINSTALL'; 557 | break; 558 | case 2: 559 | func = $scope.stopPackage; 560 | msg = 'FORCE-STOP'; 561 | break; 562 | } 563 | 564 | if (func) { 565 | $scope.tempPkgCmd = { 566 | func: func, 567 | msg: msg, 568 | serial: serial, 569 | packageName: packageName 570 | }; 571 | } else { 572 | $scope.tempPkgCmd = null; 573 | } 574 | }; 575 | 576 | $scope.chooseAndInstallPackage = function () { 577 | chrome.fileSystem.chooseEntry({'type': 'openFile'}, function (entry, fileEntries) { 578 | chrome.fileSystem.getDisplayPath(entry, function (displayPath) { 579 | $scope.pushFile($scope.devInfo.serial, entry, displayPath); 580 | }); 581 | }); 582 | }; 583 | 584 | $scope.loadHeapInfoOfApp = function (serial, process) { 585 | $scope.clearIntervalOfHeapInfo(); 586 | $scope.procName = process; 587 | $scope.heapChartList = new Array(2); 588 | for (var i = 0; i < 2; i++) { 589 | var name = getChartId(i); 590 | var data = [newZeroArray($scope.numOfXAxis)]; 591 | $scope.heapChartList[i] = $.jqplot(name, data); 592 | } 593 | 594 | $scope.intervalIdOfHeapInfo = window.setInterval(function () { 595 | $scope.loadMemInfo(serial, process); 596 | }, 1000); 597 | 598 | $('#procMemInfoModal').on('hidden.bs.modal', function () { 599 | $scope.clearIntervalOfHeapInfo(); 600 | }); 601 | }; 602 | 603 | function drawHeapGraph(data) { 604 | // console.log(JSON.stringify(data)); 605 | for (var i = 0; i < data.length; i++) { 606 | $scope.heapChartList[i].destroy(); 607 | $scope.heapSize[i].splice(0, 1); 608 | $scope.heapAlloc[i].splice(0, 1); 609 | $scope.heapSize[i].push(data[i].size / 1024); 610 | $scope.heapAlloc[i].push(data[i].alloc / 1024); 611 | 612 | $scope.heapChartList[i].replot({ 613 | data: [$scope.heapSize[i], $scope.heapAlloc[i]], 614 | title: data[i].area, 615 | legend: {show: true, location: 'e', placement: 'insideGrid'}, 616 | series: [ 617 | {label: 'Heap Size (MB)'}, 618 | {label: 'Heap Alloc (MB)'} 619 | ] 620 | }); 621 | } 622 | } 623 | 624 | $scope.scaleOfMousePad = 2; 625 | $scope.mouseDownX = -1; 626 | $scope.mouseDownY = -1; 627 | $scope.swipeDuration = 100; 628 | $scope.packageName = 'io.github.importre.android.chromeadb'; 629 | $scope.eventFilePath = '/sdcard/chromeadb.event'; 630 | 631 | /** 632 | * Sets mouse pad size. 633 | * 634 | * Shows mousepad if parsed window size and chromeadb apk is installed. 635 | * 636 | * @param serial 637 | */ 638 | $scope.initMousePad = function (serial) { 639 | var cmd1 = 'host:transport:' + serial; 640 | $scope.logMessage = null; 641 | $scope.mousepadEnabled = false; 642 | $scope.notInstalledApk = false; 643 | $scope.mousepadMsg = 'Checking...'; 644 | 645 | $scope.getReadAllPromise(cmd1, 'shell:pm list packages') 646 | .then(function (param) { 647 | if (!param) { 648 | // not connected 649 | $scope.mousepadMsg = ''; 650 | } else if (param.data.indexOf($scope.packageName) >= 0) { 651 | // connected 652 | var cmd2 = 'shell:dumpsys window'; 653 | $scope.getReadAllPromise(cmd1, cmd2) 654 | .then(function (param) { 655 | var size = parseResolution(param.data); 656 | if (size !== null) { 657 | $scope.mousepadEnabled = true; 658 | $scope.notInstalledApk = true; 659 | $scope.devResolution = { 660 | width: (size.width / $scope.scaleOfMousePad) + 'px', 661 | height: (size.height / $scope.scaleOfMousePad) + 'px' 662 | }; 663 | 664 | if ($scope.scaleOfMousePad >= 4) { 665 | $('#mousepad-size-group label:last').click(); 666 | } else { 667 | $('#mousepad-size-group label:first').click(); 668 | } 669 | } else { 670 | // failed to parse `dumpsys windows` 671 | $scope.mousepadEnabled = false; 672 | var title = 'feedback mousepad'; 673 | 674 | $scope.getReadAllPromise(cmd1, 'shell:input') 675 | .then(function (param) { 676 | var body = '\n\n\n' + param.data; 677 | $scope.mousepadMsg = 'Error: ' + $scope.getFeedbackTag(title, body); 678 | }); 679 | } 680 | }); 681 | } else { 682 | // apk is not installed. 683 | $scope.notInstalledApk = true; 684 | $scope.mousepadMsg = 'Install ChromeADB for Android'; 685 | } 686 | }); 687 | }; 688 | 689 | /** 690 | * TODO: Sends Intent 691 | * 692 | * @param serial 693 | */ 694 | $scope.sendIntentApk = function (serial) { 695 | var act = 'android.intent.action.VIEW'; 696 | // var uri = 'http://play.google.com/store/apps/details?id=io.github.importre.android.chromeadb'; 697 | var uri = 'market://details?id=io.github.importre.android.chromeadb'; 698 | var cmd1 = 'host:transport:' + serial; 699 | var cmd2 = 'shell:am start -a ' + act + ' -d ' + uri; 700 | $scope.getReadAllPromise(cmd1, cmd2) 701 | .then(function (param) { 702 | $scope.logMessage = { 703 | cmd: 'PlayStore', 704 | res: 'See your device and Install ChromeADB for Android' 705 | }; 706 | }); 707 | }; 708 | 709 | $scope.mouseDown = function (event) { 710 | $scope.mouseDownX = event.offsetX * $scope.scaleOfMousePad; 711 | $scope.mouseDownY = event.offsetY * $scope.scaleOfMousePad; 712 | }; 713 | 714 | $scope.mouseUp = function (serial, event) { 715 | var x = event.offsetX * $scope.scaleOfMousePad; 716 | var y = event.offsetY * $scope.scaleOfMousePad; 717 | 718 | var cmd1 = 'host:transport:' + serial; 719 | var cmd2 = 'shell:input touchscreen tap ' + x + ' ' + y; 720 | 721 | var x1 = $scope.mouseDownX; 722 | var y1 = $scope.mouseDownY; 723 | 724 | if (x1 >= 0 && y1 >= 0) { 725 | var dist = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2)); 726 | // console.log('dist : ' + dist); 727 | if (dist > 30) { 728 | cmd2 = 'shell:input touchscreen swipe ' + [x1, y1, x, y].join(' '); 729 | console.log(cmd2); 730 | } 731 | } 732 | 733 | $scope.mouseDownX = -1; 734 | $scope.mouseDownY = -1; 735 | 736 | var getLogMessage = function (data) { 737 | return { 738 | cmd: 'MousePad', 739 | res: data.split('\n')[0] 740 | }; 741 | }; 742 | 743 | $scope.getReadAllPromise(cmd1, cmd2) 744 | .then(function (param) { 745 | if (param && param.data) { 746 | var errMsg = param.data.split('\n')[0].toLowerCase(); 747 | if (errMsg.indexOf('error') >= 0 || errMsg.indexOf('unknown command') >= 0) { 748 | // remove touchscreen command and retry tab or swipe command 749 | cmd2 = cmd2.replace('touchscreen ', ''); 750 | $scope.getReadAllPromise(cmd1, cmd2) 751 | .then(function (param) { 752 | if (param && param.data) { 753 | $scope.logMessage = getLogMessage(param.data); 754 | } 755 | }); 756 | } else { 757 | $scope.logMessage = getLogMessage(param.data); 758 | } 759 | } 760 | }); 761 | }; 762 | 763 | $scope.mouseMove = function (serial, event) { 764 | var x = event.offsetX * $scope.scaleOfMousePad; 765 | var y = event.offsetY * $scope.scaleOfMousePad; 766 | 767 | $scope.mouseMoveLog = 'coord: (' + x + ', ' + y + ')'; 768 | 769 | if (!$scope.coords) { 770 | $scope.coords = []; 771 | } 772 | 773 | $scope.coords.push(x); 774 | $scope.coords.push(y); 775 | 776 | if ($scope.coords.length > 2) { 777 | var cmd1 = 'host:transport:' + serial; 778 | var cmd2 = 'shell: echo move ' + $scope.coords.join(',') + ' >> ' + $scope.eventFilePath; 779 | 780 | $scope.getReadAllPromise(cmd1, cmd2) 781 | .then(function (param) { 782 | }); 783 | $scope.coords = []; 784 | } 785 | }; 786 | 787 | $scope.mouseEnter = function (serial) { 788 | var cmd1 = 'host:transport:' + serial; 789 | var cmd2 = 'shell:am startservice --user 0 -n ' + $scope.packageName + '/.ChromeAdbService'; 790 | 791 | $scope.getReadAllPromise(cmd1, cmd2) 792 | .then(function (param) { 793 | if (param && param.data) { 794 | if (param.data.indexOf('--user') >= 0) { 795 | cmd2 = cmd2.replace('--user 0 ', ''); 796 | $scope.getReadAllPromise(cmd1, cmd2) 797 | .then(function (param) { 798 | }); 799 | } 800 | } 801 | }); 802 | }; 803 | 804 | $scope.mouseLeave = function (serial) { 805 | var cmd1 = 'host:transport:' + serial; 806 | var cmd2 = 'shell:rm -r ' + $scope.eventFilePath; 807 | 808 | $scope.getReadAllPromise(cmd1, cmd2) 809 | .then(function (param) { 810 | cmd2 = 'shell:am stopservice -n ' + $scope.packageName + '/.ChromeAdbService'; 811 | 812 | $scope.getReadAllPromise(cmd1, cmd2) 813 | .then(function (param) { 814 | }); 815 | }); 816 | }; 817 | 818 | $scope.rotateMousePad = function () { 819 | $scope.devResolution = { 820 | width: $scope.devResolution.height, 821 | height: $scope.devResolution.width 822 | }; 823 | }; 824 | 825 | $scope.setMousePadSize = function (serial, scale) { 826 | $scope.scaleOfMousePad = scale; 827 | $scope.initMousePad(serial); 828 | }; 829 | 830 | $scope.getFeedbackTag = function (title, body) { 831 | title = '[ChromeADB] ' + title; 832 | body = encodeURIComponent(body); 833 | 834 | var to = 'chromeadb@gmail.com'; 835 | var mailto = $sce.trustAsHtml('mailto:' + to + '?subject=' + title + '&body=' + body); 836 | return 'Send feedback'; 837 | }; 838 | }]); 839 | 840 | -------------------------------------------------------------------------------- /src/scripts/parser.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, importre. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | /* exported parseProcessList */ 7 | /* exported parseDeviceInfoList */ 8 | /* exported parsePackageList */ 9 | /* exported makeCommand */ 10 | /* exported parseMemInfo */ 11 | /* exported parsePackageMemInfo */ 12 | /* exported parseDiskSpace */ 13 | /* exported parseResolution */ 14 | 15 | /** 16 | * Parses the result of $scope.loadDevices(). 17 | * 18 | * @param data 19 | * @returns {{firstSerial: null, deviceInfoList: Object, numOfDevices: Number}} 20 | */ 21 | function parseDeviceInfoList(data) { 22 | var lines = data.trim().split('\n'); 23 | var deviceInfoList = {}; 24 | var firstSerial = null; 25 | 26 | for (var i = 0; i < lines.length; i++) { 27 | lines[i] = lines[i].trim().split(/\s+/g); 28 | var serial = lines[i][0]; 29 | 30 | if (0 === i) { 31 | firstSerial = serial; 32 | } 33 | 34 | deviceInfoList[serial] = { 35 | serial: serial, 36 | state: lines[i][1], 37 | usb: null, 38 | product: null, 39 | model: null, 40 | device: null 41 | }; 42 | 43 | for (var j = 2; j < lines[i].length; j++) { 44 | if (lines[i][j].match(/^usb:/)) { 45 | deviceInfoList[serial].usb = lines[i][j].substr(4); 46 | } else if (lines[i][j].match(/^product:/)) { 47 | deviceInfoList[serial].product = lines[i][j].substr(8); 48 | } else if (lines[i][j].match(/^model:/)) { 49 | deviceInfoList[serial].model = lines[i][j].substr(6); 50 | } else if (lines[i][j].match(/^device:/)) { 51 | deviceInfoList[serial].device = lines[i][j].substr(7); 52 | } 53 | } 54 | } 55 | 56 | var keys = Object.keys(deviceInfoList); 57 | if (keys.length > 0) { 58 | firstSerial = keys.sort()[0]; 59 | } 60 | 61 | return { 62 | firstSerial: firstSerial, 63 | deviceInfoList: deviceInfoList, 64 | numOfDevices: lines.length 65 | }; 66 | } 67 | 68 | /** 69 | * Parses the result of $scope.loadPackages(). 70 | * 71 | * @param data 72 | * @returns {Array} 73 | */ 74 | function parsePackageList(data) { 75 | var lines = data.trim().split('\n'); 76 | 77 | for (var i = 0; i < lines.length; i++) { 78 | lines[i] = lines[i].replace(/^package:/, '').trim(); 79 | } 80 | 81 | return lines; 82 | } 83 | 84 | /** 85 | * Makes adb command. 86 | * 87 | * @param cmd 88 | * @returns {string} 89 | */ 90 | function makeCommand(cmd) { 91 | var hex = cmd.length.toString(16); 92 | while (hex.length < 4) { 93 | hex = '0' + hex; 94 | } 95 | 96 | cmd = hex + cmd; 97 | return cmd; 98 | } 99 | 100 | /** 101 | * Parses the result of $scope.loadProcessList() 102 | * 103 | * @param data 104 | * @returns {Array} 105 | */ 106 | function parseProcessList(data) { 107 | // parse oldstyle ps result 108 | var ore = new RegExp(/^(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+([a-fA-F0-9]+)\s+([a-fA-F0-9]+ \w)\s+(.+)/m); 109 | // parse 4.4 or above ps result 110 | var nre = new RegExp(/^(\d+)\s+(\d+)\s+(\d+m?)\s+(\w+\s*= 0) { 146 | pss++; 147 | continue; 148 | } 149 | 150 | if (pss === 1) { 151 | line = re.exec(line); 152 | if (line) { 153 | ret.push({ 154 | process: line[2], 155 | pid: line[3], 156 | kb: line[1] + ' KB', 157 | mb: parseInt(parseFloat(line[1]) / 1024 + 0.5) + ' MB' 158 | }); 159 | } else { 160 | break; 161 | } 162 | } 163 | } 164 | return ret; 165 | } 166 | 167 | function parsePackageMemInfo(data) { 168 | var lines = data.trim().split('\n'); 169 | var line, tempLine, length; 170 | var ret = []; 171 | var cnt = 0; 172 | var found = false; 173 | var idxOfSize, idxOfAlloc, idxOfFree; 174 | 175 | for (var i = 0; i < lines.length; i++) { 176 | line = lines[i].trim(); 177 | tempLine = line.split(/\s+/); 178 | length = tempLine.length; 179 | 180 | if (!found) { 181 | idxOfSize = tempLine.indexOf('Size'); 182 | idxOfAlloc = tempLine.indexOf('Alloc'); 183 | idxOfFree = tempLine.indexOf('Free'); 184 | 185 | if (idxOfSize >= 0 && idxOfAlloc >= 0 && idxOfFree >= 0) { 186 | idxOfSize = length - idxOfSize; 187 | idxOfAlloc = length - idxOfAlloc; 188 | idxOfFree = length - idxOfFree; 189 | found = true; 190 | continue; 191 | } 192 | } 193 | 194 | if (found && (tempLine[0] === 'Native' || tempLine[0] === 'Dalvik')) { 195 | ret.push({ 196 | area: tempLine[0], 197 | size: tempLine[length - idxOfSize], 198 | alloc: tempLine[length - idxOfAlloc], 199 | free: tempLine[length - idxOfFree] 200 | }); 201 | cnt++; 202 | } 203 | 204 | if (cnt >= 2) { 205 | break; 206 | } 207 | } 208 | return ret; 209 | } 210 | 211 | function parseDiskSpace(data) { 212 | var lines = data.trim().split('\n'); 213 | var line, head, body = []; 214 | 215 | for (var i = 0; i < lines.length; i++) { 216 | line = lines[i].trim().split(/\s+/); 217 | if (i === 0) { 218 | head = line; 219 | } else { 220 | body.push(line); 221 | } 222 | } 223 | return {head: head, body: body}; 224 | } 225 | 226 | function parseResolution(data) { 227 | var re = /init=(\d+)x(\d+)/g; 228 | var res = re.exec(data); 229 | if (res === null) { 230 | re = /mDisplayWidth=(\d+)\s+mDisplayHeight=(\d+)/g; 231 | res = re.exec(data); 232 | if (res === null) { 233 | return null; 234 | } 235 | } 236 | return {width: res[1], height: res[2]}; 237 | } 238 | 239 | -------------------------------------------------------------------------------- /src/scripts/services.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, importre. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | 7 | var adb = angular.module('chromeADB'); 8 | 9 | adb.factory('socketService', ['$rootScope', '$q', function ($rootScope, $q) { 10 | function create() { 11 | var defer = $q.defer(); 12 | 13 | chrome.socket.create('tcp', {}, function (createInfo) { 14 | if (createInfo.socketId >= 0) { 15 | $rootScope.$apply(function () { 16 | defer.resolve(createInfo); 17 | }); 18 | } else { 19 | // console.log('create error:', createInfo); 20 | } 21 | }); 22 | 23 | return defer.promise; 24 | } 25 | 26 | function connect(createInfo, host, port) { 27 | var defer = $q.defer(); 28 | 29 | if (typeof port !== 'number') { 30 | port = parseInt(port, 10); 31 | } 32 | 33 | chrome.socket.connect(createInfo.socketId, host, port, function (result) { 34 | if (result >= 0) { 35 | $rootScope.$apply(function () { 36 | defer.resolve(createInfo); 37 | }); 38 | } else { 39 | chrome.socket.destroy(createInfo.socketId); 40 | defer.reject(createInfo); 41 | } 42 | }); 43 | 44 | return defer.promise; 45 | } 46 | 47 | function write(createInfo, str) { 48 | var defer = $q.defer(); 49 | 50 | stringToArrayBuffer(str, function (bytes) { 51 | writeBytes(createInfo, bytes) 52 | .then(function (createInfo) { 53 | defer.resolve(createInfo); 54 | }); 55 | }); 56 | 57 | return defer.promise; 58 | } 59 | 60 | function writeBytes(createInfo, bytes) { 61 | var defer = $q.defer(); 62 | 63 | chrome.socket.write(createInfo.socketId, bytes, function (writeInfo) { 64 | // console.log('writeInfo:', writeInfo); 65 | if (writeInfo.bytesWritten > 0) { 66 | $rootScope.$apply(function () { 67 | var param = { 68 | createInfo: createInfo, 69 | writeInfo: writeInfo 70 | }; 71 | defer.resolve(param); 72 | }); 73 | } else { 74 | // console.log('write error:', arrayBuffer); 75 | defer.reject(writeInfo); 76 | } 77 | }); 78 | 79 | return defer.promise; 80 | } 81 | 82 | function read(createInfo, size) { 83 | var defer = $q.defer(); 84 | 85 | chrome.socket.read(createInfo.socketId, size, function (readInfo) { 86 | if (readInfo.resultCode > 0) { 87 | // console.log(readInfo); 88 | arrayBufferToString(readInfo.data, function (str) { 89 | $rootScope.$apply(function () { 90 | var param = { 91 | createInfo: createInfo, 92 | data: str 93 | }; 94 | defer.resolve(param); 95 | }); 96 | }); 97 | } else { 98 | defer.reject(readInfo); 99 | } 100 | }); 101 | 102 | return defer.promise; 103 | } 104 | 105 | function readAll(createInfo, stringConverter) { 106 | var defer = $q.defer(); 107 | var data = ''; 108 | 109 | (function readAllData() { 110 | chrome.socket.read(createInfo.socketId, 1024, function (readInfo) { 111 | if (readInfo.resultCode > 0) { 112 | stringConverter(readInfo.data, function (str) { 113 | data += str; 114 | readAllData(); 115 | }); 116 | } else { 117 | $rootScope.$apply(function () { 118 | var param = { 119 | createInfo: createInfo, 120 | data: data 121 | }; 122 | defer.resolve(param); 123 | }); 124 | } 125 | }); 126 | })(); 127 | 128 | return defer.promise; 129 | } 130 | 131 | return { 132 | create: create, 133 | connect: connect, 134 | write: write, 135 | writeBytes: writeBytes, 136 | read: read, 137 | readAll: readAll 138 | }; 139 | }]); 140 | -------------------------------------------------------------------------------- /src/scripts/utils.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, importre. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | /* exported arrayBufferToString */ 7 | /* exported arrayBufferToBinaryString */ 8 | /* exported stringToArrayBuffer */ 9 | /* exported newZeroArray */ 10 | /* exported getChartId */ 11 | /* exported integerToArrayBuffer */ 12 | 13 | /** 14 | * Converts ArrayBuffer to string. 15 | * 16 | * @param buf 17 | * @param callback 18 | */ 19 | function arrayBufferToString(buf, callback) { 20 | var b = new Blob([new Uint8Array(buf)]); 21 | var f = new FileReader(); 22 | f.onload = function (e) { 23 | callback(e.target.result); 24 | }; 25 | f.readAsText(b); 26 | } 27 | 28 | function arrayBufferToBinaryString(buf, callback) { 29 | var b = new Blob([new Uint8Array(buf)]); 30 | var f = new FileReader(); 31 | f.onload = function (e) { 32 | callback(e.target.result); 33 | }; 34 | f.readAsBinaryString(b); 35 | } 36 | 37 | /** 38 | * Converts string to ArrayBuffer. 39 | * 40 | * @param buf 41 | * @param callback 42 | */ 43 | function stringToArrayBuffer(str, callback) { 44 | var b = new Blob([str]); 45 | var f = new FileReader(); 46 | f.onload = function (e) { 47 | callback(e.target.result); 48 | }; 49 | f.readAsArrayBuffer(b); 50 | } 51 | 52 | function newZeroArray(size) { 53 | var arr = new Array(size); 54 | for (var i = 0; i < size; i++) { 55 | arr[i] = 0; 56 | } 57 | return arr; 58 | } 59 | 60 | function getChartId(idx) { 61 | switch (idx) { 62 | case 0: 63 | return 'heap_native_chart'; 64 | case 1: 65 | return 'heap_dalvik_chart'; 66 | } 67 | return null; 68 | } 69 | 70 | function integerToArrayBuffer(value) { 71 | var result = new Uint32Array(1); 72 | result[0] = value; 73 | return result; 74 | } 75 | -------------------------------------------------------------------------------- /src/styles/chromeadb.css: -------------------------------------------------------------------------------- 1 | html { 2 | overflow-y: auto; 3 | } 4 | 5 | body { 6 | padding-top: 70px; 7 | padding-bottom: 70px; 8 | } 9 | 10 | .tab-pane input { 11 | margin-bottom: 10px; 12 | } 13 | 14 | .tab-content { 15 | margin-top: 10px; 16 | } 17 | 18 | .tab-pane .btn { 19 | width: 80px; 20 | } 21 | 22 | .badge { 23 | background-color: #d9544f; 24 | } 25 | 26 | tr > td.active { 27 | font-weight: bold; 28 | } 29 | 30 | .install-package-button { 31 | width: 150px !important; 32 | } 33 | 34 | div .search-packages { 35 | float: right; 36 | width: 80%; 37 | } 38 | 39 | div .install-package { 40 | float: left; 41 | } 42 | 43 | .navbar-brand { 44 | padding: 0 0 0 15px; 45 | } 46 | 47 | .navbar-brand img { 48 | height: 50px; 49 | } 50 | 51 | .navbar-bottom-brand { 52 | padding: 0; 53 | } 54 | 55 | .navbar-bottom-brand img { 56 | height: 50px; 57 | } 58 | 59 | .navbar-bottom-brand a:hover { 60 | text-decoration: none; 61 | } 62 | 63 | th { 64 | text-align: center; 65 | } 66 | 67 | .navbar { 68 | background-color: #000; 69 | } 70 | 71 | #mousepad { 72 | color: white; 73 | background-color: black; 74 | text-align: center; 75 | vertical-align: middle; 76 | display: table-cell; 77 | } 78 | 79 | .ng-hide { 80 | display: block !important; 81 | position: absolute; 82 | top: -9999px; 83 | left: -9999px; 84 | } 85 | -------------------------------------------------------------------------------- /src/views/controller.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 | 12 | 14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 |
Hard/Soft Button
22 |
23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 71 | 77 | 83 | 84 | 85 | 91 | 98 | 104 | 105 | 106 | 107 |
29 | 33 |
39 | 44 | 47 | 51 |
58 | 62 |
66 | 70 | 72 | 76 | 78 | 82 |
86 | 90 | 92 | 97 | 99 | 103 |
108 |
109 |
110 |
111 | 112 |
113 |
114 |
Keyboard
115 |
116 | 117 | 118 | 119 | 125 | 127 | 129 | 135 | 136 | 137 | 139 | 145 | 147 | 153 | 154 | 155 | 161 | 167 | 173 | 179 | 180 | 181 |
120 | 124 | 126 | 128 | 130 | 134 |
138 | 140 | 144 | 146 | 148 | 152 |
156 | 160 | 162 | 166 | 168 | 172 | 174 | 178 |
182 |
183 |
184 |
185 |
186 | 187 |
188 |
189 |
190 |
Mouse Pad
191 |
192 |
193 | 196 | 199 |
200 | 205 |
206 |
213 | {{ mouseMoveLog }} 214 |
215 |
216 |
217 |
218 | 223 |
224 |
225 |
226 |
227 |
228 | -------------------------------------------------------------------------------- /src/views/diskspace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 |
9 | {{ item.toUpperCase(); }} 10 |
16 | {{ item }} 17 |
21 |
22 | -------------------------------------------------------------------------------- /src/views/meminfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 |
PROCESSPIDTOTAL PSS (KB)TOTAL PSS (MB)
18 | 20 | {{ info.process }} 21 | 22 | {{ info.pid }}{{ info.kb }}{{ info.mb }}
29 |
30 | 31 | 32 | 33 | 53 | -------------------------------------------------------------------------------- /src/views/packages.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 | 8 |
9 |
10 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 36 | 43 | 50 | 51 | 52 |
PACKAGECLEAR DATAUNINSTALLFORCE-STOP
27 | {{ package }} 28 | 30 | 35 | 37 | 42 | 44 | 49 |
53 |
54 |
55 | 56 | -------------------------------------------------------------------------------- /src/views/processes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 |
10 | {{ item.toUpperCase(); }} 11 |
17 | {{ item }} 18 |
22 |
23 | -------------------------------------------------------------------------------- /test/parserSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('parser spec', function() { 4 | beforeEach(function() { 5 | }); 6 | 7 | it('test \'adb devices -l\'', function() { 8 | var data = '000000 device usb:1111111 product:razor model:Nexus_7 device:flo'; 9 | var res = parseDeviceInfoList(data); 10 | var serial = res.firstSerial; 11 | expect(serial).toBe('000000'); 12 | expect(res.deviceInfoList[serial].usb).toBe('1111111'); 13 | expect(res.deviceInfoList[serial].product).toBe('razor'); 14 | expect(res.deviceInfoList[serial].model).toBe('Nexus_7'); 15 | expect(res.deviceInfoList[serial].device).toBe('flo'); 16 | }); 17 | }); 18 | --------------------------------------------------------------------------------