@ -0,0 +1,13 @@ |
|||
*.iml |
|||
.gradle |
|||
/local.properties |
|||
/.idea/caches |
|||
/.idea/libraries |
|||
/.idea/modules.xml |
|||
/.idea/workspace.xml |
|||
/.idea/navEditor.xml |
|||
/.idea/assetWizardSettings.xml |
|||
.DS_Store |
|||
/build |
|||
/captures |
|||
.externalNativeBuild |
@ -0,0 +1 @@ |
|||
/build |
@ -0,0 +1,58 @@ |
|||
apply plugin: 'com.android.application' |
|||
apply plugin: 'androidx.navigation.safeargs' |
|||
apply plugin: 'com.jaredsburrows.license' |
|||
|
|||
android { |
|||
compileSdkVersion 28 |
|||
defaultConfig { |
|||
applicationId "com.skulixlabs.iotcontrol" |
|||
minSdkVersion 21 |
|||
targetSdkVersion 28 |
|||
versionCode 1 |
|||
versionName "1.0" |
|||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" |
|||
} |
|||
applicationVariants.all { variant -> |
|||
variant.resValue "string", "appVersion", variant.versionName |
|||
} |
|||
buildTypes { |
|||
release { |
|||
minifyEnabled false |
|||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
|||
} |
|||
} |
|||
} |
|||
|
|||
/*licenseReport { |
|||
generateHtmlReport = false |
|||
generateJsonReport = true |
|||
copyHtmlReportToAssets = true |
|||
copyJsonReportToAssets = false |
|||
}*/ |
|||
|
|||
dependencies { |
|||
def nav_version = "2.1.0" |
|||
def jackson_ver = "2.9.9" |
|||
|
|||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
|||
implementation 'androidx.appcompat:appcompat:1.0.0' |
|||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' |
|||
//implementation 'com.google.android.material:material:1.0.0' |
|||
implementation 'androidx.preference:preference:1.1.0-alpha05' |
|||
implementation 'androidx.legacy:legacy-support-v4:1.0.0' |
|||
testImplementation 'junit:junit:4.12' |
|||
androidTestImplementation 'androidx.test:runner:1.1.0' |
|||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' |
|||
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-3' |
|||
implementation "com.google.android.material:material:1.1.0-alpha10" |
|||
implementation "androidx.navigation:navigation-fragment:$nav_version" |
|||
implementation "androidx.navigation:navigation-ui:$nav_version" |
|||
implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_ver" |
|||
implementation "com.fasterxml.jackson.core:jackson-core:$jackson_ver" |
|||
implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_ver" |
|||
implementation 'commons-io:commons-io:2.6' |
|||
implementation 'com.google.android:flexbox:1.1.1' |
|||
|
|||
implementation 'br.com.simplepass:loading-button-android:2.1.5' |
|||
implementation 'com.github.StevenDXC:DxLoadingButton:2.2' |
|||
} |
@ -0,0 +1,333 @@ |
|||
|
|||
- artifact: androidx.slidingpanelayout:slidingpanelayout:+ |
|||
name: Android Support Library Sliding Pane Layout |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.appcompat:appcompat:+ |
|||
name: Android AppCompat Library v7 |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: androidx.appcompat:appcompat-resources:+ |
|||
name: Android Resources Library |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: androidx.customview:customview:+ |
|||
name: Android Support Library Custom View |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: org.jetbrains.kotlin:kotlin-stdlib-common:+ |
|||
name: org.jetbrains.kotlin:kotlin-stdlib-common |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://kotlinlang.org/ |
|||
- artifact: androidx.swiperefreshlayout:swiperefreshlayout:+ |
|||
name: Android Support Library Custom View |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.navigation:navigation-fragment:+ |
|||
name: Android Navigation Fragment |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.savedstate:savedstate:+ |
|||
name: Activity |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: com.google.android.material:material:+ |
|||
name: Material Components for Android |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.fragment:fragment:+ |
|||
name: Android Support Library fragment |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: androidx.lifecycle:lifecycle-livedata:+ |
|||
name: Android Lifecycle LiveData |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.constraintlayout:constraintlayout:+ |
|||
name: Android ConstraintLayout |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://tools.android.com |
|||
- artifact: androidx.localbroadcastmanager:localbroadcastmanager:+ |
|||
name: Android Support Library Local Broadcast Manager |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.preference:preference:+ |
|||
name: AndroidX Preference |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.legacy:legacy-support-core-utils:+ |
|||
name: Android Support Library core utils |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.coordinatorlayout:coordinatorlayout:+ |
|||
name: Android Support Library Coordinator Layout |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.legacy:legacy-support-v4:+ |
|||
name: Android Support Library v4 |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: commons-io:commons-io:+ |
|||
name: Apache Commons IO |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: #LICENSE# |
|||
url: http://commons.apache.org/proper/commons-io/ |
|||
- artifact: androidx.navigation:navigation-common:+ |
|||
name: Android Navigation Common |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.versionedparcelable:versionedparcelable:+ |
|||
name: VersionedParcelable |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.print:print:+ |
|||
name: Android Support Library Print |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.drawerlayout:drawerlayout:+ |
|||
name: Android Support Library Drawer Layout |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.navigation:navigation-runtime:+ |
|||
name: Android Navigation Runtime |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.core:core:+ |
|||
name: Android Support Library compat |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.lifecycle:lifecycle-common:+ |
|||
name: Android Lifecycle-Common |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.interpolator:interpolator:+ |
|||
name: Android Support Library Interpolators |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: org.jetbrains.kotlin:kotlin-stdlib:+ |
|||
name: org.jetbrains.kotlin:kotlin-stdlib |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://kotlinlang.org/ |
|||
- artifact: androidx.viewpager:viewpager:+ |
|||
name: Android Support Library View Pager |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.lifecycle:lifecycle-runtime:+ |
|||
name: Android Lifecycle Runtime |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.arch.core:core-common:+ |
|||
name: Android Arch-Common |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.lifecycle:lifecycle-viewmodel:+ |
|||
name: Android Lifecycle ViewModel |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.vectordrawable:vectordrawable:+ |
|||
name: Android Support VectorDrawable |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: androidx.lifecycle:lifecycle-livedata-core:+ |
|||
name: Android Lifecycle LiveData Core |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.media:media:+ |
|||
name: Android Support Library media compat |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: br.com.simplepass:loading-button-android:+ |
|||
name: LoadingButtonAndroid |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://github.com/leandroBorgesFerreira/LoadingButtonAndroid |
|||
- artifact: androidx.documentfile:documentfile:+ |
|||
name: Android Support Library Document File |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.cursoradapter:cursoradapter:+ |
|||
name: Android Support Library Cursor Adapter |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: org.jetbrains:annotations:+ |
|||
name: IntelliJ IDEA Annotations |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://www.jetbrains.org |
|||
- artifact: androidx.arch.core:core-runtime:+ |
|||
name: Android Arch-Runtime |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: androidx.recyclerview:recyclerview:+ |
|||
name: Android Support RecyclerView v7 |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: com.fasterxml.jackson.core:jackson-core:+ |
|||
name: Jackson-core |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: #LICENSE# |
|||
url: https://github.com/FasterXML/jackson-core |
|||
- artifact: androidx.cardview:cardview:+ |
|||
name: Android Support CardView v7 |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.legacy:legacy-support-core-ui:+ |
|||
name: Android Support Library core UI |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: com.fasterxml.jackson.core:jackson-databind:+ |
|||
name: jackson-databind |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: #LICENSE# |
|||
url: http://github.com/FasterXML/jackson |
|||
- artifact: androidx.vectordrawable:vectordrawable-animated:+ |
|||
name: Android Support AnimatedVectorDrawable |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: androidx.annotation:annotation:+ |
|||
name: Android Support Library Annotations |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.transition:transition:+ |
|||
name: Android Transition Support Library |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.navigation:navigation-ui:+ |
|||
name: Android Navigation UI |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/topic/libraries/architecture/index.html |
|||
- artifact: com.fasterxml.jackson.core:jackson-annotations:+ |
|||
name: Jackson-annotations |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: #LICENSE# |
|||
url: http://github.com/FasterXML/jackson |
|||
- artifact: androidx.constraintlayout:constraintlayout-solver:+ |
|||
name: Android ConstraintLayout Solver |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://tools.android.com |
|||
- artifact: androidx.viewpager2:viewpager2:+ |
|||
name: AndroidX Widget ViewPager2 |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: androidx.asynclayoutinflater:asynclayoutinflater:+ |
|||
name: Android Support Library Async Layout Inflater |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: com.github.StevenDXC:DxLoadingButton:+ |
|||
name: StevenDXC/DxLoadingButton |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: Apache License 2.0 |
|||
licenseUrl: https://api.github.com/licenses/apache-2.0 |
|||
url: https://github.com/StevenDXC/DxLoadingButton |
|||
- artifact: androidx.loader:loader:+ |
|||
name: Android Support Library loader |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
|||
- artifact: androidx.activity:activity:+ |
|||
name: Activity |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: https://developer.android.com/jetpack/androidx |
|||
- artifact: androidx.collection:collection:+ |
|||
name: Android Support Library collections |
|||
copyrightHolder: #COPYRIGHT_HOLDER# |
|||
license: The Apache Software License, Version 2.0 |
|||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt |
|||
url: http://developer.android.com/tools/extras/support-library.html |
@ -0,0 +1,21 @@ |
|||
# Add project specific ProGuard rules here. |
|||
# You can control the set of applied configuration files using the |
|||
# proguardFiles setting in build.gradle. |
|||
# |
|||
# For more details, see |
|||
# http://developer.android.com/guide/developing/tools/proguard.html |
|||
|
|||
# If your project uses WebView with JS, uncomment the following |
|||
# and specify the fully qualified class name to the JavaScript interface |
|||
# class: |
|||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
|||
# public *; |
|||
#} |
|||
|
|||
# Uncomment this to preserve the line number information for |
|||
# debugging stack traces. |
|||
#-keepattributes SourceFile,LineNumberTable |
|||
|
|||
# If you keep the line number information, uncomment this to |
|||
# hide the original source file name. |
|||
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,26 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
import android.content.Context; |
|||
import androidx.test.InstrumentationRegistry; |
|||
import androidx.test.runner.AndroidJUnit4; |
|||
|
|||
import org.junit.Test; |
|||
import org.junit.runner.RunWith; |
|||
|
|||
import static org.junit.Assert.*; |
|||
|
|||
/** |
|||
* Instrumented test, which will execute on an Android device. |
|||
* |
|||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
|||
*/ |
|||
@RunWith(AndroidJUnit4.class) |
|||
public class ExampleInstrumentedTest { |
|||
@Test |
|||
public void useAppContext() { |
|||
// Context of the app under test.
|
|||
Context appContext = InstrumentationRegistry.getTargetContext(); |
|||
|
|||
assertEquals("com.example.gatecontrol", appContext.getPackageName()); |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
|||
package="com.skulixlabs.iotcontrol"> |
|||
|
|||
<uses-permission android:name="android.permission.INTERNET" /> |
|||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> |
|||
|
|||
<application |
|||
android:allowBackup="true" |
|||
android:icon="@mipmap/ic_launcher" |
|||
android:label="@string/app_name" |
|||
android:roundIcon="@mipmap/ic_launcher_round" |
|||
android:supportsRtl="true" |
|||
android:theme="@style/AppTheme"> |
|||
<activity |
|||
android:name="com.skulixlabs.iotcontrol.MainActivity" |
|||
android:label="@string/app_name"> |
|||
<intent-filter> |
|||
<action android:name="android.intent.action.MAIN" /> |
|||
|
|||
<category android:name="android.intent.category.LAUNCHER" /> |
|||
</intent-filter> |
|||
</activity> |
|||
</application> |
|||
|
|||
</manifest> |
@ -0,0 +1,385 @@ |
|||
<html> |
|||
<head> |
|||
<style>body { font-family: sans-serif } pre { background-color: #eeeeee; padding: 1em; white-space: pre-wrap; display: inline-block }</style> |
|||
<title>Open source licenses</title> |
|||
</head> |
|||
<body> |
|||
<h3>Notice for packages:</h3> |
|||
<ul> |
|||
<li> |
|||
<a href="#314129783">Activity</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Activity</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android AppCompat Library v7</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Arch-Common</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Arch-Runtime</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android ConstraintLayout</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android ConstraintLayout Solver</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Lifecycle LiveData</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Lifecycle LiveData Core</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Lifecycle Runtime</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Lifecycle ViewModel</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Lifecycle-Common</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Navigation Common</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Navigation Fragment</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Navigation Runtime</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Navigation UI</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Resources Library</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support AnimatedVectorDrawable</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support CardView v7</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Annotations</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Async Layout Inflater</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library collections</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library compat</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Coordinator Layout</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library core UI</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library core utils</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Cursor Adapter</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Custom View</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Custom View</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Document File</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Drawer Layout</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library fragment</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Interpolators</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library loader</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Local Broadcast Manager</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library media compat</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Print</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library Sliding Pane Layout</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library v4</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support Library View Pager</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support RecyclerView v7</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Support VectorDrawable</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Android Transition Support Library</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">AndroidX Preference</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">AndroidX Widget ViewPager2</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Apache Commons IO</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">flexbox-layout</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">IntelliJ IDEA Annotations</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Jackson-annotations</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Jackson-core</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">jackson-databind</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">LoadingButtonAndroid</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">Material Components for Android</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">org.jetbrains.kotlin:kotlin-stdlib</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">org.jetbrains.kotlin:kotlin-stdlib-common</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">StevenDXC/DxLoadingButton</a> |
|||
</li> |
|||
<li> |
|||
<a href="#314129783">VersionedParcelable</a> |
|||
</li> |
|||
<a name="314129783" /> |
|||
<pre> Apache License |
|||
Version 2.0, January 2004 |
|||
http://www.apache.org/licenses/ |
|||
|
|||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|||
|
|||
1. Definitions. |
|||
|
|||
"License" shall mean the terms and conditions for use, reproduction, |
|||
and distribution as defined by Sections 1 through 9 of this document. |
|||
|
|||
"Licensor" shall mean the copyright owner or entity authorized by |
|||
the copyright owner that is granting the License. |
|||
|
|||
"Legal Entity" shall mean the union of the acting entity and all |
|||
other entities that control, are controlled by, or are under common |
|||
control with that entity. For the purposes of this definition, |
|||
"control" means (i) the power, direct or indirect, to cause the |
|||
direction or management of such entity, whether by contract or |
|||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|||
outstanding shares, or (iii) beneficial ownership of such entity. |
|||
|
|||
"You" (or "Your") shall mean an individual or Legal Entity |
|||
exercising permissions granted by this License. |
|||
|
|||
"Source" form shall mean the preferred form for making modifications, |
|||
including but not limited to software source code, documentation |
|||
source, and configuration files. |
|||
|
|||
"Object" form shall mean any form resulting from mechanical |
|||
transformation or translation of a Source form, including but |
|||
not limited to compiled object code, generated documentation, |
|||
and conversions to other media types. |
|||
|
|||
"Work" shall mean the work of authorship, whether in Source or |
|||
Object form, made available under the License, as indicated by a |
|||
copyright notice that is included in or attached to the work |
|||
(an example is provided in the Appendix below). |
|||
|
|||
"Derivative Works" shall mean any work, whether in Source or Object |
|||
form, that is based on (or derived from) the Work and for which the |
|||
editorial revisions, annotations, elaborations, or other modifications |
|||
represent, as a whole, an original work of authorship. For the purposes |
|||
of this License, Derivative Works shall not include works that remain |
|||
separable from, or merely link (or bind by name) to the interfaces of, |
|||
the Work and Derivative Works thereof. |
|||
|
|||
"Contribution" shall mean any work of authorship, including |
|||
the original version of the Work and any modifications or additions |
|||
to that Work or Derivative Works thereof, that is intentionally |
|||
submitted to Licensor for inclusion in the Work by the copyright owner |
|||
or by an individual or Legal Entity authorized to submit on behalf of |
|||
the copyright owner. For the purposes of this definition, "submitted" |
|||
means any form of electronic, verbal, or written communication sent |
|||
to the Licensor or its representatives, including but not limited to |
|||
communication on electronic mailing lists, source code control systems, |
|||
and issue tracking systems that are managed by, or on behalf of, the |
|||
Licensor for the purpose of discussing and improving the Work, but |
|||
excluding communication that is conspicuously marked or otherwise |
|||
designated in writing by the copyright owner as "Not a Contribution." |
|||
|
|||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|||
on behalf of whom a Contribution has been received by Licensor and |
|||
subsequently incorporated within the Work. |
|||
|
|||
2. Grant of Copyright License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
copyright license to reproduce, prepare Derivative Works of, |
|||
publicly display, publicly perform, sublicense, and distribute the |
|||
Work and such Derivative Works in Source or Object form. |
|||
|
|||
3. Grant of Patent License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
(except as stated in this section) patent license to make, have made, |
|||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|||
where such license applies only to those patent claims licensable |
|||
by such Contributor that are necessarily infringed by their |
|||
Contribution(s) alone or by combination of their Contribution(s) |
|||
with the Work to which such Contribution(s) was submitted. If You |
|||
institute patent litigation against any entity (including a |
|||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|||
or a Contribution incorporated within the Work constitutes direct |
|||
or contributory patent infringement, then any patent licenses |
|||
granted to You under this License for that Work shall terminate |
|||
as of the date such litigation is filed. |
|||
|
|||
4. Redistribution. You may reproduce and distribute copies of the |
|||
Work or Derivative Works thereof in any medium, with or without |
|||
modifications, and in Source or Object form, provided that You |
|||
meet the following conditions: |
|||
|
|||
(a) You must give any other recipients of the Work or |
|||
Derivative Works a copy of this License; and |
|||
|
|||
(b) You must cause any modified files to carry prominent notices |
|||
stating that You changed the files; and |
|||
|
|||
(c) You must retain, in the Source form of any Derivative Works |
|||
that You distribute, all copyright, patent, trademark, and |
|||
attribution notices from the Source form of the Work, |
|||
excluding those notices that do not pertain to any part of |
|||
the Derivative Works; and |
|||
|
|||
(d) If the Work includes a "NOTICE" text file as part of its |
|||
distribution, then any Derivative Works that You distribute must |
|||
include a readable copy of the attribution notices contained |
|||
within such NOTICE file, excluding those notices that do not |
|||
pertain to any part of the Derivative Works, in at least one |
|||
of the following places: within a NOTICE text file distributed |
|||
as part of the Derivative Works; within the Source form or |
|||
documentation, if provided along with the Derivative Works; or, |
|||
within a display generated by the Derivative Works, if and |
|||
wherever such third-party notices normally appear. The contents |
|||
of the NOTICE file are for informational purposes only and |
|||
do not modify the License. You may add Your own attribution |
|||
notices within Derivative Works that You distribute, alongside |
|||
or as an addendum to the NOTICE text from the Work, provided |
|||
that such additional attribution notices cannot be construed |
|||
as modifying the License. |
|||
|
|||
You may add Your own copyright statement to Your modifications and |
|||
may provide additional or different license terms and conditions |
|||
for use, reproduction, or distribution of Your modifications, or |
|||
for any such Derivative Works as a whole, provided Your use, |
|||
reproduction, and distribution of the Work otherwise complies with |
|||
the conditions stated in this License. |
|||
|
|||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|||
any Contribution intentionally submitted for inclusion in the Work |
|||
by You to the Licensor shall be under the terms and conditions of |
|||
this License, without any additional terms or conditions. |
|||
Notwithstanding the above, nothing herein shall supersede or modify |
|||
the terms of any separate license agreement you may have executed |
|||
with Licensor regarding such Contributions. |
|||
|
|||
6. Trademarks. This License does not grant permission to use the trade |
|||
names, trademarks, service marks, or product names of the Licensor, |
|||
except as required for reasonable and customary use in describing the |
|||
origin of the Work and reproducing the content of the NOTICE file. |
|||
|
|||
7. Disclaimer of Warranty. Unless required by applicable law or |
|||
agreed to in writing, Licensor provides the Work (and each |
|||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|||
implied, including, without limitation, any warranties or conditions |
|||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|||
appropriateness of using or redistributing the Work and assume any |
|||
risks associated with Your exercise of permissions under this License. |
|||
|
|||
8. Limitation of Liability. In no event and under no legal theory, |
|||
whether in tort (including negligence), contract, or otherwise, |
|||
unless required by applicable law (such as deliberate and grossly |
|||
negligent acts) or agreed to in writing, shall any Contributor be |
|||
liable to You for damages, including any direct, indirect, special, |
|||
incidental, or consequential damages of any character arising as a |
|||
result of this License or out of the use or inability to use the |
|||
Work (including but not limited to damages for loss of goodwill, |
|||
work stoppage, computer failure or malfunction, or any and all |
|||
other commercial damages or losses), even if such Contributor |
|||
has been advised of the possibility of such damages. |
|||
|
|||
9. Accepting Warranty or Additional Liability. While redistributing |
|||
the Work or Derivative Works thereof, You may choose to offer, |
|||
and charge a fee for, acceptance of support, warranty, indemnity, |
|||
or other liability obligations and/or rights consistent with this |
|||
License. However, in accepting such obligations, You may act only |
|||
on Your own behalf and on Your sole responsibility, not on behalf |
|||
of any other Contributor, and only if You agree to indemnify, |
|||
defend, and hold each Contributor harmless for any liability |
|||
incurred by, or claims asserted against, such Contributor by reason |
|||
of your accepting any such warranty or additional liability. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
APPENDIX: How to apply the Apache License to your work. |
|||
|
|||
To apply the Apache License to your work, attach the following |
|||
boilerplate notice, with the fields enclosed by brackets "[]" |
|||
replaced with your own identifying information. (Don't include |
|||
the brackets!) The text should be enclosed in the appropriate |
|||
comment syntax for the file format. We also recommend that a |
|||
file or class name and description of purpose be included on the |
|||
same "printed page" as the copyright notice for easier |
|||
identification within third-party archives. |
|||
|
|||
Copyright [yyyy] [name of copyright owner] |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
</pre> |
|||
</ul> |
|||
</body> |
|||
</html> |
@ -0,0 +1,65 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
import android.app.Dialog; |
|||
import android.content.DialogInterface; |
|||
import android.os.Bundle; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.appcompat.app.AlertDialog; |
|||
import androidx.fragment.app.DialogFragment; |
|||
import androidx.fragment.app.Fragment; |
|||
|
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
import android.webkit.WebView; |
|||
|
|||
|
|||
public class AboutFragment extends Fragment { |
|||
@Override |
|||
public View onCreateView(LayoutInflater inflater, ViewGroup container, |
|||
Bundle savedInstanceState) { |
|||
// Inflate the layout for this fragment
|
|||
return inflater.inflate(R.layout.fragment_about, container, false); |
|||
} |
|||
|
|||
@Override |
|||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { |
|||
super.onViewCreated(view, savedInstanceState); |
|||
|
|||
view.findViewById(R.id.btnLicenses).setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
new OpenSourceLicensesDialog().newInstance().show(getChildFragmentManager(), "dialog_licenses"); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public static class OpenSourceLicensesDialog extends DialogFragment { |
|||
|
|||
public static OpenSourceLicensesDialog newInstance() { |
|||
OpenSourceLicensesDialog dialog = new OpenSourceLicensesDialog(); |
|||
Bundle args = new Bundle(); |
|||
dialog.setArguments(args); |
|||
return dialog; |
|||
} |
|||
|
|||
@Override |
|||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { |
|||
WebView webView = new WebView(requireActivity()); |
|||
webView.loadUrl("file:///android_asset/open_source_licenses.html"); |
|||
|
|||
return new AlertDialog.Builder(requireActivity()) |
|||
.setTitle("Open Source Licenses") |
|||
.setView(webView) |
|||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { |
|||
@Override |
|||
public void onClick(DialogInterface dialog, int i) { |
|||
dialog.dismiss(); |
|||
} |
|||
}) |
|||
.create(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,231 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
import android.graphics.Color; |
|||
import android.os.AsyncTask; |
|||
import android.os.Handler; |
|||
import android.text.Spannable; |
|||
import android.text.SpannableString; |
|||
import android.text.style.ForegroundColorSpan; |
|||
import android.util.Log; |
|||
|
|||
import com.dx.dxloadingbutton.lib.LoadingButton; |
|||
import com.skulixlabs.iotcontrol.adapter.ItemAdapter; |
|||
import com.skulixlabs.iotcontrol.model.Cmd; |
|||
import com.skulixlabs.iotcontrol.model.CmdResponse; |
|||
import com.skulixlabs.iotcontrol.util.Utils; |
|||
|
|||
import java.io.ByteArrayOutputStream; |
|||
import java.lang.ref.WeakReference; |
|||
import java.nio.ByteBuffer; |
|||
import java.util.Arrays; |
|||
|
|||
import javax.crypto.Mac; |
|||
import javax.crypto.spec.SecretKeySpec; |
|||
|
|||
import br.com.simplepass.loadingbutton.customViews.CircularProgressButton; |
|||
|
|||
public class ConnectTaskFromAdapter extends AsyncTask<Void, Spannable, ConnectTaskFromAdapter.ConnectTaskResult> { |
|||
private final String TAG = ConnectTaskFromAdapter.class.getName(); |
|||
final ConnectTaskFromAdapter.ConnectTaskResult result = new ConnectTaskFromAdapter.ConnectTaskResult(); // If we were to save to a Byte var, then a final Byte array should be initiated
|
|||
|
|||
WeakReference<ItemAdapter.ItemViewHolder> holder; |
|||
WeakReference<MainFragment> fragment; |
|||
LoadingButton actionButton; |
|||
TcpClient mTcpClient = null; |
|||
Mac mac = null; |
|||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
|||
ByteBuffer resHash; |
|||
ByteBuffer gotBytes; |
|||
int gotBytesNum = 0; |
|||
Cmd cmd; |
|||
|
|||
public ConnectTaskFromAdapter(ItemAdapter.ItemViewHolder holder, WeakReference<MainFragment> fragment, Cmd cmd, LoadingButton actionButton) { |
|||
this.holder = new WeakReference<>(holder); |
|||
this.fragment = fragment; |
|||
this.cmd = cmd; |
|||
this.actionButton = actionButton; |
|||
} |
|||
|
|||
@Override |
|||
protected void onPreExecute() { |
|||
try { |
|||
mac = Mac.getInstance("HmacSHA256"); |
|||
mac.init(new SecretKeySpec(cmd.getOptions().getHmacKey().getBytes(), cmd.getOptions().getHmacKey())); |
|||
} catch (Exception e) { |
|||
//onMessage(e.getMessage());
|
|||
cancel(true); |
|||
result.exception = e; |
|||
return; |
|||
} |
|||
|
|||
gotBytes = ByteBuffer.allocate(cmd.getOptions().getRandDataLength()); |
|||
resHash = ByteBuffer.allocate(cmd.getOptions().getHashByteLength()); |
|||
} |
|||
|
|||
@Override |
|||
protected ConnectTaskFromAdapter.ConnectTaskResult doInBackground(final Void... voids) { |
|||
if (isCancelled()) |
|||
return null; |
|||
Log.d(TAG, "Sending command: " + cmd.getValue()); |
|||
mTcpClient = new TcpClient(cmd.getOptions().getUrl(), new TcpClient.OnMessageReceived() { |
|||
@Override |
|||
public void messageReceived(byte[] data) { |
|||
try { |
|||
gotBytesNum += data.length; |
|||
|
|||
if (gotBytesNum <= cmd.getOptions().getRandDataLength()) { |
|||
mac.update(data); |
|||
for (int i = 0; i < data.length; i++) { |
|||
gotBytes.put(gotBytesNum - data.length + i, data[i]); |
|||
} |
|||
} |
|||
|
|||
if (gotBytesNum == cmd.getOptions().getRandDataLength()) { |
|||
Log.d(TAG, "Sending action with value: " + cmd.getValue()); |
|||
mac.update((byte) cmd.getValue()); |
|||
|
|||
byte[] reqHash = mac.doFinal(outputStream.toByteArray()); |
|||
|
|||
System.out.println(Utils.bytesToHex(reqHash)); |
|||
mTcpClient.sendMessage(reqHash); |
|||
} |
|||
|
|||
if (gotBytesNum > cmd.getOptions().getRandDataLength()) { |
|||
if (gotBytesNum > (cmd.getOptions().getRandDataLength() + cmd.getOptions().getHashByteLength())) |
|||
Log.d("test", "error!"); |
|||
|
|||
for (int i = 0; i < data.length; i++) |
|||
resHash.put(gotBytesNum - cmd.getOptions().getRandDataLength() - data.length + i, data[i]); |
|||
|
|||
if (gotBytesNum == (cmd.getOptions().getRandDataLength() + cmd.getOptions().getHashByteLength())) { |
|||
Object[] objects = cmd.getResponseList().keySet().toArray(); |
|||
Byte[] bytes = Arrays.copyOf(objects, objects.length, Byte[].class); |
|||
|
|||
byte b = Utils.analyzeResponse(cmd.getOptions().getHmacKey(), bytes, gotBytes, resHash); //cmds[0].getResponseList()
|
|||
|
|||
CmdResponse cmdResponse = Utils.matchResponse(cmd, b); |
|||
if (cmdResponse != null) |
|||
publishProgress(updateState(cmdResponse.getDescription(), cmdResponse.getColor())); |
|||
else |
|||
publishProgress(updateState("Failed!", "#FF0000")); |
|||
|
|||
Log.d("test", "Response byte: " + b); |
|||
result.result = b; |
|||
|
|||
mTcpClient.stopClient(); |
|||
} |
|||
} |
|||
} catch (Exception e) { |
|||
publishProgress(updateState("Error: " + e.getMessage(), "#FF0000")); |
|||
Log.e(TAG, "An error occurred", e); |
|||
mTcpClient.stopClient(); |
|||
result.exception = e; |
|||
} |
|||
} |
|||
}, new TcpClient.OnClientError() { |
|||
@Override |
|||
public void onError(Exception e) { |
|||
|
|||
if (e instanceof java.net.ConnectException) |
|||
publishProgress(updateState("Error: Connection impossible", "#FF0000")); |
|||
else if (e instanceof java.net.SocketTimeoutException) |
|||
publishProgress(updateState("Error: Timeout", "#FF0000")); |
|||
else |
|||
publishProgress(updateState("Error: " + e.getMessage(), "#FF0000")); |
|||
mTcpClient.stopClient(); |
|||
result.exception = e; |
|||
|
|||
} |
|||
}); |
|||
|
|||
mTcpClient.run(); |
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
protected void onProgressUpdate(Spannable... values) { |
|||
try { |
|||
switch (cmd.getType()) { |
|||
case STATE: |
|||
holder.get().state.setText(values[0]); |
|||
break; |
|||
case FEEDBACK: |
|||
|
|||
} |
|||
} catch (NullPointerException e) { // holder may have been destroyed (null)
|
|||
// Just stifle the exception, preventing sudden app termination
|
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void onPostExecute(ConnectTaskFromAdapter.ConnectTaskResult result) { |
|||
super.onPostExecute(result); |
|||
if (actionButton!= null) { |
|||
if (result.exception == null) { // A response should be returned if succeeded. Otherwise use custom object including an Exception field
|
|||
actionSucceededAnimation(actionButton); |
|||
} else { |
|||
actionFailedAnimation(actionButton); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/*private void onMessage(String message) { |
|||
Toast.makeText(fragment.get().getActivity(), message, Toast.LENGTH_SHORT).show(); |
|||
}*/ |
|||
|
|||
private void actionFailedAnimation(LoadingButton actionButton) { |
|||
/*Bitmap bitmap = Utils.drawableToBitmap(ContextCompat.getDrawable(holder.get().getContext(), R.drawable.ic_close_red_24dp)); |
|||
actionButton.doneLoadingAnimation(SettingsFragment.getPrimaryColor(holder.get().getContext()), bitmap); |
|||
revertAnimation(actionButton);*/ |
|||
actionButton.loadingFailed(); // Auto reset is enabled
|
|||
} |
|||
|
|||
private void actionSucceededAnimation(final LoadingButton actionButton) { |
|||
/*Bitmap bitmap = Utils.drawableToBitmap(ContextCompat.getDrawable(holder.get().getContext(), R.drawable.ic_check_green_48dp)); |
|||
actionButton.doneLoadingAnimation(SettingsFragment.getPrimaryColor(holder.get().getContext()), bitmap); |
|||
revertAnimation(actionButton);*/ |
|||
|
|||
actionButton.loadingSuccessful(); |
|||
new Handler().postDelayed(new Runnable() { |
|||
@Override |
|||
public void run() { |
|||
actionButton.reset(); |
|||
} |
|||
}, 750); |
|||
/*actionButton.setAnimationEndAction((Function1)(new Function1() { |
|||
public Object invoke(Object var1) { |
|||
this.invoke((AnimationType)var1); |
|||
return Unit.INSTANCE; |
|||
} |
|||
|
|||
public final void invoke(@NotNull AnimationType it) { |
|||
Intrinsics.checkParameterIsNotNull(it, "it"); |
|||
Toast.makeText(holder.get().getContext().getApplicationContext(), (CharSequence)("end:" + it), Toast.LENGTH_SHORT).show(); |
|||
} |
|||
}));*/ |
|||
} |
|||
|
|||
private void revertAnimation(final CircularProgressButton actionButton) { |
|||
new Handler().postDelayed(new Runnable() { |
|||
@Override |
|||
public void run() { |
|||
actionButton.startMorphRevertAnimation(); |
|||
} |
|||
}, 500); |
|||
} |
|||
|
|||
private Spannable updateState(String str, String color) { |
|||
Spannable spannable = new SpannableString(str); |
|||
spannable.setSpan( |
|||
new ForegroundColorSpan(Color.parseColor(color)), |
|||
0, str.length(), |
|||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
return spannable; |
|||
} |
|||
|
|||
public class ConnectTaskResult { |
|||
public byte result; |
|||
public Exception exception; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,69 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
import android.os.Bundle; |
|||
|
|||
import androidx.appcompat.app.AppCompatActivity; |
|||
import androidx.appcompat.app.AppCompatDelegate; |
|||
import androidx.appcompat.widget.Toolbar; |
|||
import androidx.navigation.NavController; |
|||
import androidx.navigation.Navigation; |
|||
import androidx.navigation.ui.NavigationUI; |
|||
import androidx.preference.PreferenceManager; |
|||
|
|||
|
|||
/** |
|||
* IMPORTANT NOTES |
|||
* |
|||
* The following applies only to custom toolbars. If we use NavigationUI's default |
|||
* toolbar then everything works by default. ConstraintLayout overlaps its children. |
|||
* That means that the Toolbar will be overlapped by the fragments' content (content |
|||
* of all the pages in the graph). To avoid this our top destination (home |
|||
* page in nav graph) must have a different type of layout (linear). The other |
|||
* solution is to add the margin_top=?attr/actionBarSize for the fragment of the |
|||
* home page, but that is not recommended. |
|||
* |
|||
*/ |
|||
|
|||
// TODO: dynamic cmd and response equality check
|
|||
public class MainActivity extends AppCompatActivity { |
|||
|
|||
@Override |
|||
protected void onCreate(Bundle savedInstanceState) { |
|||
theme(); // Set theme here, save as SharedPreference, recreate when changed
|
|||
super.onCreate(savedInstanceState); |
|||
setContentView(R.layout.activity_main); |
|||
|
|||
NavController navController = Navigation.findNavController(this, R.id.my_nav_host_fragment); |
|||
Toolbar toolbar = findViewById(R.id.toolbar); |
|||
setSupportActionBar(toolbar); |
|||
NavigationUI.setupWithNavController(toolbar, navController); |
|||
} |
|||
|
|||
@Override |
|||
public boolean onSupportNavigateUp() { |
|||
Navigation.findNavController(this, R.id.my_nav_host_fragment).navigateUp(); |
|||
return super.onSupportNavigateUp(); |
|||
} |
|||
|
|||
public void theme() { |
|||
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) |
|||
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES); |
|||
else { |
|||
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO); |
|||
} |
|||
|
|||
/* Color even in dark mode, move to above else block if applied only when dark mode is off*/ |
|||
String themeColor = PreferenceManager.getDefaultSharedPreferences(this).getString("theme_color", null); |
|||
if (themeColor == null) themeColor = "default"; |
|||
switch (themeColor) { |
|||
case "red": |
|||
setTheme(R.style.AppTheme_RED); |
|||
break; |
|||
case "orange": |
|||
setTheme(R.style.AppTheme_ORANGE); |
|||
break; |
|||
default: |
|||
setTheme(R.style.AppTheme); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,124 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
|
|||
import android.os.Bundle; |
|||
import android.util.Log; |
|||
import android.view.LayoutInflater; |
|||
import android.view.Menu; |
|||
import android.view.MenuInflater; |
|||
import android.view.MenuItem; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.fragment.app.Fragment; |
|||
import androidx.navigation.Navigation; |
|||
import androidx.recyclerview.widget.LinearLayoutManager; |
|||
import androidx.recyclerview.widget.RecyclerView; |
|||
|
|||
import com.skulixlabs.iotcontrol.adapter.ItemAdapter; |
|||
import com.skulixlabs.iotcontrol.util.jackson.JsonUtils; |
|||
import com.google.android.material.snackbar.Snackbar; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
import com.skulixlabs.iotcontrol.model.CmdGroup; |
|||
|
|||
/** |
|||
* A simple {@link Fragment} subclass. |
|||
*/ |
|||
public class MainFragment extends Fragment { |
|||
|
|||
private static final String TAG = MainFragment.class.getName(); |
|||
ItemAdapter adapter = null; |
|||
|
|||
public MainFragment() { |
|||
// Required empty public constructor
|
|||
} |
|||
|
|||
@Override |
|||
public View onCreateView(LayoutInflater inflater, ViewGroup container, |
|||
Bundle savedInstanceState) { |
|||
// Inflate the layout for this fragment
|
|||
setHasOptionsMenu(true); |
|||
return inflater.inflate(R.layout.fragment_main, container, false); |
|||
} |
|||
|
|||
@Override |
|||
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) { |
|||
super.onViewCreated(view, savedInstanceState); |
|||
|
|||
RecyclerView recList = (RecyclerView) view.findViewById(R.id.cardList); |
|||
LinearLayoutManager llm = new LinearLayoutManager(getContext()); |
|||
llm.setOrientation(LinearLayoutManager.VERTICAL); |
|||
recList.setLayoutManager(llm); |
|||
|
|||
List<CmdGroup> groups = new ArrayList<>(); |
|||
try { |
|||
groups = new JsonUtils().getCommands(getActivity()); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
Snackbar.make(view, getResources().getString(R.string.invalid_commands), Snackbar.LENGTH_LONG) |
|||
.setAction(getResources().getString(R.string.load), new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
NavGraphDirections.ActionOpenSettings actionOpenSettings = SettingsFragmentDirections.actionOpenSettings(); |
|||
actionOpenSettings.setImportCmds(true); // Using Safe-args
|
|||
Navigation.findNavController(getActivity(), R.id.my_nav_host_fragment).navigate(actionOpenSettings); |
|||
} |
|||
}).show(); |
|||
} |
|||
|
|||
adapter = new ItemAdapter(null, groups); //this,groups
|
|||
recList.setAdapter(adapter); |
|||
|
|||
Log.d(TAG, "oneviewcreated"); |
|||
} |
|||
|
|||
/** |
|||
* Runs when screen is off |
|||
*/ |
|||
@Override |
|||
public void onResume() { |
|||
Log.d(TAG, "onResume"); |
|||
super.onResume(); |
|||
adapter.validateStateListeners(); |
|||
} |
|||
|
|||
@Override |
|||
public void onPause() { |
|||
Log.d(TAG, "onPause"); |
|||
super.onPause(); |
|||
adapter.invalidateStateListeners(); |
|||
} |
|||
|
|||
@Override |
|||
public void onDestroyView() { |
|||
super.onDestroyView(); |
|||
adapter = null; |
|||
} |
|||
|
|||
@Override |
|||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { |
|||
inflater.inflate(R.menu.menu_main, menu); |
|||
super.onCreateOptionsMenu(menu, inflater); |
|||
} |
|||
|
|||
@Override |
|||
public boolean onOptionsItemSelected(MenuItem item) { |
|||
// Handle action bar item clicks here. The action bar will
|
|||
// automatically handle clicks on the Home/Up button, so long
|
|||
// as you specify a parent activity in AndroidManifest.xml.
|
|||
int id = item.getItemId(); |
|||
|
|||
//noinspection SimplifiableIfStatement
|
|||
if (id == R.id.action_settings) { |
|||
Navigation.findNavController(getActivity(), R.id.my_nav_host_fragment).navigate(R.id.action_open_settings); |
|||
return true; |
|||
} |
|||
|
|||
return super.onOptionsItemSelected(item); |
|||
} |
|||
} |
@ -0,0 +1,262 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
import android.Manifest; |
|||
import android.app.Activity; |
|||
import android.app.AlertDialog; |
|||
import android.app.Dialog; |
|||
import android.content.ClipData; |
|||
import android.content.ClipboardManager; |
|||
import android.content.Context; |
|||
import android.content.DialogInterface; |
|||
import android.content.Intent; |
|||
import android.content.pm.PackageManager; |
|||
import android.net.Uri; |
|||
import android.os.Bundle; |
|||
import android.util.TypedValue; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.widget.Toast; |
|||
|
|||
import androidx.annotation.ColorInt; |
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.core.content.ContextCompat; |
|||
import androidx.fragment.app.DialogFragment; |
|||
import androidx.fragment.app.Fragment; |
|||
import androidx.navigation.Navigation; |
|||
import androidx.preference.ListPreference; |
|||
import androidx.preference.Preference; |
|||
import androidx.preference.PreferenceFragmentCompat; |
|||
import androidx.preference.SwitchPreferenceCompat; |
|||
|
|||
import com.skulixlabs.iotcontrol.util.jackson.JsonUtils; |
|||
|
|||
import java.io.InputStream; |
|||
|
|||
import static android.content.ClipDescription.MIMETYPE_TEXT_PLAIN; |
|||
import static com.skulixlabs.iotcontrol.util.jackson.JsonUtils.REQUEST_READ_FILE; |
|||
import static com.skulixlabs.iotcontrol.util.jackson.JsonUtils.REQUEST_READ_STORAGE; |
|||
|
|||
/** Preference screens does not currently support Data Binding |
|||
* because it is not a xml layout file |
|||
*/ |
|||
public class SettingsFragment extends PreferenceFragmentCompat { |
|||
@ColorInt public static Integer primaryColor = null; |
|||
|
|||
public SettingsFragment() { |
|||
} |
|||
|
|||
@Override |
|||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { |
|||
setPreferencesFromResource(R.xml.root_preferences, rootKey); |
|||
|
|||
((Preference) findPreference("load_json_commands")).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { |
|||
@Override |
|||
public boolean onPreferenceClick(Preference preference) { |
|||
showImportDialog(); |
|||
return true; |
|||
}; |
|||
}); |
|||
|
|||
((SwitchPreferenceCompat) findPreference("dark_theme")).setOnPreferenceChangeListener(updateThemeListener(themeAction())); |
|||
((ListPreference) findPreference("theme_color")).setOnPreferenceChangeListener(updateThemeListener(themeAction())); |
|||
|
|||
((Preference) findPreference("version")).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { |
|||
@Override |
|||
public boolean onPreferenceClick(Preference preference) { |
|||
Navigation.findNavController(getActivity(), R.id.my_nav_host_fragment).navigate(R.id.action_settingsFragment_to_aboutFragment); |
|||
return true; |
|||
}; |
|||
}); |
|||
|
|||
shouldShowImportDialog(); |
|||
} |
|||
|
|||
private void shouldShowImportDialog() { |
|||
if (SettingsFragmentArgs.fromBundle(getArguments()).getImportCmds()) { |
|||
getArguments().putBoolean("importCmds", false); |
|||
showImportDialog(); |
|||
} |
|||
} |
|||
|
|||
private void showImportDialog() { |
|||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); |
|||
LayoutInflater inflater = requireActivity().getLayoutInflater(); |
|||
|
|||
// Inflate and set the layout for the dialog
|
|||
// Pass null as the parent view because its going in the dialog layout
|
|||
builder.setView(inflater.inflate(R.layout.dialog_import_method, null)); |
|||
final AlertDialog alertDialog = builder.create(); |
|||
alertDialog.show(); |
|||
|
|||
alertDialog.findViewById(R.id.btnFromClipboard).setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); |
|||
String json = ""; |
|||
|
|||
// If the clipboard doesn't contain data, else start the process after validation
|
|||
if (!(clipboard.hasPrimaryClip()) || !(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))) { |
|||
Toast.makeText(getActivity(), "Not valid!", Toast.LENGTH_SHORT).show(); |
|||
((Preference) findPreference("load_json_commands")).setIcon(R.drawable.ic_error_outline_red_48dp); |
|||
} else { |
|||
try { |
|||
ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); // Since the clipboard contains plain text.
|
|||
json = item.getText().toString(); // Gets the clipboard as text.
|
|||
new JsonUtils().saveCommands(getActivity(), json); |
|||
((Preference) findPreference("load_json_commands")).setIcon(R.drawable.ic_check_green_48dp); |
|||
alertDialog.cancel(); |
|||
} catch (Exception e) { |
|||
Toast.makeText(getActivity(), "Not valid!", Toast.LENGTH_SHORT).show(); |
|||
((Preference) findPreference("load_json_commands")).setIcon(R.drawable.ic_error_outline_red_48dp); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
|
|||
alertDialog.findViewById(R.id.btnFromFile).setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
selectFile(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public Runnable themeAction() { |
|||
return new Runnable() { |
|||
@Override |
|||
public void run() { |
|||
primaryColor = null; |
|||
((MainActivity) getActivity()).theme(); |
|||
getActivity().recreate(); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
public static synchronized int getPrimaryColor(Context context) { |
|||
if (primaryColor == null) { |
|||
TypedValue typedValue = new TypedValue(); |
|||
context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true); |
|||
primaryColor = typedValue.data; |
|||
} |
|||
return primaryColor; |
|||
} |
|||
|
|||
private String FRAGMENT_DIALOG = "dialog"; |
|||
|
|||
public void selectFile() { |
|||
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) |
|||
!= PackageManager.PERMISSION_GRANTED) { |
|||
requestReadStoragePermission(); |
|||
return; |
|||
} |
|||
openFileManager(); |
|||
} |
|||
|
|||
private void openFileManager() { |
|||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); |
|||
intent.addCategory(Intent.CATEGORY_OPENABLE); |
|||
intent.setType("*/*"); |
|||
startActivityForResult(intent, REQUEST_READ_FILE); |
|||
} |
|||
|
|||
private void requestReadStoragePermission() { |
|||
if (shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) { |
|||
new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG); |
|||
} else { |
|||
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_READ_STORAGE); |
|||
} |
|||
} |
|||
|
|||
public static class ConfirmationDialog extends DialogFragment { |
|||
@NonNull |
|||
@Override |
|||
public Dialog onCreateDialog(Bundle savedInstanceState) { |
|||
final Fragment parent = getParentFragment(); |
|||
return new AlertDialog.Builder(getActivity()) |
|||
.setMessage(R.string.request_read_external_storage_permission) |
|||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { |
|||
@Override |
|||
public void onClick(DialogInterface dialog, int which) { |
|||
parent.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, |
|||
REQUEST_READ_STORAGE); |
|||
} |
|||
}) |
|||
.create(); |
|||
} |
|||
} |
|||
|
|||
public static class ErrorDialog extends DialogFragment { |
|||
|
|||
private static final String ARG_MESSAGE = "message"; |
|||
|
|||
public static ErrorDialog newInstance(String message) { |
|||
ErrorDialog dialog = new ErrorDialog(); |
|||
Bundle args = new Bundle(); |
|||
args.putString(ARG_MESSAGE, message); |
|||
dialog.setArguments(args); |
|||
return dialog; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public Dialog onCreateDialog(Bundle savedInstanceState) { |
|||
final Activity activity = getActivity(); |
|||
return new AlertDialog.Builder(activity) |
|||
.setMessage(getArguments().getString(ARG_MESSAGE)) |
|||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { |
|||
@Override |
|||
public void onClick(DialogInterface dialog, int i) { |
|||
getDialog().cancel(); |
|||
} |
|||
}) |
|||
.create(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, |
|||
@NonNull int[] grantResults) { |
|||
if (requestCode == REQUEST_READ_STORAGE) { |
|||
if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) { // one requested permission, one result expected (in results array)
|
|||
ErrorDialog.newInstance(getString(R.string.request_read_external_storage_permission)) |
|||
.show(getChildFragmentManager(), FRAGMENT_DIALOG); |
|||
} else { |
|||
openFileManager(); |
|||
} |
|||
} else { |
|||
super.onRequestPermissionsResult(requestCode, permissions, grantResults); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { |
|||
if (requestCode == REQUEST_READ_FILE && resultCode == Activity.RESULT_OK) { |
|||
if (data != null) { |
|||
Uri uri = data.getData(); |
|||
|
|||
try { |
|||
InputStream is = getActivity().getContentResolver().openInputStream(uri); |
|||
JsonUtils jsonUtils = new JsonUtils(); |
|||
jsonUtils.saveCommands(getActivity(), is); |
|||
((Preference) findPreference("load_json_commands")).setIcon(R.drawable.ic_check_green_48dp); |
|||
System.out.println(); |
|||
} catch (Exception e) { |
|||
((Preference) findPreference("load_json_commands")).setIcon(R.drawable.ic_error_outline_red_48dp); |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static Preference.OnPreferenceChangeListener updateThemeListener(final Runnable action) { |
|||
return new Preference.OnPreferenceChangeListener() { |
|||
@Override |
|||
public boolean onPreferenceChange(Preference preference, Object newValue) { |
|||
action.run(); |
|||
return true; |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,163 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
import android.util.Log; |
|||
|
|||
import java.io.DataInputStream; |
|||
import java.io.DataOutputStream; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.net.InetSocketAddress; |
|||
import java.net.Socket; |
|||
|
|||
public class TcpClient { |
|||
public static final String TAG = TcpClient.class.getName(); |
|||
public static final int TIMEOUT = 1500; |
|||
public String SERVER_IP; |
|||
public int SERVER_PORT; |
|||
|
|||
// sends message received notifications
|
|||
private OnMessageReceived mMessageListener = null; |
|||
private OnClientError mErrorListener = null; |
|||
// while this is true, the server will continue running/listening
|
|||
private boolean mRun = false; |
|||
// used to send data
|
|||
DataOutputStream mBufferOut; |
|||
|
|||
/** |
|||
* Constructor of the class. OnMessagedReceived listens for the messages received from server |
|||
*/ |
|||
public TcpClient(String ipAddressWithPort, OnMessageReceived listener, OnClientError errorListener) { |
|||
String[] ipAddressPort = ipAddressWithPort.split(":"); |
|||
SERVER_IP = ipAddressPort[0]; |
|||
SERVER_PORT = Integer.valueOf(ipAddressPort[1]); |
|||
mMessageListener = listener; |
|||
mErrorListener = errorListener; |
|||
} |
|||
|
|||
/** |
|||
* Sends the message entered by client to the server |
|||
* |
|||
* @param message text entered by client |
|||
*/ |
|||
public void sendMessage(final byte[] message) { |
|||
Runnable runnable = new Runnable() { |
|||
@Override |
|||
public void run() { |
|||
try { |
|||
if (mBufferOut != null) { |
|||
mBufferOut.write(message); |
|||
Log.d(TAG, "Sending data\n"); |
|||
mBufferOut.flush(); |
|||
} |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
}; |
|||
Thread thread = new Thread(runnable); |
|||
thread.start(); |
|||
} |
|||
|
|||
/** |
|||
* Close the connection and release the members |
|||
*/ |
|||
public void stopClient() { |
|||
mRun = false; |
|||
|
|||
if (mBufferOut != null) { |
|||
try { |
|||
mBufferOut.flush(); |
|||
mBufferOut.close(); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
unregisterListeners(); |
|||
//mBufferIn = null;
|
|||
mBufferOut = null; |
|||
|
|||
Log.d(TAG, "Client stopped successfully"); |
|||
} |
|||
|
|||
public void run() { |
|||
|
|||
mRun = true; |
|||
|
|||
try { |
|||
Log.d("TCP Client", "C: Connecting..."); |
|||
|
|||
//here you must put your computer's IP address.
|
|||
/*InetAddress serverAddr = InetAddress.getByName(SERVER_IP); |
|||
|
|||
//create a socket to make the connection with the server
|
|||
Socket socket = new Socket(serverAddr, SERVER_PORT);*/ |
|||
|
|||
InetSocketAddress sockAdr = new InetSocketAddress(SERVER_IP, SERVER_PORT); |
|||
Socket socket = new Socket(); |
|||
socket.setSoTimeout(TIMEOUT); |
|||
socket.connect(sockAdr, TIMEOUT); |
|||
|
|||
try { |
|||
|
|||
//sends the message to the server
|
|||
mBufferOut = new DataOutputStream(socket.getOutputStream()); |
|||
|
|||
//receives the message which the server sends back
|
|||
InputStream is = socket.getInputStream(); |
|||
DataInputStream dis = new DataInputStream(is); |
|||
|
|||
Log.d("test", "Client ready"); |
|||
sendMessage("X".getBytes()); // Send X and wait for response, then send command
|
|||
|
|||
//in this while the client listens for the messages sent by the server
|
|||
while (mRun) { |
|||
|
|||
// count the available bytes form the input stream
|
|||
int count = is.available(); |
|||
|
|||
// create buffer
|
|||
byte[] bs = new byte[count]; |
|||
|
|||
int read = dis.read(bs); |
|||
|
|||
if (count > 0 && mMessageListener != null) |
|||
mMessageListener.messageReceived(bs); |
|||
} |
|||
|
|||
Log.d("RESPONSE FROM SERVER", "S: Received Message"); |
|||
|
|||
} catch (Exception e) { |
|||
mErrorListener.onError(e); |
|||
Log.e(TAG, "S: Error", e); |
|||
} finally { |
|||
//the socket must be closed. It is not possible to reconnect to this socket
|
|||
// after it is closed, which means a new socket instance has to be created.
|
|||
socket.close(); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
mErrorListener.onError(e); |
|||
Log.e(TAG, "C: Error", e); |
|||
} finally { |
|||
unregisterListeners(); |
|||
} |
|||
|
|||
} |
|||
|
|||
private void unregisterListeners() { |
|||
mMessageListener = null; |
|||
mErrorListener = null; |
|||
} |
|||
|
|||
//Declare the interface. The method messageReceived(String message) will must be implemented in the Activity
|
|||
//class at on AsyncTask doInBackground
|
|||
public interface OnMessageReceived { |
|||
public void messageReceived(byte[] message); |
|||
} |
|||
|
|||
public interface OnClientError { |
|||
public void onError(Exception e); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,6 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
public enum Type { |
|||
FEEDBACK, |
|||
STATE |
|||
} |
@ -0,0 +1,168 @@ |
|||
package com.skulixlabs.iotcontrol.adapter; |
|||
|
|||
import android.content.Context; |
|||
import android.os.Handler; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
import android.widget.TextView; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.recyclerview.widget.RecyclerView; |
|||
|
|||
import com.dx.dxloadingbutton.lib.LoadingButton; |
|||
import com.google.android.flexbox.FlexboxLayout; |
|||
import com.skulixlabs.iotcontrol.ConnectTaskFromAdapter; |
|||
import com.skulixlabs.iotcontrol.MainFragment; |
|||
import com.skulixlabs.iotcontrol.R; |
|||
import com.skulixlabs.iotcontrol.bean.RunnableWithState; |
|||
import com.skulixlabs.iotcontrol.model.Cmd; |
|||
import com.skulixlabs.iotcontrol.model.CmdGroup; |
|||
import com.skulixlabs.iotcontrol.util.Utils; |
|||
|
|||
import java.lang.ref.WeakReference; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import br.com.simplepass.loadingbutton.customViews.CircularProgressButton; |
|||
|
|||
|
|||
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> { |
|||
private List<CmdGroup> groupList; |
|||
private WeakReference<MainFragment> fragment; |
|||
private Map<Handler, RunnableWithState> stateHandlers = new HashMap<>(); |
|||
|
|||
public class ItemViewHolder extends RecyclerView.ViewHolder { |
|||
public Integer stateIndex; // Holds position (index) of state action
|
|||
|
|||
public TextView title; |
|||
public TextView state; |
|||
public FlexboxLayout buttonLayout; |
|||
|
|||
public ItemViewHolder(@NonNull View itemView) { |
|||
super(itemView); |
|||
title = (TextView) itemView.findViewById(R.id.tvTitle); |
|||
state = (TextView) itemView.findViewById(R.id.tvState); |
|||
buttonLayout = (FlexboxLayout) itemView.findViewById(R.id.btnLayout); |
|||
|
|||
state.setAllCaps(false); |
|||
} |
|||
|
|||
public LoadingButton getStateButton() { |
|||
return stateIndex != null ? (LoadingButton) buttonLayout.getChildAt(stateIndex) : null; |
|||
} |
|||
|
|||
public Context getContext() { |
|||
return itemView.getContext(); |
|||
} |
|||
|
|||
private LoadingButton addButton() { |
|||
int viewId = View.generateViewId(); |
|||
LayoutInflater inflater = LayoutInflater.from(getContext()); |
|||
LoadingButton button = (LoadingButton) inflater.inflate(R.layout.material_morph_button_2, null, false); |
|||
FlexboxLayout.LayoutParams linearLayoutParams = new FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); |
|||
linearLayoutParams.setMargins(0, 0, Utils.calculatePixelsFromDp2(8, getContext()), 0); |
|||
button.setId(viewId); |
|||
buttonLayout.addView(button, linearLayoutParams); |
|||
return button; |
|||
} |
|||
} |
|||
|
|||
public ItemAdapter(MainFragment fragment, List<CmdGroup> groupList) { |
|||
this.fragment = new WeakReference<>(fragment); |
|||
this.groupList = groupList; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
|||
View itemView = LayoutInflater. |
|||
from(parent.getContext()). |
|||
inflate(R.layout.row_item, parent, false); |
|||
|
|||
return new ItemViewHolder(itemView); |
|||
} |
|||
|
|||
@Override |
|||
public void onBindViewHolder(@NonNull final ItemViewHolder holder, int position) { |
|||
CmdGroup group = groupList.get(position); |
|||
holder.title.setText(group.getName()); |
|||
|
|||
for (final Cmd cmd : group.getCmdList()) { |
|||
|
|||
switch (cmd.getType()) { |
|||
case STATE: |
|||
// State actions are not shown if repeat is enabled
|
|||
if (cmd.getRepeat() != null) { |
|||
break; // Else continue to next statement to create a button
|
|||
} else { |
|||
holder.stateIndex = holder.buttonLayout.getChildCount(); |
|||
// And continue to next statement to create a button
|
|||
} |
|||
case FEEDBACK: |
|||
final LoadingButton actionButton = holder.addButton(); |
|||
|
|||
actionButton.setText(cmd.getAction()); |
|||
actionButton.setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
//actionButton.startMorphAnimation();
|
|||
actionButton.startLoading(); |
|||
new ConnectTaskFromAdapter(holder, fragment, cmd, actionButton).execute(); |
|||
} |
|||
}); |
|||
default: |
|||
|
|||
} |
|||
|
|||
if (cmd.getRepeat() != null) { |
|||
Handler handler = addStateListener(holder, cmd); |
|||
validateStateListener(handler); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public int getItemCount() { |
|||
return groupList.size(); |
|||
} |
|||
|
|||
public List<CmdGroup> getCollection() { |
|||
return groupList; |
|||
} |
|||
|
|||
public void validateStateListeners() { |
|||
for (Map.Entry<Handler, RunnableWithState> entry : stateHandlers.entrySet()) { |
|||
validateStateListener(entry.getKey()); |
|||
} |
|||
} |
|||
|
|||
public void validateStateListener(Handler handler) { |
|||
RunnableWithState runnableWithState = stateHandlers.get(handler); |
|||
runnableWithState.isRunning = true; |
|||
handler.post(runnableWithState.runnable); |
|||
} |
|||
|
|||
public void invalidateStateListeners() { |
|||
for (Map.Entry<Handler, RunnableWithState> entry : stateHandlers.entrySet()) { |
|||
//entry.getKey().removeCallbacks(entry.getValue());
|
|||
entry.getValue().isRunning = false; |
|||
entry.getKey().removeCallbacksAndMessages(null); |
|||
} |
|||
} |
|||
|
|||
private Handler addStateListener(final ItemViewHolder holder, @NonNull final Cmd cmd) { |
|||
final Handler handler = new Handler(); |
|||
Runnable runnable = new Runnable() { |
|||
@Override |
|||
public void run() { |
|||
new ConnectTaskFromAdapter(holder, fragment, cmd, null).execute(); |
|||
if (stateHandlers.get(handler).isRunning) |
|||
handler.postDelayed(this, cmd.getRepeat()); |
|||
} |
|||
}; |
|||
stateHandlers.put(handler, new RunnableWithState(runnable, false)); |
|||
return handler; |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.skulixlabs.iotcontrol.bean; |
|||
|
|||
public class RunnableWithState { |
|||
public Runnable runnable; |
|||
public boolean isRunning; |
|||
|
|||
public RunnableWithState(Runnable runnable, boolean isRunning) { |
|||
this.runnable = runnable; |
|||
this.isRunning = isRunning; |
|||
} |
|||
} |
@ -0,0 +1,70 @@ |
|||
package com.skulixlabs.iotcontrol.model; |
|||
|
|||
import com.skulixlabs.iotcontrol.Type; |
|||
import com.skulixlabs.iotcontrol.util.jackson.CmdsToMapDeserializer; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
import com.fasterxml.jackson.annotation.JsonUnwrapped; |
|||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; |
|||
|
|||
import java.util.HashMap; |
|||
|
|||
public class Cmd { |
|||
private String action; |
|||
@JsonProperty("cmd") |
|||
private int value; |
|||
@JsonUnwrapped |
|||
private Options options; |
|||
@JsonDeserialize(using = CmdsToMapDeserializer.class) |
|||
@JsonProperty("responses") |
|||
private HashMap<Byte, CmdResponse> responseList; |
|||
private Integer repeat; |
|||
private Type type; |
|||
|
|||
public String getAction() { |
|||
return action; |
|||
} |
|||
|
|||
public void setAction(String action) { |
|||
this.action = action; |
|||
} |
|||
|
|||
public int getValue() { |
|||
return value; |
|||
} |
|||
|
|||
public void setValue(int value) { |
|||
this.value = value; |
|||
} |
|||
|
|||
public Options getOptions() { |
|||
return options; |
|||
} |
|||
|
|||
public void setOptions(Options options) { |
|||
this.options = options; |
|||
} |
|||
|
|||
public HashMap<Byte, CmdResponse> getResponseList() { |
|||
return responseList; |
|||
} |
|||
|
|||
public void setResponseList(HashMap<Byte, CmdResponse> responseList) { |
|||
this.responseList = responseList; |
|||
} |
|||
|
|||
public Integer getRepeat() { |
|||
return repeat; |
|||
} |
|||
|
|||
public void setRepeat(Integer repeat) { |
|||
this.repeat = repeat; |
|||
} |
|||
|
|||
public Type getType() { |
|||
return type; |
|||
} |
|||
|
|||
public void setType(Type type) { |
|||
this.type = type; |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
package com.skulixlabs.iotcontrol.model; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
|
|||
import java.util.List; |
|||
|
|||
public class CmdGroup { |
|||
@JsonProperty("group") |
|||
private String name; |
|||
@JsonProperty("actions") |
|||
private List<Cmd> cmdList; |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public List<Cmd> getCmdList() { |
|||
return cmdList; |
|||
} |
|||
|
|||
public void setCmdList(List<Cmd> cmdList) { |
|||
this.cmdList = cmdList; |
|||
} |
|||
} |
@ -0,0 +1,40 @@ |
|||
package com.skulixlabs.iotcontrol.model; |
|||
|
|||
public class CmdResponse { |
|||
private byte value; |
|||
private String description; |
|||
private String color; |
|||
|
|||
public CmdResponse() { |
|||
} |
|||
|
|||
public CmdResponse(byte value, String description, String color) { |
|||
this.description = description; |
|||
this.value = value; |
|||
this.color = color; |
|||
} |
|||
|
|||
public byte getValue() { |
|||
return value; |
|||
} |
|||
|
|||
public void setValue(byte value) { |
|||
this.value = value; |
|||
} |
|||
|
|||
public String getDescription() { |
|||
return description; |
|||
} |
|||
|
|||
public void setDescription(String description) { |
|||
this.description = description; |
|||
} |
|||
|
|||
public String getColor() { |
|||
return color; |
|||
} |
|||
|
|||
public void setColor(String color) { |
|||
this.color = color; |
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
package com.skulixlabs.iotcontrol.model; |
|||
|
|||
public class Options { |
|||
private String url; |
|||
private String hmacKey; |
|||
private int hashByteLength; |
|||
private int randDataLength; |
|||
|
|||
public Options() { |
|||
} |
|||
|
|||
public String getUrl() { |
|||
return url; |
|||
} |
|||
|
|||
public void setUrl(String url) { |
|||
this.url = url; |
|||
} |
|||
|
|||
public String getHmacKey() { |
|||
return hmacKey; |
|||
} |
|||
|
|||
public void setHmacKey(String hmacKey) { |
|||
this.hmacKey = hmacKey; |
|||
} |
|||
|
|||
public int getHashByteLength() { |
|||
return hashByteLength; |
|||
} |
|||
|
|||
public void setHashByteLength(int hashByteLength) { |
|||
this.hashByteLength = hashByteLength; |
|||
} |
|||
|
|||
public int getRandDataLength() { |
|||
return randDataLength; |
|||
} |
|||
|
|||
public void setRandDataLength(int randDataLength) { |
|||
this.randDataLength = randDataLength; |
|||
} |
|||
} |
@ -0,0 +1,66 @@ |
|||
package com.skulixlabs.iotcontrol.util; |
|||
|
|||
import android.annotation.TargetApi; |
|||
import android.content.Context; |
|||
import android.content.res.Configuration; |
|||
import android.content.res.Resources; |
|||
import android.os.Build; |
|||
|
|||
import androidx.preference.PreferenceManager; |
|||
|
|||
import java.util.Locale; |
|||
|
|||
public class AppUtils { |
|||
public static String lang = null; |
|||
|
|||
/** |
|||
* Override {@link android.app.Activity#attachBaseContext(Context)} and pass this |
|||
* method as the Context parameter in order to change language in runtime. This |
|||
* will not work if dark mode is enabled, because the Context is rebuild by the |
|||
* Android Framework using default parameters (passed Context is ignored). |
|||
* |
|||
* @param context |
|||
* @return |
|||
*/ |
|||
public static Context updateBaseContextLocale(Context context) { // The context probably always is the default one, even if previously modified
|
|||
if (lang == null || "".equals(lang)) { |
|||
lang = PreferenceManager |
|||
.getDefaultSharedPreferences(context).getString("language", "system_default"); |
|||
} |
|||
|
|||
if (!lang.equals("system_default")) { |
|||
|
|||
String[] langSplit = lang.split("_"); |
|||
|
|||
Locale locale = new Locale(langSplit[0], langSplit[1]); |
|||
Locale.setDefault(locale); |
|||
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |
|||
return updateResourcesLocale(context, locale); |
|||
} |
|||
|
|||
return updateResourcesLocaleLegacy(context, locale); |
|||
} |
|||
return context; |
|||
} |
|||
|
|||
@TargetApi(Build.VERSION_CODES.N) |
|||
private static Context updateResourcesLocale(Context context, Locale locale) { |
|||
/*if (context.getResources().getConfiguration().getLocales().get(0).equals(locale)) // Even though locale=en
|
|||
return context;*/ |
|||
Configuration configuration = context.getResources().getConfiguration(); |
|||
configuration.setLocale(locale); |
|||
return context.createConfigurationContext(configuration); |
|||
} |
|||
|
|||
@SuppressWarnings("deprecation") |
|||
private static Context updateResourcesLocaleLegacy(Context context, Locale locale) { |
|||
if (context.getResources().getConfiguration().locale.equals(locale)) |
|||
return context; |
|||
Resources resources = context.getResources(); |
|||
Configuration configuration = resources.getConfiguration(); |
|||
configuration.locale = locale; |
|||
resources.updateConfiguration(configuration, resources.getDisplayMetrics()); |
|||
return context; |
|||
} |
|||
} |
@ -0,0 +1,170 @@ |
|||
package com.skulixlabs.iotcontrol.util; |
|||
|
|||
import android.content.Context; |
|||
import android.graphics.Bitmap; |
|||
import android.graphics.Canvas; |
|||
import android.graphics.drawable.BitmapDrawable; |
|||
import android.graphics.drawable.Drawable; |
|||
import android.text.InputType; |
|||
import android.util.TypedValue; |
|||
import android.widget.EditText; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.preference.EditTextPreference; |
|||
|
|||
import com.skulixlabs.iotcontrol.model.Cmd; |
|||
import com.skulixlabs.iotcontrol.model.CmdResponse; |
|||
|
|||
import java.io.ByteArrayOutputStream; |
|||
import java.io.IOException; |
|||
import java.nio.ByteBuffer; |
|||
import java.security.InvalidKeyException; |
|||
import java.security.NoSuchAlgorithmException; |
|||
|
|||
import javax.crypto.Mac; |
|||
import javax.crypto.spec.SecretKeySpec; |
|||
|
|||
public class Utils { |
|||
private static final String TAG = Utils.class.getName(); |
|||
|
|||
public static byte[] generateHashWithHmac256ByByteValue(String hmacKey, byte[] data) { |
|||
try { |
|||
final String hashingAlgorithm = "HmacSHA256"; |
|||
|
|||
byte[] bytes = hmac(hashingAlgorithm, hmacKey.getBytes(), data); |
|||
|
|||
//Log.i(TAG, "message digest: " + bytes);
|
|||
return bytes; |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public static byte[] generateHashWithHmac256ByValue(String hmacKey, String message) { |
|||
try { |
|||
final String hashingAlgorithm = "HmacSHA256"; |
|||
|
|||
byte[] bytes = hmac(hashingAlgorithm, hmacKey.getBytes(), message.getBytes()); |
|||
|
|||
//Log.i(TAG, "message digest: " + bytesToHex(bytes));
|
|||
return bytes; |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public static byte[] hmac(String algorithm, byte[] key, byte[] message) throws NoSuchAlgorithmException, InvalidKeyException { |
|||
Mac mac = Mac.getInstance(algorithm); |
|||
mac.init(new SecretKeySpec(key, algorithm)); |
|||
return mac.doFinal(message); |
|||
} |
|||
|
|||
public static String bytesToHex(byte[] bytes) { |
|||
final char[] hexArray = "0123456789abcdef".toCharArray(); |
|||
char[] hexChars = new char[bytes.length * 2]; |
|||
for (int j = 0, v; j < bytes.length; j++) { |
|||
v = bytes[j] & 0xFF; |
|||
hexChars[j * 2] = hexArray[v >>> 4]; |
|||
hexChars[j * 2 + 1] = hexArray[v & 0x0F]; |
|||
} |
|||
return new String(hexChars); |
|||
} |
|||
|
|||
public static byte[] hexStringToByteArray(String s) { |
|||
int len = s.length(); |
|||
byte[] data = new byte[len / 2]; |
|||
for (int i = 0; i < len; i += 2) { |
|||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) |
|||
+ Character.digit(s.charAt(i+1), 16)); |
|||
} |
|||
return data; |
|||
} |
|||
|
|||
public static byte oneDigitHexToByte(String s) { |
|||
String[] split = s.split("x"); |
|||
int i = Integer.parseInt(split[1], 16); |
|||
return (byte) i; |
|||
} |
|||
|
|||
public static byte analyzeResponse(String hmacKey, Byte[] cmdSend, ByteBuffer gotBytes, ByteBuffer resHash) throws IOException { |
|||
gotBytes.position(0); |
|||
resHash.position(0); |
|||
|
|||
byte[] gotBytesArr = new byte[gotBytes.remaining()]; |
|||
gotBytes.get(gotBytesArr); |
|||
|
|||
for(int i=0; i<cmdSend.length; i++){ |
|||
ByteBuffer testHash = getHash(hmacKey, gotBytesArr, new byte[] {cmdSend[i]}); |
|||
if (hashesAreTheSame(resHash, testHash)){ |
|||
return cmdSend[i]; |
|||
} |
|||
} |
|||
throw new IllegalArgumentException("Illegal response"); // Illegal response
|
|||
} |
|||
|
|||
private static ByteBuffer getHash(String hmacKey, byte[] data, byte[] additionalData) throws IOException { |
|||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); |
|||
outputStream.write(data); |
|||
outputStream.write(additionalData); |
|||
return ByteBuffer.wrap(Utils.generateHashWithHmac256ByByteValue(hmacKey, outputStream.toByteArray())); |
|||
} |
|||
|
|||
private static boolean hashesAreTheSame(ByteBuffer hash1, ByteBuffer hash2){ |
|||
//Log.d(TAG, "hash1: " + printHash(hash1));
|
|||
//Log.d(TAG, "hash2: " + printHash(hash2));
|
|||
|
|||
if (hash1.capacity() != hash2.capacity()) return false; |
|||
for (int j=0; j<hash1.capacity(); j++) if(hash1.get(j) != hash2.get(j)) return false; |
|||
return true; |
|||
} |
|||
|
|||
public static EditTextPreference.OnBindEditTextListener editTextPreferenceNumericOnly() { |
|||
return new EditTextPreference.OnBindEditTextListener() { |
|||
@Override |
|||
public void onBindEditText(@NonNull EditText editText) { |
|||
editText.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
public static String printHash(ByteBuffer hash) { |
|||
byte[] bytes = new byte[hash.remaining()]; |
|||
hash.get(bytes); |
|||
return printHash(bytes); |
|||
} |
|||
|
|||
public static String printHash(byte[] bytes) { |
|||
return bytesToHex(bytes); |
|||
} |
|||
|
|||
public static boolean stringNullOrEmpty(String value) { |
|||
if (value == null || value.equalsIgnoreCase("")) |
|||
return true; |
|||
return false; |
|||
} |
|||
|
|||
public static CmdResponse matchResponse(Cmd cmd, byte b) { |
|||
return cmd.getResponseList().get(b); |
|||
} |
|||
|
|||
public static Integer calculatePixelsFromDp2(Integer dps, Context context) { |
|||
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dps, context.getResources().getDisplayMetrics())); // Or cast to int
|
|||
} |
|||
|
|||
public static Bitmap drawableToBitmap (Drawable drawable) { |
|||
if (drawable instanceof BitmapDrawable) { |
|||
return ((BitmapDrawable)drawable).getBitmap(); |
|||
} |
|||
|
|||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); |
|||
Canvas canvas = new Canvas(bitmap); |
|||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); |
|||
drawable.draw(canvas); |
|||
|
|||
return bitmap; |
|||
} |
|||
} |
@ -0,0 +1,34 @@ |
|||
package com.skulixlabs.iotcontrol.util.jackson; |
|||
|
|||
import com.skulixlabs.iotcontrol.model.CmdResponse; |
|||
import com.fasterxml.jackson.core.JsonParser; |
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.DeserializationContext; |
|||
import com.fasterxml.jackson.databind.JsonDeserializer; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
import static com.skulixlabs.iotcontrol.util.Utils.oneDigitHexToByte; |
|||
|
|||
public class CmdsToMapDeserializer extends JsonDeserializer { |
|||
|
|||
@Override |
|||
public Map<Byte, CmdResponse> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { |
|||
JsonNode node = p.getCodec().readTree(p); |
|||
|
|||
Map<Byte, CmdResponse> map = new HashMap<>(); |
|||
|
|||
for (JsonNode objectNode : node) { |
|||
byte value = oneDigitHexToByte(objectNode.get("value").asText()); |
|||
String description = objectNode.get("description").asText(); |
|||
String color = objectNode.get("color").asText(); |
|||
|
|||
map.put(value, new CmdResponse(value, description, color)); |
|||
} |
|||
|
|||
return map; |
|||
} |
|||
} |
@ -0,0 +1,53 @@ |
|||
package com.skulixlabs.iotcontrol.util.jackson; |
|||
|
|||
import android.content.Context; |
|||
|
|||
import com.skulixlabs.iotcontrol.model.CmdGroup; |
|||
import com.fasterxml.jackson.core.type.TypeReference; |
|||
import com.fasterxml.jackson.databind.MapperFeature; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
|
|||
import org.apache.commons.io.IOUtils; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.util.List; |
|||
|
|||
import static android.content.Context.MODE_PRIVATE; |
|||
|
|||
public class JsonUtils { |
|||
public static final int REQUEST_READ_STORAGE = 7; |
|||
public static final int REQUEST_READ_FILE = 8; |
|||
|
|||
public boolean saveCommands(Context context, InputStream is) throws IOException { |
|||
String json = IOUtils.toString(is, "UTF-8"); |
|||
validateJson(json); |
|||
return context.getSharedPreferences("commands", MODE_PRIVATE).edit().putString("commands", json).commit(); |
|||
} |
|||
|
|||
public boolean saveCommands(Context context, String json) throws IOException { |
|||
validateJson(json); |
|||
return context.getSharedPreferences("commands", MODE_PRIVATE).edit().putString("commands", json).commit(); |
|||
} |
|||
|
|||
public void validateJson(String json) throws IOException { |
|||
ObjectMapper objectMapper = new ObjectMapper(); |
|||
objectMapper.readTree(json); |
|||
} |
|||
|
|||
public List<CmdGroup> getCommands(Context context) throws IOException { |
|||
List<CmdGroup> cmdGroups = parseCommands(context.getSharedPreferences("commands", MODE_PRIVATE).getString("commands", null)); |
|||
return cmdGroups; |
|||
} |
|||
|
|||
public List<CmdGroup> parseCommands(String json) throws IOException { |
|||
if (json == null) throw new IllegalArgumentException("Content not valid"); |
|||
return new ObjectMapper() |
|||
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) |
|||
.readValue(json, new TypeReference<List<CmdGroup>>(){}); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,127 @@ |
|||
package com.skulixlabs.iotcontrol.util.legacy; |
|||
|
|||
import android.util.Log; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.BufferedWriter; |
|||
import java.io.InputStreamReader; |
|||
import java.io.OutputStreamWriter; |
|||
import java.io.PrintWriter; |
|||
import java.net.InetAddress; |
|||
import java.net.Socket; |
|||
|
|||
public class TcpClient_original { |
|||
public static final String TAG = TcpClient_original.class.getSimpleName(); |
|||
public static final String SERVER_IP = "192.168.1.170"; //server IP address
|
|||
public static final int SERVER_PORT = 3000; |
|||
|
|||
// message to send to the server
|
|||
private String mServerMessage; |
|||
// sends message received notifications
|
|||
private OnMessageReceived mMessageListener = null; |
|||
// while this is true, the server will continue running
|
|||
private boolean mRun = false; |
|||
// used to send messages
|
|||
private PrintWriter mBufferOut; |
|||
// used to read messages from the server
|
|||
private BufferedReader mBufferIn; |
|||
|
|||
/** |
|||
* Constructor of the class. OnMessagedReceived listens for the messages received from server |
|||
*/ |
|||
public TcpClient_original(OnMessageReceived listener) { |
|||
mMessageListener = listener; |
|||
} |
|||
|
|||
/** |
|||
* Sends the message entered by client to the server |
|||
* |
|||
* @param message text entered by client |
|||
*/ |
|||
public void sendMessage(final String message) { |
|||
Runnable runnable = new Runnable() { |
|||
@Override |
|||
public void run() { |
|||
if (mBufferOut != null) { |
|||
Log.d(TAG, "Sending: " + message); |
|||
mBufferOut.println(message); |
|||
mBufferOut.flush(); |
|||
} |
|||
} |
|||
}; |
|||
Thread thread = new Thread(runnable); |
|||
thread.start(); |
|||
} |
|||
|
|||
/** |
|||
* Close the connection and release the members |
|||
*/ |
|||
public void stopClient() { |
|||
|
|||
mRun = false; |
|||
|
|||
if (mBufferOut != null) { |
|||
mBufferOut.flush(); |
|||
mBufferOut.close(); |
|||
} |
|||
|
|||
mMessageListener = null; |
|||
mBufferIn = null; |
|||
mBufferOut = null; |
|||
mServerMessage = null; |
|||
} |
|||
|
|||
public void run() { |
|||
|
|||
mRun = true; |
|||
|
|||
try { |
|||
//here you must put your computer's IP address.
|
|||
InetAddress serverAddr = InetAddress.getByName(SERVER_IP); |
|||
|
|||
Log.d("TCP Client", "C: Connecting..."); |
|||
|
|||
//create a socket to make the connection with the server
|
|||
Socket socket = new Socket(serverAddr, SERVER_PORT); |
|||
|
|||
try { |
|||
|
|||
//sends the message to the server
|
|||
mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); |
|||
|
|||
//receives the message which the server sends back
|
|||
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream())); |
|||
|
|||
|
|||
//in this while the client listens for the messages sent by the server
|
|||
while (mRun) { |
|||
mServerMessage = mBufferIn.readLine(); |
|||
if (mServerMessage != null && mMessageListener != null) { |
|||
//sendAction the method messageReceived from MyActivity class
|
|||
mMessageListener.messageReceived(mServerMessage); |
|||
} |
|||
} |
|||
|
|||
Log.d("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'"); |
|||
|
|||
} catch (Exception e) { |
|||
Log.e("TCP", "S: Error", e); |
|||
} finally { |
|||
//the socket must be closed. It is not possible to reconnect to this socket
|
|||
// after it is closed, which means a new socket instance has to be created.
|
|||
socket.close(); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
Log.e("TCP", "C: Error", e); |
|||
} |
|||
|
|||
} |
|||
|
|||
//Declare the interface. The method messageReceived(String message) will must be implemented in the Activity
|
|||
//class at on AsyncTask doInBackground
|
|||
public interface OnMessageReceived { |
|||
public void messageReceived(String message); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,34 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:aapt="http://schemas.android.com/aapt" |
|||
android:width="108dp" |
|||
android:height="108dp" |
|||
android:viewportWidth="108" |
|||
android:viewportHeight="108"> |
|||
<path |
|||
android:fillType="evenOdd" |
|||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z" |
|||
android:strokeWidth="1" |
|||
android:strokeColor="#00000000"> |
|||
<aapt:attr name="android:fillColor"> |
|||
<gradient |
|||
android:endX="78.5885" |
|||
android:endY="90.9159" |
|||
android:startX="48.7653" |
|||
android:startY="61.0927" |
|||
android:type="linear"> |
|||
<item |
|||
android:color="#44000000" |
|||
android:offset="0.0" /> |
|||
<item |
|||
android:color="#00000000" |
|||
android:offset="1.0" /> |
|||
</gradient> |
|||
</aapt:attr> |
|||
</path> |
|||
<path |
|||
android:fillColor="#FFFFFF" |
|||
android:fillType="nonZero" |
|||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z" |
|||
android:strokeWidth="1" |
|||
android:strokeColor="#00000000" /> |
|||
</vector> |
@ -0,0 +1,5 @@ |
|||
<vector android:height="48dp" android:tint="#00F91A" |
|||
android:viewportHeight="24.0" android:viewportWidth="24.0" |
|||
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> |
|||
</vector> |
@ -0,0 +1,5 @@ |
|||
<vector android:height="24dp" android:tint="#FF0D00" |
|||
android:viewportHeight="24.0" android:viewportWidth="24.0" |
|||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#FF000000" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> |
|||
</vector> |
@ -0,0 +1,5 @@ |
|||
<vector android:height="48dp" android:tint="#FF0000" |
|||
android:viewportHeight="24.0" android:viewportWidth="24.0" |
|||
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#FF000000" android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/> |
|||
</vector> |
@ -0,0 +1,170 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="108dp" |
|||
android:height="108dp" |
|||
android:viewportWidth="108" |
|||
android:viewportHeight="108"> |
|||
<path |
|||
android:fillColor="#008577" |
|||
android:pathData="M0,0h108v108h-108z" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M9,0L9,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M19,0L19,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M29,0L29,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M39,0L39,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M49,0L49,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M59,0L59,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M69,0L69,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M79,0L79,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M89,0L89,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M99,0L99,108" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,9L108,9" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,19L108,19" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,29L108,29" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,39L108,39" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,49L108,49" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,59L108,59" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,69L108,69" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,79L108,79" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,89L108,89" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M0,99L108,99" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M19,29L89,29" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M19,39L89,39" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M19,49L89,49" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M19,59L89,59" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M19,69L89,69" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M19,79L89,79" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M29,19L29,89" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M39,19L39,89" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M49,19L49,89" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M59,19L59,89" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M69,19L69,89" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
<path |
|||
android:fillColor="#00000000" |
|||
android:pathData="M79,19L79,89" |
|||
android:strokeWidth="0.8" |
|||
android:strokeColor="#33FFFFFF" /> |
|||
</vector> |
@ -0,0 +1,34 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
tools:context=".MainActivity" |
|||
android:orientation="vertical"> |
|||
|
|||
|
|||
<com.google.android.material.appbar.AppBarLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:theme="@style/AppTheme.AppBarOverlay"> |
|||
|
|||
<androidx.appcompat.widget.Toolbar |
|||
android:id="@+id/toolbar" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="?attr/actionBarSize" |
|||
app:popupTheme="@style/AppTheme.PopupOverlay" |
|||
android:theme="@style/ToolbarTheme"/> |
|||
|
|||
</com.google.android.material.appbar.AppBarLayout> |
|||
|
|||
<fragment |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:id="@+id/my_nav_host_fragment" |
|||
android:name="androidx.navigation.fragment.NavHostFragment" |
|||
app:navGraph="@navigation/nav_graph" |
|||
app:defaultNavHost="true" /> |
|||
|
|||
</LinearLayout> |
@ -0,0 +1,29 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:orientation="vertical" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:padding="15dp"> |
|||
|
|||
|
|||
<Button |
|||
android:id="@+id/btnFromClipboard" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
app:cornerRadius="@dimen/material_button_rounded_radius" |
|||
android:text="@string/paste_from_clipboard" /> |
|||
|
|||
<include |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
layout="@layout/divider_or_horizontal" /> |
|||
|
|||
<Button |
|||
android:id="@+id/btnFromFile" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
style="@style/Widget.MaterialComponents.Button.OutlinedButton" |
|||
app:cornerRadius="@dimen/material_button_rounded_radius" |
|||
android:text="@string/import_from_file" /> |
|||
</LinearLayout> |
@ -0,0 +1,31 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:orientation="horizontal" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:weightSum="1" |
|||
android:gravity="center"> |
|||
|
|||
<View |
|||
android:layout_width="0dp" |
|||
android:layout_height="1dp" |
|||
android:layout_weight="0.45" |
|||
android:background="@android:color/darker_gray" |
|||
android:layout_marginVertical="15dp"/> |
|||
|
|||
<TextView |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="0.1" |
|||
android:gravity="center" |
|||
android:text="@string/or_header"> |
|||
</TextView> |
|||
|
|||
<View |
|||
android:layout_width="0dp" |
|||
android:layout_height="1dp" |
|||
android:layout_weight="0.45" |
|||
android:background="@android:color/darker_gray" |
|||
android:layout_marginVertical="15dp"/> |
|||
|
|||
</LinearLayout> |
@ -0,0 +1,54 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
tools:context=".AboutFragment" |
|||
android:id="@+id/aboutLayout"> |
|||
|
|||
<!-- TODO: Update blank fragment layout --> |
|||
<TextView |
|||
android:id="@+id/tvAppName" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginStart="16dp" |
|||
android:layout_marginTop="16dp" |
|||
android:text="@string/app_name" |
|||
android:textSize="30sp" |
|||
app:layout_constraintStart_toStartOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent" |
|||
android:gravity="bottom"/> |
|||
|
|||
<TextView |
|||
android:id="@+id/tvTeamName" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginTop="8dp" |
|||
android:text="by SkulixLabs" |
|||
app:layout_constraintStart_toStartOf="@+id/tvAppName" |
|||
app:layout_constraintTop_toBottomOf="@+id/tvAppName" |
|||
tools:text="by SkulixLabs" /> |
|||
|
|||
<TextView |
|||
android:id="@+id/tvAppVersion" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginTop="16dp" |
|||
android:text="@string/appVersion" |
|||
app:layout_constraintStart_toStartOf="@+id/tvTeamName" |
|||
app:layout_constraintTop_toBottomOf="@+id/tvTeamName" |
|||
tools:text="@string/appVersion" /> |
|||
|
|||
<Button |
|||
android:id="@+id/btnLicenses" |
|||
style="@style/Widget.MaterialComponents.Button.TextButton" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginTop="64dp" |
|||
android:text="@string/open_source_liceses" |
|||
app:layout_constraintEnd_toEndOf="parent" |
|||
app:layout_constraintStart_toStartOf="parent" |
|||
app:layout_constraintTop_toBottomOf="@+id/tvAppVersion" /> |
|||
|
|||
</androidx.constraintlayout.widget.ConstraintLayout> |
@ -0,0 +1,53 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
app:layout_behavior="@string/appbar_scrolling_view_behavior" |
|||
tools:context=".MainFragment" |
|||
android:id="@+id/mainLayout"> |
|||
<!--tools:showIn="@layout/activity_main"--> |
|||
|
|||
<!--<Button |
|||
android:id="@+id/send" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginStart="8dp" |
|||
android:layout_marginTop="8dp" |
|||
android:layout_marginEnd="8dp" |
|||
android:paddingHorizontal="64dp" |
|||
android:paddingVertical="48dp" |
|||
android:text="@string/btn_send" |
|||
android:textSize="20sp" |
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintEnd_toEndOf="parent" |
|||
app:layout_constraintStart_toStartOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent" |
|||
app:layout_constraintVertical_bias="0.916" />--> |
|||
|
|||
<!--<br.com.simplepass.loadingbutton.customViews.CircularProgressButton |
|||
android:id="@+id/imgBtnTest0" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:text="Test 0" |
|||
android:theme="@style/mybtn" |
|||
app:finalCornerAngle="50dp" |
|||
app:initialCornerAngle="0dp" |
|||
app:layout_constraintStart_toStartOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent" |
|||
app:spinning_bar_color="#FFFFFF" |
|||
app:spinning_bar_width="3dp" />--> |
|||
|
|||
<androidx.recyclerview.widget.RecyclerView |
|||
android:id="@+id/cardList" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="0dp" |
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintEnd_toEndOf="parent" |
|||
app:layout_constraintHorizontal_bias="1.0" |
|||
app:layout_constraintStart_toStartOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent" |
|||
app:layout_constraintVertical_bias="1.0" /> |
|||
|
|||
</androidx.constraintlayout.widget.ConstraintLayout> |
@ -0,0 +1,18 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
tools:context=".SettingsFragment"> |
|||
|
|||
<fragment |
|||
android:id="@+id/fragment" |
|||
android:name="com.skulixlabs.iotcontrol.SettingsFragment" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintEnd_toEndOf="parent" |
|||
app:layout_constraintStart_toStartOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent" /> |
|||
</androidx.constraintlayout.widget.ConstraintLayout> |
@ -0,0 +1,24 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
|
|||
<br.com.simplepass.loadingbutton.customViews.CircularProgressButton |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
style="@style/mybtn" |
|||
android:id="@+id/btn" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="85dp" |
|||
android:layout_marginLeft="18dp" |
|||
android:layout_marginRight="18dp" |
|||
android:layout_marginBottom="10dp" |
|||
android:text="Test" |
|||
app:finalCornerAngle="50dp" |
|||
app:initialCornerAngle="0dp" |
|||
app:spinning_bar_color="#FFFFFF" |
|||
app:spinning_bar_padding="0dp" |
|||
app:spinning_bar_width="3dp" |
|||
|
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintLeft_toLeftOf="parent" |
|||
app:layout_constraintRight_toRightOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent"> |
|||
</br.com.simplepass.loadingbutton.customViews.CircularProgressButton> |
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
|
|||
<com.dx.dxloadingbutton.lib.LoadingButton |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:id="@+id/btn" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginLeft="18dp" |
|||
android:layout_marginRight="18dp" |
|||
android:layout_marginBottom="10dp" |
|||
app:layout_constraintBottom_toBottomOf="parent" |
|||
app:layout_constraintLeft_toLeftOf="parent" |
|||
app:layout_constraintRight_toRightOf="parent" |
|||
app:layout_constraintTop_toTopOf="parent" |
|||
app:lb_btnText="Test" |
|||
app:lb_resetAfterFailed="true" |
|||
app:lb_btnRippleColor="#000000" |
|||
app:lb_btnColor="?attr/colorPrimary" > |
|||
</com.dx.dxloadingbutton.lib.LoadingButton> |
@ -0,0 +1,81 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:id="@+id/card_view" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
card_view:cardCornerRadius="4dp" |
|||
android:layout_margin="5dp" |
|||
card_view:contentPadding="5dp" |
|||
tools:context=".MainFragment"> |
|||
|
|||
<LinearLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:orientation="horizontal" |
|||
android:weightSum="1"> |
|||
|
|||
<androidx.constraintlayout.widget.ConstraintLayout |
|||
android:layout_width="0dp" |
|||
android:layout_height="match_parent" |
|||
android:layout_weight="0.45" |
|||
android:padding="8dp" > |
|||
|
|||
<TextView |
|||
android:id="@+id/tvTitle" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginEnd="8dp" |
|||
android:text="Title test" |
|||
android:textSize="18sp" |
|||
card_view:layout_constraintEnd_toEndOf="parent" |
|||
card_view:layout_constraintHorizontal_bias="0.0" |
|||
card_view:layout_constraintStart_toStartOf="parent" |
|||
card_view:layout_constraintTop_toTopOf="parent" /> |
|||
|
|||
<TextView |
|||
android:id="@+id/tvState" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_marginTop="8dp" |
|||
android:layout_marginEnd="8dp" |
|||
android:layout_marginBottom="8dp" |
|||
android:text="" |
|||
android:textSize="15sp" |
|||
card_view:layout_constraintBottom_toBottomOf="parent" |
|||
card_view:layout_constraintEnd_toEndOf="parent" |
|||
card_view:layout_constraintHorizontal_bias="0.0" |
|||
card_view:layout_constraintStart_toStartOf="parent" |
|||
card_view:layout_constraintTop_toBottomOf="@+id/tvTitle" /> |
|||
|
|||
</androidx.constraintlayout.widget.ConstraintLayout> |
|||
|
|||
<!--<LinearLayout |
|||
android:id="@+id/btnLayout" |
|||
style="@style/Theme.MaterialComponents.DayNight" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="0.5" |
|||
android:paddingTop="20dp" |
|||
android:orientation="horizontal" |
|||
android:gravity="right|bottom" |
|||
android:background="@color/colorAccent"/>--> |
|||
|
|||
<com.google.android.flexbox.FlexboxLayout |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:id="@+id/btnLayout" |
|||
style="@style/Theme.MaterialComponents.DayNight" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="0.55" |
|||
android:paddingTop="20dp" |
|||
app:flexWrap="wrap" |
|||
app:alignItems="flex_start" |
|||
app:alignContent="flex_start"> |
|||
</com.google.android.flexbox.FlexboxLayout> |
|||
|
|||
</LinearLayout> |
|||
</androidx.cardview.widget.CardView> |
@ -0,0 +1,33 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="90dp" |
|||
android:orientation="vertical"> |
|||
|
|||
<ImageView |
|||
android:id="@+id/imvColor" |
|||
android:layout_width="55dp" |
|||
android:layout_height="match_parent" |
|||
android:layout_alignParentTop="true" |
|||
android:layout_alignParentStart="true" |
|||
android:layout_alignParentBottom="true" |
|||
android:layout_centerVertical="true" |
|||
android:layout_marginTop="1dp" |
|||
android:layout_marginEnd="1dp" |
|||
android:layout_marginBottom="1dp" |
|||
android:padding="5dp" |
|||
android:src="@color/secondaryColorRed" /> |
|||
|
|||
<TextView |
|||
android:id="@+id/name" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_alignParentTop="true" |
|||
android:layout_toRightOf="@+id/imvColor" |
|||
android:layout_marginLeft="10dp" |
|||
android:layout_marginTop="24dp" |
|||
android:text="@string/color_header" |
|||
android:textSize="22dp" /> |
|||
|
|||
</RelativeLayout> |
@ -0,0 +1,10 @@ |
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
tools:context="com.skulixlabs.iotcontrol.MainActivity"> |
|||
<item |
|||
android:id="@+id/action_settings" |
|||
android:orderInCategory="100" |
|||
android:title="@string/settings_header" |
|||
app:showAsAction="never" /> |
|||
</menu> |
@ -0,0 +1,5 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<background android:drawable="@drawable/ic_launcher_background" /> |
|||
<foreground android:drawable="@drawable/ic_launcher_foreground" /> |
|||
</adaptive-icon> |
@ -0,0 +1,5 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<background android:drawable="@drawable/ic_launcher_background" /> |
|||
<foreground android:drawable="@drawable/ic_launcher_foreground" /> |
|||
</adaptive-icon> |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,41 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<navigation xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:tools="http://schemas.android.com/tools" |
|||
android:id="@+id/nav_graph" |
|||
app:startDestination="@+id/mainFragment"> |
|||
|
|||
<fragment |
|||
android:id="@+id/mainFragment" |
|||
android:name="com.skulixlabs.iotcontrol.MainFragment" |
|||
android:label="@string/app_name" |
|||
tools:layout="@layout/fragment_main"></fragment> |
|||
|
|||
<!--Settings fragment--> |
|||
<fragment |
|||
android:id="@+id/settingsFragment" |
|||
android:name="com.skulixlabs.iotcontrol.SettingsFragment" |
|||
android:label="@string/settings_header" |
|||
tools:layout="@layout/fragment_settings"> |
|||
<argument |
|||
android:name="importCmds" |
|||
app:argType="boolean" |
|||
android:defaultValue="false" /> |
|||
<action |
|||
android:id="@+id/action_settingsFragment_to_aboutFragment" |
|||
app:destination="@id/aboutFragment" /> |
|||
</fragment> |
|||
|
|||
<!--Global action--> |
|||
<action |
|||
android:id="@+id/action_open_settings" |
|||
app:destination="@id/settingsFragment" /> |
|||
|
|||
<!--About Fragment--> |
|||
<fragment |
|||
android:id="@+id/aboutFragment" |
|||
android:name="com.skulixlabs.iotcontrol.AboutFragment" |
|||
android:label="@string/about_header" |
|||
tools:layout="@layout/fragment_about" /> |
|||
|
|||
</navigation> |
@ -0,0 +1,24 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<resources> |
|||
<string name="about_header">Σχετικά με</string> |
|||
<string name="theme_header">Θέμα</string> |
|||
<string name="version">Έκδοση</string> |
|||
<string name="import_from_file">Εισαγωγή από αρχείο</string> |
|||
<string name="load_json_commands">Φόρτωση εντολών</string> |
|||
<string name="open_source_liceses">Άδειες ανοιχτού λογισμικού</string> |
|||
<string name="options_header">Επιλογές</string> |
|||
<string name="or_header">Ή</string> |
|||
<string name="paste_from_clipboard">Επικόλληση από πρόχειρο</string> |
|||
<string name="color_header">Χρώμα</string> |
|||
<string name="dark_theme_title">Σκούρο θέμα</string> |
|||
<string name="settings_header">Ρυθμίσεις</string> |
|||
<string name="request_read_external_storage_permission">Η εφαρμογή χρειάζεται άδεια πρόσβασης στα αρχεία της συσκευής.</string> |
|||
<string name="language_header">Γλώσσα</string> |
|||
<string name="option_default">Προεπιλογή</string> |
|||
<string name="orange">Πορτοκαλί</string> |
|||
<string name="red">Κόκκινο</string> |
|||
<string name="system_default">Προεπιλογή συστήματος</string> |
|||
<string name="select_commands_load_method">Επιλογή μεθόδου φόρτωσης</string> |
|||
<string name="load">Φόρτωση</string> |
|||
<string name="invalid_commands">Μη έγκυρες εντολές</string> |
|||
</resources> |
@ -0,0 +1,86 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<resources> |
|||
|
|||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"> |
|||
<item name="colorPrimary">@color/colorPrimaryNight</item> |
|||
<!--<item name="colorPrimaryDark">@color/colorPrimaryDarkNight</item>--> |
|||
<item name="colorAccent">@color/colorAccentNight</item> |
|||
|
|||
<!--<item name="actionBarStyle">@style/AppTheme.MyActionBar</item>--> |
|||
|
|||
<!-- Primary color is applied as text color of modal buttons. |
|||
Overriding dark mode colors for better user experience --> |
|||
<!-- <item name="alertDialogTheme">@style/AlertDialogTheme</item>--> |
|||
</style> |
|||
|
|||
<style name="AppTheme.RED" parent="AppTheme.NoActionBar"> |
|||
<item name="colorPrimary">@color/primaryColorRedNight</item> |
|||
<!--<item name="colorPrimaryDark">@color/primaryDarkColorRedNight</item>--> |
|||
<item name="colorAccent">@color/secondaryColorRedNight</item> |
|||
</style> |
|||
|
|||
<style name="AppTheme.ORANGE" parent="AppTheme.NoActionBar"> |
|||
<item name="colorPrimary">@color/primaryColorOrangeNight</item> |
|||
<!--<item name="colorPrimaryDark">@color/primaryDarkColorOrangeNight</item>--> |
|||
<item name="colorAccent">@color/secondaryColorOrangeNight</item> |
|||
</style> |
|||
|
|||
<style name="AlertDialogTheme" parent="ThemeOverlay.MaterialComponents.Dialog.Alert"> |
|||
<item name="buttonBarNegativeButtonStyle">@style/NegativeButtonStyle</item> |
|||
<item name="buttonBarPositiveButtonStyle">@style/PositiveButtonStyle</item> |
|||
</style> |
|||
|
|||
<style name="NegativeButtonStyle" parent="Widget.MaterialComponents.Button.TextButton.Dialog"> |
|||
<item name="android:textColor">#ef9a9a</item> |
|||
</style> |
|||
|
|||
<style name="PositiveButtonStyle" parent="Widget.MaterialComponents.Button.TextButton.Dialog"> |
|||
<item name="android:textColor">#b0bec5</item> |
|||
</style> |
|||
|
|||
<style name="ToolbarTheme" parent="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"> |
|||
<!-- android:textColorPrimary is the color of the title text in the Toolbar --> |
|||
<!--<item name="android:textColorPrimary">@android:color/holo_blue_light</item>--> |
|||
<!-- actionMenuTextColor/textColor is the color of the text of action (menu) items --> |
|||
<!--<item name="actionMenuTextColor">@android:color/holo_green_light</item>--> |
|||
<item name="android:textColor">@color/white</item> |
|||
<!-- Tints the input fields like checkboxes and text fields --> |
|||
<!--<item name="colorAccent">#000000</item>--> |
|||
<!-- Applies to views in their normal state. --> |
|||
<!--<item name="colorControlNormal">#000000</item>--> |
|||
<!-- Applies to views in their activated state (i.e checked or switches) --> |
|||
<!--<item name="colorControlActivated">#000000</item>--> |
|||
<!-- Applied to framework control highlights (i.e ripples or list selectors) --> |
|||
<!--<item name="colorControlHighlight">#000000</item>--> |
|||
|
|||
<!-- Enable these below if you want clicking icons to trigger a ripple effect --> |
|||
<!-- |
|||
<item name="selectableItemBackground">?android:selectableItemBackground</item> |
|||
<item name="selectableItemBackgroundBorderless">?android:selectableItemBackground</item> |
|||
--> |
|||
</style> |
|||
|
|||
<!--<style name="AppTheme." parent="ThemeOverlay.MaterialComponents.Dialog.Alert"> |
|||
<item name="" |
|||
</style>--> |
|||
|
|||
|
|||
|
|||
|
|||
<style name="AppTheme.MyActionBar" |
|||
parent="@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse"> |
|||
<item name="android:background">@color/colorPrimaryNight</item> |
|||
<item name="android:textColor">#000</item> |
|||
<!-- Support library compatibility --> |
|||
<item name="background">@color/colorPrimaryNight</item> |
|||
</style> |
|||
|
|||
|
|||
<!--<style name="AppTheme.MyActionBar" |
|||
parent="Theme.MaterialComponents.DayNight.DarkActionBar"> |
|||
<item name="android:background">@color/colorPrimary</item> |
|||
<!– Support library compatibility –> |
|||
<item name="background">@color/colorPrimary</item> |
|||
</style>--> |
|||
|
|||
</resources> |
@ -0,0 +1,27 @@ |
|||
<resources> |
|||
<!-- Settings Language Preference --> |
|||
<string-array name="language_list"> |
|||
<item>@string/system_default</item> |
|||
<item>English</item> |
|||
<item>Ελληνικά</item> |
|||
</string-array> |
|||
|
|||
<string-array name="language_list_values"> |
|||
<item>system_default</item> |
|||
<item>en_US</item> |
|||
<item>el_GR</item> |
|||
</string-array> |
|||
|
|||
<!-- Theme Color Preference --> |
|||
<string-array name="theme_color_list"> |
|||
<item>@string/option_default</item> |
|||
<item>@string/red</item> |
|||
<item>@string/orange</item> |
|||
</string-array> |
|||
|
|||
<string-array name="theme_color_list_values"> |
|||
<item>default</item> |
|||
<item>red</item> |
|||
<item>orange</item> |
|||
</string-array> |
|||
</resources> |
@ -0,0 +1,27 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<resources> |
|||
<color name="colorPrimary">#008577</color> |
|||
<color name="colorPrimaryDark">#00574B</color> |
|||
<color name="colorAccent">#D81B60</color> |
|||
|
|||
<color name="colorPrimaryNight">#616161</color> |
|||
<color name="colorPrimaryDarkNight">#000000</color> |
|||
<color name="colorAccentNight">#c1d5e0</color> |
|||
|
|||
<color name="primaryColorRed">#d32f2f</color> |
|||
<color name="primaryDarkColorRed">#9a0007</color> |
|||
<color name="secondaryColorRed">#ff6659</color> |
|||
<color name="primaryColorRedNight">#ef9a9a</color> |
|||
<color name="primaryDarkColorRedNight">#ba6b6c</color> |
|||
<color name="secondaryColorRedNight">#ffcccb</color> |
|||
|
|||
<color name="primaryColorOrange">#f57c00</color> |
|||
<color name="primaryDarkColorOrange">#bb4d00</color> |
|||
<color name="secondaryColorOrange">#ffad42</color> |
|||
<color name="primaryColorOrangeNight">#ffcc80</color> |
|||
<color name="primaryDarkColorOrangeNight">#ca9b52</color> |
|||
<color name="secondaryColorOrangeNight">#ffffb0</color> |
|||
|
|||
<color name="white">#FFFFFF</color> |
|||
<color name="transparent">#80000000</color> |
|||
</resources> |
@ -0,0 +1,5 @@ |
|||
<resources> |
|||
<dimen name="fab_margin">16dp</dimen> |
|||
|
|||
<dimen name="material_button_rounded_radius">10dp</dimen> |
|||
</resources> |
@ -0,0 +1,46 @@ |
|||
<resources> |
|||
<string name="app_name" translatable="false">IoT Control</string> |
|||
<string name="settings_header">Settings</string> |
|||
|
|||
<!-- Preference Titles --> |
|||
<string name="options_header">Options</string> |
|||
<string name="theme_header">Theme</string> |
|||
<string name="color_header">Color</string> |
|||
|
|||
<!-- Options Preferences --> |
|||
<!--<string name="ip_address_port_title">IP Address and port</string> |
|||
<string name="hmac_key">Secret key</string> |
|||
<string name="hash_byte_length_key">Byte Length</string> |
|||
<string name="rand_data_length_key">Random Data Length</string>--> |
|||
<string name="load_json_commands">Load Commands</string> |
|||
|
|||
<!-- Theme Preferences --> |
|||
<string name="dark_theme_title">Dark theme</string> |
|||
|
|||
<!-- Sync Preferences --> |
|||
<!--<string name="sync_title">Sync email periodically</string> |
|||
<string name="attachment_title">Download incoming attachments</string> |
|||
<string name="attachment_summary_on">Automatically download attachments for incoming emails</string> |
|||
<string name="attachment_summary_off">Only download attachments when manually requested</string>--> |
|||
|
|||
<!-- JSON Dialog --> |
|||
<string name="request_read_external_storage_permission">This application needs permission to access files in your phone.</string> |
|||
<string name="version">Version</string> |
|||
<string name="about_header">About</string> |
|||
<string name="skulix_labs" translatable="false">Skulix Labs</string> |
|||
<string name="open_source_liceses">Open Source Licenses</string> |
|||
<string name="invalid_commands">Commands were not valid</string> |
|||
<string name="load">Load</string> |
|||
<string name="select_commands_load_method">Select load method</string> |
|||
<string name="import_from_file">Import from file</string> |
|||
<string name="paste_from_clipboard">Paste from clipboard</string> |
|||
<string name="or_header">OR</string> |
|||
<string name="language_header">Language</string> |
|||
|
|||
<!-- Option dialogs - Sparse arrays --> |
|||
<string name="system_default">System default</string> |
|||
<string name="option_default">Default</string> |
|||
<string name="red">Red</string> |
|||
<string name="orange">Orange</string> |
|||
|
|||
</resources> |
@ -0,0 +1,46 @@ |
|||
<resources> |
|||
|
|||
<!-- Base application theme. --> |
|||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"> |
|||
<!-- Customize your theme here. --> |
|||
<item name="colorPrimary">@color/colorPrimary</item> |
|||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> |
|||
<item name="colorAccent">@color/colorAccent</item> |
|||
</style> |
|||
|
|||
<style name="ToolbarTheme" parent="@style/ThemeOverlay.MaterialComponents.ActionBar"> |
|||
|
|||
</style> |
|||
|
|||
<!-- App theme without action bar --> |
|||
<style name="AppTheme.NoActionBar"> |
|||
<item name="windowActionBar">false</item> |
|||
<item name="windowNoTitle">true</item> |
|||
</style> |
|||
|
|||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" /> |
|||
|
|||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" /> |
|||
|
|||
<style name="AppTheme.RED" parent="AppTheme.NoActionBar"> |
|||
<item name="colorPrimary">@color/primaryColorRed</item> |
|||
<item name="colorPrimaryDark">@color/primaryDarkColorRed</item> |
|||
<item name="colorAccent">@color/secondaryColorRed</item> |
|||
</style> |
|||
|
|||
<style name="AppTheme.ORANGE" parent="AppTheme.NoActionBar"> |
|||
<item name="colorPrimary">@color/primaryColorOrange</item> |
|||
<item name="colorPrimaryDark">@color/primaryDarkColorOrange</item> |
|||
<item name="colorAccent">@color/secondaryColorOrange</item> |
|||
</style> |
|||
|
|||
<!-- <style name="mybtn" parent="@style/Widget.AppCompat.Button.Colored"> |
|||
<item name="android:colorButtonNormal">@color/primaryColorOrange</item> |
|||
<item name="android:textColor">@color/primaryColorOrange</item> |
|||
</style>--> |
|||
|
|||
<style name="mybtn" parent="Widget.MaterialComponents.Button"> |
|||
<item name="backgroundTint">?attr/colorPrimary</item> |
|||
</style> |
|||
|
|||
</resources> |
@ -0,0 +1,62 @@ |
|||
<!-- |
|||
~ Copyright 2018 The app Open Source Project |
|||
~ |
|||
~ Licensed under the Apache License, Version 2.0 (the "License"); |
|||
~ you may not use this file except in compliance with the License. |
|||
~ You may obtain a copy of the License at |
|||
~ |
|||
~ http://www.apache.org/licenses/LICENSE-2.0 |
|||
~ |
|||
~ Unless required by applicable law or agreed to in writing, software |
|||
~ distributed under the License is distributed on an "AS IS" BASIS, |
|||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
~ See the License for the specific language governing permissions and |
|||
~ limitations under the License. |
|||
--> |
|||
|
|||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
|
|||
<PreferenceCategory app:title="@string/options_header"> |
|||
|
|||
<Preference |
|||
app:key="load_json_commands" |
|||
app:title="@string/load_json_commands" |
|||
app:summary="@string/select_commands_load_method"/> |
|||
|
|||
<!--<ListPreference |
|||
app:defaultValue="system_default" |
|||
app:entries="@array/language_list" |
|||
app:entryValues="@array/language_list_values" |
|||
app:key="language" |
|||
app:title="@string/language_header" |
|||
app:useSimpleSummaryProvider="true" />--> |
|||
|
|||
</PreferenceCategory> |
|||
|
|||
<PreferenceCategory app:title="@string/theme_header"> |
|||
|
|||
<SwitchPreferenceCompat |
|||
app:key="dark_theme" |
|||
app:title="@string/dark_theme_title" /> |
|||
|
|||
<ListPreference |
|||
app:defaultValue="default" |
|||
app:entries="@array/theme_color_list" |
|||
app:entryValues="@array/theme_color_list_values" |
|||
app:key="theme_color" |
|||
app:title="@string/color_header" |
|||
app:useSimpleSummaryProvider="true" /> |
|||
|
|||
</PreferenceCategory> |
|||
|
|||
<PreferenceCategory app:title="@string/about_header"> |
|||
|
|||
<Preference |
|||
app:key="version" |
|||
app:title="@string/version" |
|||
app:summary="@string/appVersion"/> |
|||
|
|||
</PreferenceCategory> |
|||
|
|||
</PreferenceScreen> |
@ -0,0 +1,17 @@ |
|||
package com.skulixlabs.iotcontrol; |
|||
|
|||
import org.junit.Test; |
|||
|
|||
import static org.junit.Assert.*; |
|||
|
|||
/** |
|||
* Example local unit test, which will execute on the development machine (host). |
|||
* |
|||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
|||
*/ |
|||
public class ExampleUnitTest { |
|||
@Test |
|||
public void addition_isCorrect() { |
|||
assertEquals(4, 2 + 2); |
|||
} |
|||
} |
@ -0,0 +1,31 @@ |
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules. |
|||
|
|||
buildscript { |
|||
repositories { |
|||
google() |
|||
jcenter() |
|||
|
|||
} |
|||
dependencies { |
|||
def nav_version = "2.1.0" |
|||
|
|||
classpath 'com.android.tools.build:gradle:3.5.1' |
|||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" |
|||
classpath 'com.jaredsburrows:gradle-license-plugin:0.8.5' |
|||
|
|||
// NOTE: Do not place your application dependencies here; they belong |
|||
// in the individual module build.gradle files |
|||
} |
|||
} |
|||
|
|||
allprojects { |
|||
repositories { |
|||
google() |
|||
jcenter() |
|||
maven { url 'https://jitpack.io' } |
|||
} |
|||
} |
|||
|
|||
task clean(type: Delete) { |
|||
delete rootProject.buildDir |
|||
} |
@ -0,0 +1,17 @@ |
|||
# Project-wide Gradle settings. |
|||
# IDE (e.g. Android Studio) users: |
|||
# Gradle settings configured through the IDE *will override* |
|||
# any settings specified in this file. |
|||
# For more details on how to configure your build environment visit |
|||
# http://www.gradle.org/docs/current/userguide/build_environment.html |
|||
# Specifies the JVM arguments used for the daemon process. |
|||
# The setting is particularly useful for tweaking memory settings. |
|||
android.enableJetifier=true |
|||
android.useAndroidX=true |
|||
org.gradle.jvmargs=-Xmx1536m |
|||
# When configured, Gradle will run in incubating parallel mode. |
|||
# This option should only be used with decoupled projects. More details, visit |
|||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
|||
# org.gradle.parallel=true |
|||
|
|||
|
@ -0,0 +1,6 @@ |
|||
#Wed Sep 25 21:02:35 EEST 2019 |
|||
distributionBase=GRADLE_USER_HOME |
|||
distributionPath=wrapper/dists |
|||
zipStoreBase=GRADLE_USER_HOME |
|||
zipStorePath=wrapper/dists |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip |
@ -0,0 +1,172 @@ |
|||
#!/usr/bin/env sh |
|||
|
|||
############################################################################## |
|||
## |
|||
## Gradle start up script for UN*X |
|||
## |
|||
############################################################################## |
|||
|
|||
# Attempt to set APP_HOME |
|||
# Resolve links: $0 may be a link |
|||
PRG="$0" |
|||
# Need this for relative symlinks. |
|||
while [ -h "$PRG" ] ; do |
|||
ls=`ls -ld "$PRG"` |
|||
link=`expr "$ls" : '.*-> \(.*\)$'` |
|||
if expr "$link" : '/.*' > /dev/null; then |
|||
PRG="$link" |
|||
else |
|||
PRG=`dirname "$PRG"`"/$link" |
|||
fi |
|||
done |
|||
SAVED="`pwd`" |
|||
cd "`dirname \"$PRG\"`/" >/dev/null |
|||
APP_HOME="`pwd -P`" |
|||
cd "$SAVED" >/dev/null |
|||
|
|||
APP_NAME="Gradle" |
|||
APP_BASE_NAME=`basename "$0"` |
|||
|
|||
# Add default JVM optionsOld here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM optionsOld to this script. |
|||
DEFAULT_JVM_OPTS="" |
|||
|
|||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
|||
MAX_FD="maximum" |
|||
|
|||
warn () { |
|||
echo "$*" |
|||
} |
|||
|
|||
die () { |
|||
echo |
|||
echo "$*" |
|||
echo |
|||
exit 1 |
|||
} |
|||
|
|||
# OS specific support (must be 'true' or 'false'). |
|||
cygwin=false |
|||
msys=false |
|||
darwin=false |
|||
nonstop=false |
|||
case "`uname`" in |
|||
CYGWIN* ) |
|||
cygwin=true |
|||
;; |
|||
Darwin* ) |
|||
darwin=true |
|||
;; |
|||
MINGW* ) |
|||
msys=true |
|||
;; |
|||
NONSTOP* ) |
|||
nonstop=true |
|||
;; |
|||
esac |
|||
|
|||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
|||
|
|||
# Determine the Java command to use to start the JVM. |
|||
if [ -n "$JAVA_HOME" ] ; then |
|||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
|||
# IBM's JDK on AIX uses strange locations for the executables |
|||
JAVACMD="$JAVA_HOME/jre/sh/java" |
|||
else |
|||
JAVACMD="$JAVA_HOME/bin/java" |
|||
fi |
|||
if [ ! -x "$JAVACMD" ] ; then |
|||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
|||
|
|||
Please set the JAVA_HOME variable in your environment to match the |
|||
location of your Java installation." |
|||
fi |
|||
else |
|||
JAVACMD="java" |
|||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
|||
|
|||
Please set the JAVA_HOME variable in your environment to match the |
|||
location of your Java installation." |
|||
fi |
|||
|
|||
# Increase the maximum file descriptors if we can. |
|||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then |
|||
MAX_FD_LIMIT=`ulimit -H -n` |
|||
if [ $? -eq 0 ] ; then |
|||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then |
|||
MAX_FD="$MAX_FD_LIMIT" |
|||
fi |
|||
ulimit -n $MAX_FD |
|||
if [ $? -ne 0 ] ; then |
|||
warn "Could not set maximum file descriptor limit: $MAX_FD" |
|||
fi |
|||
else |
|||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" |
|||
fi |
|||
fi |
|||
|
|||
# For Darwin, add optionsOld to specify how the application appears in the dock |
|||
if $darwin; then |
|||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" |
|||
fi |
|||
|
|||
# For Cygwin, switch paths to Windows format before running java |
|||
if $cygwin ; then |
|||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
|||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
|||
JAVACMD=`cygpath --unix "$JAVACMD"` |
|||
|
|||
# We build the pattern for arguments to be converted via cygpath |
|||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` |
|||
SEP="" |
|||
for dir in $ROOTDIRSRAW ; do |
|||
ROOTDIRS="$ROOTDIRS$SEP$dir" |
|||
SEP="|" |
|||
done |
|||
OURCYGPATTERN="(^($ROOTDIRS))" |
|||
# Add a user-defined pattern to the cygpath arguments |
|||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then |
|||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" |
|||
fi |
|||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
|||
i=0 |
|||
for arg in "$@" ; do |
|||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` |
|||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option |
|||
|
|||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition |
|||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` |
|||
else |
|||
eval `echo args$i`="\"$arg\"" |
|||
fi |
|||
i=$((i+1)) |
|||
done |
|||
case $i in |
|||
(0) set -- ;; |
|||
(1) set -- "$args0" ;; |
|||
(2) set -- "$args0" "$args1" ;; |
|||
(3) set -- "$args0" "$args1" "$args2" ;; |
|||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; |
|||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; |
|||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; |
|||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; |
|||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; |
|||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; |
|||
esac |
|||
fi |
|||
|
|||
# Escape application args |
|||
save () { |
|||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done |
|||
echo " " |
|||
} |
|||
APP_ARGS=$(save "$@") |
|||
|
|||
# Collect all arguments for the java command, following the shell quoting and substitution rules |
|||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" |
|||
|
|||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong |
|||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then |
|||
cd "$(dirname "$0")" |
|||
fi |
|||
|
|||
exec "$JAVACMD" "$@" |
@ -0,0 +1,84 @@ |
|||
@if "%DEBUG%" == "" @echo off |
|||
@rem ########################################################################## |
|||
@rem |
|||
@rem Gradle startup script for Windows |
|||
@rem |
|||
@rem ########################################################################## |
|||
|
|||
@rem Set local scope for the variables with windows NT shell |
|||
if "%OS%"=="Windows_NT" setlocal |
|||
|
|||
set DIRNAME=%~dp0 |
|||
if "%DIRNAME%" == "" set DIRNAME=. |
|||
set APP_BASE_NAME=%~n0 |
|||
set APP_HOME=%DIRNAME% |
|||
|
|||
@rem Add default JVM optionsOld here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM optionsOld to this script. |
|||
set DEFAULT_JVM_OPTS= |
|||
|
|||
@rem Find java.exe |
|||
if defined JAVA_HOME goto findJavaFromJavaHome |
|||
|
|||
set JAVA_EXE=java.exe |
|||
%JAVA_EXE% -version >NUL 2>&1 |
|||
if "%ERRORLEVEL%" == "0" goto init |
|||
|
|||
echo. |
|||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
|||
echo. |
|||
echo Please set the JAVA_HOME variable in your environment to match the |
|||
echo location of your Java installation. |
|||
|
|||
goto fail |
|||
|
|||
:findJavaFromJavaHome |
|||
set JAVA_HOME=%JAVA_HOME:"=% |
|||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
|||
|
|||
if exist "%JAVA_EXE%" goto init |
|||
|
|||
echo. |
|||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
|||
echo. |
|||
echo Please set the JAVA_HOME variable in your environment to match the |
|||
echo location of your Java installation. |
|||
|
|||
goto fail |
|||
|
|||
:init |
|||
@rem Get command-line arguments, handling Windows variants |
|||
|
|||
if not "%OS%" == "Windows_NT" goto win9xME_args |
|||
|
|||
:win9xME_args |
|||
@rem Slurp the command line arguments. |
|||
set CMD_LINE_ARGS= |
|||
set _SKIP=2 |
|||
|
|||
:win9xME_args_slurp |
|||
if "x%~1" == "x" goto execute |
|||
|
|||
set CMD_LINE_ARGS=%* |
|||
|
|||
:execute |
|||
@rem Setup the command line |
|||
|
|||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
|||
|
|||
@rem Execute Gradle |
|||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% |
|||
|
|||
:end |
|||
@rem End local scope for the variables with windows NT shell |
|||
if "%ERRORLEVEL%"=="0" goto mainEnd |
|||
|
|||
:fail |
|||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
|||
rem the _cmd.exe /c_ return code! |
|||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
|||
exit /b 1 |
|||
|
|||
:mainEnd |
|||
if "%OS%"=="Windows_NT" endlocal |
|||
|
|||
:omega |
@ -0,0 +1 @@ |
|||
include ':app' |