├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CNAME ├── LICENSE ├── README.md ├── WallPanelApp ├── .gitignore ├── build.gradle ├── lint.xml ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── xyz │ │ └── wallpanel │ │ └── app │ │ └── BrowserActivityNativeTest.kt │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── error_page.html │ ├── icon.png │ └── styles.css │ ├── java │ ├── com │ │ └── jjoe64 │ │ │ └── motiondetection │ │ │ └── motiondetection │ │ │ ├── AggregateLumaMotionDetection.java │ │ │ ├── Comparer.java │ │ │ ├── IMotionDetection.java │ │ │ ├── ImageProcessing.java │ │ │ ├── MotionDetector.java │ │ │ ├── MotionDetectorCallback.java │ │ │ └── State.java │ └── xyz │ │ └── wallpanel │ │ └── app │ │ ├── AppExceptionHandler.kt │ │ ├── BootUpReceiver.kt │ │ ├── WallPanel.kt │ │ ├── di │ │ ├── ActivityModule.java │ │ ├── ActivityScope.java │ │ ├── AndroidBindingModule.kt │ │ ├── ApplicationComponent.java │ │ ├── ApplicationModule.java │ │ ├── ApplicationScope.java │ │ ├── DaggerViewModelFactory.kt │ │ ├── DaggerViewModelInjectionModule.kt │ │ ├── ServiceSubcomponent.java │ │ ├── ServicesModule.java │ │ └── ViewModelKey.kt │ │ ├── ext │ │ ├── ArrayExt.kt │ │ └── StringExt.kt │ │ ├── modules │ │ ├── CameraCallback.java │ │ ├── CameraReader.kt │ │ ├── MQTTModule.kt │ │ ├── Motion.kt │ │ ├── MotionDetector.kt │ │ ├── SensorCallback.kt │ │ ├── SensorReader.kt │ │ ├── Stream.kt │ │ ├── StreamingDetector.kt │ │ └── TextToSpeechModule.kt │ │ ├── network │ │ ├── ConnectionLiveData.kt │ │ ├── IMqttManagerListener.kt │ │ ├── MQTT3Service.kt │ │ ├── MQTT5Service.kt │ │ ├── MQTTOptions.kt │ │ ├── MQTTServiceInterface.kt │ │ └── WallPanelService.kt │ │ ├── persistence │ │ └── Configuration.kt │ │ ├── ui │ │ ├── DetectionViewModel.kt │ │ ├── activities │ │ │ ├── BaseBrowserActivity.kt │ │ │ ├── BrowserActivityNative.kt │ │ │ ├── LiveCameraActivity.kt │ │ │ ├── SettingsActivity.kt │ │ │ └── TestActivity.kt │ │ ├── fragments │ │ │ ├── AboutFragment.kt │ │ │ ├── BaseSettingsFragment.kt │ │ │ ├── CameraSettingsFragment.kt │ │ │ ├── CodeBottomSheetFragment.kt │ │ │ ├── FaceSettingsFragment.kt │ │ │ ├── HttpSettingsFragment.kt │ │ │ ├── MotionSettingsFragment.kt │ │ │ ├── MqttSettingsFragment.kt │ │ │ ├── QrCodeSettingsFragment.kt │ │ │ ├── SensorsSettingsFragment.kt │ │ │ └── SettingsFragment.kt │ │ └── views │ │ │ ├── BaseView.kt │ │ │ ├── CameraSourcePreview.kt │ │ │ ├── CustomWebView.kt │ │ │ ├── ScreenSaverView.kt │ │ │ ├── SettingsCodeView.kt │ │ │ └── WebClientCallback.kt │ │ └── utils │ │ ├── BrowserUtils.kt │ │ ├── CameraUtils.kt │ │ ├── CrashlyticsDebugTree.kt │ │ ├── CrashlyticsTree.java │ │ ├── DateUtils.kt │ │ ├── DialogUtils.kt │ │ ├── InternalWebChromeClient.kt │ │ ├── InternalWebClient.kt │ │ ├── LauncherShortcuts.kt │ │ ├── MqttUtils.kt │ │ ├── NotificationUtils.java │ │ ├── ScreenUtils.kt │ │ ├── StringUtils.java │ │ ├── WallpanelDebugTree.kt │ │ └── WebClientRenderWrapper.kt │ └── res │ ├── drawable-anydpi-v24 │ └── ic_stat_name.xml │ ├── drawable-hdpi │ └── ic_stat_name.png │ ├── drawable-mdpi │ └── ic_stat_name.png │ ├── drawable-xhdpi │ └── ic_stat_name.png │ ├── drawable-xxhdpi │ └── ic_stat_name.png │ ├── drawable │ ├── button_blue.xml │ ├── button_blue_pressed.xml │ ├── button_blue_selector.xml │ ├── button_border.xml │ ├── button_border_bottom.xml │ ├── button_border_bottom_corner.xml │ ├── button_border_bottom_corner_white.xml │ ├── button_border_bottom_white.xml │ ├── button_border_left.xml │ ├── button_border_left_white.xml │ ├── button_border_top_corner.xml │ ├── button_border_top_corner_white.xml │ ├── button_disabled.xml │ ├── button_green.xml │ ├── button_green_pressed.xml │ ├── button_green_selector.xml │ ├── ic_baseline_backspace.xml │ ├── ic_baseline_close.xml │ ├── ic_baseline_help.xml │ ├── ic_baseline_lock.xml │ ├── ic_baseline_lock_open.xml │ ├── ic_baseline_refresh.xml │ ├── ic_baseline_videocam.xml │ ├── ic_cloud.xml │ ├── ic_dashboard.xml │ ├── ic_dashboard_white.xml │ ├── ic_directions_run.xml │ ├── ic_email_black.xml │ ├── ic_face.xml │ ├── ic_file_edit.xml │ ├── ic_github_blk.xml │ ├── ic_help.xml │ ├── ic_help_black.xml │ ├── ic_mister.xml │ ├── ic_photo_camera.xml │ ├── ic_qr_code.xml │ ├── ic_radio_button_checked_black.xml │ ├── ic_radio_button_unchecked_black.xml │ ├── ic_sensor.xml │ ├── ic_settings_brightness.xml │ ├── ic_settings_cyan.xml │ ├── ic_social_reddit.xml │ ├── ic_star_black.xml │ └── logo_front.xml │ ├── layout-land │ ├── dialog_screen_saver.xml │ └── fragment_code_bottom_sheet.xml │ ├── layout-sw600dp-land │ ├── dialog_screen_saver.xml │ └── fragment_code_bottom_sheet.xml │ ├── layout-sw600dp │ ├── dialog_screen_saver.xml │ └── fragment_code_bottom_sheet.xml │ ├── layout-sw720dp-land │ ├── dialog_screen_saver.xml │ └── fragment_code_bottom_sheet.xml │ ├── layout-sw720dp │ ├── dialog_screen_saver.xml │ └── fragment_code_bottom_sheet.xml │ ├── layout │ ├── activity_browser.xml │ ├── activity_live_camera.xml │ ├── activity_settings.xml │ ├── activity_test.xml │ ├── activity_welcome.xml │ ├── dialog_code_set.xml │ ├── dialog_screen_saver.xml │ ├── fragment_about.xml │ ├── fragment_code_bottom_sheet.xml │ └── view_keypad.xml │ ├── menu │ ├── menu_dashboard.xml │ └── menu_help.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_background.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_background.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── navigation │ └── settings_nav_graph.xml │ ├── values-night │ ├── colors.xml │ └── styles.xml │ ├── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── donottranslate.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── styles.xml │ ├── web_hi_res_512.png │ └── xml │ ├── network_config.xml │ ├── pref_camera.xml │ ├── pref_face.xml │ ├── pref_general.xml │ ├── pref_http.xml │ ├── pref_motion.xml │ ├── pref_mqtt.xml │ ├── pref_qrcode.xml │ └── pref_sensors.xml ├── _config.yml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── dashboard1.png ├── dashboard2.png ├── dashboard3.png └── logo.png ├── settings.gradle └── website ├── .gitignore ├── .prettierrc ├── README.md ├── babel.config.js ├── docs ├── getting-started.md ├── launch-external-apps.md ├── limitations.md ├── remote-control │ ├── _category_.json │ ├── commands.md │ ├── mqtt-setup.md │ └── sensors.md ├── screensaver.md └── video-streaming.md ├── docusaurus.config.js ├── package-lock.json ├── package.json ├── sidebars.js ├── src ├── components │ └── HomepageFeatures │ │ ├── index.tsx │ │ └── styles.module.css ├── css │ └── custom.css └── pages │ ├── index.module.css │ ├── index.tsx │ └── privacy-policy.md ├── static ├── .nojekyll └── img │ ├── favicon.ico │ ├── logo.png │ ├── mqtt.png │ ├── mqtt_client.png │ ├── mqtt_discovery.png │ ├── settings_button.png │ ├── settings_button_options.png │ ├── settings_code.png │ └── settings_dashboard.png ├── tsconfig.json └── yarn.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ["TheTimeWalker"] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report an issue 4 | title: '[BUG]' 5 | 6 | --- 7 | 8 | **Describe the bug** 9 | A clear and concise description of what the bug is. 10 | 11 | **To Reproduce** 12 | Steps to reproduce the behavior: 13 | 14 | 15 | **Smartphone (please complete the following information):** 16 | - Device: [e.g. Samsun, Android, Fire Tablet] 17 | - OS: [e.g. Android 21, Oreo, Fire OS 7] 18 | - Applicaiton version [app > settings > version] 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Your feature request. Please describe.** 11 | What is the feature, why is it valuable to the community or application? 12 | 13 | **NOTE** 14 | We get many feature requests, each feature requires community support and also development time. Features that have no community support are not considered. If you are not contributing to the feature, then the feature may not happen. 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ 2 | *.iml 3 | .idea/ 4 | misc.xml 5 | deploymentTargetDropDown.xml 6 | render.experimental.xml 7 | 8 | # Gradle 9 | .gradle/ 10 | build/ 11 | 12 | # Local configuration file (sdk path, etc) 13 | local.properties 14 | reports 15 | 16 | # Apple 17 | .DS_Store 18 | npm-debug.log 19 | 20 | #Fabric 21 | crashlytics.properties 22 | fabric.properties 23 | 24 | # Log/OS Files 25 | *.log 26 | 27 | # Android Studio generated files and folders 28 | captures/ 29 | .externalNativeBuild/ 30 | .cxx/ 31 | *.apk 32 | output.json 33 | 34 | # Keystore files 35 | *.jks 36 | *.keystore 37 | 38 | # Google Services (e.g. APIs or Firebase) 39 | google-services.json 40 | 41 | # Android Profiling 42 | *.hprof 43 | keystore.gradle 44 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | wallpanel.xyz -------------------------------------------------------------------------------- /WallPanelApp/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # IntelliJ IDEA 3 | .idea 4 | *.iml 5 | app.iml 6 | /build 7 | 8 | # Gradle 9 | .gradle 10 | gradlew.bat 11 | build 12 | local.properties 13 | reports 14 | 15 | # Apple 16 | .DS_Store 17 | npm-debug.log 18 | 19 | #Fabric 20 | crashlytics.properties 21 | 22 | # Keystore files 23 | # Uncomment the following lines if you do not want to check your keystore files in. 24 | /keystore 25 | *.jks 26 | *.keystore 27 | keystore.gradle 28 | -------------------------------------------------------------------------------- /WallPanelApp/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /WallPanelApp/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\raimund\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | -keepclassmembernames class io.netty.** { *; } 20 | -keepclassmembers class org.jctools.** { *; } -------------------------------------------------------------------------------- /WallPanelApp/src/androidTest/java/xyz/wallpanel/app/BrowserActivityNativeTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Wallpanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app 18 | 19 | import xyz.wallpanel.app.utils.BrowserUtils 20 | import junit.framework.TestCase 21 | 22 | import org.junit.After 23 | import org.junit.Before 24 | import org.junit.Test 25 | 26 | class BrowserActivityNativeTest : TestCase() { 27 | 28 | @Before 29 | public override fun setUp() { 30 | } 31 | 32 | @After 33 | public override fun tearDown() { 34 | } 35 | 36 | @Test 37 | fun testParseIntentMethod() { 38 | val browserUtils = BrowserUtils() 39 | var intent = browserUtils.parseIntent("intent:#Intent;launchFlags=0x10000000;component=com.google.android.apps.maps/com.google.android.maps.MapsActivity;end") 40 | assertNotNull(intent) 41 | assertEquals("com.google.android.maps.MapsActivity", intent?.component?.className) 42 | assertEquals("com.google.android.apps.maps", intent?.component?.packageName) 43 | assertEquals("android.intent.action.VIEW", intent?.action) 44 | 45 | intent = browserUtils.parseIntent("intent:#Intent;launchFlags=0x10000000;component=com.amazon.avod/.client.activity.HomeScreenActivity;end") 46 | assertNotNull(intent) 47 | assertEquals(".client.activity.HomeScreenActivity", intent?.component?.className) 48 | assertEquals("com.amazon.avod", intent?.component?.packageName) 49 | assertEquals("android.intent.action.VIEW", intent?.action) 50 | } 51 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/assets/error_page.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 |
26 | 27 |

