├── .circleci
└── config.yml
├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── KeyEvent-Display---Android-AS.iml
├── KeyEvent-Display---Android.iml
├── LICENSE-2.0.html
├── README.md
├── apkdetails.sh
├── app
├── .gitignore
├── app.iml
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── aws
│ │ └── apps
│ │ └── keyeventdisplay
│ │ ├── KeyEventApplication.java
│ │ ├── deviceinfo
│ │ ├── DeviceCapabilities.java
│ │ └── DeviceInfoCollator.java
│ │ └── ui
│ │ ├── common
│ │ ├── AlertDialogFragment.java
│ │ ├── ColorProvider.java
│ │ ├── DialogFactory.java
│ │ └── NotifyUser.java
│ │ ├── main
│ │ ├── KeyEventConsumptionChecker.java
│ │ ├── MainActivity.java
│ │ ├── View.java
│ │ ├── ViewState.java
│ │ ├── export
│ │ │ ├── DeviceInfo.java
│ │ │ ├── Exporter.java
│ │ │ └── WriteToDiskDelegate.java
│ │ ├── logview
│ │ │ ├── Line.java
│ │ │ ├── LogViewWrapper.java
│ │ │ └── SpannableTextFormatHelper.java
│ │ └── markup
│ │ │ ├── LineMarkup.java
│ │ │ ├── LineMarkupFactory.java
│ │ │ └── Tag.java
│ │ └── tv
│ │ └── TvActivity.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_close.png
│ ├── ic_info.png
│ ├── ic_save.png
│ └── ic_share.png
│ ├── drawable-mdpi
│ ├── ic_close.png
│ ├── ic_info.png
│ ├── ic_save.png
│ └── ic_share.png
│ ├── drawable-xhdpi
│ ├── ic_close.png
│ ├── ic_info.png
│ ├── ic_save.png
│ └── ic_share.png
│ ├── drawable-xxhdpi
│ ├── ic_close.png
│ ├── ic_info.png
│ ├── ic_save.png
│ └── ic_share.png
│ ├── drawable-xxxhdpi
│ ├── ic_close.png
│ ├── ic_info.png
│ ├── ic_save.png
│ └── ic_share.png
│ ├── layout
│ ├── activity_main.xml
│ └── dialog_textview.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ ├── banner_android_tv.png
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-v21
│ └── styles.xml
│ └── values
│ ├── arrays.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── buildconstants
├── android-sdk-versions.gradle
└── dependency-versions.gradle
├── buildsystem
├── android-defaults.gradle
├── apkdetails
│ └── apkdetails-1.2.2.jar
├── codequality
│ └── lint.xml
├── common-methods.gradle
├── generate_dependency_hashfile.sh
├── jacocoxml
│ └── jacocoxmlparser-1.0.0.jar
├── multidex
│ └── multidex.pro
├── proguard-rules
│ ├── dagger2-rules.pro
│ ├── gson-rules.pro
│ └── kotlin-rules.pro
└── signing_keys
│ └── debug.keystore
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── KeyEventDisplay.svg
└── KeyEventDisplay_512.png
├── import-summary.txt
├── keyevent-display.iml
├── monitors
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── uk
│ └── co
│ └── alt236
│ └── keyeventdisplay
│ └── monitors
│ ├── Filter.java
│ ├── Monitor.java
│ ├── MonitorCallback.java
│ ├── kernel
│ └── KernelLogMonitor.java
│ ├── logcat
│ └── LogCatMonitor.java
│ └── util
│ ├── ClosableHelper.java
│ └── ProcessWrapper.java
├── print_codecov.sh
└── settings.gradle
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | ##
4 | ## REFERENCES
5 | ################################################################
6 | references:
7 |
8 | #
9 | # CONFIGURATION
10 | #
11 | workspace: &workspace
12 | ~/code
13 |
14 | environment_config: &environment_config
15 | working_directory: *workspace
16 | docker:
17 | - image: circleci/android:api-29
18 | environment:
19 | JVM_OPTS: -Xmx2048m
20 | GRADLE_OPTS: -Xmx1536m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false
21 |
22 | #
23 | # CACHE CONTROL
24 | #
25 | generate_dependency_hashfile: &generate_dependency_hashfile
26 | run:
27 | name: Generate Dependency Hashfile
28 | command: ./buildsystem/generate_dependency_hashfile.sh ./ ./dependency_hashfile.tmp
29 |
30 | print_dependency_hashfile: &print_dependency_hashfile
31 | run:
32 | name: Print Dependency Hashfile Contents
33 | command: cat ./dependency_hashfile.tmp
34 |
35 | cache_key: &cache_key
36 | key: cache-v1-{{ checksum "dependency_hashfile.tmp" }}
37 |
38 | cache_key_fallback: &cache_key_fallback
39 | key: cache-v1-
40 |
41 | restore_cache: &restore_cache
42 | restore_cache:
43 | <<: *cache_key
44 | <<: *cache_key_fallback
45 |
46 | save_cache: &save_cache
47 | save_cache:
48 | <<: *cache_key
49 | paths:
50 | - ~/.gradle
51 | - ~/.m2
52 |
53 | #
54 | # DOWNLOADING DEPENDENCIES
55 | #
56 | download_android_dependencies: &download_android_dependencies
57 | run:
58 | name: Download Dependencies
59 | command: ./gradlew dependencies androidDependencies
60 |
61 | #
62 | # RUNNING UNIT TESTS
63 | #
64 | run_android_lint: &run_android_lint
65 | run:
66 | name: Running lint
67 | command: ./gradlew lintDebug
68 |
69 | run_unit_tests: &run_unit_tests
70 | run:
71 | name: Running unit tests
72 | command: ./gradlew testDebug monitors:testDebug
73 |
74 | produce_code_coverage: &produce_code_coverage
75 | run:
76 | name: Producing Code Coverage
77 | command: ./gradlew jacocoTestReport
78 |
79 | print_code_coverage: &print_code_coverage
80 | run:
81 | name: Printing code coverage
82 | command: ./print_codecov.sh
83 |
84 | #
85 | # BUILDING DEBUG APKS (FOR FIREBASE)
86 | #
87 | build_debug_apks: &build_debug_apks
88 | run:
89 | name: Building Debug APKs
90 | command: |
91 | ./gradlew assembleDebug
92 |
93 | #
94 | # BUILDING RELEASE APKS
95 | #
96 | build_release_apks: &build_release_apks
97 | run:
98 | name: Building Release APKs
99 | command: |
100 | ./gradlew assembleRelease
101 |
102 | setup_environment: &setup_environment
103 | run:
104 | name: Setup environment
105 | command: |
106 | echo "$ENCODED_KEYSTORE" | base64 -di >> "${HOME}"/keystore.jks
107 | echo "$ENCODED_GPLAY_DEPLOY_KEY" | base64 -di --decode >> "${HOME}"/deployment_private_key.json
108 | echo "export ANDROID_KEYSTORE=${HOME}/keystore.jks" >> "$BASH_ENV"
109 | echo "export GPLAY_DEPLOY_KEY=${HOME}/deployment_private_key.json" >> "$BASH_ENV"
110 |
111 | ##
112 | ## COMMANDS
113 | ################################################################
114 | commands:
115 | upload_test_results_and_artifacts:
116 | description: "Upload the test reports and artifacts for a given module"
117 | parameters:
118 | module_name:
119 | type: string
120 | default: "[MISSING]"
121 | steps:
122 | - store_artifacts:
123 | path: << parameters.module_name >>/build/reports
124 | destination: reports-<< parameters.module_name >>
125 | - store_test_results:
126 | path: << parameters.module_name >>/build/test-results
127 |
128 | upload_apks_to_ci:
129 | description: "Upload the APKs generated for a given module"
130 | parameters:
131 | module_name:
132 | type: string
133 | default: "[MISSING]"
134 | steps:
135 | - store_artifacts:
136 | path: << parameters.module_name >>/build/outputs/apk
137 | destination: apks-<< parameters.module_name >>
138 |
139 | print_apk_info:
140 | description: "Collect information of compiled APKs"
141 | parameters:
142 | module_name:
143 | type: string
144 | default: "[MISSING]"
145 | steps:
146 | - run:
147 | name: "Collect information of compiled APKs"
148 | when: on_success
149 | command: ./apkdetails.sh -i << parameters.module_name >>/build/outputs/apk/ -r -h -v
150 |
151 | setup_dependency_cache:
152 | description: "Restore (if present) populate and save (if needed) the dependency cache"
153 | steps:
154 | - *generate_dependency_hashfile
155 | - *print_dependency_hashfile
156 | - *restore_cache
157 | - *download_android_dependencies
158 |
159 | deploy_to_google_play:
160 | description: "Deploy APKs to Google Play"
161 | parameters:
162 | only_for_branch:
163 | type: string
164 | default: "[MISSING]"
165 | steps:
166 | - deploy:
167 | name: "Deploy to Google Play"
168 | when: on_success
169 | command: |
170 | if [ "${CIRCLE_BRANCH}" == "<< parameters.only_for_branch >>" ]; then
171 | ./gradlew app:publish
172 | else
173 | echo "Branch is not '<< parameters.only_for_branch >>'. Skipping deployment."
174 | fi
175 |
176 | ##
177 | ## JOBS
178 | ################################################################
179 | jobs:
180 | local_test:
181 | <<: *environment_config
182 | steps:
183 | - checkout
184 | - *setup_environment
185 | - setup_dependency_cache
186 | - *run_unit_tests
187 | - *produce_code_coverage # Produce code coverage needs to be straight after running unit tests
188 | - *print_code_coverage
189 | - *run_android_lint
190 | - *build_debug_apks
191 | - *build_release_apks
192 | - *save_cache # Moved after test runs to capture dep downloads from the previous step
193 | - print_apk_info:
194 | module_name: "app"
195 | - persist_to_workspace:
196 | root: *workspace
197 | paths:
198 | - app/build/
199 | - monitors/build/
200 | - upload_test_results_and_artifacts:
201 | module_name: "app"
202 | - upload_test_results_and_artifacts:
203 | module_name: "monitors"
204 | - upload_apks_to_ci:
205 | module_name: "app"
206 | - deploy_to_google_play:
207 | only_for_branch: "master"
208 |
209 | workflows:
210 | version: 2.1
211 | build-and-deploy:
212 | jobs:
213 | - local_test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/kotlin,java,android,androidstudio,intellij
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=kotlin,java,android,androidstudio,intellij
4 |
5 | ### Android ###
6 | # Built application files
7 | *.apk
8 | *.aar
9 | *.ap_
10 | *.aab
11 |
12 | # Files for the ART/Dalvik VM
13 | *.dex
14 |
15 | # Java class files
16 | *.class
17 |
18 | # Generated files
19 | bin/
20 | gen/
21 | out/
22 | # Uncomment the following line in case you need and you don't have the release build type files in your app
23 | # release/
24 |
25 | # Gradle files
26 | .gradle/
27 | build/
28 |
29 | # Local configuration file (sdk path, etc)
30 | local.properties
31 |
32 | # Proguard folder generated by Eclipse
33 | proguard/
34 |
35 | # Log Files
36 | *.log
37 |
38 | # Android Studio Navigation editor temp files
39 | .navigation/
40 |
41 | # Android Studio captures folder
42 | captures/
43 |
44 | # IntelliJ
45 | *.iml
46 | .idea/workspace.xml
47 | .idea/tasks.xml
48 | .idea/gradle.xml
49 | .idea/assetWizardSettings.xml
50 | .idea/dictionaries
51 | .idea/libraries
52 | # Android Studio 3 in .gitignore file.
53 | .idea/caches
54 | .idea/modules.xml
55 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
56 | .idea/navEditor.xml
57 |
58 | # Keystore files
59 | # Uncomment the following lines if you do not want to check your keystore files in.
60 | #*.jks
61 | #*.keystore
62 |
63 | # External native build folder generated in Android Studio 2.2 and later
64 | .externalNativeBuild
65 | .cxx/
66 |
67 | # Google Services (e.g. APIs or Firebase)
68 | # google-services.json
69 |
70 | # Freeline
71 | freeline.py
72 | freeline/
73 | freeline_project_description.json
74 |
75 | # fastlane
76 | fastlane/report.xml
77 | fastlane/Preview.html
78 | fastlane/screenshots
79 | fastlane/test_output
80 | fastlane/readme.md
81 |
82 | # Version control
83 | vcs.xml
84 |
85 | # lint
86 | lint/intermediates/
87 | lint/generated/
88 | lint/outputs/
89 | lint/tmp/
90 | # lint/reports/
91 |
92 | ### Android Patch ###
93 | gen-external-apklibs
94 | output.json
95 |
96 | # Replacement of .externalNativeBuild directories introduced
97 | # with Android Studio 3.5.
98 |
99 | ### Intellij ###
100 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
101 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
102 |
103 | # User-specific stuff
104 | .idea/**/workspace.xml
105 | .idea/**/tasks.xml
106 | .idea/**/usage.statistics.xml
107 | .idea/**/dictionaries
108 | .idea/**/shelf
109 |
110 | # Generated files
111 | .idea/**/contentModel.xml
112 |
113 | # Sensitive or high-churn files
114 | .idea/**/dataSources/
115 | .idea/**/dataSources.ids
116 | .idea/**/dataSources.local.xml
117 | .idea/**/sqlDataSources.xml
118 | .idea/**/dynamic.xml
119 | .idea/**/uiDesigner.xml
120 | .idea/**/dbnavigator.xml
121 |
122 | # Gradle
123 | .idea/**/gradle.xml
124 | .idea/**/libraries
125 |
126 | # Gradle and Maven with auto-import
127 | # When using Gradle or Maven with auto-import, you should exclude module files,
128 | # since they will be recreated, and may cause churn. Uncomment if using
129 | # auto-import.
130 | .idea/artifacts
131 | .idea/compiler.xml
132 | .idea/jarRepositories.xml
133 | .idea/modules.xml
134 | .idea/*.iml
135 | .idea/modules
136 | *.iml
137 | *.ipr
138 |
139 | # CMake
140 | cmake-build-*/
141 |
142 | # Mongo Explorer plugin
143 | .idea/**/mongoSettings.xml
144 |
145 | # File-based project format
146 | *.iws
147 |
148 | # IntelliJ
149 |
150 | # mpeltonen/sbt-idea plugin
151 | .idea_modules/
152 |
153 | # JIRA plugin
154 | atlassian-ide-plugin.xml
155 |
156 | # Cursive Clojure plugin
157 | .idea/replstate.xml
158 |
159 | # Crashlytics plugin (for Android Studio and IntelliJ)
160 | com_crashlytics_export_strings.xml
161 | crashlytics.properties
162 | crashlytics-build.properties
163 | fabric.properties
164 |
165 | # Editor-based Rest Client
166 | .idea/httpRequests
167 |
168 | # Android studio 3.1+ serialized cache file
169 | .idea/caches/build_file_checksums.ser
170 |
171 | ### Intellij Patch ###
172 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
173 |
174 | # *.iml
175 | # modules.xml
176 | # .idea/misc.xml
177 | # *.ipr
178 |
179 | # Sonarlint plugin
180 | .idea/**/sonarlint/
181 |
182 | # SonarQube Plugin
183 | .idea/**/sonarIssues.xml
184 |
185 | # Markdown Navigator plugin
186 | .idea/**/markdown-navigator.xml
187 | .idea/**/markdown-navigator-enh.xml
188 | .idea/**/markdown-navigator/
189 |
190 | # Cache file creation bug
191 | # See https://youtrack.jetbrains.com/issue/JBR-2257
192 | .idea/$CACHE_FILE$
193 |
194 | ### Java ###
195 | # Compiled class file
196 |
197 | # Log file
198 |
199 | # BlueJ files
200 | *.ctxt
201 |
202 | # Mobile Tools for Java (J2ME)
203 | .mtj.tmp/
204 |
205 | # Package Files #
206 | *.jar
207 | *.war
208 | *.nar
209 | *.ear
210 | *.zip
211 | *.tar.gz
212 | *.rar
213 |
214 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
215 | hs_err_pid*
216 |
217 | ### Kotlin ###
218 | # Compiled class file
219 |
220 | # Log file
221 |
222 | # BlueJ files
223 |
224 | # Mobile Tools for Java (J2ME)
225 |
226 | # Package Files #
227 |
228 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
229 |
230 | ### AndroidStudio ###
231 | # Covers files to be ignored for android development using Android Studio.
232 |
233 | # Built application files
234 |
235 | # Files for the ART/Dalvik VM
236 |
237 | # Java class files
238 |
239 | # Generated files
240 |
241 | # Gradle files
242 | .gradle
243 |
244 | # Signing files
245 | .signing/
246 |
247 | # Local configuration file (sdk path, etc)
248 |
249 | # Proguard folder generated by Eclipse
250 |
251 | # Log Files
252 |
253 | # Android Studio
254 | /*/build/
255 | /*/local.properties
256 | /*/out
257 | /*/*/build
258 | /*/*/production
259 | *.ipr
260 | *~
261 | *.swp
262 |
263 | # Android Patch
264 |
265 | # External native build folder generated in Android Studio 2.2 and later
266 |
267 | # NDK
268 | obj/
269 |
270 | # IntelliJ IDEA
271 | /out/
272 |
273 | # User-specific configurations
274 | .idea/caches/
275 | .idea/libraries/
276 | .idea/shelf/
277 | .idea/.name
278 | .idea/compiler.xml
279 | .idea/copyright/profiles_settings.xml
280 | .idea/encodings.xml
281 | .idea/misc.xml
282 | .idea/scopes/scope_settings.xml
283 | .idea/vcs.xml
284 | .idea/jsLibraryMappings.xml
285 | .idea/datasources.xml
286 | .idea/dataSources.ids
287 | .idea/sqlDataSources.xml
288 | .idea/dynamic.xml
289 | .idea/uiDesigner.xml
290 |
291 | # OS-specific files
292 | .DS_Store
293 | .DS_Store?
294 | ._*
295 | .Spotlight-V100
296 | .Trashes
297 | ehthumbs.db
298 | Thumbs.db
299 |
300 | # Legacy Eclipse project files
301 | .classpath
302 | .project
303 | .cproject
304 | .settings/
305 |
306 | # Mobile Tools for Java (J2ME)
307 |
308 | # Package Files #
309 |
310 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
311 |
312 | ## Plugin-specific files:
313 |
314 | # mpeltonen/sbt-idea plugin
315 |
316 | # JIRA plugin
317 |
318 | # Mongo Explorer plugin
319 | .idea/mongoSettings.xml
320 |
321 | # Crashlytics plugin (for Android Studio and IntelliJ)
322 |
323 | ### AndroidStudio Patch ###
324 |
325 | !/gradle/wrapper/gradle-wrapper.jar
326 | !/buildsystem/**/*.jar
327 | # End of https://www.toptal.com/developers/gitignore/api/kotlin,java,android,androidstudio,intellij
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
9 |
22 |
27 |
39 |
11 | Apache License
12 | Version 2.0, January 2004
13 | http://www.apache.org/licenses/
14 |
16 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 17 |
18 | 19 |20 | "License" shall mean the terms and conditions for use, reproduction, 21 | and distribution as defined by Sections 1 through 9 of this document. 22 |
23 |24 | "Licensor" shall mean the copyright owner or entity authorized by 25 | the copyright owner that is granting the License. 26 |
27 |28 | "Legal Entity" shall mean the union of the acting entity and all 29 | other entities that control, are controlled by, or are under common 30 | control with that entity. For the purposes of this definition, 31 | "control" means (i) the power, direct or indirect, to cause the 32 | direction or management of such entity, whether by contract or 33 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 34 | outstanding shares, or (iii) beneficial ownership of such entity. 35 |
36 |37 | "You" (or "Your") shall mean an individual or Legal Entity 38 | exercising permissions granted by this License. 39 |
40 |41 | "Source" form shall mean the preferred form for making modifications, 42 | including but not limited to software source code, documentation 43 | source, and configuration files. 44 |
45 |46 | "Object" form shall mean any form resulting from mechanical 47 | transformation or translation of a Source form, including but 48 | not limited to compiled object code, generated documentation, 49 | and conversions to other media types. 50 |
51 |52 | "Work" shall mean the work of authorship, whether in Source or 53 | Object form, made available under the License, as indicated by a 54 | copyright notice that is included in or attached to the work 55 | (an example is provided in the Appendix below). 56 |
57 |58 | "Derivative Works" shall mean any work, whether in Source or Object 59 | form, that is based on (or derived from) the Work and for which the 60 | editorial revisions, annotations, elaborations, or other modifications 61 | represent, as a whole, an original work of authorship. For the purposes 62 | of this License, Derivative Works shall not include works that remain 63 | separable from, or merely link (or bind by name) to the interfaces of, 64 | the Work and Derivative Works thereof. 65 |
66 |67 | "Contribution" shall mean any work of authorship, including 68 | the original version of the Work and any modifications or additions 69 | to that Work or Derivative Works thereof, that is intentionally 70 | submitted to Licensor for inclusion in the Work by the copyright owner 71 | or by an individual or Legal Entity authorized to submit on behalf of 72 | the copyright owner. For the purposes of this definition, "submitted" 73 | means any form of electronic, verbal, or written communication sent 74 | to the Licensor or its representatives, including but not limited to 75 | communication on electronic mailing lists, source code control systems, 76 | and issue tracking systems that are managed by, or on behalf of, the 77 | Licensor for the purpose of discussing and improving the Work, but 78 | excluding communication that is conspicuously marked or otherwise 79 | designated in writing by the copyright owner as "Not a Contribution." 80 |
81 |82 | "Contributor" shall mean Licensor and any individual or Legal Entity 83 | on behalf of whom a Contribution has been received by Licensor and 84 | subsequently incorporated within the Work. 85 |
86 |2. Grant of Copyright License. 87 | Subject to the terms and conditions of 88 | this License, each Contributor hereby grants to You a perpetual, 89 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 90 | copyright license to reproduce, prepare Derivative Works of, 91 | publicly display, publicly perform, sublicense, and distribute the 92 | Work and such Derivative Works in Source or Object form. 93 |
94 |3. Grant of Patent License. 95 | Subject to the terms and conditions of 96 | this License, each Contributor hereby grants to You a perpetual, 97 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 98 | (except as stated in this section) patent license to make, have made, 99 | use, offer to sell, sell, import, and otherwise transfer the Work, 100 | where such license applies only to those patent claims licensable 101 | by such Contributor that are necessarily infringed by their 102 | Contribution(s) alone or by combination of their Contribution(s) 103 | with the Work to which such Contribution(s) was submitted. If You 104 | institute patent litigation against any entity (including a 105 | cross-claim or counterclaim in a lawsuit) alleging that the Work 106 | or a Contribution incorporated within the Work constitutes direct 107 | or contributory patent infringement, then any patent licenses 108 | granted to You under this License for that Work shall terminate 109 | as of the date such litigation is filed. 110 |
111 |4. Redistribution. 112 | You may reproduce and distribute copies of the 113 | Work or Derivative Works thereof in any medium, with or without 114 | modifications, and in Source or Object form, provided that You 115 | meet the following conditions: 116 |
5. Submission of Contributions. 157 | Unless You explicitly state otherwise, 158 | any Contribution intentionally submitted for inclusion in the Work 159 | by You to the Licensor shall be under the terms and conditions of 160 | this License, without any additional terms or conditions. 161 | Notwithstanding the above, nothing herein shall supersede or modify 162 | the terms of any separate license agreement you may have executed 163 | with Licensor regarding such Contributions. 164 |
165 |6. Trademarks. 166 | This License does not grant permission to use the trade 167 | names, trademarks, service marks, or product names of the Licensor, 168 | except as required for reasonable and customary use in describing the 169 | origin of the Work and reproducing the content of the NOTICE file. 170 |
171 |7. Disclaimer of Warranty. 172 | Unless required by applicable law or 173 | agreed to in writing, Licensor provides the Work (and each 174 | Contributor provides its Contributions) on an "AS IS" BASIS, 175 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 176 | implied, including, without limitation, any warranties or conditions 177 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 178 | PARTICULAR PURPOSE. You are solely responsible for determining the 179 | appropriateness of using or redistributing the Work and assume any 180 | risks associated with Your exercise of permissions under this License. 181 |
182 |8. Limitation of Liability. 183 | In no event and under no legal theory, 184 | whether in tort (including negligence), contract, or otherwise, 185 | unless required by applicable law (such as deliberate and grossly 186 | negligent acts) or agreed to in writing, shall any Contributor be 187 | liable to You for damages, including any direct, indirect, special, 188 | incidental, or consequential damages of any character arising as a 189 | result of this License or out of the use or inability to use the 190 | Work (including but not limited to damages for loss of goodwill, 191 | work stoppage, computer failure or malfunction, or any and all 192 | other commercial damages or losses), even if such Contributor 193 | has been advised of the possibility of such damages. 194 |
195 |9. Accepting Warranty or Additional Liability. 196 | While redistributing 197 | the Work or Derivative Works thereof, You may choose to offer, 198 | and charge a fee for, acceptance of support, warranty, indemnity, 199 | or other liability obligations and/or rights consistent with this 200 | License. However, in accepting such obligations, You may act only 201 | on Your own behalf and on Your sole responsibility, not on behalf 202 | of any other Contributor, and only if You agree to indemnify, 203 | defend, and hold each Contributor harmless for any liability 204 | incurred by, or claims asserted against, such Contributor by reason 205 | of your accepting any such warranty or additional liability. 206 |
207 |208 | END OF TERMS AND CONDITIONS 209 |
210 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | KeyEvent Display - Android 2 | ======================== 3 | 4 | Once, I was playing with a number of Chinese tablets and trying different ROMs on them as they are technically the same hardware ([HSG X5A variants](http://www.huashiguang.com/MID.html)). 5 | 6 | I've had some problems getting the hard buttons to work though, so I wrote this application to detect key events and print them out. It will print out the following: 7 | 8 | * KeyEvents: The KeyEvents as Android understands them (KeyUp, KeyDown, KeyLongPress, KeyMultiple) 9 | 10 | * LogCat: Any relevant messages in logcat. Its filtered based on keywords declared in `arrays.xml` 11 | 12 | * Kernel: Any relevant messages in the kernel log. Its filtered based on keywords declared in `arrays.xml`. Kernel log parsing needs root. 13 | 14 | 15 | The three checkboxes at the top control what information will be displayed. 16 | 17 | 18 | * This is a personal debug tool, but I hope it will be of some use to someone else. 19 | 20 | * No Ads. 21 | 22 | Notes 23 | ----------- 24 | * While the application is running, the only "hard" keys which should work is "Home" and power. All others will produce their keycodes. 25 | 26 | * The SU request is to read the kernel log, so I can check if any keyevents are thrown by the kernel. 27 | 28 | * The location of keylayout files in Android is `/system/usr/keylayout`. 29 | 30 | * Kernel log parsing needs root 31 | 32 | * Both logcat and kernel log monitoring will only display lines containing words from two arrays in `arrays.xml` 33 | 34 | Currently the filters are: 35 | 36 | 37 | 1. Logcat: 38 | 1. HwGPIOE->GPDA 39 | 1. keycode 40 | 1. keycharacter 41 | 1. Kernel: 42 | 1. HwGPIOE->GPDA 43 | 1. keycode 44 | 1. keycharacter 45 | 46 | Permission Explanation 47 | -------------- 48 | * `READ_LOGS`: Used to access the Logcat log. 49 | * `WRITE_EXTERNAL_STORAGE`: Used to write the exported data to the SD card. 50 | 51 | Changelog 52 | -------------- 53 | * v0.0.1: First public release. 54 | * v0.0.2: Improved stability, added Exit button. 55 | * v0.0.3: Code updates. 56 | * v1.0.0: Redesign, added Android TV support. 57 | 58 | Links 59 | ------- 60 | * Market link: [https://market.android.com/details?id=aws.apps.keyeventdisplay](https://market.android.com/details?id=aws.apps.keyeventdisplay) 61 | * Webpage: [http://aschillings.co.uk/html/keyevent_display.html](http://aschillings.co.uk/html/keyevent_display.html) 62 | * Github: [https://github.com/alt236/KeyEvent-Display---Android](https://github.com/alt236/KeyEvent-Display---Android) 63 | 64 | Credits 65 | ------- 66 | 67 | Author: Alexandros Schillings. 68 | 69 | All logos are the property of their respective owners 70 | 71 | The code in this project is licensed under the [Apache Software License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). 72 | 73 | Copyright (c) 2011 Alexandros Schillings. 74 | -------------------------------------------------------------------------------- /apkdetails.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -o xtrace 5 | java -jar ./buildsystem/apkdetails/apkdetails-1.2.2.jar "$@" 6 | set +o xtrace -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 |4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package aws.apps.keyeventdisplay.ui.main; 17 | 18 | import android.os.Bundle; 19 | import android.util.Log; 20 | import android.view.KeyEvent; 21 | 22 | import androidx.appcompat.app.AppCompatActivity; 23 | import aws.apps.keyeventdisplay.R; 24 | import aws.apps.keyeventdisplay.ui.common.ColorProvider; 25 | import aws.apps.keyeventdisplay.ui.common.DialogFactory; 26 | import aws.apps.keyeventdisplay.ui.common.NotifyUser; 27 | import aws.apps.keyeventdisplay.ui.main.export.Exporter; 28 | import aws.apps.keyeventdisplay.ui.main.export.WriteToDiskDelegate; 29 | import aws.apps.keyeventdisplay.ui.main.markup.LineMarkup; 30 | import aws.apps.keyeventdisplay.ui.main.markup.LineMarkupFactory; 31 | import uk.co.alt236.keyeventdisplay.monitors.Monitor; 32 | import uk.co.alt236.keyeventdisplay.monitors.MonitorCallback; 33 | import uk.co.alt236.keyeventdisplay.monitors.kernel.KernelLogMonitor; 34 | import uk.co.alt236.keyeventdisplay.monitors.logcat.LogCatMonitor; 35 | 36 | public class MainActivity extends AppCompatActivity { 37 | private final static String TAG = MainActivity.class.getSimpleName(); 38 | 39 | private static final int LAYOUT_ID = R.layout.activity_main; 40 | 41 | private WriteToDiskDelegate writeToDiskDelegate; 42 | private Monitor logCatMonitor; 43 | private Monitor kernelMonitor; 44 | private NotifyUser notifyUser; 45 | private Exporter exporter; 46 | private aws.apps.keyeventdisplay.ui.main.View view; 47 | private LineMarkupFactory markupFactory; 48 | private KeyEventConsumptionChecker keyEventConsumptionChecker; 49 | 50 | @Override 51 | public void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | Log.d(TAG, "Starting: " + this.getClass().getName()); 54 | 55 | setContentView(LAYOUT_ID); 56 | 57 | final ColorProvider colorProvider = new ColorProvider(getResources(), getTheme()); 58 | 59 | markupFactory = new LineMarkupFactory(colorProvider); 60 | keyEventConsumptionChecker = new KeyEventConsumptionChecker(); 61 | 62 | view = new aws.apps.keyeventdisplay.ui.main.View(colorProvider); 63 | view.bind(this); 64 | 65 | view.setClearLogButtonListener(v -> view.clearLog()); 66 | view.setAppendBreakButtonListener(v -> view.appendBreakToLog()); 67 | view.setAboutButtonListener(v -> showAboutDialog()); 68 | view.setExitButtonListener(v -> quitApp()); 69 | view.setShareLogButtonListener(v -> shareLog()); 70 | view.setSaveLogButtonListener(v -> saveLogToDisk()); 71 | 72 | notifyUser = new NotifyUser(this); 73 | exporter = new Exporter(this, notifyUser); 74 | writeToDiskDelegate = new WriteToDiskDelegate(this, exporter, notifyUser); 75 | 76 | final String[] logCatFilter = getResources().getStringArray(R.array.logcat_filter); 77 | final String[] kernelFilter = getResources().getStringArray(R.array.kmsg_filter); 78 | logCatMonitor = new LogCatMonitor(logCatFilter); 79 | kernelMonitor = new KernelLogMonitor(kernelFilter); 80 | 81 | final Object lastState = getLastCustomNonConfigurationInstance(); 82 | if (lastState != null) { 83 | view.setState((ViewState) lastState); 84 | } 85 | } 86 | 87 | @Override 88 | public boolean onKeyDown(int keyCode, KeyEvent event) { 89 | final LineMarkup markup = markupFactory.getForKeyDown(); 90 | addKeyEventLine(markup, event); 91 | return keyEventConsumptionChecker.shouldConsumeEvent(event); 92 | } 93 | 94 | @Override 95 | public boolean onKeyLongPress(int keyCode, KeyEvent event) { 96 | final LineMarkup markup = markupFactory.getForKeyLongPress(); 97 | addKeyEventLine(markup, event); 98 | return keyEventConsumptionChecker.shouldConsumeEvent(event); 99 | } 100 | 101 | @Override 102 | public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { 103 | final LineMarkup markup = markupFactory.getForKeyMultiple(); 104 | addKeyEventLine(markup, event); 105 | return keyEventConsumptionChecker.shouldConsumeEvent(event); 106 | } 107 | 108 | @Override 109 | public boolean onKeyUp(int keyCode, KeyEvent event) { 110 | final LineMarkup markup = markupFactory.getForKeyUp(); 111 | addKeyEventLine(markup, event); 112 | return keyEventConsumptionChecker.shouldConsumeEvent(event); 113 | } 114 | 115 | @Override 116 | public Object onRetainCustomNonConfigurationInstance() { 117 | return view.getState(); 118 | } 119 | 120 | @Override 121 | public void onStart() { 122 | Log.d(TAG, "^ onStart called"); 123 | 124 | logCatMonitor.startMonitor(new MonitorCallback() { 125 | @Override 126 | public void onError(final String msg, final Throwable e) { 127 | runOnUiThread(() -> notifyUser.notifyLong("LogCatMonitor: " + msg + ": " + e)); 128 | } 129 | 130 | @Override 131 | public void onNewline(String line) { 132 | runOnUiThread(() -> addLogCatLine(line)); 133 | } 134 | }); 135 | 136 | kernelMonitor.startMonitor(new MonitorCallback() { 137 | @Override 138 | public void onError(final String msg, final Throwable e) { 139 | runOnUiThread(() -> notifyUser.notifyLong("KernelLogMonitor: " + msg + ": " + e)); 140 | } 141 | 142 | @Override 143 | public void onNewline(String line) { 144 | runOnUiThread(() -> addKernelLine(line)); 145 | } 146 | 147 | }); 148 | super.onStart(); 149 | } 150 | 151 | @Override 152 | public void onStop() { 153 | Log.d(TAG, "^ onStop called"); 154 | logCatMonitor.stopMonitor(); 155 | kernelMonitor.stopMonitor(); 156 | super.onStop(); 157 | } 158 | 159 | private void addKernelLine(String text) { 160 | if (view.isKernelChecked()) { 161 | final LineMarkup markup = markupFactory.getForKernel(); 162 | view.appendLogLine(markup.getTag(), text, markup.getColour()); 163 | } 164 | } 165 | 166 | private void addLogCatLine(String text) { 167 | if (view.isLogcatChecked()) { 168 | final LineMarkup markup = markupFactory.getForLogcat(); 169 | view.appendLogLine(markup.getTag(), text, markup.getColour()); 170 | } 171 | } 172 | 173 | private void addKeyEventLine(final LineMarkup markup, 174 | final KeyEvent event) { 175 | if (view.isKeyEventsChecked()) { 176 | view.appendKeyEvent(markup.getTag(), event, markup.getColour()); 177 | } 178 | } 179 | 180 | private void quitApp() { 181 | onStop(); 182 | System.exit(0); 183 | } 184 | 185 | private void showAboutDialog() { 186 | DialogFactory.createAboutDialog(this).show(getSupportFragmentManager(), "ALERT_DIALOG"); 187 | } 188 | 189 | private void saveLogToDisk() { 190 | final String text = view.getEventLogText().toString(); 191 | final boolean isSharable = isSharable(text); 192 | 193 | if (isSharable) { 194 | writeToDiskDelegate.saveLogToDisk(text); 195 | } else { 196 | notifyUser.notifyShort(R.string.nothing_to_save); 197 | } 198 | } 199 | 200 | private void shareLog() { 201 | final String text = view.getEventLogText().toString(); 202 | final boolean isSharable = isSharable(text); 203 | 204 | if (isSharable) { 205 | exporter.share(text); 206 | } else { 207 | notifyUser.notifyShort(R.string.nothing_to_share); 208 | } 209 | } 210 | 211 | private boolean isSharable(final String content) { 212 | final String startText = getString(R.string.greeting); 213 | 214 | return content != null 215 | && !content.isEmpty() 216 | && !startText.equals(content); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /app/src/main/java/aws/apps/keyeventdisplay/ui/main/View.java: -------------------------------------------------------------------------------- 1 | package aws.apps.keyeventdisplay.ui.main; 2 | 3 | import android.app.Activity; 4 | import android.view.KeyEvent; 5 | import android.widget.Button; 6 | import android.widget.CheckBox; 7 | import android.widget.ImageButton; 8 | import android.widget.TextView; 9 | 10 | import aws.apps.keyeventdisplay.R; 11 | import aws.apps.keyeventdisplay.ui.common.ColorProvider; 12 | import aws.apps.keyeventdisplay.ui.main.logview.LogViewWrapper; 13 | 14 | class View { 15 | private final ColorProvider colorProvider; 16 | private LogViewWrapper eventLogWrapper; 17 | 18 | private CheckBox chkKernel; 19 | private CheckBox chkKeyEvents; 20 | private CheckBox chkLogcat; 21 | private Button btnClearLog; 22 | private Button btnAddBreakToLog; 23 | private ImageButton btnSaveLog; 24 | private ImageButton btnShareLog; 25 | private ImageButton btnAbout; 26 | private ImageButton btnExit; 27 | private TextView eventLog; 28 | 29 | View(final ColorProvider colorProvider) { 30 | this.colorProvider = colorProvider; 31 | } 32 | 33 | void bind(final Activity activity) { 34 | chkKernel = activity.findViewById(R.id.chkKernel); 35 | chkKeyEvents = activity.findViewById(R.id.chkKeyEvents); 36 | chkLogcat = activity.findViewById(R.id.chkLogCat); 37 | btnClearLog = activity.findViewById(R.id.btnClear); 38 | btnAddBreakToLog = activity.findViewById(R.id.btnBreak); 39 | btnSaveLog = activity.findViewById(R.id.btnSave); 40 | btnShareLog = activity.findViewById(R.id.btnShare); 41 | btnAbout = activity.findViewById(R.id.btnAbout); 42 | btnExit = activity.findViewById(R.id.btnExit); 43 | eventLog = activity.findViewById(R.id.fldEvent); 44 | 45 | eventLogWrapper = new LogViewWrapper(eventLog, colorProvider); 46 | } 47 | 48 | boolean isKernelChecked() { 49 | return chkKernel.isChecked(); 50 | } 51 | 52 | boolean isLogcatChecked() { 53 | return chkLogcat.isChecked(); 54 | } 55 | 56 | boolean isKeyEventsChecked() { 57 | return chkKeyEvents.isChecked(); 58 | } 59 | 60 | ViewState getState() { 61 | final ViewState state = new ViewState(); 62 | 63 | state.setChkKernel(isKernelChecked()); 64 | state.setChkLogcat(isLogcatChecked()); 65 | state.setChkKeyEvents(isKeyEventsChecked()); 66 | state.setLogText(eventLog.getText()); 67 | 68 | return state; 69 | } 70 | 71 | void setState(final ViewState viewState) { 72 | eventLog.setText(viewState.getLogText()); 73 | chkKernel.setChecked(viewState.isChkKernel()); 74 | chkKeyEvents.setChecked(viewState.isChkKeyEvents()); 75 | chkLogcat.setChecked(viewState.isChkLogcat()); 76 | eventLogWrapper.autoScroll(); 77 | } 78 | 79 | CharSequence getEventLogText() { 80 | return eventLog.getText(); 81 | } 82 | 83 | void appendLogLine(String title, String event, int color) { 84 | eventLogWrapper.appendLogLine(title, event, color); 85 | } 86 | 87 | void appendKeyEvent(String title, KeyEvent event, int color) { 88 | eventLogWrapper.appendKeyEvent(title, event, color); 89 | } 90 | 91 | void appendBreakToLog() { 92 | eventLogWrapper.appendBreak(); 93 | } 94 | 95 | void clearLog() { 96 | eventLogWrapper.clear(); 97 | } 98 | 99 | void setClearLogButtonListener(final android.view.View.OnClickListener listener) { 100 | btnClearLog.setOnClickListener(listener); 101 | } 102 | 103 | void setAppendBreakButtonListener(final android.view.View.OnClickListener listener) { 104 | btnAddBreakToLog.setOnClickListener(listener); 105 | } 106 | 107 | void setAboutButtonListener(final android.view.View.OnClickListener listener) { 108 | btnAbout.setOnClickListener(listener); 109 | } 110 | 111 | void setExitButtonListener(final android.view.View.OnClickListener listener) { 112 | btnExit.setOnClickListener(listener); 113 | } 114 | 115 | void setShareLogButtonListener(final android.view.View.OnClickListener listener) { 116 | btnShareLog.setOnClickListener(listener); 117 | } 118 | 119 | void setSaveLogButtonListener(final android.view.View.OnClickListener listener) { 120 | btnSaveLog.setOnClickListener(listener); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/aws/apps/keyeventdisplay/ui/main/ViewState.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2012 Alexandros Schillings 3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package aws.apps.keyeventdisplay.ui.main;
17 |
18 | /*package*/class ViewState {
19 | private CharSequence logText;
20 | private boolean chkKeyEvents;
21 | private boolean chkLogcat;
22 | private boolean chkKernel;
23 |
24 | public CharSequence getLogText() {
25 | return logText;
26 | }
27 |
28 | public void setLogText(CharSequence logText) {
29 | this.logText = logText;
30 | }
31 |
32 | public boolean isChkKernel() {
33 | return chkKernel;
34 | }
35 |
36 | public void setChkKernel(boolean chkKernel) {
37 | this.chkKernel = chkKernel;
38 | }
39 |
40 | public boolean isChkKeyEvents() {
41 | return chkKeyEvents;
42 | }
43 |
44 | public void setChkKeyEvents(boolean chkKeyEvents) {
45 | this.chkKeyEvents = chkKeyEvents;
46 | }
47 |
48 | public boolean isChkLogcat() {
49 | return chkLogcat;
50 | }
51 |
52 | public void setChkLogcat(boolean chkLogcat) {
53 | this.chkLogcat = chkLogcat;
54 | }
55 |
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/aws/apps/keyeventdisplay/ui/main/export/DeviceInfo.java:
--------------------------------------------------------------------------------
1 | package aws.apps.keyeventdisplay.ui.main.export;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.Map;
6 |
7 | import aws.apps.keyeventdisplay.deviceinfo.DeviceInfoCollator;
8 |
9 | /*package*/ final class DeviceInfo {
10 |
11 | private DeviceInfoCollator deviceInfoCollator;
12 |
13 | DeviceInfo(Context context) {
14 | this.deviceInfoCollator = new DeviceInfoCollator(context);
15 | }
16 |
17 | public void collectDeviceInfo(final StringBuilder sb) {
18 | final Map
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package uk.co.alt236.keyeventdisplay.monitors;
17 |
18 | public interface Monitor {
19 | int BUFFER_SIZE = 1024;
20 |
21 | void startMonitor(final MonitorCallback callback);
22 |
23 | void stopMonitor();
24 | }
25 |
--------------------------------------------------------------------------------
/monitors/src/main/java/uk/co/alt236/keyeventdisplay/monitors/MonitorCallback.java:
--------------------------------------------------------------------------------
1 | package uk.co.alt236.keyeventdisplay.monitors;
2 |
3 | public interface MonitorCallback {
4 | void onError(String msg, Throwable e);
5 |
6 | void onNewline(String line);
7 | }
8 |
--------------------------------------------------------------------------------
/monitors/src/main/java/uk/co/alt236/keyeventdisplay/monitors/kernel/KernelLogMonitor.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Alexandros Schillings
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package uk.co.alt236.keyeventdisplay.monitors.kernel;
17 |
18 | import android.util.Log;
19 |
20 | import java.io.BufferedReader;
21 | import java.io.DataInputStream;
22 | import java.io.IOException;
23 | import java.io.InputStreamReader;
24 | import java.io.OutputStreamWriter;
25 |
26 | import uk.co.alt236.keyeventdisplay.monitors.Filter;
27 | import uk.co.alt236.keyeventdisplay.monitors.Monitor;
28 | import uk.co.alt236.keyeventdisplay.monitors.MonitorCallback;
29 | import uk.co.alt236.keyeventdisplay.monitors.util.ClosableHelper;
30 | import uk.co.alt236.keyeventdisplay.monitors.util.ProcessWrapper;
31 |
32 | public class KernelLogMonitor implements Monitor {
33 | private static final String SU_CMD = "su";
34 | private static final String KERNEL_LOG_CMD = "cat /proc/kmsg";
35 | private final Filter filter;
36 | private KernelMonitorRunnable runnable;
37 |
38 | public KernelLogMonitor(String[] stringArray) {
39 | filter = new Filter(stringArray);
40 | }
41 |
42 | @Override
43 | public void startMonitor(final MonitorCallback callback) {
44 | runnable = new KernelMonitorRunnable(callback, filter);
45 | new Thread(runnable).start();
46 | }
47 |
48 | @Override
49 | public void stopMonitor() {
50 | if (runnable != null) {
51 | runnable.stop();
52 | runnable = null;
53 | }
54 | }
55 |
56 |
57 | private static class KernelMonitorRunnable implements Runnable {
58 | private final String TAG = this.getClass().getName();
59 | private final MonitorCallback callback;
60 | private final ProcessWrapper processWrapper;
61 | private final Filter filter;
62 | private boolean stopped;
63 |
64 | private KernelMonitorRunnable(final MonitorCallback callback,
65 | final Filter filter) {
66 | this.callback = callback;
67 | this.filter = filter;
68 | this.processWrapper = new ProcessWrapper();
69 | }
70 |
71 | public void stop() {
72 | stopped = true;
73 | }
74 |
75 | @Override
76 | public void run() {
77 | Log.d(TAG, "KernelLogMonitor started...");
78 | String line;
79 | BufferedReader reader = null;
80 |
81 | final boolean procStartedOk = processWrapper.execute(SU_CMD);
82 | if (!procStartedOk) {
83 | Log.e(TAG, "KernelLogMonitor: Can't open log file. Exiting.");
84 | } else {
85 | try {
86 | final DataInputStream is = new DataInputStream(processWrapper.getInputStream());
87 | final OutputStreamWriter os = new OutputStreamWriter(processWrapper.getOutputStream());
88 |
89 | os.write(KERNEL_LOG_CMD + "\n");
90 | os.flush();
91 | os.close();
92 |
93 | reader = new BufferedReader(new InputStreamReader(is), BUFFER_SIZE);
94 |
95 | Log.d(TAG, "Pre loop!");
96 |
97 | while ((line = reader.readLine()) != null && !stopped) {
98 | Log.d(TAG, "New line!");
99 | if (filter.isValidLine(line)) {
100 | callback.onNewline(line);
101 | }
102 | }
103 |
104 | Log.d(TAG, "Post loop!");
105 | } catch (IOException e) {
106 | Log.e(TAG, "KernelLogMonitor error: " + e.getMessage());
107 | callback.onError("Error reading from process " + KERNEL_LOG_CMD, e);
108 | } finally {
109 | ClosableHelper.close(reader);
110 | }
111 | Log.d(TAG, "KernelLogMonitor has finished...");
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/monitors/src/main/java/uk/co/alt236/keyeventdisplay/monitors/logcat/LogCatMonitor.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Alexandros Schillings
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package uk.co.alt236.keyeventdisplay.monitors.logcat;
17 |
18 | import android.util.Log;
19 |
20 | import java.io.BufferedReader;
21 | import java.io.IOException;
22 | import java.io.InputStreamReader;
23 |
24 | import uk.co.alt236.keyeventdisplay.monitors.Filter;
25 | import uk.co.alt236.keyeventdisplay.monitors.Monitor;
26 | import uk.co.alt236.keyeventdisplay.monitors.MonitorCallback;
27 | import uk.co.alt236.keyeventdisplay.monitors.util.ClosableHelper;
28 | import uk.co.alt236.keyeventdisplay.monitors.util.ProcessWrapper;
29 |
30 | public class LogCatMonitor implements Monitor {
31 | private static final String[] LOGCAT_CLEAR_CMD = new String[]{"logcat", "-c"};
32 | private static final String[] LOGCAT_CMD = new String[]{"logcat"};
33 | private final Filter filter;
34 | private LogCatMonitorRunnable runnable;
35 |
36 | public LogCatMonitor(String[] stringArray) {
37 | filter = new Filter(stringArray);
38 | }
39 |
40 | @Override
41 | public void startMonitor(final MonitorCallback callback) {
42 | runnable = new LogCatMonitorRunnable(callback, filter);
43 | new Thread(runnable).start();
44 | }
45 |
46 | @Override
47 | public void stopMonitor() {
48 | if (runnable != null) {
49 | runnable.stop();
50 | runnable = null;
51 | }
52 | }
53 |
54 | private static class LogCatMonitorRunnable implements Runnable {
55 | private final String TAG = this.getClass().getName();
56 | private final MonitorCallback callback;
57 | private final ProcessWrapper processWrapper;
58 | private final Filter filter;
59 | private boolean stopped;
60 |
61 | private LogCatMonitorRunnable(final MonitorCallback callback,
62 | final Filter filter) {
63 | this.callback = callback;
64 | this.filter = filter;
65 | this.processWrapper = new ProcessWrapper();
66 | }
67 |
68 | public void stop() {
69 | stopped = true;
70 | }
71 |
72 | @Override
73 | public void run() {
74 | Log.d(TAG, "LogCatMonitor started...");
75 | BufferedReader reader = null;
76 | String line;
77 |
78 | processWrapper.execute(LOGCAT_CLEAR_CMD);
79 | final boolean procStartedOk = processWrapper.execute(LOGCAT_CMD);
80 |
81 | if (!procStartedOk) {
82 | Log.e(TAG, "LogCatMonitor: Can't open log file. Exiting.");
83 | } else {
84 | try {
85 | reader = new BufferedReader(new InputStreamReader(processWrapper.getInputStream()), BUFFER_SIZE);
86 |
87 | Log.d(TAG, "Pre loop!");
88 | while ((line = reader.readLine()) != null && !stopped) {
89 | if (!line.contains(TAG) && filter.isValidLine(line)) {
90 | callback.onNewline(line);
91 | }
92 | }
93 | Log.d(TAG, "Post loop!");
94 | } catch (IOException e) {
95 | Log.e(TAG, "LogCatMonitor error: " + e.getMessage());
96 | callback.onError("Error reading from process " + LOGCAT_CMD[0], e);
97 | } finally {
98 | ClosableHelper.close(reader);
99 | }
100 |
101 | Log.w(TAG, "LogCatMonitor thread has exited...");
102 | }
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/monitors/src/main/java/uk/co/alt236/keyeventdisplay/monitors/util/ClosableHelper.java:
--------------------------------------------------------------------------------
1 | package uk.co.alt236.keyeventdisplay.monitors.util;
2 |
3 | import java.io.Closeable;
4 | import java.io.IOException;
5 |
6 | public final class ClosableHelper {
7 |
8 | public static void close(final Closeable closeable) {
9 | if (closeable == null) {
10 | return;
11 | }
12 |
13 | try {
14 | closeable.close();
15 | } catch (IOException e) {
16 | e.printStackTrace();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/monitors/src/main/java/uk/co/alt236/keyeventdisplay/monitors/util/ProcessWrapper.java:
--------------------------------------------------------------------------------
1 | package uk.co.alt236.keyeventdisplay.monitors.util;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.OutputStream;
8 | import java.util.Arrays;
9 |
10 | public class ProcessWrapper {
11 | private static final String TAG = ProcessWrapper.class.getSimpleName();
12 |
13 | private Process mProcess = null;
14 |
15 | public boolean execute(String command[]) {
16 | try {
17 | mProcess = Runtime.getRuntime().exec(command);
18 | return true;
19 | } catch (Exception e) {
20 | Log.e(TAG, "^ Can't startMonitor: " + Arrays.toString(command) + " " + e.getMessage());
21 | stop();
22 | return false;
23 | }
24 | }
25 |
26 | public boolean execute(String command) {
27 | try {
28 | mProcess = Runtime.getRuntime().exec(command);
29 | return true;
30 | } catch (IOException e) {
31 | Log.e(TAG, "^ Can't startMonitor: " + command + " " + e.getMessage());
32 | stop();
33 | return false;
34 | }
35 | }
36 |
37 |
38 | public void stop() {
39 | if (mProcess != null) {
40 | mProcess.destroy();
41 | mProcess = null;
42 | }
43 | }
44 |
45 | public InputStream getInputStream() {
46 | return mProcess.getInputStream();
47 | }
48 |
49 | public OutputStream getOutputStream() {
50 | return mProcess.getOutputStream();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/print_codecov.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PATTERN='jacoco*.xml'
4 | JAR_FILE='./buildsystem/jacocoxml/jacocoxmlparser-1.0.0.jar'
5 | COLOR_FLAG=''
6 |
7 | if which tput > /dev/null 2>&1 && [[ $(tput -T${TERM} colors) -ge 8 ]]; then
8 | COLOR_FLAG='--color'
9 | fi
10 |
11 | find -iname ${PATTERN} -print0 \
12 | | sort -z \
13 | | xargs -0 -I '{}' java -jar ${JAR_FILE} ${COLOR_FLAG} --global-stats -i '{}'
14 |
15 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':monitors'
3 |
--------------------------------------------------------------------------------