From f11ca6ca9f4e8324485a40b8a23fbdf1e779c99f Mon Sep 17 00:00:00 2001 From: kangping Date: Mon, 26 Oct 2020 09:37:33 +0800 Subject: [PATCH 01/56] [android] initial Commissioner Android App --- .github/workflows/android.yml | 56 +++ .gitignore | 5 +- android/BUILDING.md | 24 ++ android/README.md | 7 + android/build-commissioner-libs.sh | 83 +++++ android/openthread_commissioner/.gitignore | 15 + .../openthread_commissioner/app/.gitignore | 1 + .../openthread_commissioner/app/build.gradle | 53 +++ .../app/proguard-rules.pro | 21 ++ .../app/ExampleInstrumentedTest.java | 26 ++ .../app/src/main/AndroidManifest.xml | 23 ++ .../commissioner/app/MainActivity.java | 160 ++++++++ .../res/drawable-anydpi/ic_openthread.xml | 21 ++ .../main/res/drawable-hdpi/ic_openthread.png | Bin 0 -> 273 bytes .../main/res/drawable-mdpi/ic_openthread.png | Bin 0 -> 188 bytes .../main/res/drawable-xhdpi/ic_openthread.png | Bin 0 -> 357 bytes .../res/drawable-xxhdpi/ic_openthread.png | Bin 0 -> 598 bytes .../app/src/main/res/drawable/ic_launcher.png | Bin 0 -> 2269 bytes .../app/src/main/res/layout/activity_main.xml | 49 +++ .../app/src/main/res/menu/menu_main.xml | 10 + .../app/src/main/res/values-night/themes.xml | 18 + .../app/src/main/res/values/colors.xml | 10 + .../app/src/main/res/values/strings.xml | 5 + .../app/src/main/res/values/themes.xml | 27 ++ android/openthread_commissioner/build.gradle | 24 ++ .../openthread_commissioner/gradle.properties | 19 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + android/openthread_commissioner/gradlew | 172 +++++++++ android/openthread_commissioner/gradlew.bat | 84 +++++ .../service/.gitignore | 3 + .../service/build.gradle | 48 +++ .../service/consumer-rules.pro | 0 .../service/proguard-rules.pro | 21 ++ .../service/CommissionerUtilsTest.java | 77 ++++ .../service/src/main/AndroidManifest.xml | 20 + .../commissioner/service/BorderAgentDao.java | 61 ++++ .../service/BorderAgentDatabase.java | 93 +++++ .../service/BorderAgentDiscoverer.java | 236 ++++++++++++ .../commissioner/service/BorderAgentInfo.java | 98 +++++ .../service/BorderAgentRecord.java | 98 +++++ .../commissioner/service/CHIPDeviceInfo.java | 93 +++++ .../service/CameraSourceView.java | 147 ++++++++ .../service/CommissionerActivity.java | 123 +++++++ .../service/CommissionerServiceApp.java | 54 +++ .../service/CommissionerUtils.java | 79 ++++ .../commissioner/service/Constants.java | 41 +++ .../FetchCredentialDialogFragment.java | 143 ++++++++ .../service/FragmentCallback.java | 37 ++ .../InputNetworkPasswordDialogFragment.java | 79 ++++ .../service/JoinerDeviceInfo.java | 79 ++++ .../commissioner/service/MeshcopFragment.java | 192 ++++++++++ .../service/NativeCommissionerLogger.java | 42 +++ .../commissioner/service/NetworkAdapter.java | 121 +++++++ .../service/NetworkCredential.java | 33 ++ .../service/ScanQrCodeFragment.java | 235 ++++++++++++ .../service/SelectNetworkFragment.java | 262 ++++++++++++++ .../service/ThreadCommissionerException.java | 57 +++ .../service/ThreadCommissionerService.java | 59 +++ .../ThreadCommissionerServiceFactory.java | 35 ++ .../ThreadCommissionerServiceImpl.java | 342 ++++++++++++++++++ .../service/ThreadNetworkCredential.java | 77 ++++ .../service/ThreadNetworkInfo.java | 88 +++++ .../service/ThreadNetworkInfoHolder.java | 82 +++++ .../src/main/res/drawable/ic_done_icon.xml | 9 + .../src/main/res/drawable/ic_error_icon.xml | 9 + .../res/drawable/ic_network_selected_icon.xml | 9 + .../res/drawable/ic_wireless_network_icon.xml | 9 + .../main/res/layout/activity_commissioner.xml | 9 + .../fragment_fetch_credential_dialog.xml | 15 + .../src/main/res/layout/fragment_meshcop.xml | 77 ++++ .../fragment_network_password_dialog.xml | 17 + .../main/res/layout/fragment_scan_qrcode.xml | 51 +++ .../res/layout/fragment_select_network.xml | 85 +++++ .../src/main/res/layout/network_list_item.xml | 17 + .../service/src/main/res/values/colors.xml | 6 + .../service/src/main/res/values/strings.xml | 22 ++ .../service/src/main/res/values/styles.xml | 13 + .../openthread_commissioner/settings.gradle | 3 + script/bootstrap.sh | 10 - tests/integration/bootstrap.sh | 1 + 81 files changed, 4522 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/android.yml create mode 100644 android/BUILDING.md create mode 100644 android/README.md create mode 100755 android/build-commissioner-libs.sh create mode 100644 android/openthread_commissioner/.gitignore create mode 100644 android/openthread_commissioner/app/.gitignore create mode 100644 android/openthread_commissioner/app/build.gradle create mode 100644 android/openthread_commissioner/app/proguard-rules.pro create mode 100644 android/openthread_commissioner/app/src/androidTest/java/io/openthread/commissioner/app/ExampleInstrumentedTest.java create mode 100644 android/openthread_commissioner/app/src/main/AndroidManifest.xml create mode 100644 android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/MainActivity.java create mode 100644 android/openthread_commissioner/app/src/main/res/drawable-anydpi/ic_openthread.xml create mode 100644 android/openthread_commissioner/app/src/main/res/drawable-hdpi/ic_openthread.png create mode 100644 android/openthread_commissioner/app/src/main/res/drawable-mdpi/ic_openthread.png create mode 100644 android/openthread_commissioner/app/src/main/res/drawable-xhdpi/ic_openthread.png create mode 100644 android/openthread_commissioner/app/src/main/res/drawable-xxhdpi/ic_openthread.png create mode 100644 android/openthread_commissioner/app/src/main/res/drawable/ic_launcher.png create mode 100644 android/openthread_commissioner/app/src/main/res/layout/activity_main.xml create mode 100644 android/openthread_commissioner/app/src/main/res/menu/menu_main.xml create mode 100644 android/openthread_commissioner/app/src/main/res/values-night/themes.xml create mode 100644 android/openthread_commissioner/app/src/main/res/values/colors.xml create mode 100644 android/openthread_commissioner/app/src/main/res/values/strings.xml create mode 100644 android/openthread_commissioner/app/src/main/res/values/themes.xml create mode 100644 android/openthread_commissioner/build.gradle create mode 100644 android/openthread_commissioner/gradle.properties create mode 100644 android/openthread_commissioner/gradle/wrapper/gradle-wrapper.jar create mode 100644 android/openthread_commissioner/gradle/wrapper/gradle-wrapper.properties create mode 100755 android/openthread_commissioner/gradlew create mode 100644 android/openthread_commissioner/gradlew.bat create mode 100644 android/openthread_commissioner/service/.gitignore create mode 100644 android/openthread_commissioner/service/build.gradle create mode 100644 android/openthread_commissioner/service/consumer-rules.pro create mode 100644 android/openthread_commissioner/service/proguard-rules.pro create mode 100644 android/openthread_commissioner/service/src/androidTest/java/io/openthread/commissioner/service/CommissionerUtilsTest.java create mode 100644 android/openthread_commissioner/service/src/main/AndroidManifest.xml create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDao.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDatabase.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentDiscoverer.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentInfo.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/BorderAgentRecord.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CHIPDeviceInfo.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CameraSourceView.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerActivity.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerServiceApp.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/CommissionerUtils.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/Constants.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FetchCredentialDialogFragment.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/FragmentCallback.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/InputNetworkPasswordDialogFragment.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/JoinerDeviceInfo.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/MeshcopFragment.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NativeCommissionerLogger.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkAdapter.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/NetworkCredential.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ScanQrCodeFragment.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/SelectNetworkFragment.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerException.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerService.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceFactory.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadCommissionerServiceImpl.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkCredential.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkInfo.java create mode 100644 android/openthread_commissioner/service/src/main/java/io/openthread/commissioner/service/ThreadNetworkInfoHolder.java create mode 100644 android/openthread_commissioner/service/src/main/res/drawable/ic_done_icon.xml create mode 100644 android/openthread_commissioner/service/src/main/res/drawable/ic_error_icon.xml create mode 100644 android/openthread_commissioner/service/src/main/res/drawable/ic_network_selected_icon.xml create mode 100644 android/openthread_commissioner/service/src/main/res/drawable/ic_wireless_network_icon.xml create mode 100644 android/openthread_commissioner/service/src/main/res/layout/activity_commissioner.xml create mode 100644 android/openthread_commissioner/service/src/main/res/layout/fragment_fetch_credential_dialog.xml create mode 100644 android/openthread_commissioner/service/src/main/res/layout/fragment_meshcop.xml create mode 100644 android/openthread_commissioner/service/src/main/res/layout/fragment_network_password_dialog.xml create mode 100644 android/openthread_commissioner/service/src/main/res/layout/fragment_scan_qrcode.xml create mode 100644 android/openthread_commissioner/service/src/main/res/layout/fragment_select_network.xml create mode 100644 android/openthread_commissioner/service/src/main/res/layout/network_list_item.xml create mode 100644 android/openthread_commissioner/service/src/main/res/values/colors.xml create mode 100644 android/openthread_commissioner/service/src/main/res/values/strings.xml create mode 100644 android/openthread_commissioner/service/src/main/res/values/styles.xml create mode 100644 android/openthread_commissioner/settings.gradle diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 000000000..e2f911b61 --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,56 @@ +# +# Copyright (c) 2020, The OpenThread Commissioner Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +name: Android App + +on: [push, pull_request] + +jobs: + nightly-build: + runs-on: macos-latest + strategy: + matrix: + android-abi: [x86, x86_64] + android-api: [24, 29] + steps: + - uses: actions/checkout@v2 + - name: Bootstrap + run: | + script/bootstrap.sh + - name: Build + run: | + cd android + ANDROID_ABI=${{ matrix.android-abi }} ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle ./build-commissioner-libs.sh + cd openthread_commissioner + ./gradlew build + - name: Tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.android-api }} + arch: ${{ matrix.android-abi }} + script: "cd android/openthread_commissioner && ./gradlew connectedAndroidTest" diff --git a/.gitignore b/.gitignore index 28c262792..c01a2c3d2 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,7 @@ Makefile Makefile.in # build -._build +.build-* build cmake-build-* @@ -64,6 +64,3 @@ doc __pycache__/ venv/ *.py[cod] - -# Java (autogenerated) -**/io/openthread/commissioner diff --git a/android/BUILDING.md b/android/BUILDING.md new file mode 100644 index 000000000..7858f2c73 --- /dev/null +++ b/android/BUILDING.md @@ -0,0 +1,24 @@ +# Build OpenThread Commissioner App + +This documents describes instructions to build the OT Commissioner (Android) App. + +## Prerequisites + +- macOS or Linux computer. +- Install latest Android Studio from [here](https://developer.android.com/studio). + +## Build shared library + +The Commissioner Android App is built atop of the native OT Commissioner library. There is a `build-commissioner-libs.sh` script in current directory to help building the required libraries: + +```shell +ANDROID_ABI=arm64-v8a ANDROID_NDK_HOME=$HOME/Library/Android/sdk/ndk/21.3.6528147 ./build-commissioner-libs.sh +``` + +This script creates a build directory (`.build-${ANDROID_ABI}`) in current directory and copies generated libraries into target sub-folders in `openthread_commissioner`. + +_Note: you need to set env `ANDROID_ABI` to the ABI of your phone. This value can be got with command `adb shell getprop ro.product.cpu.abi` after connecting the phone to your computer._ + +## Build the App with Android Studio + +Connect the phone to your computer and we can now open the `openthread_commissioner` directory with Android Studio. Click the `Gradle Sync` and `Run` buttons to run the Commissioner App on your phone. diff --git a/android/README.md b/android/README.md new file mode 100644 index 000000000..5b588165c --- /dev/null +++ b/android/README.md @@ -0,0 +1,7 @@ +# OpenThread Commissioner Android App + +The OpenThread (OT) Commissioner sample app commissions a new Thread 1.1 Device into existing Thread Network. + +## Build + +See [BUILDING.md](./BUILDING.md). diff --git a/android/build-commissioner-libs.sh b/android/build-commissioner-libs.sh new file mode 100755 index 000000000..1054904d8 --- /dev/null +++ b/android/build-commissioner-libs.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Copyright (c) 2020, The OpenThread Commissioner Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +readonly CUR_DIR="$(dirname "$(realpath -s "$0")")" + +set -e + +if [ -z "${ANDROID_ABI}" ]; then + echo "ANDROID_ABI not set! Candidates: armeabi-v7a, arm64-v8a, x86 and x86_64" + exit 1 +fi + +if [ -z "${ANDROID_NDK_HOME}" ]; then + echo "ANDROID_NDK_HOME not set! Please set it to your Android NDK location!" + exit 1 +fi + +cd "${CUR_DIR}" + +readonly BUILD_DIR=".build-$ANDROID_ABI" + +mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR" +cmake -GNinja \ + -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME"/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI="$ANDROID_ABI" \ + -DANDROID_ARM_NEON=ON \ + -DANDROID_NATIVE_API_LEVEL=21 \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_CXX_STANDARD=11 \ + -DCMAKE_CXX_STANDARD_REQUIRED=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DOT_COMM_ANDROID=ON \ + -DOT_COMM_JAVA_BINDING=ON \ + -DOT_COMM_APP=OFF \ + -DOT_COMM_TEST=OFF \ + -DOT_COMM_CCM=OFF \ + ../.. + +ninja commissioner-java +cd ../ + +rm -rf "$BUILD_DIR"/libs && mkdir -p "$BUILD_DIR"/libs + +## Create JAR library +javac -source 8 -target 8 "$BUILD_DIR"/src/java/io/openthread/commissioner/*.java + +cd "$BUILD_DIR"/src/java +find ./io/openthread/commissioner -name "*.class" | xargs jar cvf ../../libs/libotcommissioner.jar +cd ../../../ + +## Copy shared native libraries +cp "$BUILD_DIR"/src/java/libcommissioner-java.so "$BUILD_DIR"/libs + +mkdir -p openthread_commissioner/service/libs +mkdir -p openthread_commissioner/service/src/main/jniLibs/"${ANDROID_ABI}" +cp "$BUILD_DIR"/libs/libotcommissioner.jar openthread_commissioner/service/libs +cp "$BUILD_DIR"/libs/*.so openthread_commissioner/service/src/main/jniLibs/"${ANDROID_ABI}" diff --git a/android/openthread_commissioner/.gitignore b/android/openthread_commissioner/.gitignore new file mode 100644 index 000000000..aa724b770 --- /dev/null +++ b/android/openthread_commissioner/.gitignore @@ -0,0 +1,15 @@ +*.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 +.cxx +local.properties diff --git a/android/openthread_commissioner/app/.gitignore b/android/openthread_commissioner/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/android/openthread_commissioner/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/android/openthread_commissioner/app/build.gradle b/android/openthread_commissioner/app/build.gradle new file mode 100644 index 000000000..7545d8558 --- /dev/null +++ b/android/openthread_commissioner/app/build.gradle @@ -0,0 +1,53 @@ +plugins { + id 'com.android.application' +} + +def getGitHash = { -> + def stdout = new ByteArrayOutputStream() + exec { + commandLine 'git', 'rev-parse', '--short', 'HEAD' + standardOutput = stdout + } + return stdout.toString().trim() +} + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.1" + ndkVersion "21.3.6528147" + + defaultConfig { + applicationId "io.openthread.commissioner.app" + minSdkVersion 24 + targetSdkVersion 30 + versionCode 1 + versionName "0.0.1" + + buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation project(':service') + + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.2.1' + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' + testImplementation 'junit:junit:4.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' +} \ No newline at end of file diff --git a/android/openthread_commissioner/app/proguard-rules.pro b/android/openthread_commissioner/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/android/openthread_commissioner/app/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/android/openthread_commissioner/app/src/androidTest/java/io/openthread/commissioner/app/ExampleInstrumentedTest.java b/android/openthread_commissioner/app/src/androidTest/java/io/openthread/commissioner/app/ExampleInstrumentedTest.java new file mode 100644 index 000000000..82810869b --- /dev/null +++ b/android/openthread_commissioner/app/src/androidTest/java/io/openthread/commissioner/app/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package io.openthread.commissioner.app; + +import android.content.Context; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.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 Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("io.openthread.commissioner.app", appContext.getPackageName()); + } +} diff --git a/android/openthread_commissioner/app/src/main/AndroidManifest.xml b/android/openthread_commissioner/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..99bdb4637 --- /dev/null +++ b/android/openthread_commissioner/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/MainActivity.java b/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/MainActivity.java new file mode 100644 index 000000000..1a7a43173 --- /dev/null +++ b/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/MainActivity.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2020, The OpenThread Commissioner Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package io.openthread.commissioner.app; + +import android.app.Activity; +import android.content.Intent; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import android.os.Bundle; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import io.openthread.commissioner.app.BuildConfig; +import io.openthread.commissioner.service.FragmentCallback; +import io.openthread.commissioner.service.JoinerDeviceInfo; +import io.openthread.commissioner.service.MeshcopFragment; +import io.openthread.commissioner.service.ScanQrCodeFragment; +import io.openthread.commissioner.service.SelectNetworkFragment; +import io.openthread.commissioner.service.ThreadNetworkInfoHolder; + +public class MainActivity extends AppCompatActivity implements FragmentCallback { + + private static final String TAG = MainActivity.class.getSimpleName(); + + @Nullable + private ThreadNetworkInfoHolder selectedNetwork; + + @Nullable + private byte[] pskc; + + @Nullable + private JoinerDeviceInfo joinerDeviceInfo; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + setSupportActionBar(findViewById(R.id.toolbar)); + + TextView versionName = findViewById(R.id.version_name); + versionName.setText(BuildConfig.VERSION_NAME); + TextView gitHash = findViewById(R.id.git_hash); + gitHash.setText(BuildConfig.GIT_HASH); + + if (savedInstanceState == null) { + showFragment(new SelectNetworkFragment(this, null), false); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // TODO(wgtdkp): + // 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(); + + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } + + private void showFragment(Fragment fragment, boolean addToBackStack) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName()); + if (addToBackStack) { + transaction.addToBackStack(null); + } + transaction.commit(); + } + + private void clearFragmentsInBackStack() { + getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + + private void finishCommissioning(int result) { + // TODO(wgtdkp): show a dialog to the user. + selectedNetwork = null; + pskc = null; + joinerDeviceInfo = null; + clearFragmentsInBackStack(); + } + + @Override + public void onNetworkSelected(@Nullable ThreadNetworkInfoHolder networkInfoHolder, @Nullable byte[] pskc) { + if (networkInfoHolder == null || pskc == null) { + Log.e(TAG, "failed to get selected network or PSKc!"); + finishCommissioning(Activity.RESULT_CANCELED); + return; + } + + this.selectedNetwork = networkInfoHolder; + this.pskc = pskc; + showFragment(new ScanQrCodeFragment(this), true); + } + + @Override + public void onJoinerInfoReceived(@Nullable JoinerDeviceInfo joinerDeviceInfo) { + if (joinerDeviceInfo == null) { + // TODO(wgtdkp): show dialog + Log.e(TAG, "failed to get Joiner Device info!"); + finishCommissioning(Activity.RESULT_CANCELED); + return; + } + + if (this.joinerDeviceInfo == null) { + this.joinerDeviceInfo = joinerDeviceInfo; + showFragment(new MeshcopFragment(this, selectedNetwork, pskc, joinerDeviceInfo), true); + } + } + + @Override + public void onMeshcopResult(int result) { + finishCommissioning(result); + } +} \ No newline at end of file diff --git a/android/openthread_commissioner/app/src/main/res/drawable-anydpi/ic_openthread.xml b/android/openthread_commissioner/app/src/main/res/drawable-anydpi/ic_openthread.xml new file mode 100644 index 000000000..d87fb30e2 --- /dev/null +++ b/android/openthread_commissioner/app/src/main/res/drawable-anydpi/ic_openthread.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/android/openthread_commissioner/app/src/main/res/drawable-hdpi/ic_openthread.png b/android/openthread_commissioner/app/src/main/res/drawable-hdpi/ic_openthread.png new file mode 100644 index 0000000000000000000000000000000000000000..fa35747699da86b02d5c7a071d5100e95daa307d GIT binary patch literal 273 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 iDD@jL{3iY%Y5>1D<6LL0Pgu{q0H(%PM)g + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/openthread_commissioner/app/src/main/res/menu/menu_main.xml b/android/openthread_commissioner/app/src/main/res/menu/menu_main.xml new file mode 100644 index 000000000..4fb3a1419 --- /dev/null +++ b/android/openthread_commissioner/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/openthread_commissioner/app/src/main/res/values-night/themes.xml b/android/openthread_commissioner/app/src/main/res/values-night/themes.xml new file mode 100644 index 000000000..ec2133380 --- /dev/null +++ b/android/openthread_commissioner/app/src/main/res/values-night/themes.xml @@ -0,0 +1,18 @@ + + + + \ No newline at end of file diff --git a/android/openthread_commissioner/app/src/main/res/values/colors.xml b/android/openthread_commissioner/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..09837df62 --- /dev/null +++ b/android/openthread_commissioner/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/android/openthread_commissioner/app/src/main/res/values/strings.xml b/android/openthread_commissioner/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..1e0341e7e --- /dev/null +++ b/android/openthread_commissioner/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + OpenThread Commissioner + Settings + Commission New Device + diff --git a/android/openthread_commissioner/app/src/main/res/values/themes.xml b/android/openthread_commissioner/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..7e5126319 --- /dev/null +++ b/android/openthread_commissioner/app/src/main/res/values/themes.xml @@ -0,0 +1,27 @@ + + + + + + + + + - \ No newline at end of file + diff --git a/android/openthread_commissioner/app/src/main/res/values/colors.xml b/android/openthread_commissioner/app/src/main/res/values/colors.xml index 09837df62..758655a2e 100644 --- a/android/openthread_commissioner/app/src/main/res/values/colors.xml +++ b/android/openthread_commissioner/app/src/main/res/values/colors.xml @@ -7,4 +7,4 @@ #FF018786 #FF000000 #FFFFFFFF - \ No newline at end of file + diff --git a/android/openthread_commissioner/app/src/main/res/values/themes.xml b/android/openthread_commissioner/app/src/main/res/values/themes.xml index 7e5126319..176d03a3e 100644 --- a/android/openthread_commissioner/app/src/main/res/values/themes.xml +++ b/android/openthread_commissioner/app/src/main/res/values/themes.xml @@ -24,4 +24,4 @@