Connection Error

28 |

This page will automatically reload when connected.

29 |
30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTimeWalker/wallpanel-android/2775abc1a9428209c9bbed04bb2d8bd6142d9b0d/WallPanelApp/src/main/assets/icon.png -------------------------------------------------------------------------------- /WallPanelApp/src/main/assets/styles.css: -------------------------------------------------------------------------------- 1 | html { box-sizing: border-box; } 2 | 3 | *, 4 | *::before, 5 | *::after { box-sizing: inherit; } 6 | 7 | body * { 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | body { 13 | font: normal 100%/1.15 "Merriweather", serif; 14 | background-color: #ffffff; 15 | color: #fff; 16 | } 17 | 18 | .wrapper { 19 | position: relative; 20 | max-width: 1298px; 21 | height: auto; 22 | margin: 1em auto 0 auto; 23 | } 24 | 25 | /* https://www.flaticon.com/authors/vectors-market */ 26 | /* https://www.flaticon.com/authors/icomoon */ 27 | .box { 28 | max-width: 70%; 29 | min-height: auto; 30 | margin: 0 auto; 31 | padding: 2em 0em; 32 | text-align: center; 33 | } 34 | 35 | h1, p:not(:last-of-type) { } 36 | 37 | h1 { 38 | margin: 0 0 1rem 0; 39 | font-size: 2em; 40 | color: #216f79; 41 | } 42 | 43 | p { 44 | margin-top: 0.5em; 45 | margin-bottom: 0.5em; 46 | font-size: 1.5em; 47 | text-align: center; 48 | color: #216f79; 49 | } 50 | 51 | p:first-of-type { margin-top: 0em; } 52 | 53 | p > a { 54 | border-bottom: 1px dashed #216f79; 55 | font-style: italic; 56 | text-decoration: none; 57 | color: #216f79; 58 | } 59 | 60 | p > a:hover { text-shadow: 0 0 6px #216f79; } 61 | 62 | p img { vertical-align: bottom; } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/com/jjoe64/motiondetection/motiondetection/IMotionDetection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package com.jjoe64.motiondetection.motiondetection; 18 | 19 | public interface IMotionDetection { 20 | 21 | /** 22 | * Get the previous image in integer array format 23 | * 24 | * @return int array of previous image. 25 | */ 26 | public int[] getPrevious(); 27 | 28 | /** 29 | * Detect motion. 30 | * 31 | * @param data 32 | * integer array representing an image. 33 | * @param width 34 | * Width of the image. 35 | * @param height 36 | * Height of the image. 37 | * @return boolean True is there is motion. 38 | * @throws NullPointerException 39 | * if data integer array is NULL. 40 | */ 41 | public boolean detect(int[] data, int width, int height); 42 | } 43 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/com/jjoe64/motiondetection/motiondetection/MotionDetectorCallback.java: -------------------------------------------------------------------------------- 1 | package com.jjoe64.motiondetection.motiondetection; 2 | 3 | public interface MotionDetectorCallback { 4 | void onMotionDetected(); 5 | void onTooDark(); 6 | } 7 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/com/jjoe64/motiondetection/motiondetection/State.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package com.jjoe64.motiondetection.motiondetection; 18 | 19 | public class State { 20 | 21 | private int[] map = null; 22 | private int width; 23 | private int height; 24 | private int average; 25 | 26 | public State(int[] data, int width, int height) { 27 | if (data == null) throw new NullPointerException(); 28 | 29 | this.map = data.clone(); 30 | this.width = width; 31 | this.height = height; 32 | 33 | // build map and stats 34 | this.average = 0; 35 | for (int y = 0, xy = 0; y < this.height; y++) { 36 | for (int x = 0; x < this.width; x++, xy++) { 37 | this.average += data[xy]; 38 | } 39 | } 40 | this.average = (this.average / (this.width * this.height)); 41 | } 42 | 43 | /** 44 | * Get Map of the State. 45 | * 46 | * @return integer array of the State. 47 | */ 48 | public int[] getMap() { 49 | return map; 50 | } 51 | 52 | /** 53 | * Get the width of the State. 54 | * 55 | * @return integer representing the width of the state. 56 | */ 57 | public int getWidth() { 58 | return width; 59 | } 60 | 61 | /** 62 | * Get the height of the State. 63 | * 64 | * @return integer representing the height of the state. 65 | */ 66 | public int getHeight() { 67 | return height; 68 | } 69 | 70 | /** 71 | * {@inheritDoc} 72 | */ 73 | @Override 74 | public String toString() { 75 | StringBuilder output = new StringBuilder(); 76 | output.append("h=" + height + " w=" + width + "\n"); 77 | for (int y = 0, xy = 0; y < height; y++) { 78 | output.append('|'); 79 | for (int x = 0; x < width; x++, xy++) { 80 | output.append(map[xy]); 81 | output.append('|'); 82 | } 83 | output.append("\n"); 84 | } 85 | return output.toString(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/AppExceptionHandler.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Wallpanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app 18 | 19 | import android.app.Activity 20 | import android.app.AlarmManager 21 | import android.app.PendingIntent 22 | import android.content.Context 23 | import android.content.Intent 24 | import xyz.wallpanel.app.ui.activities.BrowserActivityNative 25 | import kotlin.system.exitProcess 26 | 27 | class AppExceptionHandler(private val activity: Activity) : Thread.UncaughtExceptionHandler { 28 | override fun uncaughtException(thread: Thread, ex: Throwable) { 29 | val intent = Intent(activity, BrowserActivityNative::class.java) 30 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP 31 | or Intent.FLAG_ACTIVITY_CLEAR_TASK 32 | or Intent.FLAG_ACTIVITY_NEW_TASK) 33 | val pendingIntent = PendingIntent.getActivity(activity.applicationContext, 0, intent, PendingIntent.FLAG_ONE_SHOT) 34 | val mgr = activity.applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager 35 | mgr[AlarmManager.RTC, System.currentTimeMillis() + 1000] = pendingIntent 36 | activity.finish() 37 | exitProcess(2) 38 | } 39 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/BootUpReceiver.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app 18 | 19 | import android.content.BroadcastReceiver 20 | import android.content.Context 21 | import android.content.Intent 22 | import androidx.preference.PreferenceManager 23 | import xyz.wallpanel.app.R 24 | import xyz.wallpanel.app.ui.activities.BrowserActivityNative 25 | 26 | class BootUpReceiver : BroadcastReceiver() { 27 | 28 | override fun onReceive(context: Context, intent: Intent) { 29 | if (Intent.ACTION_BOOT_COMPLETED.equals(intent.action)) { 30 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) 31 | val startOnBoot = sharedPreferences.getBoolean(context.getString(R.string.key_setting_android_startonboot), false) 32 | if (startOnBoot) { 33 | val i = Intent(context, BrowserActivityNative::class.java) 34 | i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 35 | context.startActivity(i) 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ActivityModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di; 18 | 19 | import android.app.Application; 20 | import android.content.Context; 21 | import android.content.SharedPreferences; 22 | 23 | import android.content.res.Resources; 24 | import android.location.LocationManager; 25 | import androidx.preference.PreferenceManager; 26 | import android.view.LayoutInflater; 27 | 28 | import xyz.wallpanel.app.modules.CameraReader; 29 | import xyz.wallpanel.app.modules.SensorReader; 30 | import xyz.wallpanel.app.network.MQTTOptions; 31 | import xyz.wallpanel.app.persistence.Configuration; 32 | import xyz.wallpanel.app.utils.DialogUtils; 33 | import xyz.wallpanel.app.utils.ScreenUtils; 34 | 35 | import javax.inject.Singleton; 36 | 37 | import dagger.Module; 38 | import dagger.Provides; 39 | 40 | @Module 41 | class ActivityModule { 42 | 43 | @Provides 44 | static DialogUtils providesDialogUtils(Application application) { 45 | return new DialogUtils(application); 46 | } 47 | 48 | @Provides 49 | static Resources providesResources(Application application) { 50 | return application.getResources(); 51 | } 52 | 53 | @Provides 54 | static LayoutInflater providesInflater(Application application) { 55 | return (LayoutInflater) application.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 56 | } 57 | 58 | @Provides 59 | static LocationManager provideLocationManager(Application application) { 60 | return (LocationManager) application.getSystemService(Context.LOCATION_SERVICE); 61 | } 62 | 63 | @Provides 64 | @Singleton 65 | SharedPreferences provideSharedPreferences(Application app) { 66 | return PreferenceManager.getDefaultSharedPreferences(app.getApplicationContext()); 67 | } 68 | 69 | @Provides 70 | static Configuration provideConfiguration(Application app, SharedPreferences sharedPreferences) { 71 | return new Configuration(app, sharedPreferences); 72 | } 73 | 74 | @Provides 75 | static CameraReader provideCameraReader(Application app) { 76 | return new CameraReader(app); 77 | } 78 | 79 | @Provides 80 | static SensorReader provideSensorReader(Application app) { 81 | return new SensorReader(app); 82 | } 83 | 84 | @Provides 85 | static MQTTOptions provideMQTTOptions(Configuration configuration) { 86 | return new MQTTOptions(configuration); 87 | } 88 | 89 | @Provides 90 | static ScreenUtils screenUtils(Application application, Configuration configuration) { 91 | return new ScreenUtils(application, configuration); 92 | } 93 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ActivityScope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | 22 | import javax.inject.Scope; 23 | 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | @Scope 27 | @Documented 28 | @Retention(RUNTIME) 29 | public @interface ActivityScope { 30 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/AndroidBindingModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di 18 | 19 | import androidx.lifecycle.ViewModel 20 | import xyz.wallpanel.app.BootUpReceiver 21 | import xyz.wallpanel.app.network.WallPanelService 22 | import xyz.wallpanel.app.ui.* 23 | import xyz.wallpanel.app.ui.activities.* 24 | import xyz.wallpanel.app.ui.fragments.* 25 | import dagger.Binds 26 | import dagger.Module 27 | import dagger.android.ContributesAndroidInjector 28 | import dagger.multibindings.IntoMap 29 | 30 | @Module 31 | internal abstract class AndroidBindingModule { 32 | 33 | @Binds 34 | @IntoMap 35 | @ViewModelKey(DetectionViewModel::class) 36 | abstract fun cameraViewModel(viewModel: DetectionViewModel): ViewModel 37 | 38 | @ContributesAndroidInjector 39 | internal abstract fun alarmService(): WallPanelService 40 | 41 | @ContributesAndroidInjector 42 | internal abstract fun settingsActivity(): SettingsActivity 43 | 44 | @ContributesAndroidInjector 45 | internal abstract fun browserActivity(): BaseBrowserActivity 46 | 47 | @ContributesAndroidInjector 48 | internal abstract fun browserActivityNative(): BrowserActivityNative 49 | 50 | @ContributesAndroidInjector 51 | internal abstract fun liveCameraActivity(): LiveCameraActivity 52 | 53 | @ContributesAndroidInjector 54 | internal abstract fun bootupReceiver(): BootUpReceiver 55 | 56 | @ContributesAndroidInjector 57 | internal abstract fun baseSettingsFragment(): BaseSettingsFragment 58 | 59 | @ContributesAndroidInjector 60 | internal abstract fun settingsFragment(): SettingsFragment 61 | 62 | @ContributesAndroidInjector 63 | internal abstract fun cameraSettings(): CameraSettingsFragment 64 | 65 | @ContributesAndroidInjector 66 | internal abstract fun mqttSettings(): MqttSettingsFragment 67 | 68 | @ContributesAndroidInjector 69 | internal abstract fun httpSettings(): HttpSettingsFragment 70 | 71 | @ContributesAndroidInjector 72 | internal abstract fun motionSettings(): MotionSettingsFragment 73 | 74 | @ContributesAndroidInjector 75 | internal abstract fun faceSettings(): FaceSettingsFragment 76 | 77 | @ContributesAndroidInjector 78 | internal abstract fun qrCodeSettings(): QrCodeSettingsFragment 79 | 80 | @ContributesAndroidInjector 81 | internal abstract fun sensorsSettings(): SensorsSettingsFragment 82 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ApplicationComponent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di; 18 | 19 | import xyz.wallpanel.app.WallPanel; 20 | 21 | import javax.inject.Singleton; 22 | 23 | import dagger.Component; 24 | import dagger.android.AndroidInjector; 25 | import dagger.android.support.AndroidSupportInjectionModule; 26 | 27 | @Singleton 28 | @Component(modules = { 29 | AndroidSupportInjectionModule.class, 30 | ApplicationModule.class, 31 | ActivityModule.class, 32 | AndroidBindingModule.class, 33 | DaggerViewModelInjectionModule.class 34 | }) 35 | 36 | @ApplicationScope 37 | public interface ApplicationComponent extends AndroidInjector { 38 | @Component.Builder 39 | abstract class Builder extends AndroidInjector.Builder{ 40 | } 41 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ApplicationModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di; 18 | 19 | import android.app.Application; 20 | import android.content.Context; 21 | 22 | import xyz.wallpanel.app.WallPanel; 23 | 24 | import javax.inject.Singleton; 25 | 26 | import dagger.Binds; 27 | import dagger.Module; 28 | import dagger.Provides; 29 | 30 | @Module 31 | abstract class ApplicationModule { 32 | 33 | @Binds 34 | abstract Application application(WallPanel baseApplication); 35 | 36 | @Provides 37 | @Singleton 38 | static Context provideContext(Application application) { 39 | return application; 40 | } 41 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ApplicationScope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | 22 | import javax.inject.Scope; 23 | 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | @Scope 27 | @Documented 28 | @Retention(RUNTIME) 29 | public @interface ApplicationScope { 30 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/DaggerViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di 18 | 19 | import androidx.lifecycle.ViewModel 20 | import androidx.lifecycle.ViewModelProvider 21 | import javax.inject.Inject 22 | import javax.inject.Provider 23 | import javax.inject.Singleton 24 | 25 | @Suppress("UNCHECKED_CAST") 26 | @Singleton 27 | class DaggerViewModelFactory 28 | @Inject constructor( 29 | private val creators: Map, @JvmSuppressWildcards Provider>) : ViewModelProvider.Factory { 30 | 31 | override fun create(modelClass: Class): T { 32 | val creator = creators[modelClass] ?: 33 | creators.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value 34 | ?: throw IllegalArgumentException("unknown model class " + modelClass) 35 | 36 | return try { 37 | creator.get() as T 38 | } catch (e: Exception) { 39 | throw RuntimeException(e) 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/DaggerViewModelInjectionModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di 18 | 19 | import androidx.lifecycle.ViewModelProvider 20 | import dagger.Binds 21 | import dagger.Module 22 | 23 | @Module 24 | abstract class DaggerViewModelInjectionModule { 25 | @Binds 26 | internal abstract fun bindViewModelFactory(factory: DaggerViewModelFactory): ViewModelProvider.Factory 27 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ServiceSubcomponent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di; 18 | 19 | import xyz.wallpanel.app.network.WallPanelService; 20 | 21 | import dagger.Subcomponent; 22 | import dagger.android.AndroidInjector; 23 | 24 | @Subcomponent(modules = {}) 25 | public interface ServiceSubcomponent extends AndroidInjector { 26 | @Subcomponent.Builder 27 | abstract class Builder extends AndroidInjector.Builder { 28 | } 29 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ServicesModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di; 18 | 19 | import xyz.wallpanel.app.network.WallPanelService; 20 | 21 | import dagger.Module; 22 | import dagger.android.ContributesAndroidInjector; 23 | 24 | @Module 25 | abstract class ServicesModule { 26 | 27 | @ContributesAndroidInjector 28 | abstract WallPanelService contributeMyService(); 29 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/di/ViewModelKey.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.di 18 | 19 | import androidx.lifecycle.ViewModel 20 | import dagger.MapKey 21 | import kotlin.reflect.KClass 22 | 23 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) 24 | @MapKey 25 | annotation class ViewModelKey(val value: KClass) -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/ext/ArrayExt.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.ext 2 | 3 | fun Array.convertArrayToString(): String { 4 | val strSeparator = "," 5 | val str = StringBuilder() 6 | for (i in this.indices) { 7 | str.append(this[i]) 8 | // Do not append comma at the end of last element 9 | if (i < this.size - 1) { 10 | str.append(strSeparator) 11 | } 12 | } 13 | return str.toString() 14 | } 15 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/ext/StringExt.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.ext 2 | 3 | 4 | fun String.convertStringToArray(str: String): Array { 5 | val strSeparator = "," 6 | return str.split(strSeparator).toTypedArray() 7 | } 8 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/modules/CameraCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.modules; 18 | 19 | public interface CameraCallback { 20 | void onMotionDetected(); 21 | void onTooDark(); 22 | void onFaceDetected(); 23 | void onQRCode(String data); 24 | void onCameraError(); 25 | void onDetectorError(); 26 | } 27 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/modules/Motion.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.modules 18 | 19 | /** 20 | * Created by Michael Ritchie on 7/6/18. 21 | */ 22 | class Motion { 23 | 24 | var type = MOTION_NOT_DETECTED 25 | var byteArray: ByteArray? = null 26 | var width: Int? = null 27 | var height: Int? = null 28 | 29 | companion object { 30 | val MOTION_TOO_DARK = "motion_too_dark" 31 | val MOTION_DETECTED = "motion_detected" 32 | val MOTION_NOT_DETECTED = "motion_not_detected" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/modules/SensorCallback.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.modules 18 | 19 | import org.json.JSONObject 20 | 21 | interface SensorCallback { 22 | fun publishSensorData(sensorName: String, sensorData: JSONObject) 23 | } 24 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/modules/Stream.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.modules 18 | 19 | /** 20 | * Created by Michael Ritchie on 7/6/18. 21 | */ 22 | class Stream { 23 | var byteArray: ByteArray? = null 24 | var width: Int? = null 25 | var height: Int? = null 26 | companion object { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/modules/StreamingDetector.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.modules 18 | 19 | import android.util.SparseArray 20 | 21 | import com.google.android.gms.vision.Detector 22 | import com.google.android.gms.vision.Frame 23 | 24 | /** 25 | * Created by Michael Ritchie on 7/6/18. 26 | */ 27 | class StreamingDetector private constructor() : Detector() { 28 | init { 29 | } 30 | override fun detect(frame: Frame?): SparseArray { 31 | if (frame == null) { 32 | throw IllegalArgumentException("No frame supplied.") 33 | } else { 34 | val sparseArray = SparseArray() 35 | val byteBuffer = frame.grayscaleImageData 36 | val bytes = byteBuffer.array() 37 | val w = frame.metadata.width 38 | val h = frame.metadata.height 39 | val stream = Stream() 40 | stream.byteArray = bytes 41 | stream.width = w 42 | stream.height = h 43 | sparseArray.put(0, stream) 44 | return sparseArray 45 | } 46 | } 47 | class Builder() { 48 | fun build(): StreamingDetector { 49 | return StreamingDetector() 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/network/ConnectionLiveData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.network 18 | 19 | import androidx.lifecycle.MutableLiveData 20 | import android.content.BroadcastReceiver 21 | import android.content.Context 22 | import android.content.Intent 23 | import android.content.IntentFilter 24 | import android.net.ConnectivityManager 25 | 26 | import timber.log.Timber 27 | import java.util.concurrent.atomic.AtomicBoolean 28 | 29 | class ConnectionLiveData(private val context: Context) : MutableLiveData() { 30 | 31 | private var connCallbackListener: ConnCallbackListener? = null 32 | 33 | init { 34 | connCallbackListener = object : ConnCallbackListener { 35 | override fun networkConnect() { 36 | value = true 37 | } 38 | override fun networkDisconnect() { 39 | value = false 40 | } 41 | } 42 | } 43 | 44 | override fun onActive() { 45 | super.onActive() 46 | context.registerReceiver(connectionReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)) 47 | } 48 | 49 | override fun onInactive() { 50 | super.onInactive() 51 | context.unregisterReceiver(connectionReceiver) 52 | } 53 | 54 | private val connectionReceiver = object : BroadcastReceiver() { 55 | override fun onReceive(context: Context, intent: Intent) { 56 | val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 57 | val currentNetworkInfo = connectivityManager.activeNetworkInfo 58 | if (currentNetworkInfo != null && currentNetworkInfo.isConnected) { 59 | Timber.d("Network Connected") 60 | hasNetwork.set(true) 61 | value = true 62 | } else if (hasNetwork.get()) { 63 | Timber.d("Network Disconnected") 64 | hasNetwork.set(false) 65 | value = false 66 | } 67 | } 68 | } 69 | 70 | interface ConnCallbackListener { 71 | fun networkConnect() 72 | fun networkDisconnect() 73 | } 74 | 75 | companion object { 76 | var hasNetwork = AtomicBoolean(true) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/network/IMqttManagerListener.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.network 2 | 3 | interface IMqttManagerListener { 4 | fun subscriptionMessage(id: String, topic: String, payload: String) 5 | fun handleMqttException(errorMessage: String) 6 | fun handleMqttDisconnected() 7 | fun handleMqttConnected() 8 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/network/MQTTServiceInterface.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.network 2 | 3 | import android.content.Context 4 | import com.hivemq.client.mqtt.mqtt5.exceptions.Mqtt5MessageException 5 | 6 | interface MQTTServiceInterface { 7 | val isReady: Boolean 8 | 9 | fun publish(topic: String, payload: String, retain: Boolean) 10 | fun reconfigure(context: Context, options: MQTTOptions, listener: IMqttManagerListener) 11 | 12 | @Throws(Mqtt5MessageException::class) 13 | fun close() 14 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/ui/activities/SettingsActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.ui.activities 18 | 19 | 20 | import android.content.Context 21 | import android.content.Intent 22 | import android.os.Bundle 23 | import android.view.MenuItem 24 | import xyz.wallpanel.app.R 25 | import xyz.wallpanel.app.persistence.Configuration 26 | import xyz.wallpanel.app.utils.DialogUtils 27 | import dagger.android.support.DaggerAppCompatActivity 28 | import javax.inject.Inject 29 | 30 | class SettingsActivity : DaggerAppCompatActivity() { 31 | 32 | @Inject 33 | lateinit var configuration: Configuration 34 | 35 | @Inject 36 | lateinit var dialogUtils: DialogUtils 37 | 38 | public override fun onCreate(savedInstance: Bundle?) { 39 | super.onCreate(savedInstance) 40 | 41 | setContentView(R.layout.activity_settings) 42 | 43 | supportActionBar?.show() 44 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 45 | supportActionBar?.setDisplayShowHomeEnabled(true) 46 | supportActionBar?.title = (getString(R.string.title_settings)) 47 | 48 | lifecycle.addObserver(dialogUtils) 49 | } 50 | 51 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 52 | val id = item.itemId 53 | if (id == android.R.id.home) { 54 | onBackPressed() 55 | return true 56 | } 57 | return super.onOptionsItemSelected(item) 58 | } 59 | 60 | companion object { 61 | const val PERMISSIONS_REQUEST_WRITE_SETTINGS = 200 62 | fun createStartIntent(context: Context): Intent { 63 | return Intent(context, SettingsActivity::class.java) 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/ui/activities/TestActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Wallpanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.ui.activities 18 | 19 | import androidx.appcompat.app.AppCompatActivity 20 | import android.os.Bundle 21 | import android.view.ViewGroup 22 | import android.widget.Button 23 | import xyz.wallpanel.app.R 24 | 25 | class TestActivity : AppCompatActivity() { 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | setContentView(R.layout.activity_test) 29 | 30 | val crashButton = Button(this) 31 | crashButton.text = "Test Crash" 32 | crashButton.setOnClickListener { 33 | throw RuntimeException("Test Crash") // Force a crash 34 | } 35 | 36 | addContentView(crashButton, ViewGroup.LayoutParams( 37 | ViewGroup.LayoutParams.MATCH_PARENT, 38 | ViewGroup.LayoutParams.WRAP_CONTENT)) 39 | } 40 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/ui/fragments/QrCodeSettingsFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.ui.fragments 18 | 19 | import android.content.Context 20 | import android.os.Bundle 21 | import androidx.preference.SwitchPreference 22 | import android.view.Menu 23 | import android.view.MenuInflater 24 | import android.view.MenuItem 25 | import android.view.View 26 | import androidx.navigation.Navigation 27 | import xyz.wallpanel.app.R 28 | import xyz.wallpanel.app.ui.activities.SettingsActivity 29 | import dagger.android.support.AndroidSupportInjection 30 | 31 | class QrCodeSettingsFragment : BaseSettingsFragment() { 32 | 33 | private var qrCodePreference: SwitchPreference? = null 34 | 35 | override fun onAttach(context: Context) { 36 | AndroidSupportInjection.inject(this) 37 | super.onAttach(context) 38 | setHasOptionsMenu(true) 39 | } 40 | 41 | override fun onActivityCreated(savedInstanceState: Bundle?) { 42 | super.onActivityCreated(savedInstanceState) 43 | if((activity as SettingsActivity).supportActionBar != null) { 44 | (activity as SettingsActivity).supportActionBar!!.setDisplayHomeAsUpEnabled(true) 45 | (activity as SettingsActivity).supportActionBar!!.setDisplayShowHomeEnabled(true) 46 | (activity as SettingsActivity).supportActionBar!!.title = (getString(R.string.title_facedetection_settings)) 47 | } 48 | } 49 | 50 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { 51 | super.onCreateOptionsMenu(menu, inflater) 52 | inflater.inflate(R.menu.menu_help, menu) 53 | } 54 | 55 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 56 | val id = item.itemId 57 | if (id == android.R.id.home) { 58 | view?.let { Navigation.findNavController(it).navigate(R.id.camera_action) } 59 | return true 60 | } else if (id == R.id.action_help) { 61 | showSupport() 62 | return true 63 | } 64 | return super.onOptionsItemSelected(item) 65 | } 66 | 67 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 68 | addPreferencesFromResource(R.xml.pref_qrcode) 69 | } 70 | 71 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 72 | 73 | super.onViewCreated(view, savedInstanceState) 74 | 75 | qrCodePreference = findPreference(getString(R.string.key_setting_camera_qrcodeenabled)) as SwitchPreference 76 | 77 | bindPreferenceSummaryToValue(qrCodePreference!!) 78 | } 79 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/ui/views/WebClientCallback.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.ui.views 2 | 3 | import android.webkit.PermissionRequest 4 | 5 | interface WebClientCallback { 6 | fun askForWebkitPermission(permission: String, requestCode: Int) 7 | 8 | fun complete() 9 | 10 | fun pageLoadComplete(url: String) 11 | 12 | fun setWebkitPermissionRequest(request: PermissionRequest?) 13 | 14 | var isConnected: Boolean 15 | 16 | fun isFinishing(): Boolean 17 | 18 | fun displayProgress(): Boolean 19 | 20 | fun startReloadDelay() 21 | 22 | fun stopReloadDelay() 23 | 24 | fun certPermissionsShown() : Boolean 25 | 26 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/utils/BrowserUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 xyz.wallpanel.app.utils 17 | 18 | import android.content.Intent 19 | import timber.log.Timber 20 | 21 | class BrowserUtils { 22 | /** 23 | * DEPRECATED 24 | * This methods parses url's with intent strings 25 | * "intent:#Intent;launchFlags=0x10000000;component=com.amazon.avod/com.amazon.avod.client.activity.HomeScreenActivity;end" 26 | */ 27 | fun parseIntent(url: String): Intent? { 28 | val separated = url.split(";").toTypedArray() 29 | return if (separated.size == 4) { 30 | Timber.d(separated[0]) // this will contain "intent:#Intent" 31 | Timber.d(separated[1]) // this will contain "launch flag" 32 | Timber.d(separated[2]) // this will contain "component" 33 | Timber.d(separated[3]) // this will contain "end" 34 | val component = separated[2].removePrefix("component=") 35 | val classname = component.split("/").toTypedArray() 36 | val pkgName = classname[0] // this will set the packageName: 37 | val clsName = classname[1] // this will set the className: 38 | val intent = Intent() 39 | intent.action = Intent.ACTION_VIEW 40 | intent.setClassName(pkgName, clsName) 41 | intent 42 | } else { 43 | null 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/utils/CameraUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.utils 18 | 19 | import android.content.Context 20 | import android.hardware.Camera 21 | import xyz.wallpanel.app.R 22 | import java.util.ArrayList 23 | 24 | /** 25 | * Created by Michael Ritchie on 7/9/18. 26 | */ 27 | class CameraUtils { 28 | 29 | companion object { 30 | 31 | open class CameraList { 32 | var cameraId: Int = 0 33 | var description: String = "" 34 | var width:Int = 640 35 | var height:Int = 480 36 | var orientation:Int = 0 37 | } 38 | 39 | @Throws(RuntimeException::class) 40 | fun getCameraList(context: Context): ArrayList { 41 | val cameraList: ArrayList = ArrayList() 42 | for (i in 0 until Camera.getNumberOfCameras()) { 43 | var description: String 44 | val c = Camera.open(i) 45 | val p = c.parameters 46 | val previewSize = p.previewSize 47 | val width = previewSize.width 48 | val height = previewSize.height 49 | val info = Camera.CameraInfo() 50 | Camera.getCameraInfo(i, info) 51 | val patternString = context.getString(R.string.text_camera_pattern) 52 | val facing = 53 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 54 | context.getString(R.string.text_front) 55 | else 56 | context.getString(R.string.text_back) 57 | description = java.text.MessageFormat.format( 58 | patternString, 59 | i, 60 | facing, 61 | info.orientation, 62 | width, 63 | height) 64 | c.stopPreview() 65 | c.release() 66 | 67 | val cameraListItem = CameraList() 68 | cameraListItem.description = description 69 | cameraListItem.cameraId = i 70 | cameraListItem.width = width 71 | cameraListItem.height = height 72 | cameraListItem.orientation = info.orientation 73 | cameraList.add(cameraListItem) 74 | } 75 | return cameraList 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/utils/CrashlyticsDebugTree.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.utils 2 | 3 | import android.util.Log 4 | import timber.log.Timber 5 | import com.google.firebase.crashlytics.FirebaseCrashlytics 6 | import java.lang.Exception 7 | import java.util.* 8 | 9 | class CrashlyticsDebugTree : Timber.Tree() { 10 | 11 | override fun log(priority: Int, tag: String?, message: String, throwable: Throwable?) { 12 | if (priority != Log.ERROR) { 13 | return 14 | } 15 | val crashlytics = FirebaseCrashlytics.getInstance() 16 | crashlytics.setCustomKey(CRASHLYTICS_KEY_PRIORITY, priority) 17 | if (tag != null) crashlytics.setCustomKey(CRASHLYTICS_KEY_TAG, tag) 18 | crashlytics.setCustomKey(CRASHLYTICS_KEY_MESSAGE, message) 19 | if (throwable == null) { 20 | crashlytics.recordException(trimmedException(Exception(message))) 21 | } else { 22 | crashlytics.recordException(throwable) 23 | } 24 | } 25 | 26 | companion object { 27 | private const val CRASHLYTICS_KEY_PRIORITY = "priority" 28 | private const val CRASHLYTICS_KEY_TAG = "tag" 29 | private const val CRASHLYTICS_KEY_MESSAGE = "message" 30 | 31 | private fun trimmedException(e: Exception): Throwable { 32 | val elements = e.stackTrace 33 | var trim = 0 34 | for (i in elements.indices) { 35 | val element = elements[i] 36 | val className = element.className 37 | if (!className.contains("Timber") && !className.contains("CrashlyticsReportingTree")) { 38 | trim = i 39 | break 40 | } 41 | } 42 | e.stackTrace = Arrays.copyOfRange(elements, trim, elements.size) 43 | return e 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/utils/DateUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.utils 18 | 19 | import java.text.SimpleDateFormat 20 | import java.util.Date 21 | import java.util.Locale 22 | import java.util.concurrent.TimeUnit 23 | 24 | 25 | /** 26 | * Date utils 27 | */ 28 | object DateUtils { 29 | 30 | var SECONDS_VALUE = 60000 31 | var MINUTES_VALUE = 1800000 32 | 33 | fun generateCreatedAtDate(): String { 34 | val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US) 35 | return dateFormat.format(Date()) 36 | } 37 | 38 | fun padTimePickerOutput(timeValue: String): String { 39 | var value = timeValue 40 | if (value.length == 1) { 41 | value = "0$value" 42 | } 43 | return value 44 | } 45 | 46 | fun getHourFromTimePicker(timeValue: String): Int { 47 | val values = timeValue.split(":") 48 | if(values.size > 1) { 49 | val value = values[0].toInt() 50 | return value 51 | } 52 | return 0 53 | } 54 | 55 | fun getMinutesFromTimePicker(timeValue: String): Int { 56 | val values = timeValue.split(":") 57 | if(values.size > 1) { 58 | val value = values[1].toInt() 59 | return value 60 | } 61 | return 0 62 | } 63 | 64 | fun getHourAndMinutesFromTimePicker(timePickerValue: String): Float { 65 | return timePickerValue.replace(":", ".").toFloat() 66 | } 67 | 68 | /** 69 | * This converts the milliseconds to a day of the week, but we try to account 70 | * for time that is shorter than expected from DarkSky API . 71 | * @param apiTime 72 | * @return 73 | */ 74 | fun dayOfWeek(apiTime: Long): String { 75 | var time = apiTime 76 | if (apiTime.toString().length == 10) { 77 | time = apiTime * 1000 78 | } 79 | val sdf = SimpleDateFormat("EEEE", Locale.getDefault()) 80 | return sdf.format(Date(time)) 81 | } 82 | 83 | fun convertInactivityTime(inactivityValue: Long): String { 84 | return if (inactivityValue < SECONDS_VALUE) { 85 | TimeUnit.MILLISECONDS.toSeconds(inactivityValue).toString() 86 | } else if (inactivityValue > MINUTES_VALUE) { 87 | TimeUnit.MILLISECONDS.toHours(inactivityValue).toString() 88 | } else { 89 | TimeUnit.MILLISECONDS.toMinutes(inactivityValue).toString() 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/utils/InternalWebChromeClient.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.utils 2 | 3 | import android.content.res.Resources 4 | import android.os.Build 5 | import android.webkit.JsResult 6 | import android.webkit.PermissionRequest 7 | import android.webkit.WebChromeClient 8 | import android.webkit.WebView 9 | import android.widget.Toast 10 | import androidx.annotation.RequiresApi 11 | import androidx.appcompat.app.AlertDialog 12 | import com.google.android.material.snackbar.Snackbar 13 | import xyz.wallpanel.app.R 14 | import xyz.wallpanel.app.ui.activities.BaseBrowserActivity 15 | import xyz.wallpanel.app.ui.views.WebClientCallback 16 | 17 | class InternalWebChromeClient(val resources: Resources, val callback: WebClientCallback) : 18 | WebChromeClient() { 19 | 20 | var snackbar: Snackbar? = null 21 | 22 | override fun onProgressChanged(view: WebView, newProgress: Int) { 23 | if (newProgress == 100) { 24 | snackbar?.dismiss() 25 | if (view.url != null) { 26 | 27 | } else { 28 | Toast.makeText( 29 | view.context, 30 | resources.getString(R.string.toast_empty_url), 31 | Toast.LENGTH_SHORT 32 | ).show() 33 | callback.complete() 34 | } 35 | return 36 | } 37 | if (callback.displayProgress()) { 38 | val text = 39 | resources.getString(R.string.text_loading_percent, newProgress.toString(), view.url) 40 | if (snackbar == null) { 41 | snackbar = Snackbar.make(view, text, Snackbar.LENGTH_INDEFINITE) 42 | } else { 43 | snackbar?.setText(text) 44 | } 45 | snackbar?.show() 46 | } 47 | } 48 | 49 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 50 | override fun onPermissionRequest(request: PermissionRequest?) { 51 | super.onPermissionRequest(request) 52 | callback.setWebkitPermissionRequest(request) 53 | request?.resources?.forEach { 54 | when (it) { 55 | PermissionRequest.RESOURCE_AUDIO_CAPTURE -> { 56 | callback.askForWebkitPermission( 57 | it, 58 | BaseBrowserActivity.REQUEST_CODE_PERMISSION_AUDIO 59 | ) 60 | } 61 | PermissionRequest.RESOURCE_VIDEO_CAPTURE -> { 62 | callback.askForWebkitPermission( 63 | it, 64 | BaseBrowserActivity.REQUEST_CODE_PERMISSION_CAMERA 65 | ) 66 | } 67 | } 68 | } 69 | } 70 | 71 | override fun onJsAlert( 72 | view: WebView, 73 | url: String, 74 | message: String, 75 | result: JsResult 76 | ): Boolean { 77 | if (view.context != null && !callback.isFinishing()) { 78 | AlertDialog.Builder(view.context) 79 | .setMessage(message) 80 | .setPositiveButton(android.R.string.ok, null) 81 | .show() 82 | } 83 | return true 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/utils/LauncherShortcuts.kt: -------------------------------------------------------------------------------- 1 | package xyz.wallpanel.app.utils 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.content.pm.ShortcutInfo 7 | import android.content.pm.ShortcutManager 8 | import android.graphics.drawable.Icon 9 | import android.os.Build 10 | import xyz.wallpanel.app.R 11 | import xyz.wallpanel.app.ui.activities.SettingsActivity 12 | import java.util.* 13 | 14 | @TargetApi(Build.VERSION_CODES.N_MR1) 15 | class LauncherShortcuts { 16 | companion object { 17 | 18 | fun createShortcuts(context: Context) { 19 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { 20 | val shortcutManager = context.getSystemService(ShortcutManager::class.java) 21 | shortcutManager!!.dynamicShortcuts = Arrays.asList(settingsShortcut(context, 0)) 22 | } 23 | } 24 | 25 | /** 26 | * If we ever want to customize the shortcut options 27 | */ 28 | fun updateShortcutStatus(context: Context, searchEnabled: Boolean) { 29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { 30 | val shortcutManager = context.getSystemService(ShortcutManager::class.java) 31 | shortcutManager!!.removeAllDynamicShortcuts() 32 | val list = LinkedList() 33 | 34 | if (searchEnabled) { 35 | list.add(settingsShortcut(context, list.size)) 36 | } 37 | if (!list.isEmpty()) { 38 | shortcutManager.dynamicShortcuts = list 39 | } 40 | } 41 | } 42 | 43 | private fun settingsShortcut(context: Context, rank: Int): ShortcutInfo { 44 | return ShortcutInfo.Builder(context, context.getString(R.string.shortcut_settings_id)) 45 | .setShortLabel(context.getString(R.string.shortcut_settings_shortlabel)) 46 | .setLongLabel(context.getString(R.string.shortcut_settings_longlabel)) 47 | .setIcon(Icon.createWithResource(context, R.drawable.ic_settings_cyan)) 48 | .setDisabledMessage(context.getString(R.string.shortcut_settings_disabled_message)) 49 | .setIntent( 50 | Intent(context, SettingsActivity::class.java) 51 | .setAction(Intent.ACTION_VIEW) 52 | .setFlags( 53 | Intent.FLAG_ACTIVITY_NEW_TASK or 54 | Intent.FLAG_ACTIVITY_CLEAR_TOP or 55 | Intent.FLAG_ACTIVITY_CLEAR_TASK)) 56 | .setRank(rank) 57 | .build() 58 | } 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /WallPanelApp/src/main/java/xyz/wallpanel/app/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 WallPanel 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 distributed 11 | * 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 | 17 | package xyz.wallpanel.app.utils; 18 | 19 | public class StringUtils { 20 | 21 | private static String strSeparator = ","; 22 | 23 | public static String convertArrayToString(String[] array){ 24 | StringBuilder str = new StringBuilder(); 25 | for (int i = 0; i < array.length; i++) { 26 | str.append(array[i]); 27 | // Do not append comma at the end of last element 28 | if(i 16 | 17 | 23 | 27 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable-hdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTimeWalker/wallpanel-android/2775abc1a9428209c9bbed04bb2d8bd6142d9b0d/WallPanelApp/src/main/res/drawable-hdpi/ic_stat_name.png -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable-mdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTimeWalker/wallpanel-android/2775abc1a9428209c9bbed04bb2d8bd6142d9b0d/WallPanelApp/src/main/res/drawable-mdpi/ic_stat_name.png -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable-xhdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTimeWalker/wallpanel-android/2775abc1a9428209c9bbed04bb2d8bd6142d9b0d/WallPanelApp/src/main/res/drawable-xhdpi/ic_stat_name.png -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable-xxhdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTimeWalker/wallpanel-android/2775abc1a9428209c9bbed04bb2d8bd6142d9b0d/WallPanelApp/src/main/res/drawable-xxhdpi/ic_stat_name.png -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_blue_pressed.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_blue_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_bottom_corner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_bottom_corner_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_bottom_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_left_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_top_corner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_border_top_corner_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_disabled.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_green_pressed.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/button_green_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_baseline_backspace.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_baseline_close.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_baseline_help.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_baseline_lock.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_baseline_lock_open.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_baseline_refresh.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_baseline_videocam.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_cloud.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_dashboard.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_dashboard_white.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_directions_run.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_email_black.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_face.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_file_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_github_blk.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_help.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_help_black.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_photo_camera.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_radio_button_checked_black.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_radio_button_unchecked_black.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_settings_brightness.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_settings_cyan.xml: -------------------------------------------------------------------------------- 1 | 8 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_social_reddit.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/ic_star_black.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/drawable/logo_front.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout-land/dialog_screen_saver.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 33 | 34 | 35 | 41 | 42 | 46 | 47 | 48 | 49 | 56 | 57 | 66 | 67 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout-sw600dp-land/dialog_screen_saver.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 33 | 34 | 40 | 41 | 45 | 46 | 47 | 48 | 55 | 56 | 65 | 66 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout-sw600dp/dialog_screen_saver.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 33 | 34 | 40 | 41 | 45 | 46 | 47 | 48 | 55 | 56 | 65 | 66 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout-sw720dp-land/dialog_screen_saver.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 34 | 35 | 41 | 42 | 46 | 47 | 48 | 49 | 56 | 57 | 66 | 67 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout-sw720dp/dialog_screen_saver.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 33 | 34 | 40 | 41 | 45 | 46 | 47 | 48 | 55 | 56 | 65 | 66 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout/activity_browser.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 29 | 30 | 34 | 35 | 39 | 40 | 46 | 47 | 48 | 49 | 50 | 51 | 62 | 63 | 77 | 78 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout/activity_live_camera.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 23 | 24 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 48 | 49 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 16 | 22 | 23 | 30 | 31 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout/activity_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | -------------------------------------------------------------------------------- /WallPanelApp/src/main/res/layout/activity_welcome.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 23 | 24 | 27 | 28 | 33 | 34 | 37 | 38 |