Commit 7b70e22c authored by vunguyencuong's avatar vunguyencuong

Invalid, no access

parents
# Tuya Defines
/src/main/assets/*.mist
google-services.json
/tysrc
/tyconfig
/tybuild
.DS_Store
/preconfig
# Built application files
*.apk
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Uncomment the following line in case you need and you don't have the release build type files in your app
# release/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
#IntelliJ IDEA
.idea/
*.iml
*.ipr
*.iws
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
.cxx/
# Google Services (e.g. APIs or Firebase)
# google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md
# Version control
vcs.xml
# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/
# gitignore
t_s.bmp
\ No newline at end of file
/build
\ No newline at end of file
plugins {
id 'com.android.application'
id 'kotlin-android'
}
if (new File("thingMapping.gradle").exists()) {
apply from : "thingMapping.gradle"
}
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
signingConfigs {
debug {
storeFile file('../app/key/tuya.jks')
storePassword '05052002'
keyAlias 'key_tuya'
keyPassword '05052002'
}
}
defaultConfig {
applicationId "com.example.smarthomecontrol"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
manifestPlaceholders = [
TUYA_SMART_APPKEY: "${properties.getProperty("crvyt9phy3wr7md4jkcv")}",
TUYA_SMART_SECRET: "${properties.getProperty("qfuh5mp5k5ady4k3khgeywdppjhrgqvv")}",
]
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
signingConfig signingConfigs.debug
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
lintOptions {
abortOnError false
}
packagingOptions {
pickFirst 'lib/*/libc++_shared.so' // 多个aar存在此so,需要选择第一个
pickFirst 'lib/*/libgnustl_shared.so'//业务包需要
pickFirst 'lib/*/liblog.so'
pickFirst 'lib/*/libopenh264.so'
}
buildTypes {
debug {
debuggable true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
configurations.all {
exclude group: "com.thingclips.smart" ,module: 'thingsmart-modularCampAnno'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0-alpha04'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.alibaba:fastjson:1.1.67.android'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9'
implementation project(':base_res')
implementation project(":home")
implementation project(":device_config")
implementation project(":device_management")
implementation project(":ipc")
implementation project(":sweeper")
implementation 'cn.yipianfengye.android:zxing-library:2.2'
}
\ No newline at end of file
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.test007.demo",
"variantName": "debug",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-debug.apk"
}
],
"elementType": "File"
}
\ No newline at end of file
# 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
#fastJson
-keep class com.alibaba.fastjson.**{*;}
-dontwarn com.alibaba.fastjson.**
#mqtt
-keep class com.tuya.smart.mqttclient.mqttv3.** { *; }
-dontwarn com.tuya.smart.mqttclient.mqttv3.**
#OkHttp3
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
#Okio
-keep class okio.** { *; }
-dontwarn okio.**
#Tuya
-keep class com.tuya.**{*;}
-dontwarn com.tuya.**
# Matter SDK
-keep class chip.** { *; }
-dontwarn chip.**
package com.tuya.appsdk.sample
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.tuya.appsdk.sample", appContext.packageName)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.tuya.appsdk.sample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".BaseApplication"
android:theme="@style/Theme.MaterialComponents.Light.NoActionBar"
tools:replace="android:allowBackup,android:supportsRtl">
<meta-data
android:name="THING_SMART_APPKEY"
android:value="crvyt9phy3wr7md4jkcv" />
<meta-data
android:name="THING_SMART_SECRET"
android:value="qfuh5mp5k5ady4k3khgeywdppjhrgqvv" />
<!-- Main -->
<activity
android:name=".main.MainSampleListActivity"
android:exported="false"
android:screenOrientation="portrait" />
<!-- User -->
<activity
android:name=".user.main.UserFuncActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".user.login.UserLoginActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".user.register.UserRegisterActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".user.resetPassword.UserResetPasswordActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".user.info.UserInfoActivity"
android:exported="false"
android:screenOrientation="portrait" />
</application>
</manifest>
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample
import android.app.Application
import com.tuya.smart.android.demo.camera.CameraUtils
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.optimus.sdk.ThingOptimusSdk
import com.uuzuche.lib_zxing.activity.ZXingLibrary
/**
* Base Application
*
* @author qianqi <a href="mailto:developer@tuya.com"/>
* @since 2021/1/6 11:50 AM
*/
class BaseApplication : Application() {
override fun onCreate() {
super.onCreate()
ThingHomeSdk.init(this)
ThingHomeSdk.setDebugMode(true)
ThingOptimusSdk.init(this)
ZXingLibrary.initDisplayOpinion(this)
CameraUtils.init(this)
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.main
import android.content.Intent
import android.os.Bundle
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.tuya.appsdk.sample.R
import com.tuya.appsdk.sample.device.config.main.DeviceConfigFuncWidget
import com.tuya.appsdk.sample.device.mgt.main.DeviceMgtFuncWidget
import com.tuya.appsdk.sample.home.main.HomeFuncWidget
import com.tuya.appsdk.sample.resource.HomeModel
import com.tuya.appsdk.sample.user.info.UserInfoActivity
import com.tuya.appsdk.sample.user.main.UserFuncActivity
import com.thingclips.smart.android.user.api.ILogoutCallback
import com.thingclips.smart.home.sdk.ThingHomeSdk
/**
* Sample Main List Page
*
* @author qianqi <a href="mailto:developer@tuya.com"/>
* @since 2021/1/8 5:41 PM
*/
class MainSampleListActivity : AppCompatActivity() {
lateinit var homeFuncWidget: HomeFuncWidget
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity_sample_list)
findViewById<TextView>(R.id.tvUserInfo).setOnClickListener {
// User Info
startActivity(Intent(this, UserInfoActivity::class.java))
}
findViewById<TextView>(R.id.tvLogout).setOnClickListener {
// Logout
ThingHomeSdk.getUserInstance().logout(object : ILogoutCallback {
override fun onSuccess() {
// Clear cache
HomeModel.INSTANCE.clear(this@MainSampleListActivity)
// Navigate to User Func Navigation Page
val intent = Intent(this@MainSampleListActivity, UserFuncActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
}
override fun onError(code: String?, error: String?) {
}
})
}
val llFunc: LinearLayout = findViewById(R.id.llFunc)
// Home Management
homeFuncWidget = HomeFuncWidget()
llFunc.addView(homeFuncWidget.render(this))
// Device Configuration Management
val deviceConfigFucWidget = DeviceConfigFuncWidget()
llFunc.addView(deviceConfigFucWidget.render(this))
// Device Management
val deviceMgtFuncWidget = DeviceMgtFuncWidget()
llFunc.addView(deviceMgtFuncWidget.render(this))
}
override fun onResume() {
super.onResume()
homeFuncWidget.refresh()
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.user.info
import android.annotation.SuppressLint
import android.content.DialogInterface
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.ListPopupWindow
import androidx.appcompat.widget.Toolbar
import com.tuya.appsdk.sample.R
import com.tuya.appsdk.sample.resource.HomeModel
import com.tuya.appsdk.sample.user.main.UserFuncActivity
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.sdk.ThingSdk
import com.thingclips.smart.sdk.api.IResultCallback
import com.thingclips.smart.sdk.enums.TempUnitEnum
import java.time.ZoneId
/**
* User Info Example
*
* @author qianqi <a href="mailto:developer@tuya.com"/>
* @since 2021/1/5 5:13 PM
*/
class UserInfoActivity : AppCompatActivity() {
lateinit var lat: String
lateinit var lon: String
lateinit var items: List<String>
@SuppressLint("WrongViewCast")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.user_activity_info)
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
val user = ThingHomeSdk.getUserInstance().user
findViewById<TextView>(R.id.tvName).text = user?.nickName
findViewById<TextView>(R.id.tvPhone).text = user?.mobile
findViewById<TextView>(R.id.tvEmail).text = user?.email
findViewById<TextView>(R.id.tvCountryCode).text = user?.phoneCode
val tempUnit = findViewById<Button>(R.id.Temperature)
tempUnit.text = if (user?.tempUnit == 1) "°C" else "°F"
tempUnit.setOnClickListener {
val listPopupWindow = ListPopupWindow(
this,
null,
com.tuya.appsdk.sample.device.mgt.R.attr.listPopupWindowStyle
)
listPopupWindow.anchorView = tempUnit
val items = listOf("°C", "°F")
val adapter = ArrayAdapter(this, R.layout.device_mgt_item_dp_enum_popup_item, items)
listPopupWindow.setAdapter(adapter)
listPopupWindow.setOnItemClickListener { parent, view, position, id ->
ThingHomeSdk.getUserInstance().setTempUnit(
if (items[position] == "°C") TempUnitEnum.Celsius else TempUnitEnum.Fahrenheit, object : IResultCallback {
override fun onSuccess() {
tempUnit.text = items[position]
}
override fun onError(code: String?, error: String?) {
Toast.makeText(
this@UserInfoActivity,
" error->$error",
Toast.LENGTH_LONG
).show()
}
})
listPopupWindow.dismiss()
}
listPopupWindow.show()
}
findViewById<Button>(R.id.Updata).setOnClickListener {
val country = arrayOf(
this.getString(R.string.user_country_China),
this.getString(R.string.user_country_America),
this.getString(R.string.user_country_English),
this.getString(R.string.user_country_Australia),
this.getString(R.string.user_country_Japan),
this.getString(R.string.user_country_Egypt)
)
val builder = AlertDialog.Builder(this)
builder.setItems(
country,
DialogInterface.OnClickListener { dialog, which ->
when (which) {
1 -> {
lat = "116.20"
lon = "39.55"
}
2 -> {
lat = "-77.02"
lon = "39.91"
}
3 -> {
lat = "-0.05"
lon = "51.36"
}
4 -> {
lat = "139.46"
lon = "35.42"
}
5 -> {
lat = "31.14"
lon = "30.01"
}
}
ThingSdk.setLatAndLong(lat, lon)
Toast.makeText(
this@UserInfoActivity,
"success",
Toast.LENGTH_LONG
).show()
})
builder.create().show()
}
findViewById<Button>(R.id.deactive).setOnClickListener {
ThingHomeSdk.getUserInstance().cancelAccount(
object : IResultCallback {
override fun onSuccess() {
// Clear cache
HomeModel.INSTANCE.clear(this@UserInfoActivity)
// Navigate to User Func Navigation Page
val intent = Intent(this@UserInfoActivity, UserFuncActivity::class.java)
intent.flags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
}
override fun onError(code: String?, error: String?) {
Toast.makeText(
this@UserInfoActivity,
" error->$error",
Toast.LENGTH_LONG
).show()
}
})
}
val btTimeZone = findViewById<Button>(R.id.btTimeZone)
btTimeZone.text = user?.timezoneId
// Data can be issued by the cloud.
val listPopupWindow = ListPopupWindow(this, null, R.attr.listPopupWindowStyle)
listPopupWindow.anchorView = btTimeZone
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val availableZoneIds = ZoneId.getAvailableZoneIds()
items = availableZoneIds.toList()
} else {
items = arrayOf(
this.getString(R.string.user_time_America),
this.getString(R.string.user_time_Asia), this.getString(R.string.user_time_Etc)
).toList()
}
val arrayAdapter: ArrayAdapter<*> =
ArrayAdapter<Any?>(this, R.layout.user_activity_item_time_item, items)
listPopupWindow.setAdapter(arrayAdapter)
listPopupWindow.setOnItemClickListener { parent, view, position, id ->
val timezoneId = items[position]
ThingHomeSdk.getUserInstance().updateTimeZone(
timezoneId,
object : IResultCallback {
override fun onSuccess() {
Toast.makeText(
this@UserInfoActivity,
"success",
Toast.LENGTH_SHORT
).show()
btTimeZone.text = items[position]
}
override fun onError(code: String, error: String) {
Toast.makeText(
this@UserInfoActivity,
"error$error$timezoneId",
Toast.LENGTH_LONG
).show()
}
})
listPopupWindow.dismiss()
}
btTimeZone.setOnClickListener { listPopupWindow.show() }
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.user.login
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.tuya.appsdk.sample.R
import com.tuya.appsdk.sample.main.MainSampleListActivity
import com.tuya.appsdk.sample.user.resetPassword.UserResetPasswordActivity
import com.thingclips.smart.android.common.utils.ValidatorUtil
import com.thingclips.smart.android.user.api.ILoginCallback
import com.thingclips.smart.android.user.bean.User
import com.thingclips.smart.home.sdk.ThingHomeSdk
/**
* User Login Example
*
* @author qianqi <a href="mailto:developer@tuya.com">Contact me.</a>
* @since 2021/1/5 5:13 PM
*/
class UserLoginActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.user_activity_login)
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
findViewById<Button>(R.id.btnLogin).setOnClickListener(this)
findViewById<Button>(R.id.btnForget).setOnClickListener(this)
}
override fun onClick(v: View?) {
val strAccount = findViewById<EditText>(R.id.etAccount).text.toString()
val strCountryCode = findViewById<EditText>(R.id.etCountryCode).text.toString()
val strPassword = findViewById<EditText>(R.id.etPassword).text.toString()
v?.id?.let {
if (it == R.id.btnLogin) {
// Login with phone
val callback = object : ILoginCallback {
override fun onSuccess(user: User?) {
Toast.makeText(
this@UserLoginActivity,
"Login success",
Toast.LENGTH_LONG
).show()
startActivity(
Intent(
this@UserLoginActivity,
MainSampleListActivity::class.java
)
)
}
override fun onError(code: String?, error: String?) {
Toast.makeText(
this@UserLoginActivity,
"login error->$error",
Toast.LENGTH_LONG
).show()
}
}
if (ValidatorUtil.isEmail(strAccount)) {
ThingHomeSdk.getUserInstance()
.loginWithEmail(strCountryCode, strAccount, strPassword, callback)
} else {
ThingHomeSdk.getUserInstance()
.loginWithPhonePassword(strCountryCode, strAccount, strPassword, callback)
}
} else if (it == R.id.btnForget) {
startActivity(Intent(this, UserResetPasswordActivity::class.java))
}
}
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.user.main
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.tuya.appsdk.sample.R
import com.tuya.appsdk.sample.main.MainSampleListActivity
import com.tuya.appsdk.sample.user.login.UserLoginActivity
import com.tuya.appsdk.sample.user.register.UserRegisterActivity
import com.thingclips.smart.home.sdk.ThingHomeSdk
/**
* User Func Navigation Page
*
* @author qianqi <a href="mailto:developer@tuya.com"/>
* @since 2021/1/5 4:31 PM
*/
class UserFuncActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// If login, then navigate to MainSampleList
if (ThingHomeSdk.getUserInstance().isLogin) {
startActivity(Intent(this, MainSampleListActivity::class.java))
finish()
}
setContentView(R.layout.user_activity_func)
findViewById<Button>(R.id.btnRegister).setOnClickListener(this)
findViewById<Button>(R.id.btnLogin).setOnClickListener(this)
try {
val pInfo: PackageInfo = packageManager.getPackageInfo(packageName, 0)
findViewById<TextView>(R.id.tvAppVersion).text =
String.format(getString(R.string.app_version_tips), pInfo.versionName)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
}
override fun onClick(v: View?) {
v?.id?.let {
if (it == R.id.btnRegister) {
// Register
startActivity(Intent(this, UserRegisterActivity::class.java))
} else if (it == R.id.btnLogin) {
// Login
startActivity(Intent(this, UserLoginActivity::class.java))
}
}
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.user.register
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.tuya.appsdk.sample.R
import com.thingclips.smart.android.user.api.IRegisterCallback
import com.thingclips.smart.android.user.api.IValidateCallback
import com.thingclips.smart.android.user.bean.User
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.sdk.api.IResultCallback
import java.util.regex.Matcher
import java.util.regex.Pattern
/**
* User Register Example
*
* @author qianqi <a href="mailto:developer@tuya.com">Contact me.</a>
* @since 2021/1/5 5:13 PM
*/
class UserRegisterActivity : AppCompatActivity(), View.OnClickListener {
private val check =
"^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"
private val regex: Pattern = Pattern.compile(check)
private val mRegisterType = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.user_activity_register)
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
findViewById<Button>(R.id.btnRegister).setOnClickListener(this)
findViewById<Button>(R.id.btnCode).setOnClickListener(this)
}
override fun onClick(v: View?) {
val strAccount = findViewById<EditText>(R.id.etAccount).text.toString()
val strCountryCode = findViewById<EditText>(R.id.etCountryCode).text.toString()
val strPassword = findViewById<EditText>(R.id.etPassword).text.toString()
val strCode = findViewById<EditText>(R.id.etCode).text.toString()
val matcher: Matcher = regex.matcher(strAccount)
val isEmail: Boolean = matcher.matches()
v?.id?.let {
if (it == R.id.btnRegister) {
val callback = object : IRegisterCallback {
override fun onSuccess(user: User?) {
Toast.makeText(
this@UserRegisterActivity,
"Register success",
Toast.LENGTH_LONG
).show()
}
override fun onError(code: String?, error: String?) {
Toast.makeText(
this@UserRegisterActivity,
"Register error->$error",
Toast.LENGTH_LONG
).show()
}
}
if (isEmail) {
// Register by email
ThingHomeSdk.getUserInstance().registerAccountWithEmail(
strCountryCode,
strAccount,
strPassword,
strCode,
callback
)
} else {
// Register by phone
ThingHomeSdk.getUserInstance().registerAccountWithPhone(
strCountryCode,
strAccount,
strPassword,
strCode,
callback
)
}
} else if (it == R.id.btnCode) {
// Get verification code code
ThingHomeSdk.getUserInstance().sendVerifyCodeWithUserName(
strAccount,
"",
strCountryCode,
mRegisterType,
object : IResultCallback {
override fun onSuccess() {
Toast.makeText(
this@UserRegisterActivity,
"Got validateCode",
Toast.LENGTH_LONG
).show()
}
override fun onError(code: String?, error: String?) {
Toast.makeText(
this@UserRegisterActivity,
"getValidateCode error->$error",
Toast.LENGTH_LONG
).show()
}
})
}
}
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.user.resetPassword
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.tuya.appsdk.sample.R
import com.thingclips.smart.android.user.api.IResetPasswordCallback
import com.thingclips.smart.android.user.api.IValidateCallback
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.sdk.api.IResultCallback
import java.util.regex.Matcher
import java.util.regex.Pattern
/**
* User Register Example
*
* @author qianqi <a href="mailto:developer@tuya.com">Contact me.</a>
* @since 2021/1/5 5:13 PM
*/
class UserResetPasswordActivity : AppCompatActivity(), View.OnClickListener {
private val check =
"^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"
private val regex: Pattern = Pattern.compile(check)
private val mResetPasswordType = 3
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.user_activity_reset_password)
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
findViewById<Button>(R.id.btnReset).setOnClickListener(this)
findViewById<Button>(R.id.btnCode).setOnClickListener(this)
}
override fun onClick(v: View?) {
val strAccount = findViewById<EditText>(R.id.etAccount).text.toString()
val strCountryCode = findViewById<EditText>(R.id.etCountryCode).text.toString()
val strPassword = findViewById<EditText>(R.id.etPassword).text.toString()
val strCode = findViewById<EditText>(R.id.etCode).text.toString()
val matcher: Matcher = regex.matcher(strAccount)
val isEmail: Boolean = matcher.matches()
v?.id?.let {
if (it == R.id.btnReset) {
val callback = object : IResetPasswordCallback {
override fun onSuccess() {
Toast.makeText(
this@UserResetPasswordActivity,
"Register success",
Toast.LENGTH_LONG
).show()
}
override fun onError(code: String?, error: String?) {
Toast.makeText(
this@UserResetPasswordActivity,
"Register error->$error",
Toast.LENGTH_LONG
).show()
}
}
if (!isEmail) {
// Reset phone password
ThingHomeSdk.getUserInstance().resetPhonePassword(
strCountryCode,
strAccount,
strCode,
strPassword,
callback
)
} else {
// Reset email password
ThingHomeSdk.getUserInstance().resetEmailPassword(
strCountryCode,
strAccount,
strCode,
strPassword,
callback
)
}
} else if (it == R.id.btnCode) {
// Get verification code code
ThingHomeSdk.getUserInstance().sendVerifyCodeWithUserName(
strAccount,
"",
strCountryCode,
mResetPasswordType,
object : IResultCallback {
override fun onSuccess() {
Toast.makeText(
this@UserResetPasswordActivity,
"Got validateCode",
Toast.LENGTH_LONG
).show()
}
override fun onError(code: String?, error: String?) {
Toast.makeText(
this@UserResetPasswordActivity,
"getValidateCode error->$error",
Toast.LENGTH_LONG
).show()
}
})
}
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFEEEEEE">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:paddingBottom="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:text="@string/main_logo"
android:textSize="30dp" />
</FrameLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp">
<LinearLayout
android:id="@+id/llFunc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="@string/user_management"
android:textSize="18dp" />
<TextView
android:id="@+id/tvUserInfo"
style="@style/item_func"
android:text="@string/user_info_title" />
<TextView
android:id="@+id/tvLogout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center"
android:text="@string/user_logout"
android:textColor="@color/red"
android:textSize="18dp" />
</LinearLayout>
</ScrollView>
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:layout_marginTop="50dp"
android:layout_marginLeft="20dp"
android:text="@string/user_guide_title" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:layout_gravity="bottom"
android:layout_marginBottom="40dp"
android:paddingBottom="20dp">
<Button
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/user_login" />
<Button
android:id="@+id/btnRegister"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/user_register" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="10dp"
android:id="@+id/tvAppVersion" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/user_info_title" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_name"
android:textSize="18dp" />
<Space
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FF888888" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_phone_number"
android:textSize="18dp" />
<Space
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<TextView
android:id="@+id/tvPhone"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FF888888" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_email_address"
android:textSize="18dp" />
<Space
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<TextView
android:id="@+id/tvEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FF888888" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_country_code"
android:textSize="18dp" />
<Space
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<TextView
android:id="@+id/tvCountryCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FF888888" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_time_zone"
android:textSize="18dp" />
<Space
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<Button
android:id="@+id/btTimeZone"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FF888888" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_unit_temperature"
android:textSize="18dp" />
<Space
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<Button
android:id="@+id/Temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FF888888" />
<Button
android:id="@+id/Updata"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="50dp"
android:text="@string/user_update_coordinate"
/>
<Button
android:id="@+id/deactive"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:text="@string/user_deactive_account" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="?attr/textAppearanceSubtitle1">
</TextView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/user_login" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginTop="20dp"
android:hint="@string/user_country_code"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etCountryCode"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_account_tips"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etAccount"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_password"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnForget"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="50dp"
android:text="@string/user_forget_password_tips" />
<Button
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="10dp"
android:text="@string/user_login" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/user_register" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginTop="20dp"
android:hint="@string/user_country_code"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etCountryCode"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_account_tips"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etAccount"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_password"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_verification_code"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etCode"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnCode"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/user_send_code" />
<Button
android:id="@+id/btnRegister"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/user_register" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/user_reset_password" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginTop="20dp"
android:hint="@string/user_country_code"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etCountryCode"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_account_tips"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etAccount"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_password"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/user_verification_code"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etCode"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnCode"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/user_send_code" />
<Button
android:id="@+id/btnReset"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/user_reset_password" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Tuya SDK Kotlin</string>
<string name="user_guide_title">涂鸦SDK例子</string>
<string name="user_login">登录</string>
<string name="user_country_code">国家码</string>
<string name="user_account_tips">邮箱或手机号</string>
<string name="user_password">密码</string>
<string name="user_forget_password_tips">忘记密码?</string>
<string name="user_register">注册</string>
<string name="user_verification_code">验证码</string>
<string name="user_send_code">发送验证码</string>
<string name="user_reset_password">重置密码</string>
<string name="user_new_password">新密码</string>
<string name="user_info_title">用户信息</string>
<string name="user_name">用户名</string>
<string name="user_phone_number">手机</string>
<string name="user_email_address">邮箱</string>
<string name="user_time_zone">时区</string>
<string name="user_management">用户管理</string>
<string name="user_logout">登出</string>
<string name="app_version_tips">版本号: %s</string>
<string name="main_logo">涂鸦智能</string>
<string name="user_update_coordinate">更新坐标</string>
<string name="user_unit_temperature">温度单位</string>
<string name="user_deactive_account">停用账号</string>
<string name="user_country_China">中国</string>
<string name="user_country_America">美国</string>
<string name="user_country_English">英国</string>
<string name="user_country_Australia">澳大利亚</string>
<string name="user_country_Japan">日本</string>
<string name="user_country_Egypt">埃及</string>
<string name="user_time_Asia">亚洲/亚丁</string>
<string name="user_time_America">美国/库亚巴</string>
<string name="user_time_Etc">Etc/Gmt+9</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><resources>
<string name="app_name">Tuya SDK Kotlin</string>
<string name="user_guide_title">Tuya SDK Sample</string>
<string name="user_login">Login</string>
<string name="user_country_code">Country Code</string>
<string name="user_account_tips">Email Address or Phone Number</string>
<string name="user_password">Password</string>
<string name="user_forget_password_tips">Forget Password?</string>
<string name="user_register">Register</string>
<string name="user_verification_code">Verification Code</string>
<string name="user_send_code">Send Verification Code</string>
<string name="user_reset_password">Reset Password</string>
<string name="user_new_password">Reset Password</string>
<string name="user_info_title">User Information</string>
<string name="user_name">User Name</string>
<string name="user_phone_number">Phone Number</string>
<string name="user_email_address">Email Address</string>
<string name="user_management">USER MANAGEMENT</string>
<string name="user_logout">Logout</string>
<string name="user_time_zone">Time Zone</string>
<string name="user_unit_temperature">Unit of Temperature</string>
<string name="app_version_tips">SDK Ver: %s</string>
<string name="main_logo">Tuya Smart</string>
<string name="user_update_coordinate">Updata Geographic Coordinate</string>
<string name="user_deactive_account">Deactive Account</string>
<string name="user_country_China">China</string>
<string name="user_country_America">America</string>
<string name="user_country_English">English</string>
<string name="user_country_Australia">Australia</string>
<string name="user_country_Japan">Japan</string>
<string name="user_country_Egypt">Egypt</string>
<string name="user_time_Asia">Asia/Aden</string>
<string name="user_time_America">America/Cuiaba</string>
<string name="user_time_Etc">Etc/Gmt+9"</string>
</resources>
package com.tuya.appsdk.sample
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
\ No newline at end of file
/build
\ No newline at end of file
plugins {
id 'com.android.library'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0-alpha04'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
api 'com.thingclips.smart:thingsmart:5.8.1'
}
\ No newline at end of file
# 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
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tuya.appsdk.sample.resource">
</manifest>
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.resource
import android.content.Context
/**
* Home Model Cache
*
* @author qianqi <a href="mailto:developer@tuya.com"/>
* @since 2021/1/20 3:01 PM
*/
enum class HomeModel {
INSTANCE;
companion object {
const val CURRENT_HOME_ID = "currentHomeId"
}
/**
* Set current home's homeId
*/
fun setCurrentHome(context: Context, homeId: Long) {
val sp = context.getSharedPreferences("HomeModel", Context.MODE_PRIVATE)
val editor = sp.edit()
editor.putLong(CURRENT_HOME_ID, homeId)
editor.apply()
}
/**
* Get current home's homeId
*/
fun getCurrentHome(context: Context): Long {
val sp = context.getSharedPreferences("HomeModel", Context.MODE_PRIVATE)
return sp.getLong(CURRENT_HOME_ID, 0)
}
/**
* check if current home set
*/
fun checkHomeId(context: Context): Boolean {
return HomeModel.INSTANCE.getCurrentHome(context) != 0L
}
fun clear(context: Context) {
val sp = context.getSharedPreferences("HomeModel", Context.MODE_PRIVATE)
val editor = sp.edit()
editor.clear()
editor.apply()
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home_current_home_tips">请设置当前家庭</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="darkGrey">#a9a9a9</color>
<color name="white">#ffffff</color>
<color name="red">#C80F1F</color>
<color name="black">#FF000000</color>
<color name="green">#FF03DAC5</color>
<color name="gray">#888888</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home_current_home_tips">Please set current home</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="item_func">
<item name="android:layout_height">48dp</item>
<item name="background">@color/white</item>
<item name="android:gravity">center_vertical</item>
<item name="android:paddingLeft">20dp</item>
<item name="android:textSize">18dp</item>
<item name="android:drawableRight">@drawable/ic_next</item>
<item name="android:paddingRight">10dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:textColor">@color/black</item>
</style>
<!--user information-->
<style name="user_information">
<item name="android:layout_height">48dp</item>
<item name="backgroundColor">#FFFFFFFF</item>
<item name="android:gravity">center_vertical</item>
<item name="android:textSize">18dp</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:textColor">@color/black</item>
</style>
<!--line-->
<style name="line">
<item name="android:layout_height">1dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:background">@color/black</item>
<item name="android:layout_marginLeft">20dp</item>
<item name="android:layout_marginRight">10dp</item>
</style>
</resources>
\ No newline at end of file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.6.20"
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
configurations.all {
exclude group: "com.thingclips.smart" ,module: 'thingsmart-modularCampAnno'
}
repositories {
maven { url 'https://maven-other.tuya.com/repository/maven-releases/' }
maven { url "https://maven-other.tuya.com/repository/maven-commercial-releases/" }
google()
jcenter()
maven { url 'https://jitpack.io' }
maven {url'https : //dl.bintray.com/jenly/maven ' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
\ No newline at end of file
/build
\ No newline at end of file
plugins {
id 'com.android.library'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0-alpha04'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.alibaba:fastjson:1.1.67.android'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9'
implementation project(':base_res')
implementation 'cn.yipianfengye.android:zxing-library:2.2'
}
\ No newline at end of file
# 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
package com.example.networks
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.networks.test", appContext.packageName)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tuya.appsdk.sample.device.config">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<application>
<activity
android:name=".ap.DeviceConfigAPActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".ez.DeviceConfigEZActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".ble.DeviceConfigBleActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".dual.DeviceConfigDualActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".zigbee.gateway.DeviceConfigZbGatewayActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".zigbee.sub.DeviceConfigZbSubDeviceActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".zigbee.sub.DeviceConfigChooseZbGatewayActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity android:name=".scan.DeviceConfigQrCodeDeviceActivity"
android:exported="false"
android:screenOrientation="portrait"/>
<activity android:name=".qrcode.QrCodeConfigActivity"
android:exported="false"
android:screenOrientation="portrait"/>
</application>
</manifest>
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.device.config.ap
import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.home.sdk.builder.ActivatorBuilder
import com.thingclips.smart.sdk.api.IThingActivator
import com.thingclips.smart.sdk.api.IThingActivatorGetToken
import com.thingclips.smart.sdk.api.IThingSmartActivatorListener
import com.thingclips.smart.sdk.bean.DeviceBean
import com.thingclips.smart.sdk.enums.ActivatorModelEnum
/**
* Device Configuration AP Mode Sample
*
* @author qianqi <a href="mailto:developer@tuya.com">Contact me.</a>
* @since 2021/1/5 5:13 PM
*/
class DeviceConfigAPActivity : AppCompatActivity(), View.OnClickListener {
companion object {
const val TAG = "DeviceConfigEZ"
}
lateinit var cpiLoading: CircularProgressIndicator
lateinit var btnSearch: Button
lateinit var mToken: String
private var mTuyaActivator: IThingActivator? = null
lateinit var strSsid: String
lateinit var strPassword: String
lateinit var mContentTv: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_activity)
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
toolbar.title = getString(R.string.device_config_ap_title)
mContentTv=findViewById(R.id.content_tv)
mContentTv.text=getString(R.string.device_config_ap_description)
cpiLoading = findViewById(R.id.cpiLoading)
btnSearch = findViewById(R.id.btnSearch)
btnSearch.setOnClickListener(this)
}
override fun onClick(v: View?) {
strSsid = findViewById<EditText>(R.id.etSsid).text.toString()
strPassword = findViewById<EditText>(R.id.etPassword).text.toString()
v?.id?.let {
if (it == R.id.btnSearch) {
val homeId = HomeModel.INSTANCE.getCurrentHome(this)
// Get Network Configuration Token
ThingHomeSdk.getActivatorInstance().getActivatorToken(homeId,
object : IThingActivatorGetToken {
override fun onSuccess(token: String) {
mToken = token
// Start network configuration -- AP mode
onClickSetting()
//Stop configuration
// mTuyaActivator.stop()
//Exit the page to destroy some cache data and monitoring data.
// mTuyaActivator.onDestroy()
}
override fun onFailure(s: String, s1: String) {
}
})
}
}
}
override fun onPause() {
super.onPause()
}
override fun onRestart() {
super.onRestart()
//Show loading progress, disable btnSearch clickable
cpiLoading.visibility = View.VISIBLE
btnSearch.isClickable = false
cpiLoading.isIndeterminate = true
val builder = ActivatorBuilder()
.setSsid(strSsid)
.setContext(this)
.setPassword(strPassword)
.setActivatorModel(ActivatorModelEnum.THING_AP)
.setTimeOut(100)
.setToken(mToken)
.setListener(object : IThingSmartActivatorListener {
@Override
override fun onStep(step: String?, data: Any?) {
Log.i(TAG, "$step --> $data")
}
override fun onActiveSuccess(devResp: DeviceBean?) {
cpiLoading.visibility = View.GONE
Log.i(TAG, "Activate success")
Toast.makeText(
this@DeviceConfigAPActivity,
"Activate success",
Toast.LENGTH_LONG
).show()
finish()
}
override fun onError(
errorCode: String?,
errorMsg: String?
) {
cpiLoading.visibility = View.GONE
btnSearch.isClickable = true
Toast.makeText(
this@DeviceConfigAPActivity,
"Activate error-->$errorMsg",
Toast.LENGTH_LONG
).show()
}
}
)
mTuyaActivator =
ThingHomeSdk.getActivatorInstance().newActivator(builder)
//Start configuration
mTuyaActivator?.start()
}
/**
*
* wifi setting
*/
private fun onClickSetting() {
var wifiSettingsIntent = Intent("android.settings.WIFI_SETTINGS")
if (null == wifiSettingsIntent.resolveActivity(packageManager)) {
wifiSettingsIntent = Intent(Settings.ACTION_WIFI_SETTINGS)
}
if (null == wifiSettingsIntent.resolveActivity(packageManager)){
return
}
startActivity(wifiSettingsIntent)
}
override fun onDestroy() {
super.onDestroy()
mTuyaActivator?.onDestroy()
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.ble
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.android.ble.api.BleConfigType
import com.thingclips.smart.android.ble.api.IThingBleConfigListener
import com.thingclips.smart.android.ble.api.ScanType
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.sdk.bean.DeviceBean
/**
* Device Configuration Ble Low Energy Sample
*
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/24/21 10:36 AM
*/
class DeviceConfigBleActivity : AppCompatActivity() {
companion object {
private const val TAG = "DeviceConfigBleActivity"
const val REQUEST_CODE = 1001
}
lateinit var cpiLoading: CircularProgressIndicator
lateinit var searchButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_info_hint_activity)
initToolbar()
initView()
checkPermission()
}
// You need to check permissions before using Bluetooth devices
private fun checkPermission() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
REQUEST_CODE
)
}
}
private fun initView() {
findViewById<TextView>(R.id.tv_hint_info).text = getString(R.string.device_config_ble_hint)
cpiLoading = findViewById(R.id.cpiLoading)
searchButton = findViewById(R.id.bt_search)
searchButton.setOnClickListener {
// Check Bluetooth is Opened
if (!ThingHomeSdk.getBleOperator().isBluetoothOpened) {
Toast.makeText(this, "Please turn on bluetooth", Toast.LENGTH_LONG).show()
return@setOnClickListener
}
scanSingleBleDevice()
}
}
private fun scanSingleBleDevice() {
val currentHomeId = HomeModel.INSTANCE.getCurrentHome(this)
setPbViewVisible(true)
// Scan Single Ble Device
ThingHomeSdk.getBleOperator().startLeScan(60 * 1000, ScanType.SINGLE) { bean ->
Log.i(TAG, "scanSingleBleDevice: deviceUUID=${bean.uuid}")
// Start configuration -- Single Ble Device
if (bean?.configType == BleConfigType.CONFIG_TYPE_SINGLE.type) {
ThingHomeSdk.getBleManager().startBleConfig(currentHomeId, bean.uuid, null,
object : IThingBleConfigListener {
override fun onSuccess(bean: DeviceBean?) {
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigBleActivity,
"Config Success",
Toast.LENGTH_LONG
).show()
finish()
}
override fun onFail(code: String?, msg: String?, handle: Any?) {
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigBleActivity,
"Config Failed",
Toast.LENGTH_LONG
).show()
}
})
}
}
}
private fun initToolbar() {
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
toolbar.setTitle(R.string.device_config_ble_title)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
REQUEST_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: agree")
} else {
finish()
Log.e(TAG, "onRequestPermissionsResult: denied")
}
}
}
}
private fun setPbViewVisible(isShow: Boolean) {
cpiLoading.visibility = if (isShow) View.VISIBLE else View.GONE
searchButton.isEnabled = !isShow
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.dual
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.google.android.material.textfield.TextInputEditText
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.device.config.ble.DeviceConfigBleActivity
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.android.ble.api.BleConfigType
import com.thingclips.smart.android.ble.api.IThingBleConfigListener
import com.thingclips.smart.android.ble.api.ScanType
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.sdk.api.IThingActivatorGetToken
import com.thingclips.smart.sdk.bean.DeviceBean
/**
* Device Configuration Dual Device Sample
*
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/24/21 11:08 AM
*/
class DeviceConfigDualActivity : AppCompatActivity() {
companion object {
private const val TAG = "DeviceConfigDualMode"
const val REQUEST_CODE = 1002
}
private val homeId: Long by lazy {
HomeModel.INSTANCE.getCurrentHome(this)
}
lateinit var etSsid: TextInputEditText
lateinit var etPassword: TextInputEditText
lateinit var btSearch: Button
lateinit var cpiLoading: CircularProgressIndicator
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_activity)
initToolbar()
initView()
checkPermission()
}
private fun initView() {
etSsid = findViewById(R.id.etSsid)
etPassword = findViewById(R.id.etPassword)
btSearch = findViewById(R.id.btnSearch)
cpiLoading = findViewById(R.id.cpiLoading)
btSearch.setOnClickListener {
val strSsid = etSsid.text.toString()
val strPassword = etPassword.text.toString()
if (strSsid.isEmpty() || strPassword.isEmpty()) {
return@setOnClickListener
}
if (!ThingHomeSdk.getBleOperator().isBluetoothOpened) {
Toast.makeText(this, "Please turn on bluetooth", Toast.LENGTH_LONG).show()
return@setOnClickListener
}
scanDualBleDevice()
}
}
private fun initToolbar() {
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
toolbar.setTitle(R.string.device_config_dual_title)
}
// You need to check permissions before using Bluetooth devices
private fun checkPermission() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
DeviceConfigBleActivity.REQUEST_CODE
)
}
}
private fun setPbViewVisible(isShow: Boolean) {
cpiLoading.visibility = if (isShow) View.VISIBLE else View.GONE
btSearch.isEnabled = !isShow
}
// Scan Ble Device
private fun scanDualBleDevice() {
setPbViewVisible(true)
ThingHomeSdk.getBleOperator().startLeScan(60 * 1000, ScanType.SINGLE) { bean ->
Log.i(TAG, "scanDualBleDevice: beanType=${bean.configType},uuid=${bean.uuid}")
// Start configuration -- Dual Device
if (bean.configType == BleConfigType.CONFIG_TYPE_WIFI.type) {
// Get Network Configuration Token
ThingHomeSdk.getActivatorInstance().getActivatorToken(homeId,
object : IThingActivatorGetToken {
override fun onSuccess(token: String) {
// Start configuration -- Dual Ble Device
val param = mutableMapOf<String, String>()
param["ssid"] = etSsid.text.toString()
param["password"] = etPassword.text.toString()
param["token"] = token
ThingHomeSdk.getBleManager()
.startBleConfig(homeId, bean.uuid, param as Map<String, String>,
object : IThingBleConfigListener {
override fun onSuccess(bean: DeviceBean?) {
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigDualActivity,
"Config Success",
Toast.LENGTH_LONG
).show()
finish()
}
override fun onFail(
code: String?,
msg: String?,
handle: Any?
) {
setPbViewVisible(false)
finish()
Toast.makeText(
this@DeviceConfigDualActivity,
"Config Failed",
Toast.LENGTH_LONG
).show()
}
})
}
override fun onFailure(errorCode: String?, errorMsg: String?) {
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigDualActivity,
"Error->$errorMsg",
Toast.LENGTH_LONG
).show()
}
})
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
REQUEST_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: agree")
} else {
finish()
Log.e(TAG, "onRequestPermissionsResult: denied")
}
}
}
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.device.config.ez
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.home.sdk.builder.ActivatorBuilder
import com.thingclips.smart.sdk.api.IThingActivatorGetToken
import com.thingclips.smart.sdk.api.IThingSmartActivatorListener
import com.thingclips.smart.sdk.bean.DeviceBean
import com.thingclips.smart.sdk.enums.ActivatorModelEnum
/**
* Device Configuration EZ Mode Sample
*
* @author qianqi <a href="mailto:developer@tuya.com">Contact me.</a>
* @since 2021/1/5 5:13 PM
*/
class DeviceConfigEZActivity : AppCompatActivity(), View.OnClickListener {
companion object {
const val TAG = "DeviceConfigEZ"
}
lateinit var cpiLoading: CircularProgressIndicator
lateinit var btnSearch: Button
lateinit var mContentTv: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_activity)
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
toolbar.title = getString(R.string.device_config_ez_title)
mContentTv=findViewById(R.id.content_tv)
mContentTv.text=getString(R.string.device_config_ez_description)
cpiLoading = findViewById(R.id.cpiLoading)
btnSearch = findViewById(R.id.btnSearch)
btnSearch.setOnClickListener(this)
}
override fun onClick(v: View?) {
val strSsid = findViewById<EditText>(R.id.etSsid).text.toString()
val strPassword = findViewById<EditText>(R.id.etPassword).text.toString()
v?.id?.let { it ->
if (it == R.id.btnSearch) {
val homeId = HomeModel.INSTANCE.getCurrentHome(this)
// Get Network Configuration Token
ThingHomeSdk.getActivatorInstance().getActivatorToken(homeId,
object : IThingActivatorGetToken {
override fun onSuccess(token: String) {
// Start network configuration -- EZ mode
val builder = ActivatorBuilder()
.setSsid(strSsid)
.setContext(v.context)
.setPassword(strPassword)
.setActivatorModel(ActivatorModelEnum.THING_EZ)
.setTimeOut(100)
.setToken(token)
.setListener(object : IThingSmartActivatorListener {
@Override
override fun onStep(step: String?, data: Any?) {
Log.i(TAG, "$step --> $data")
}
override fun onActiveSuccess(devResp: DeviceBean?) {
cpiLoading.visibility = View.GONE
Log.i(TAG, "Activate success")
Toast.makeText(
this@DeviceConfigEZActivity,
"Activate success",
Toast.LENGTH_LONG
).show()
finish()
}
override fun onError(
errorCode: String?,
errorMsg: String?
) {
cpiLoading.visibility = View.GONE
btnSearch.isClickable = true
Toast.makeText(
this@DeviceConfigEZActivity,
"Activate error-->$errorMsg",
Toast.LENGTH_LONG
).show()
}
}
)
val mTuyaActivator =
ThingHomeSdk.getActivatorInstance().newMultiActivator(builder)
//Start configuration
mTuyaActivator.start()
//Show loading progress, disable btnSearch clickable
cpiLoading.visibility = View.VISIBLE
btnSearch.isClickable = false
//Stop configuration
// mTuyaActivator.stop()
//Exit the page to destroy some cache data and monitoring data.
// mTuyaActivator.onDestroy()
}
override fun onFailure(s: String, s1: String) {}
})
}
}
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Tuya Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.tuya.appsdk.sample.device.config.main
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import android.widget.Toast
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.device.config.ap.DeviceConfigAPActivity
import com.tuya.appsdk.sample.device.config.ble.DeviceConfigBleActivity
import com.tuya.appsdk.sample.device.config.dual.DeviceConfigDualActivity
import com.tuya.appsdk.sample.device.config.ez.DeviceConfigEZActivity
import com.tuya.appsdk.sample.device.config.scan.DeviceConfigQrCodeDeviceActivity
import com.tuya.appsdk.sample.device.config.qrcode.QrCodeConfigActivity
import com.tuya.appsdk.sample.device.config.zigbee.gateway.DeviceConfigZbGatewayActivity
import com.tuya.appsdk.sample.device.config.zigbee.sub.DeviceConfigZbSubDeviceActivity
import com.tuya.appsdk.sample.resource.HomeModel
/**
* Device configuration func Widget
*
* @author qianqi <a href="mailto:developer@tuya.com"/>
* @since 2021/1/9 5:06 PM
*/
class DeviceConfigFuncWidget {
lateinit var mContext: Context
fun render(context: Context): View {
val rootView =
LayoutInflater.from(context).inflate(R.layout.device_config_view_func, null, false)
mContext = context
initView(rootView)
return rootView
}
private fun initView(rootView: View) {
// EZ Mode
rootView.findViewById<TextView>(R.id.tvEzMode).setOnClickListener {
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
mContext,
mContext.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(Intent(it.context, DeviceConfigEZActivity::class.java))
}
// AP Mode
rootView.findViewById<TextView>(R.id.tvApMode).setOnClickListener {
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
mContext,
mContext.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(Intent(it.context, DeviceConfigAPActivity::class.java))
}
// Ble Low Energy
rootView.findViewById<TextView>(R.id.tv_ble).setOnClickListener {
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
mContext,
mContext.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(Intent(it.context, DeviceConfigBleActivity::class.java))
}
// Dual Mode
rootView.findViewById<TextView>(R.id.tv_dual_mode).setOnClickListener {
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
mContext,
mContext.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(Intent(it.context, DeviceConfigDualActivity::class.java))
}
// ZigBee Gateway
rootView.findViewById<TextView>(R.id.tv_zigBee_gateway).setOnClickListener {
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
mContext,
mContext.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(Intent(it.context, DeviceConfigZbGatewayActivity::class.java))
}
// ZigBee Sub Device
rootView.findViewById<TextView>(R.id.tv_zigBee_subDevice).setOnClickListener {
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
mContext,
mContext.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(
Intent(
it.context,
DeviceConfigZbSubDeviceActivity::class.java
)
)
}
// Scan Qr Code
rootView.findViewById<TextView>(R.id.tv_qrcode_subDevice).setOnClickListener {
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
mContext,
mContext.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(
Intent(
it.context,
DeviceConfigQrCodeDeviceActivity::class.java
)
)
}
// Qr Code
rootView.findViewById<TextView>(R.id.tv_qr_code).setOnClickListener{
if (!HomeModel.INSTANCE.checkHomeId(mContext)) {
Toast.makeText(
rootView.context,
rootView.context.getString(R.string.home_current_home_tips),
Toast.LENGTH_LONG
).show()
return@setOnClickListener
}
it.context.startActivity(
Intent(
it.context,
QrCodeConfigActivity::class.java
)
)
}
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.qrcode
import android.graphics.Bitmap
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.google.zxing.WriterException
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.device.config.util.qrcode.DensityUtil
import com.tuya.appsdk.sample.device.config.util.qrcode.QRCodeUtil
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.home.sdk.builder.ThingCameraActivatorBuilder
import com.thingclips.smart.sdk.api.IThingActivatorGetToken
import com.thingclips.smart.sdk.api.IThingCameraDevActivator
import com.thingclips.smart.sdk.api.IThingSmartCameraActivatorListener
import com.thingclips.smart.sdk.bean.DeviceBean
/**
* TODO feature
*二维码配网 QrCode Config
* @author hou qing <a href="mailto:developer@tuya.com"/>
* @since 2021/7/28 2:52 下午
*/
class QrCodeConfigActivity : AppCompatActivity(),View.OnClickListener{
private var wifiSSId = ""
private var wifiPwd = ""
private val mtoken = ""
private lateinit var mIvQr: ImageView
private lateinit var mLlInputWifi: LinearLayout
private lateinit var mEtInputWifiSSid: EditText
private lateinit var mEtInputWifiPwd: EditText
private lateinit var mBtnSave: Button
private var mTuyaActivator: IThingCameraDevActivator? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_qr_code)
val toolbar = findViewById<Toolbar>(R.id.toolbar_view)
setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener { finish() }
mLlInputWifi = findViewById(R.id.ll_input_wifi)
mEtInputWifiSSid = findViewById(R.id.et_wifi_ssid)
mEtInputWifiPwd = findViewById(R.id.et_wifi_pwd)
mBtnSave = findViewById(R.id.btn_save)
mBtnSave.setOnClickListener(this)
mIvQr = findViewById(R.id.iv_qrcode)
}
private fun hideKeyboard(v: View) {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0)
}
override fun onClick(v: View) {
if (v.id == R.id.btn_save) {
wifiSSId = mEtInputWifiSSid.text.toString()
wifiPwd = mEtInputWifiPwd.text.toString()
val homeId: Long = HomeModel.INSTANCE.getCurrentHome(this)
// Get Network Configuration Token
ThingHomeSdk.getActivatorInstance().getActivatorToken(homeId,
object : IThingActivatorGetToken {
override fun onSuccess(token: String) {
//Create and show qrCode
val builder = ThingCameraActivatorBuilder()
.setToken(token)
.setPassword(wifiPwd)
.setTimeOut(100)
.setContext(this@QrCodeConfigActivity)
.setSsid(wifiSSId)
.setListener(object : IThingSmartCameraActivatorListener {
override fun onQRCodeSuccess(qrcodeUrl: String) {
val bitmap: Bitmap
try {
val widthAndHeight: Int = DensityUtil.getScreenDispalyWidth(this@QrCodeConfigActivity) - DensityUtil.dip2px(this@QrCodeConfigActivity, 50f)
bitmap = QRCodeUtil.createQRCode(qrcodeUrl, widthAndHeight)
runOnUiThread {
mIvQr.setImageBitmap(bitmap)
mLlInputWifi.visibility = View.GONE
mIvQr.visibility = View.VISIBLE
}
} catch (e: WriterException) {
e.printStackTrace()
}
}
override fun onError(errorCode: String, errorMsg: String) {
}
override fun onActiveSuccess(devResp: DeviceBean) {
Toast.makeText(this@QrCodeConfigActivity, "config success!", Toast.LENGTH_LONG).show()
}
})
mTuyaActivator = ThingHomeSdk.getActivatorInstance().newCameraDevActivator(builder)
mTuyaActivator?.createQRCode()
mTuyaActivator?.start()
}
override fun onFailure(errorCode: String, errorMsg: String) {}
})
hideKeyboard(v)
}
}
override fun onDestroy() {
super.onDestroy()
mTuyaActivator?.stop()
mTuyaActivator?.onDestroy()
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.scan
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.material.appbar.MaterialToolbar
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.home.sdk.builder.ThingQRCodeActivatorBuilder
import com.thingclips.smart.sdk.api.IThingDataCallback
import com.thingclips.smart.sdk.api.IThingSmartActivatorListener
import com.thingclips.smart.sdk.bean.DeviceBean
import com.uuzuche.lib_zxing.activity.CaptureActivity
import com.uuzuche.lib_zxing.activity.CodeUtils
import org.json.JSONObject
import java.util.*
/**
* Qr Code
*
* @author yueguang [](mailto:developer@tuya.com)
* @since 2021/3/11 3:13 PM
*/
class DeviceConfigQrCodeDeviceActivity : AppCompatActivity(), View.OnClickListener {
private var topAppBar: MaterialToolbar? = null
private var bt_search: Button? = null
private var mUuid: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_info_hint_activity)
initView()
}
private fun initView() {
topAppBar = findViewById<View>(R.id.topAppBar) as MaterialToolbar
topAppBar!!.setNavigationOnClickListener { finish() }
topAppBar!!.title = getString(R.string.device_qr_code_service_title)
bt_search = findViewById<View>(R.id.bt_search) as Button
bt_search!!.setOnClickListener(this)
bt_search!!.setText(R.string.device_qr_code_service_title)
}
override fun onClick(v: View) {
if (v.id == R.id.bt_search) {
startQrCode()
}
}
private fun startQrCode() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CODE_SCAN
)
return
}
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
REQUEST_CODE_SCAN
)
return
}
val intent = Intent(this, CaptureActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SCAN)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_SCAN) {
if (null != data) {
val bundle = data.extras ?: return
if (bundle.getInt(CodeUtils.RESULT_TYPE) == CodeUtils.RESULT_SUCCESS) {
val result = bundle.getString(CodeUtils.RESULT_STRING)
Toast.makeText(this, "result:$result", Toast.LENGTH_LONG).show()
deviceQrCode(result)
} else if (bundle.getInt(CodeUtils.RESULT_TYPE) == CodeUtils.RESULT_FAILED) {
Toast.makeText(this, "解析二维码失败", Toast.LENGTH_LONG).show()
}
}
}
}
private fun deviceQrCode(result: String?) {
val postData = HashMap<String, Any?>()
postData["code"] = result
ThingHomeSdk.getRequestInstance().requestWithApiNameWithoutSession(
"tuya.m.qrcode.parse",
"4.0",
postData,
String::class.java,
object : IThingDataCallback<String> {
override fun onSuccess(result: String) {
initQrCode(result)
}
override fun onError(errorCode: String, errorMessage: String) {}
}
)
}
private fun initQrCode(result: String) {
val homeId = HomeModel.INSTANCE.getCurrentHome(this)
val obj = JSONObject(result)
val actionObj = obj.optJSONObject("actionData")
if (null != actionObj) {
mUuid = actionObj.optString("uuid")
val builder = ThingQRCodeActivatorBuilder()
.setUuid(mUuid)
.setHomeId(homeId)
.setContext(this)
.setTimeOut(100)
.setListener(object : IThingSmartActivatorListener {
override fun onError(errorCode: String, errorMsg: String) {}
override fun onActiveSuccess(devResp: DeviceBean) {
Toast.makeText(
this@DeviceConfigQrCodeDeviceActivity,
"ActiveSuccess",
Toast.LENGTH_LONG
).show()
}
override fun onStep(step: String, data: Any) {}
})
val iTuyaActivator = ThingHomeSdk.getActivatorInstance().newQRCodeDevActivator(builder)
iTuyaActivator.start()
}
}
companion object {
private const val REQUEST_CODE_SCAN = 1
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.util.qrcode
import android.content.Context
import android.view.WindowManager
/**
* TODO feature
*
* @author hou qing <a href="mailto:developer@tuya.com"/>
* @since 2021/7/28 6:19 下午
*/
class DensityUtil {
companion object{
fun dip2px(context: Context, dpValue: Float): Int {
val scale = context.resources.displayMetrics.density
return (dpValue * scale + 0.5f).toInt()
}
fun dip2pxF(context: Context, dpValue: Float): Float {
val scale = context.resources.displayMetrics.density
return dpValue * scale + 0.5f
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
fun px2dip(context: Context, pxValue: Float): Int {
val scale = context.resources.displayMetrics.density
return (pxValue / scale + 0.5f).toInt()
}
/**
* 将px值转换为sp值,保证文字大小不变
*
* @param pxValue
* @param context
* (DisplayMetrics类中属性scaledDensity)
* @return
*/
fun px2sp(context: Context, pxValue: Float): Int {
val fontScale = context.resources.displayMetrics.scaledDensity
return (pxValue / fontScale + 0.5f).toInt()
}
/**
* 将sp值转换为px值,保证文字大小不变
*
* @param spValue
* @param context
* (DisplayMetrics类中属性scaledDensity)
* @return
*/
fun sp2px(context: Context, spValue: Float): Int {
val fontScale = context.resources.displayMetrics.scaledDensity
return (spValue * fontScale + 0.5f).toInt()
}
fun getScreenDispalyWidth(context: Context): Int {
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val width = wm.defaultDisplay.width //手机屏幕的宽度
val height = wm.defaultDisplay.height //手机屏幕的高度
return if (width > height) height else width
}
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.util.qrcode
import android.graphics.Bitmap
import android.graphics.Color
import android.text.TextUtils
import androidx.annotation.ColorInt
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.MultiFormatWriter
import com.google.zxing.WriterException
import com.google.zxing.qrcode.QRCodeWriter
import java.util.*
import kotlin.collections.HashMap
/**
* TODO feature
*
* @author hou qing <a href="mailto:developer@tuya.com"/>
* @since 2021/7/28 2:54 下午
*/
class QRCodeUtil {
/**
* Create a QR code bitmap
* @param content content(Support Chinese)
* @param width width, unit px
* @param height height, unit px
*/
fun createQRCodeBitmap(content: String?, width: Int, height: Int): Bitmap? {
return createQRCodeBitmap(
content,
width,
height,
"UTF-8",
"H",
"2",
Color.BLACK,
Color.WHITE
)
}
/**
* Create QR code bitmap (support custom configuration and custom style)
*
* @param content content(Support Chinese)
* @param width width, unit px
* @param height height, unit px
* @param character_set Character set/character transcoding format. When passing null, zxing source code uses "ISO-8859-1" by default
* @param error_correction Fault tolerance level. When passing null, zxing source code uses "L" by default
* @param margin Blank margin (can be modified, requirement: integer and >=0), when passing null, zxing source code uses "4" by default
* @param color_black Custom color value of black color block
* @param color_white Custom color value of white color block
* @return
*/
private fun createQRCodeBitmap(
content: String?, width: Int, height: Int,
character_set: String?, error_correction: String?, margin: String?,
@ColorInt color_black: Int, @ColorInt color_white: Int): Bitmap? {
/** 1.Parameter legality judgment */
if (TextUtils.isEmpty(content)) { // The string content is blank
return null
}
if (width < 0 || height < 0) { // Both width and height need to be >=0
return null
}
try {
/** 2.Set the QR code related configuration and generate BitMatrix objects */
val hints = Hashtable<EncodeHintType, String?>()
if (!TextUtils.isEmpty(character_set)) {
hints[EncodeHintType.CHARACTER_SET] =
character_set // Character transcoding format setting
}
if (!TextUtils.isEmpty(error_correction)) {
hints[EncodeHintType.ERROR_CORRECTION] =
error_correction // Fault tolerance level setting
}
if (!TextUtils.isEmpty(margin)) {
hints[EncodeHintType.MARGIN] = margin // Margin settings
}
val bitMatrix =
QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
/** 3.Create a pixel array and assign color values to the array elements according to the BitMatrix object */
val pixels = IntArray(width * height)
for (y in 0 until height) {
for (x in 0 until width) {
if (bitMatrix[x, y]) {
pixels[y * width + x] = color_black // Black color block pixel settings
} else {
pixels[y * width + x] = color_white // White color block pixel setting
}
}
}
/** 4.Create a Bitmap object, set the color value of each pixel of the Bitmap according to the pixel array, and then return the Bitmap object */
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
return bitmap
} catch (e: WriterException) {
e.printStackTrace()
}
return null
}
companion object{
@Throws(WriterException::class)
fun createQRCode(url: String?, widthAndHeight: Int): Bitmap {
val hints: Hashtable<EncodeHintType, Any> = Hashtable()
hints[EncodeHintType.CHARACTER_SET] = "utf-8"
hints[EncodeHintType.MARGIN] = 0
val matrix = MultiFormatWriter().encode(url,
BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight, hints
)
val width = matrix.width
val height = matrix.height
val pixels = IntArray(width * height)
for (y in 0 until height) {
for (x in 0 until width) {
if (matrix[x, y]) {
pixels[y * width + x] = Color.BLACK //0xff000000
}
}
}
val bitmap = Bitmap.createBitmap(
width, height,
Bitmap.Config.ARGB_8888
)
bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
return bitmap
}
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.util.sp
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import kotlin.reflect.KProperty
/**
* SP Util
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/25/21 10:15 AM
*/
class Preference<T>(context: Context, val name: String, private val default: T) {
private val prefs: SharedPreferences by lazy {
context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE)
}
companion object {
private const val SP_NAME = "GATEWAY_LIST"
}
/**
* Clear all data
*/
fun clearPreference() {
prefs.edit().clear().apply()
}
/**
* Clear data by key
*/
fun clearPreference(key: String) {
prefs.edit().remove(key).apply()
}
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return getSharedPreferences(name, default)
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
putSharedPreferences(name, value)
}
@SuppressLint("CommitPrefEdits")
private fun putSharedPreferences(name: String, value: T) = with(prefs.edit()) {
when (value) {
is Long -> putLong(name, value)
is String -> putString(name, value)
is Int -> putInt(name, value)
is Boolean -> putBoolean(name, value)
is Float -> putFloat(name, value)
else -> throw IllegalArgumentException("This type can not be saved into Preferences")
}.apply()
}
@Suppress("UNCHECKED_CAST")
private fun getSharedPreferences(name: String, default: T): T = with(prefs) {
val res: Any = when (default) {
is Long -> getLong(name, default)
is Int -> getInt(name, default)
is Boolean -> getBoolean(name, default)
is Float -> getFloat(name, default)
is String -> getString(name, default) ?: ""
else -> throw IllegalArgumentException("This type can be saved into Preferences")
}
return res as T
}
}
package com.tuya.appsdk.sample.device.config.zigbee.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.device.config.util.sp.Preference
import com.tuya.appsdk.sample.device.config.zigbee.sub.DeviceConfigZbSubDeviceActivity
import com.thingclips.smart.sdk.bean.DeviceBean
/**
* Zigbee Gateway List
*
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/25/21 10:18 AM
*/
class ZigBeeGatewayListAdapter(context: Context) :
RecyclerView.Adapter<ZigBeeGatewayListAdapter.ViewHolder>() {
var data: ArrayList<DeviceBean> = arrayListOf()
var currentGatewayId: String by Preference(
context,
DeviceConfigZbSubDeviceActivity.CURRENT_GATEWAY_ID,
""
)
var currentGatewayName: String by Preference(
context,
DeviceConfigZbSubDeviceActivity.CURRENT_GATEWAY_NAME,
""
)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflate = LayoutInflater.from(parent.context)
.inflate(R.layout.device_zb_gateway_list, parent, false)
val viewHolder = ViewHolder(inflate)
viewHolder.itemView.setOnClickListener {
val deviceBean = data[viewHolder.adapterPosition]
currentGatewayId = deviceBean.devId
currentGatewayName = deviceBean.name
notifyDataSetChanged()
}
return viewHolder
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
data[position].let {
holder.itemName.text = it.name
// Switch ZigBee Gateway
if (currentGatewayId == it.devId) {
holder.itemIcon.setImageResource(R.drawable.ic_check)
} else {
holder.itemIcon.setImageResource(0)
}
}
}
override fun getItemCount(): Int {
return data.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemName: TextView = itemView.findViewById(R.id.tvName)
val itemIcon: ImageView = itemView.findViewById(R.id.ivIcon)
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.zigbee.gateway
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.android.hardware.bean.HgwBean
import com.thingclips.smart.home.sdk.ThingHomeSdk.getActivatorInstance
import com.thingclips.smart.home.sdk.builder.ThingGwActivatorBuilder
import com.thingclips.smart.sdk.api.IThingActivatorGetToken
import com.thingclips.smart.sdk.api.IThingSmartActivatorListener
import com.thingclips.smart.sdk.bean.DeviceBean
/**
* Device Configuration ZigBee Gateway Sample
*
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/24/21 11:12 AM
*/
class DeviceConfigZbGatewayActivity : AppCompatActivity() {
companion object {
private const val TAG = "DeviceConfigZbGateway"
}
private val homeId: Long by lazy {
HomeModel.INSTANCE.getCurrentHome(this@DeviceConfigZbGatewayActivity)
}
lateinit var cpiLoading: CircularProgressIndicator
lateinit var searchButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_info_hint_activity)
initToolbar()
initView()
}
private fun initView() {
findViewById<TextView>(R.id.tv_hint_info).text =
getString(R.string.device_config_zb_gateway_hint)
cpiLoading = findViewById(R.id.cpiLoading)
searchButton = findViewById(R.id.bt_search)
searchButton.setOnClickListener {
searchGatewayDevice()
}
}
private fun initToolbar() {
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
toolbar.setTitle(R.string.device_config_zb_gateway_title)
}
// Search ZigBee Gateway Device
private fun searchGatewayDevice() {
setPbViewVisible(true)
val newSearcher = getActivatorInstance().newThingGwActivator().newSearcher()
newSearcher.registerGwSearchListener {
getNetworkConfigToken(it)
}
}
// Get Network Configuration Token
private fun getNetworkConfigToken(hgwBean: HgwBean) {
Log.i(TAG, "getNetworkConfigToken: homeId=${homeId}")
Log.i(TAG, "getNetworkConfigToken: GwId->${hgwBean.getGwId()}")
getActivatorInstance().getActivatorToken(homeId,
object : IThingActivatorGetToken {
override fun onSuccess(token: String) {
Log.i(TAG, "getNetworkConfigToken: onSuccess->${token}")
startNetworkConfig(token, hgwBean)
}
override fun onFailure(errorCode: String?, errorMsg: String?) {
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigZbGatewayActivity,
"Error->$errorMsg",
Toast.LENGTH_LONG
).show()
}
})
}
// Start network configuration -- ZigBee Gateway
private fun startNetworkConfig(token: String, hgwBean: HgwBean) {
val activatorBuilder = getActivatorInstance().newGwActivator(
ThingGwActivatorBuilder()
.setContext(this@DeviceConfigZbGatewayActivity)
.setTimeOut(100)
.setToken(token)
.setHgwBean(hgwBean)
.setListener(object : IThingSmartActivatorListener {
override fun onError(errorCode: String?, errorMsg: String?) {
Log.i(TAG, "Activate error->$errorMsg")
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigZbGatewayActivity,
"Activate Error",
Toast.LENGTH_LONG
).show()
}
override fun onActiveSuccess(devResp: DeviceBean?) {
Log.i(TAG, "Activate success")
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigZbGatewayActivity,
"Activate success",
Toast.LENGTH_LONG
).show()
finish()
}
override fun onStep(step: String?, data: Any?) {
Log.i(TAG, "onStep: step->$step")
}
})
)
//Start configuration
activatorBuilder.start()
// Stop configuration
// mTuyaActivator.stop()
// Exit the page to destroy some cache data and monitoring data.
// mTuyaActivator.onDestroy()
}
private fun setPbViewVisible(isShow: Boolean) {
cpiLoading.visibility = if (isShow) View.VISIBLE else View.GONE
searchButton.isEnabled = !isShow
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.zigbee.sub
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.device.config.zigbee.adapter.ZigBeeGatewayListAdapter
import com.tuya.appsdk.sample.resource.HomeModel
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.home.sdk.bean.HomeBean
import com.thingclips.smart.home.sdk.callback.IThingHomeResultCallback
import com.thingclips.smart.sdk.bean.DeviceBean
/**
* Choose Gateway
*
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/25/21 9:45 AM
*/
class DeviceConfigChooseZbGatewayActivity : AppCompatActivity() {
lateinit var adapter: ZigBeeGatewayListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_zb_choose_gateway_activity)
initToolbar()
initView()
}
private fun initView() {
val rvList = findViewById<RecyclerView>(R.id.rvList)
adapter = ZigBeeGatewayListAdapter(this)
// Set List
val linearLayoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
rvList.layoutManager = linearLayoutManager
rvList.adapter = adapter
getZigBeeGatewayList()
}
// Get ZigBee Gateway List
private fun getZigBeeGatewayList() {
val currentHomeId = HomeModel.INSTANCE.getCurrentHome(this)
ThingHomeSdk.newHomeInstance(currentHomeId).getHomeDetail(object : IThingHomeResultCallback {
override fun onSuccess(bean: HomeBean?) {
val deviceList = bean?.deviceList as ArrayList<DeviceBean>
val zigBeeGatewayList = deviceList.filter {
it.isZigBeeWifi
}
adapter.data = zigBeeGatewayList as ArrayList<DeviceBean>
adapter.notifyDataSetChanged()
}
override fun onError(errorCode: String?, errorMsg: String?) {
Toast.makeText(
this@DeviceConfigChooseZbGatewayActivity,
"Error->$errorMsg",
Toast.LENGTH_LONG
).show()
}
})
}
// init Toolbar
private fun initToolbar() {
val toolbar = findViewById<Toolbar>(R.id.topAppBar)
toolbar.setNavigationOnClickListener {
finish()
}
toolbar.setTitle(R.string.device_config_choose_gateway_title)
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.config.zigbee.sub
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.tuya.appsdk.sample.device.config.R
import com.tuya.appsdk.sample.device.config.util.sp.Preference
import com.thingclips.smart.home.sdk.ThingHomeSdk
import com.thingclips.smart.home.sdk.builder.ThingGwSubDevActivatorBuilder
import com.thingclips.smart.sdk.api.IThingSmartActivatorListener
import com.thingclips.smart.sdk.bean.DeviceBean
/**
* Device Configuration ZigBee sub device Mode Sample
*
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/24/21 11:13 AM
*/
class DeviceConfigZbSubDeviceActivity : AppCompatActivity() {
companion object {
private const val TAG = "DeviceConfigZbSubDevice"
const val CURRENT_GATEWAY_NAME = "current_gateway_name"
const val CURRENT_GATEWAY_ID = "current_gateway_id"
const val REQUEST_CODE = 1003
}
lateinit var btSearch: Button
lateinit var tvCurrentGateway: TextView
lateinit var cpiLoading: CircularProgressIndicator
var currentGatewayName: String by Preference(this, CURRENT_GATEWAY_NAME, "")
var currentGatewayId: String by Preference(this, CURRENT_GATEWAY_ID, "")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.device_config_zb_sub_device_activity)
initToolbar()
initView()
}
private fun initView() {
// init gatewayName and gatewayId
currentGatewayName = ""
currentGatewayId = ""
btSearch = findViewById(R.id.btnSearch)
cpiLoading = findViewById(R.id.cpiLoading)
tvCurrentGateway = findViewById(R.id.tv_current_gateway_name)
// choose zigBee gateway
findViewById<TextView>(R.id.tv_current_zb_gateway).setOnClickListener {
startActivityForResult(
Intent(this, DeviceConfigChooseZbGatewayActivity::class.java),
REQUEST_CODE
)
}
btSearch.setOnClickListener {
subDeviceConfiguration()
}
}
// Sub-device Configuration
private fun subDeviceConfiguration() {
if (tvCurrentGateway.text.isEmpty()) {
Toast.makeText(this, "Please select gateway first", Toast.LENGTH_LONG).show()
return
}
Log.i(TAG, "subDeviceConfiguration: currentGatewayId=${currentGatewayId}")
setPbViewVisible(true)
val builder = ThingGwSubDevActivatorBuilder()
.setDevId(currentGatewayId)
.setTimeOut(100)
.setListener(object : IThingSmartActivatorListener {
override fun onError(errorCode: String?, errorMsg: String?) {
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigZbSubDeviceActivity,
"Active Error->$errorMsg",
Toast.LENGTH_LONG
).show()
}
override fun onActiveSuccess(devResp: DeviceBean?) {
setPbViewVisible(false)
Toast.makeText(
this@DeviceConfigZbSubDeviceActivity,
"Active Success",
Toast.LENGTH_LONG
).show()
finish()
}
override fun onStep(step: String?, data: Any?) {
Log.i(TAG, "onStep: step->$step")
}
})
val tuyaGWSubActivator = ThingHomeSdk.getActivatorInstance().newGwSubDevActivator(builder)
// Start network configuration
tuyaGWSubActivator.start()
// Stop network configuration
// tuyaGWSubActivator.stop();
// Destroy
// tuyaGWSubActivator.onDestroy()
}
private fun initToolbar() {
val toolbar: Toolbar = findViewById<View>(R.id.topAppBar) as Toolbar
toolbar.setNavigationOnClickListener {
finish()
}
toolbar.setTitle(R.string.device_config_zb_sub_device_title)
}
private fun setPbViewVisible(isShow: Boolean) {
cpiLoading.visibility = if (isShow) View.VISIBLE else View.GONE
btSearch.isEnabled = !isShow
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE) {
tvCurrentGateway.text = currentGatewayName
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/device_config_ez_title" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginTop="20dp"
android:hint="@string/device_config_wifi_ssid"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etSsid"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/device_config_wifi_password"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/content_tv"
android:layout_width="match_parent"
android:textSize="18sp"
android:layout_marginTop="25dp"
android:layout_height="wrap_content"
android:text="@string/device_config_sp_mode_hint" />
<Button
android:id="@+id/btnSearch"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="20dp"
android:text="@string/device_config_search" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/cpiLoading"
android:layout_gravity="center_horizontal"
android:layout_marginTop="80dp"
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_height="wrap_content"
android:indeterminate="true" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<TextView
android:id="@+id/tv_hint_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textSize="20sp"
android:padding="10dp" />
<Button
android:id="@+id/bt_search"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="50dp"
android:text="@string/device_config_search" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/cpiLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="80dp"
android:indeterminate="true"
android:visibility="gone" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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="com.tuya.appsdk.sample.device.config.qrcode.QrCodeConfigActivity"
android:background="@color/white">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_view"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/device_config_qr_code_title" />
</com.google.android.material.appbar.AppBarLayout>
<ImageView
android:id="@+id/iv_qrcode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="30dp"
android:visibility="gone" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/ll_input_wifi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginTop="20dp"
android:hint="@string/hint_wifi_name"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_wifi_ssid"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/hint_wifi_pwd"
app:endIconMode="clear_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_wifi_pwd"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="10dp"
android:text="@string/btn_save" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/device_config_module_title"
android:paddingLeft="20dp"
android:layout_marginTop="60dp"
android:textSize="18dp" />
<TextView
style="@style/item_func"
android:id="@+id/tvEzMode"
android:text="@string/device_config_ez_title" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="20dp"
android:background="#FF888888" />
<TextView
style="@style/item_func"
android:id="@+id/tvApMode"
android:text="@string/device_config_ap_title" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="20dp"
android:background="#FF888888" />
<TextView
style="@style/item_func"
android:id="@+id/tv_ble"
android:text="@string/device_config_ble_title" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="20dp"
android:background="#FF888888" />
<TextView
style="@style/item_func"
android:id="@+id/tv_dual_mode"
android:text="@string/device_config_dual_title" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="20dp"
android:background="#FF888888" />
<TextView
style="@style/item_func"
android:id="@+id/tv_zigBee_gateway"
android:text="@string/device_config_zb_gateway_title" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="20dp"
android:background="#FF888888" />
<TextView
style="@style/item_func"
android:id="@+id/tv_zigBee_subDevice"
android:text="@string/device_config_zb_sub_device_title" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="20dp"
android:background="#FF888888" />
<TextView
style="@style/item_func"
android:id="@+id/tv_qrcode_subDevice"
android:text="@string/device_qr_code_service_title" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="20dp"
android:background="#FF888888" />
<TextView
style="@style/item_func"
android:id="@+id/tv_qr_code"
android:text="@string/device_config_qr_code_title"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/device_config_ez_title" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_current_zb_gateway"
style="@style/item_func"
android:text="@string/device_config_zb_gateway_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_current_gateway_name"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="40dp" />
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:background="#FF888888" />
<Button
android:id="@+id/btnSearch"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="50dp"
android:text="@string/device_config_search" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/cpiLoading"
android:layout_gravity="center_horizontal"
android:layout_marginTop="80dp"
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_height="wrap_content"
android:indeterminate="true" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_gravity="center_vertical"
android:textSize="18sp"
android:id="@+id/tvName" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ivIcon"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="20dp" />
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="device_config_module_title">设备配网</string>
<string name="device_config_ez_title">EZ 模式</string>
<string name="device_config_ez_description">EZ 配网是指 App 发送包含 Wi-Fi 名
和 Wi-Fi 密码的 UDP 广播包或者组播包,
设备的 Wi-Fi 芯片可以接收到该 UDP 包,通过特定的 UDP 组织形式就可以解密出 Wi-Fi
名和 Wi-Fi 密码,接着设备配置 Wi-Fi,然后设备可上网连接云,
将设备信息注册到云端的过程</string>
<string name="device_config_ap_title">AP 模式</string>
<string name="device_config_ap_description">AP模式,也称为热点模式。 手机连接智能设备的热点,双方建立了Socket连接,
通过约定的端口交换数据。\n让设备处于配对模式,然后将手机的Wi-Fi切换到设备的热点。
输入您希望设备连接的Wi-Fi的SSID和密码,然后点击“搜索”。</string>
<string name="device_config_ble_title">低功耗蓝牙模式</string>
<string name="device_config_dual_title">双模模式</string>
<string name="device_config_zb_gateway_title">Zigbee 网关</string>
<string name="device_config_zb_sub_device_title">Zigbee 子设备</string>
<string name="device_config_choose_gateway_title">选择网关</string>
<string name="device_qr_code_service_title">扫描二维码</string>
<string name="device_config_qr_code_title">二维码配网</string>
<string name="device_config_wifi_ssid">WIFI 名称</string>
<string name="device_config_wifi_password">WIFI 密码</string>
<string name="device_config_search">搜索</string>
<string name="btn_save">保存</string>
<string name="hint_wifi_name">Wifi 名称</string>
<string name="hint_wifi_pwd">Wifi 密码</string>
<string name="device_config_ble_hint">单点蓝牙设备是指通过蓝牙与手机终端进行一对一连接的设备,
例如蓝牙手环,蓝牙耳机,蓝牙音响等。每个设备可以同时连接到手机 ,
目前每个手机终端同时蓝牙连接数限制为6到7。\n\n点击搜索并与蓝牙设备配对。</string>
<string name="device_config_zb_gateway_hint">让Zigbee网关连接到路由器,并确保手机和网关在同一局域网中,然后点按搜索。 </string>
<string name="device_config_sp_mode_hint">AP模式,也称为热点模式。 手机连接智能设备的热点,双方建立了Socket连接,通过约定的端口交换数据。\n让设备处于配对模式,然后将手机的Wi-Fi切换到设备的热点。 输入您希望设备连接的Wi-Fi的SSID和密码,然后点击“搜索”。</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="device_config_module_title">DEVICE NETWORK CONFIGURATION</string>
<string name="device_config_ez_title">EZ Mode</string>
<string name="device_config_ez_description">EZ Mode ,it means that the App sends a UDP broadcast
packet or multicast packet containing Wi-Fi name and Wi-Fi password, the Wi-Fi
chip of the device can receive the UDP packet and decrypt the Wi-Fi name and Wi-Fi
password through a specific form of UDP organization, then the device configures Wi-Fi,
and then the device can go online to connect to the cloud, the process of registering the
device information to the cloud
Translated with www.DeepL.com/Translator (free version)</string>
<string name="device_config_ap_title">AP Mode</string>
<string name="device_config_ap_description">AP Mode, also known as hotspot mode.
The mobile phone connects the smart device’s hotspot, and the two parties establish
a Socket connection to exchange data through the agreed port.Let the device in pairing mode,
\nthen switch iPhone’s Wi-Fi to the device’s hotspot. Type in the SSID and password
of which Wi-Fi you want the device connect to, then tap Search.</string>
<string name="device_config_ble_title">Bluetooth Low Energy</string>
<string name="device_config_dual_title">Dual Mode</string>
<string name="device_config_zb_gateway_title">Zigbee Gateway</string>
<string name="device_config_zb_sub_device_title">Zigbee Subdevice</string>
<string name="device_config_choose_gateway_title">Choose Gateway</string>
<string name="device_qr_code_service_title">Scan QR Code</string>
<string name="device_config_qr_code_title">QR Code</string>
<string name="device_config_wifi_ssid">WIFI SSID</string>
<string name="device_config_wifi_password">WIFI Password</string>
<string name="device_config_search">Search</string>
<string name="btn_save">Save</string>
<string name="hint_wifi_name">Wifi SSID</string>
<string name="hint_wifi_pwd">Wifi password</string>
<string name="device_config_ble_hint">Single-point Bluetooth devices are devices that have a one-to-one connection with a cell phone terminal via Bluetooth, such as Bluetooth bracelets,
Bluetooth headsets, Bluetooth speakers, etc.
Each device can be connected to a cell phone at the same time,
and the number of simultaneous Bluetooth connections per cell phone terminal is currently
limited to 6 to 7.\n\nTap Search to pair BLE device.</string>
<string name="device_config_zb_gateway_hint">Let the Zigbee Gateway connect to the router,
and make sure iPhone and the gateway are in the same local area network, then tap search. </string>
<string name="device_config_sp_mode_hint">AP Mode, also known as hotspot mode. The mobile phone connects the smart device’s hotspot, and the two parties establish a Socket connection to exchange data through the agreed port.Let the device in pairing mode, \nthen switch iPhone’s Wi-Fi to the device’s hotspot. Type in the SSID and password of which Wi-Fi you want the device connect to, then tap Search.</string>
</resources>
\ No newline at end of file
package com.example.networks
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
\ No newline at end of file
/build
\ No newline at end of file
plugins {
id 'com.android.library'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0-alpha04'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.alibaba:fastjson:1.1.67.android'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9'
implementation 'com.github.bumptech.glide:glide:4.16.0'
implementation project(':base_res')
implementation project(':ipc')
implementation project(':sweeper')
}
\ No newline at end of file
# 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
package com.example.management
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.management.test", appContext.packageName)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tuya.appsdk.sample.device.mgt">
<application>
<activity
android:name=".list.activity.DeviceMgtListActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".control.activity.DeviceMgtControlActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".list.activity.DeviceSubZigbeeActivity"
android:exported="false"
android:screenOrientation="portrait" />
</application>
</manifest>
\ No newline at end of file
This diff is collapsed.
package com.tuya.appsdk.sample.device.mgt
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.thingclips.sdk.core.PluginManager
import com.thingclips.smart.dp.parser.api.IDeviceDpParser
import com.thingclips.smart.dp.parser.api.IDpParser
import com.thingclips.smart.dp.parser.api.ISwitch
import com.thingclips.smart.interior.api.IAppDpParserPlugin
import com.thingclips.smart.sdk.bean.DeviceBean
import com.tuya.appsdk.sample.device.mgt.list.adapter.DeviceMgtAdapter
import java.util.concurrent.Executors
/**
* create by dongdaqing[mibo] 2023/9/20 14:23
*/
class DeviceDataHandler(lifecycleOwner: LifecycleOwner, private val adapter: DeviceMgtAdapter) :
LifecycleEventObserver {
private val plugin by lazy {
PluginManager.service(IAppDpParserPlugin::class.java)
}
private val handler by lazy {
Handler(Looper.getMainLooper())
}
private val mExecutor by lazy {
Executors.newSingleThreadExecutor()
}
init {
lifecycleOwner.lifecycle.addObserver(this)
}
fun execute(runnable: Runnable) {
mExecutor.execute(runnable)
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_DESTROY) {
mExecutor.shutdownNow()
}
}
fun updateAdapter(list: List<DeviceBean>) {
val data = java.util.ArrayList<SimpleDevice>()
for (deviceBean in list) {
val parser: IDeviceDpParser = plugin.update(deviceBean)
val switch = parser.getSwitchDp()
val simpleDevice = SimpleDevice(
deviceBean.devId,
deviceBean.getIconUrl(),
deviceBean.getName(),
deviceBean.isOnline,
deviceBean.productBean.category,
convert(deviceBean.devId, parser.getDisplayDp(), true),
convert(deviceBean.devId, parser.getOperableDp(), false),
if (switch == null) null else SimpleSwitch(switch.getSwitchStatus() == ISwitch.SWITCH_STATUS_ON)
)
data.add(simpleDevice)
}
handler.post { adapter.update(data) }
}
private fun convert(
devId: String,
list: List<IDpParser<Any>>,
display: Boolean
): List<SimpleDp> {
val data = java.util.ArrayList<SimpleDp>()
for (dp in list) {
val simpleDp = SimpleDp(
devId,
dp.getDpId(),
dp.getIconFont(),
if (display) dp.getDisplayStatus() else dp.getDisplayStatusForQuickOp(),
dp.getDisplayTitle(),
dp.getType()
)
data.add(simpleDp)
}
return data
}
}
\ No newline at end of file
package com.tuya.appsdk.sample.device.mgt.list.enum
/**
* Device List Type Page
*
* @author aiwen <a href="mailto:developer@tuya.com"/>
* @since 2/25/21 2:16 PM
*/
interface DeviceListTypePage {
companion object {
const val NORMAL_DEVICE_LIST = 1
const val ZIGBEE_GATEWAY_LIST = 2
const val ZIGBEE_SUB_DEVICE_LIST = 3
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="MissingDefaultResource">
<corners android:radius="8dp" />
<solid android:color="#ffffffff" />
</shape>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment