├── README.md
├── arduino
└── ir.ino
├── assets
├── 1.gif
├── 1.jpeg
├── 2.jpeg
├── 3.jpeg
├── 4.jpeg
├── 5.jpeg
├── how.png
├── phone_1.gif
├── phone_2.gif
└── sch.jpg
├── mobile
├── .gitignore
├── Readme.md
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── mbakgun
│ │ │ └── mobile
│ │ │ ├── App.kt
│ │ │ ├── data
│ │ │ ├── IrData.kt
│ │ │ └── NearbyMessage.kt
│ │ │ ├── di
│ │ │ ├── InjectionViewModelProvider.kt
│ │ │ ├── components
│ │ │ │ └── AppComponent.kt
│ │ │ ├── modules
│ │ │ │ ├── ActivityInjectorsModule.kt
│ │ │ │ ├── AppModule.kt
│ │ │ │ └── MainActivityModule.kt
│ │ │ └── qualifiers
│ │ │ │ └── ViewModelInjection.kt
│ │ │ ├── ui
│ │ │ ├── IrDataAdapter.kt
│ │ │ ├── MainActivity.kt
│ │ │ └── MainActivityVM.kt
│ │ │ └── util
│ │ │ ├── AlertDialog.kt
│ │ │ ├── MarginItemDecoration.kt
│ │ │ └── NearbyCommunication.kt
│ │ └── res
│ │ ├── drawable
│ │ ├── ic_add.xml
│ │ ├── ic_delete.xml
│ │ ├── ic_edit.xml
│ │ ├── ic_location_disabled.xml
│ │ └── ic_sync.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── empty_item.xml
│ │ └── ir_item.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
├── build.gradle
├── buildSrc
│ ├── .gitignore
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ ├── Libs.kt
│ │ └── Versions.kt
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
└── settings.gradle
└── things
├── .gitignore
├── Readme.md
├── app
├── .gitignore
├── build.gradle
├── libs
│ ├── models.aar
│ └── tts.aar
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── mbakgun
│ │ └── things
│ │ ├── App.kt
│ │ ├── data
│ │ ├── IrDao.kt
│ │ ├── IrData.kt
│ │ ├── IrDatabase.kt
│ │ └── NearbyMessage.kt
│ │ ├── di
│ │ ├── components
│ │ │ └── AppComponent.kt
│ │ └── modules
│ │ │ ├── ActivityInjectorsModule.kt
│ │ │ └── AppModule.kt
│ │ ├── ui
│ │ └── MainActivity.kt
│ │ └── util
│ │ ├── NearbyCommunication.kt
│ │ ├── PocketSphinx.kt
│ │ └── SerialCommunication.kt
│ └── res
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── buildSrc
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── Libs.kt
│ └── Versions.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── settings.gradle
/README.md:
--------------------------------------------------------------------------------
1 | ## Android Things IR Remote Hacker
2 |
3 |
4 |
5 |
6 | This Android Things project integrates `Nearby Communication` , `Serial Communication` and `Voice Recognition` together to
7 | build a connected IR remote that explores the relationships between surfaces and content.
8 |
9 | This repo contains all the app code that powers IR Remote Controled Android Things powered Raspberry Pi.
10 |
11 | The project is split into three modules:
12 |
13 | - `/things` - the Android Things app
14 | - `/mobile` - the companion mobile app
15 | - `/arduino` - the Arduino code
16 |
17 |
18 |
19 | ### Pre-requisites
20 |
21 | - Android Things compatible board
22 | - Android Studio 3.2+
23 | - [Arduino](https://www.arduino.cc/) and the following individual components:
24 | - 1 IR Receiver
25 | - 1 IR Transmitter
26 | - Jumper wires
27 | - (optional) 1 MI-305 - USB Microphone
28 |
29 |
2 |
3 | int RECV_PIN = 2;
4 | IRrecv irrecv(RECV_PIN);
5 | IRsend irsend;
6 |
7 | decode_results results;
8 |
9 | long hstol(String recv) {
10 | char c[recv.length() + 1];
11 | recv.toCharArray(c, recv.length() + 1);
12 | return strtol(c, NULL, 16);
13 | }
14 |
15 | void readIr(String str) {
16 | if (irrecv.decode(&results)) {
17 | str.trim();
18 | Serial.print("saved:" + str + "-");
19 | Serial.println(results.value, HEX);
20 | irrecv.resume();
21 | } else {
22 | Serial.println("No Signal - No capture signal found");
23 | }
24 | }
25 |
26 | void sendIr(String str) {
27 | irsend.sendNEC(hstol(str), 32);
28 | irrecv.enableIRIn();
29 | Serial.println("Command Sent");
30 | delay(100);
31 | }
32 |
33 | void setup()
34 | {
35 | Serial.begin(9600);
36 | irrecv.enableIRIn();
37 | }
38 |
39 | void loop() {
40 | if (Serial.available() > 0) {
41 | String incoming = Serial.readString();
42 | if (incoming.startsWith("read:")) {
43 | readIr(incoming.substring(5)); // read:
44 | } else if (incoming.startsWith("send:")) {
45 | sendIr(incoming.substring(5)); // send:
46 | }
47 | Serial.flush();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/assets/1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/1.gif
--------------------------------------------------------------------------------
/assets/1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/1.jpeg
--------------------------------------------------------------------------------
/assets/2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/2.jpeg
--------------------------------------------------------------------------------
/assets/3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/3.jpeg
--------------------------------------------------------------------------------
/assets/4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/4.jpeg
--------------------------------------------------------------------------------
/assets/5.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/5.jpeg
--------------------------------------------------------------------------------
/assets/how.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/how.png
--------------------------------------------------------------------------------
/assets/phone_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/phone_1.gif
--------------------------------------------------------------------------------
/assets/phone_2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/phone_2.gif
--------------------------------------------------------------------------------
/assets/sch.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/assets/sch.jpg
--------------------------------------------------------------------------------
/mobile/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 |
--------------------------------------------------------------------------------
/mobile/Readme.md:
--------------------------------------------------------------------------------
1 | ## Companion Android Application
2 |
3 | Mobile application is easy to use with simple steps.
4 |
5 | - Power on Android Things Device with application
6 | - Install Application to your phone then run
7 | - Give permission to use Nearby Api
8 | - Wait for the connection between devices
9 |
10 |
11 |
12 | - Press Float Action Button (+) to capture a new IR Signal
13 | - Push any button to send Remote(Radio)-Control signal to Android Things
14 | - In dialog give a name to recently recorded signal
15 | - In order to send IR signal select list item
16 |
17 |
18 |
--------------------------------------------------------------------------------
/mobile/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/mobile/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'kotlin-kapt'
5 |
6 | android {
7 | compileSdkVersion 28
8 | defaultConfig {
9 | applicationId "com.mbakgun.mobile"
10 | minSdkVersion 16
11 | targetSdkVersion 28
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | dataBinding {
22 | enabled = true
23 | }
24 | }
25 |
26 | dependencies {
27 | //android
28 | implementation Libs.appcompat
29 | implementation Libs.constraintlayout
30 | api Libs.play_services_nearby
31 | implementation Libs.lifecycle_extensions
32 | implementation Libs.material
33 | implementation Libs.kotlin_stdlib_jdk7
34 |
35 | //dagger
36 | kapt Libs.dagger_compiler
37 | kapt Libs.dagger_android_processor
38 | implementation Libs.dagger_android_support
39 |
40 | //Gson
41 | implementation Libs.gson
42 | }
43 |
--------------------------------------------------------------------------------
/mobile/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/mobile/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/App.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile
2 |
3 | import android.app.Application
4 | import com.mbakgun.mobile.di.components.DaggerAppComponent
5 | import dagger.android.AndroidInjector
6 | import dagger.android.DispatchingAndroidInjector
7 | import dagger.android.HasAndroidInjector
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Created by burakakgun on 8.06.2019.
12 | */
13 | class App : Application(), HasAndroidInjector {
14 |
15 | @Inject
16 | lateinit var androidInjector: DispatchingAndroidInjector
17 |
18 | override fun onCreate() {
19 | super.onCreate()
20 |
21 | DaggerAppComponent
22 | .builder()
23 | .application(this)
24 | .build()
25 | .inject(this)
26 | }
27 |
28 | override fun androidInjector(): AndroidInjector = androidInjector
29 | }
30 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/data/IrData.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.data
2 |
3 | /**
4 | * Created by burakakgun on 8.06.2019.
5 | */
6 | data class IrData(var id: Int = 0, var name: String, var hexCode: String)
7 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/data/NearbyMessage.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.data
2 |
3 | /**
4 | * Created by burakakgun on 9.06.2019.
5 | */
6 |
7 | enum class NearbyType {
8 | UPDATE, DELETE, GET_ALL, MESSAGE
9 | }
10 |
11 | data class NearbyMessage(val nearbyType: NearbyType, val value: String = "")
12 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/di/InjectionViewModelProvider.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.di
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.fragment.app.FragmentActivity
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.ViewModelProvider
7 | import androidx.lifecycle.ViewModelProviders
8 | import javax.inject.Inject
9 | import kotlin.reflect.KClass
10 |
11 | typealias ViewModelInjectionField = dagger.Lazy
12 |
13 | class InjectionViewModelProvider @Inject constructor(
14 | private val lazyViewModel: dagger.Lazy
15 | ) {
16 |
17 | @Suppress("UNCHECKED_CAST")
18 | @SuppressWarnings("unchecked")
19 | private val viewModelFactory = object : ViewModelProvider.Factory {
20 | override fun create(modelClass: Class) = lazyViewModel.get() as T
21 | }
22 |
23 | fun get(activity: ACTIVITY, viewModelClass: KClass) =
24 | ViewModelProviders.of(activity, viewModelFactory).get(viewModelClass.java)
25 |
26 | fun get(fragment: FRAGMENT, viewModelClass: KClass) =
27 | ViewModelProviders.of(fragment, viewModelFactory).get(viewModelClass.java)
28 | }
29 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/di/components/AppComponent.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.di.components
2 |
3 | import com.mbakgun.mobile.App
4 | import com.mbakgun.mobile.di.modules.ActivityInjectorsModule
5 | import com.mbakgun.mobile.di.modules.AppModule
6 | import dagger.BindsInstance
7 | import dagger.Component
8 | import dagger.android.support.AndroidSupportInjectionModule
9 | import javax.inject.Singleton
10 |
11 | /**
12 | * Created by burakakgun on 8.06.2019.
13 | */
14 | @Singleton
15 | @Component(
16 | modules = [
17 | AndroidSupportInjectionModule::class,
18 | ActivityInjectorsModule::class,
19 | AppModule::class]
20 | )
21 | @SuppressWarnings("unchecked")
22 | interface AppComponent {
23 | @Component.Builder
24 | interface Builder {
25 | @BindsInstance
26 | fun application(application: App): Builder
27 |
28 | fun build(): AppComponent
29 | }
30 |
31 | fun inject(app: App)
32 | }
33 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/di/modules/ActivityInjectorsModule.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.di.modules
2 |
3 | import com.mbakgun.mobile.ui.MainActivity
4 | import dagger.Module
5 | import dagger.android.ContributesAndroidInjector
6 |
7 | /**
8 | * Created by burakakgun on 8.06.2019.
9 | */
10 | @Module
11 | abstract class ActivityInjectorsModule {
12 |
13 | @ContributesAndroidInjector(modules = [MainActivityModule::class])
14 | abstract fun mainActivityInjector(): MainActivity
15 | }
16 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/di/modules/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.di.modules
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import com.mbakgun.mobile.App
6 | import dagger.Module
7 | import dagger.Provides
8 | import javax.inject.Singleton
9 |
10 | /**
11 | * Created by burakakgun on 8.06.2019.
12 | */
13 | @Module
14 | class AppModule {
15 |
16 | @Provides
17 | @Singleton
18 | fun provideApplication(app: App): Application = app
19 |
20 | @Provides
21 | @Singleton
22 | fun provideApplicationContext(app: App): Context = app.applicationContext
23 | }
24 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/di/modules/MainActivityModule.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.di.modules
2 |
3 | import com.mbakgun.mobile.di.InjectionViewModelProvider
4 | import com.mbakgun.mobile.di.qualifiers.ViewModelInjection
5 | import com.mbakgun.mobile.ui.MainActivity
6 | import com.mbakgun.mobile.ui.MainActivityVM
7 | import dagger.Module
8 | import dagger.Provides
9 |
10 | /**
11 | * Created by burakakgun on 8.06.2019.
12 | */
13 | @Module
14 | class MainActivityModule {
15 |
16 | @Provides
17 | @ViewModelInjection
18 | fun provideMainActivityVM(
19 | activity: MainActivity,
20 | viewModelProvider: InjectionViewModelProvider
21 | ) = viewModelProvider.get(activity, MainActivityVM::class)
22 | }
23 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/di/qualifiers/ViewModelInjection.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.di.qualifiers
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @MustBeDocumented
7 | @Retention(AnnotationRetention.RUNTIME)
8 | @Target(AnnotationTarget.FIELD, AnnotationTarget.FUNCTION)
9 | annotation class ViewModelInjection
10 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/ui/IrDataAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.ui
2 |
3 | /**
4 | * Created by burakakgun on 9.06.2019.
5 | */
6 | import android.util.Log
7 | import android.view.LayoutInflater
8 | import android.view.ViewGroup
9 | import androidx.databinding.DataBindingUtil.inflate
10 | import androidx.recyclerview.widget.RecyclerView
11 | import com.google.gson.Gson
12 | import com.mbakgun.mobile.R
13 | import com.mbakgun.mobile.data.IrData
14 | import com.mbakgun.mobile.data.NearbyMessage
15 | import com.mbakgun.mobile.data.NearbyType
16 | import com.mbakgun.mobile.databinding.EmptyItemBinding
17 | import com.mbakgun.mobile.databinding.IrItemBinding
18 | import com.mbakgun.mobile.util.showAlertWithTextInputLayout
19 | import javax.inject.Inject
20 |
21 | class IrDataAdapter @Inject constructor(private val vm: MainActivityVM) :
22 | RecyclerView.Adapter() {
23 |
24 | private val irDataList = mutableListOf()
25 |
26 | companion object {
27 | const val EMPTY = 0
28 | const val IR_ITEM = 1
29 | }
30 |
31 | fun updateList(list: List) {
32 | Log.d("IrDataAdapter", "current list: $list")
33 | irDataList.clear()
34 | if (list.isEmpty()) {
35 | irDataList.add(null)
36 | } else {
37 | irDataList.addAll(list)
38 | }
39 | notifyDataSetChanged()
40 | }
41 |
42 | override fun getItemViewType(position: Int): Int = if (irDataList[0] == null) EMPTY else IR_ITEM
43 |
44 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
45 | val inflater = LayoutInflater.from(parent.context)
46 | return when (viewType) {
47 | IR_ITEM -> {
48 | val binding = inflate(
49 | inflater, R.layout.ir_item, parent, false
50 | )
51 | IrViewHolder(binding)
52 | }
53 | else -> { // EMPTY
54 | val binding = inflate(
55 | inflater, R.layout.empty_item, parent, false
56 | )
57 | EmptyViewHolder(binding)
58 | }
59 | }
60 | }
61 |
62 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
63 | when (getItemViewType(position)) {
64 | EMPTY -> holder as EmptyViewHolder
65 | IR_ITEM -> {
66 | irDataList[position]?.let {
67 | holder as IrViewHolder
68 | holder.bind(it)
69 | }
70 | }
71 | }
72 | }
73 |
74 | override fun getItemCount(): Int {
75 | return irDataList.size
76 | }
77 |
78 | inner class IrViewHolder(private val binding: IrItemBinding) :
79 | RecyclerView.ViewHolder(binding.root) {
80 | fun bind(item: IrData) {
81 | binding.root.setOnClickListener {
82 | vm.send(NearbyMessage(NearbyType.MESSAGE, "send:${item.hexCode}"))
83 | }
84 | binding.imageViewDelete.setOnClickListener {
85 | vm.send(NearbyMessage(NearbyType.DELETE, Gson().toJson(item)))
86 | }
87 | binding.imageViewEdit.setOnClickListener {
88 | showAlertWithTextInputLayout(binding.root.context, vm, item)
89 | }
90 | binding.item = item
91 | binding.executePendingBindings()
92 | }
93 | }
94 |
95 | inner class EmptyViewHolder(binding: EmptyItemBinding) : RecyclerView.ViewHolder(binding.root)
96 | }
97 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/ui/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.ui
2 |
3 | import android.content.pm.PackageManager
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.View
7 | import android.view.animation.Animation
8 | import android.view.animation.RotateAnimation
9 | import android.widget.Toast
10 | import androidx.core.app.ActivityCompat
11 | import androidx.core.content.ContextCompat
12 | import androidx.lifecycle.Observer
13 | import com.google.android.material.snackbar.Snackbar
14 | import com.google.gson.Gson
15 | import com.google.gson.reflect.TypeToken
16 | import com.mbakgun.mobile.R
17 | import com.mbakgun.mobile.data.IrData
18 | import com.mbakgun.mobile.data.NearbyMessage
19 | import com.mbakgun.mobile.data.NearbyType.GET_ALL
20 | import com.mbakgun.mobile.data.NearbyType.MESSAGE
21 | import com.mbakgun.mobile.di.ViewModelInjectionField
22 | import com.mbakgun.mobile.di.qualifiers.ViewModelInjection
23 | import com.mbakgun.mobile.util.MarginItemDecoration
24 | import com.mbakgun.mobile.util.showAlertWithTextInputLayout
25 | import dagger.android.support.DaggerAppCompatActivity
26 | import kotlinx.android.synthetic.main.activity_main.*
27 | import javax.inject.Inject
28 |
29 | /**
30 | * Created by burakakgun on 8.06.2019.
31 | */
32 | class MainActivity : DaggerAppCompatActivity() {
33 |
34 | @Inject
35 | @ViewModelInjection
36 | lateinit var vm: ViewModelInjectionField
37 | private val mainActivityVM: MainActivityVM = vm.get()
38 |
39 | @Inject
40 | lateinit var adapter: IrDataAdapter
41 |
42 | override fun onCreate(savedInstanceState: Bundle?) {
43 | super.onCreate(savedInstanceState)
44 | setContentView(R.layout.activity_main)
45 | mainActivityVM.nearByMessageObserver().observe(this, Observer { message ->
46 | val data = Gson().fromJson(message, NearbyMessage::class.java)
47 | if (data.nearbyType == GET_ALL) {
48 | progressBar.visibility = View.GONE
49 | adapter.updateList(
50 | Gson().fromJson(
51 | data.value,
52 | object : TypeToken>() {}.type
53 | )
54 | )
55 | } else if (data.nearbyType == MESSAGE) {
56 | Snackbar.make(root, data.value, Snackbar.LENGTH_LONG).show()
57 | // request new list after all events
58 | mainActivityVM.send(NearbyMessage(GET_ALL))
59 | }
60 | })
61 | mainActivityVM.nearByConnectivityObserver().observe(this, Observer { value -> applyFloatActionButton(value) })
62 | setRecyclerView()
63 | }
64 |
65 | override fun onStart() {
66 | super.onStart()
67 | if (checkPermission()) vm.get().connect()
68 | }
69 |
70 | private fun setRecyclerView() {
71 | recyclerView.setHasFixedSize(true)
72 | recyclerView.adapter = adapter
73 | recyclerView.addItemDecoration(MarginItemDecoration(resources.getDimension(R.dimen.dp_8).toInt()))
74 | }
75 |
76 | private fun applyFloatActionButton(isConnected: Boolean) {
77 | Log.d("MainActivity", "status : $isConnected")
78 | if (checkPermission()) {
79 | if (isConnected) {
80 | floatingActionButton.clearAnimation()
81 | floatingActionButton.setImageResource(R.drawable.ic_add)
82 | floatingActionButton.setOnClickListener {
83 | showAlertWithTextInputLayout(this, vm.get())
84 | }
85 | vm.get().send(NearbyMessage(GET_ALL))
86 | recyclerView.visibility = View.VISIBLE
87 | progressBar.visibility = View.VISIBLE
88 | } else {
89 | recyclerView.visibility = View.GONE
90 | floatingActionButton.setImageResource(R.drawable.ic_sync)
91 | val rotate = RotateAnimation(
92 | float_max, 0f,
93 | Animation.RELATIVE_TO_SELF, animation_pivotXValue,
94 | Animation.RELATIVE_TO_SELF, animation_pivotXValue
95 | )
96 | rotate.duration = animation_duration
97 | rotate.repeatCount = Animation.INFINITE
98 | floatingActionButton.startAnimation(rotate)
99 | vm.get().connect()
100 | floatingActionButton.setOnClickListener {
101 | Toast.makeText(this, "Connecting...", Toast.LENGTH_SHORT).show()
102 | }
103 | }
104 | } else {
105 | floatingActionButton.setImageResource(R.drawable.ic_location_disabled)
106 | floatingActionButton.setOnClickListener {
107 | checkPermission()
108 | }
109 | }
110 | }
111 |
112 | private fun checkPermission(): Boolean {
113 | if (ContextCompat.checkSelfPermission(
114 | this,
115 | android.Manifest.permission.ACCESS_COARSE_LOCATION
116 | ) != PackageManager.PERMISSION_GRANTED
117 | ) {
118 | ActivityCompat.requestPermissions(
119 | this, arrayOf(
120 | android.Manifest.permission.ACCESS_COARSE_LOCATION,
121 | android.Manifest.permission.ACCESS_FINE_LOCATION
122 | ), REQ_CODE
123 | )
124 | return false
125 | }
126 | return true
127 | }
128 |
129 | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
130 | if (requestCode == REQ_CODE &&
131 | grantResults.isNotEmpty() &&
132 | grantResults[0] == PackageManager.PERMISSION_GRANTED
133 | ) {
134 | applyFloatActionButton(false)
135 | }
136 | }
137 |
138 | companion object {
139 | const val REQ_CODE = 1453
140 | const val float_max = 360f
141 | const val animation_duration: Long = 1250
142 | const val animation_pivotXValue = 0.5f
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/ui/MainActivityVM.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.ui
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 | import com.google.gson.Gson
6 | import com.mbakgun.mobile.data.NearbyMessage
7 | import com.mbakgun.mobile.util.NearbyCommunication
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Created by burakakgun on 8.06.2019.
12 | */
13 | class MainActivityVM @Inject constructor(private val nearbyCommunication: NearbyCommunication) :
14 | ViewModel() {
15 |
16 | fun nearByMessageObserver(): MutableLiveData = nearbyCommunication.remoteMessage
17 |
18 | fun nearByConnectivityObserver(): MutableLiveData = nearbyCommunication.mIsConnected
19 |
20 | fun send(message: NearbyMessage) {
21 | nearbyCommunication.sendMessage(Gson().toJson(message))
22 | }
23 |
24 | fun connect() = nearbyCommunication.mGoogleApiClient.connect()
25 | }
26 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/util/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.util
2 |
3 | import android.content.Context
4 | import android.text.TextUtils
5 | import android.widget.EditText
6 | import android.widget.Toast
7 | import androidx.appcompat.app.AlertDialog
8 | import com.google.android.material.textfield.TextInputLayout
9 | import com.google.gson.Gson
10 | import com.mbakgun.mobile.R
11 | import com.mbakgun.mobile.data.IrData
12 | import com.mbakgun.mobile.data.NearbyMessage
13 | import com.mbakgun.mobile.data.NearbyType
14 | import com.mbakgun.mobile.ui.MainActivityVM
15 |
16 | /**
17 | * Created by burakakgun on 9.06.2019.
18 | */
19 |
20 | fun showAlertWithTextInputLayout(context: Context, vm: MainActivityVM, irData: IrData? = null) {
21 | val textInputLayout = TextInputLayout(context)
22 | textInputLayout.setPadding(
23 | context.resources.getDimensionPixelOffset(R.dimen.dp_19),
24 | 0,
25 | context.resources.getDimensionPixelOffset(R.dimen.dp_19),
26 | 0
27 | )
28 | val input = EditText(context)
29 | irData?.let { it ->
30 | input.setText(it.name)
31 | }
32 | textInputLayout.hint = "Remote Device Name"
33 | textInputLayout.addView(input)
34 | val alert = AlertDialog.Builder(context)
35 | .setTitle("Capture Infrared")
36 | .setView(textInputLayout)
37 | .setMessage("Please push any IR signal then enter your device name")
38 | .setPositiveButton("Send") { _, _ ->
39 | val text = input.text
40 | if (TextUtils.isEmpty(text).not()) {
41 | irData?.let {
42 | vm.send(NearbyMessage(NearbyType.UPDATE, Gson().toJson(it.copy(name = text.toString()))))
43 | } ?: run {
44 | vm.send(NearbyMessage(NearbyType.MESSAGE, "read:$text"))
45 | }
46 | } else {
47 | Toast.makeText(context, "Device Name is required", Toast.LENGTH_SHORT).show()
48 | }
49 | }
50 | .setNegativeButton("Cancel") { dialog, _ ->
51 | dialog.cancel()
52 | }.create()
53 | alert.show()
54 | }
55 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/util/MarginItemDecoration.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.util
2 |
3 | /**
4 | * Created by burakakgun on 9.06.2019.
5 | */
6 | import android.graphics.Rect
7 | import android.view.View
8 | import androidx.recyclerview.widget.RecyclerView
9 |
10 | /**
11 | * @author burakakgun
12 | */
13 |
14 | class MarginItemDecoration(private val spaceHeight: Int) : RecyclerView.ItemDecoration() {
15 | override fun getItemOffsets(
16 | outRect: Rect,
17 | view: View,
18 | parent: RecyclerView,
19 | state: RecyclerView.State
20 | ) {
21 | with(outRect) {
22 | if (parent.getChildAdapterPosition(view) == 0) {
23 | top = spaceHeight
24 | }
25 | left = spaceHeight
26 | right = spaceHeight
27 | bottom = spaceHeight
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/mobile/app/src/main/java/com/mbakgun/mobile/util/NearbyCommunication.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.mobile.util
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.widget.Toast
6 | import androidx.annotation.Nullable
7 | import androidx.lifecycle.MutableLiveData
8 | import com.google.android.gms.common.api.GoogleApiClient
9 | import com.google.android.gms.nearby.Nearby
10 | import com.google.android.gms.nearby.connection.ConnectionInfo
11 | import com.google.android.gms.nearby.connection.ConnectionLifecycleCallback
12 | import com.google.android.gms.nearby.connection.ConnectionResolution
13 | import com.google.android.gms.nearby.connection.ConnectionsStatusCodes
14 | import com.google.android.gms.nearby.connection.DiscoveredEndpointInfo
15 | import com.google.android.gms.nearby.connection.DiscoveryOptions
16 | import com.google.android.gms.nearby.connection.EndpointDiscoveryCallback
17 | import com.google.android.gms.nearby.connection.Payload
18 | import com.google.android.gms.nearby.connection.PayloadCallback
19 | import com.google.android.gms.nearby.connection.PayloadTransferUpdate
20 | import com.google.android.gms.nearby.connection.Strategy
21 | import com.mbakgun.mobile.App
22 | import com.mbakgun.mobile.R
23 | import java.nio.charset.Charset
24 | import javax.inject.Inject
25 | import javax.inject.Singleton
26 |
27 | /**
28 | * Created by burakakgun on 8.06.2019.
29 | */
30 | @Suppress("DEPRECATION")
31 | @Singleton
32 | class NearbyCommunication @Inject constructor(private val app: App) {
33 |
34 | lateinit var mGoogleApiClient: GoogleApiClient
35 | lateinit var mRemoteHostEndpoint: String
36 | val mIsConnected: MutableLiveData by lazy {
37 | MutableLiveData().apply {
38 | value = false
39 | }
40 | }
41 | val remoteMessage: MutableLiveData by lazy {
42 | MutableLiveData()
43 | }
44 |
45 | companion object {
46 | private const val TAG = "NearbyCommunication"
47 | }
48 |
49 | init {
50 | mGoogleApiClient = GoogleApiClient.Builder(app)
51 | .addConnectionCallbacks(object : GoogleApiClient.ConnectionCallbacks {
52 | override fun onConnected(@Nullable bundle: Bundle?) {
53 | Log.d(
54 | TAG,
55 | "onConnected: start discovering hosts to send connection requests"
56 | )
57 | startDiscovery()
58 | }
59 |
60 | override fun onConnectionSuspended(i: Int) {
61 | Log.d(TAG, "onConnectionSuspended: $i")
62 | mGoogleApiClient.reconnect()
63 | }
64 | })
65 | .addOnConnectionFailedListener { connectionResult ->
66 | Log.d(
67 | TAG,
68 | "onConnectionFailed: " + connectionResult.errorCode
69 | )
70 | }
71 | .addApi(Nearby.CONNECTIONS_API)
72 | .build()
73 | }
74 |
75 | fun sendMessage(message: String) {
76 | Log.d(TAG, "About to send message: $message")
77 | Nearby.Connections.sendPayload(
78 | mGoogleApiClient,
79 | mRemoteHostEndpoint,
80 | Payload.fromBytes(message.toByteArray(Charset.forName("UTF-8")))
81 | )
82 | }
83 |
84 | private fun startDiscovery() = Nearby.Connections.startDiscovery(
85 | mGoogleApiClient, app.getString(R.string.id), object : EndpointDiscoveryCallback() {
86 | override fun onEndpointFound(endpointId: String, info: DiscoveredEndpointInfo) {
87 | Log.d(TAG, "onEndpointFound:" + endpointId + ":" + info.endpointName)
88 |
89 | Nearby.Connections
90 | .requestConnection(mGoogleApiClient, null, endpointId, object : ConnectionLifecycleCallback() {
91 | override fun onConnectionInitiated(endpointId: String, connectionInfo: ConnectionInfo) {
92 | Log.d(TAG, "onConnectionInitiated. Token: " + connectionInfo.authenticationToken)
93 | Nearby.Connections.acceptConnection(
94 | mGoogleApiClient,
95 | endpointId,
96 | object : PayloadCallback() {
97 | override fun onPayloadReceived(endpointId: String, payload: Payload) {
98 | String(payload.asBytes()!!).apply {
99 | Log.d(TAG, "onPayloadReceived: $this")
100 | remoteMessage.postValue(this)
101 | }
102 | }
103 |
104 | override fun onPayloadTransferUpdate(
105 | endpointId: String,
106 | update: PayloadTransferUpdate
107 | ) = Unit
108 | })
109 | }
110 |
111 | override fun onConnectionResult(endpointId: String, resolution: ConnectionResolution) {
112 | Log.d(TAG, "onConnectionResult:" + endpointId + ":" + resolution.status)
113 | if (resolution.status.isSuccess) {
114 | Log.d(TAG, "Connected successfully")
115 | Nearby.Connections.stopDiscovery(mGoogleApiClient)
116 | mRemoteHostEndpoint = endpointId
117 | mIsConnected.postValue(true)
118 | Toast.makeText(app, "Connected with Android Things", Toast.LENGTH_SHORT).show()
119 | } else {
120 | if (resolution.status.statusCode == ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED) {
121 | Log.d(TAG, "The connection was rejected by one or both sides")
122 | } else {
123 | Log.d(
124 | TAG,
125 | "Connection to " + endpointId + " failed. Code: " + resolution.status.statusCode
126 | )
127 | }
128 | mIsConnected.postValue(false)
129 | }
130 | }
131 |
132 | override fun onDisconnected(endpointId: String) {
133 | Toast.makeText(app, "Disconnected", Toast.LENGTH_SHORT).show()
134 | mIsConnected.postValue(false)
135 | Log.d(TAG, "onDisconnected: $endpointId")
136 | }
137 | })
138 | }
139 |
140 | override fun onEndpointLost(endpointId: String) {
141 | Log.d(TAG, "onEndpointLost:$endpointId")
142 | }
143 | },
144 | DiscoveryOptions(Strategy.P2P_STAR)
145 | ).setResultCallback { status ->
146 | if (status.isSuccess) {
147 | Log.d(TAG, "Discovering...")
148 | } else {
149 | Log.d(
150 | TAG,
151 | "Discovering failed: " + status.statusMessage + "(" + status.statusCode + ")"
152 | )
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/drawable/ic_add.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/drawable/ic_delete.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/drawable/ic_edit.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/drawable/ic_location_disabled.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/drawable/ic_sync.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
21 |
31 |
32 |
43 |
44 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/layout/empty_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/layout/ir_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
23 |
24 |
27 |
28 |
29 |
41 |
42 |
43 |
53 |
54 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/mobile/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mobile/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/mobile/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mobile/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/mobile/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mobile/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/mobile/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mobile/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/mobile/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mobile/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 19dp
4 | 8dp
5 |
6 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | IrRemote Mobile
3 | irremote
4 | Empty List click button to add IR signal
5 |
6 |
--------------------------------------------------------------------------------
/mobile/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/mobile/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.3.31'
5 | repositories {
6 | google()
7 | jcenter()
8 |
9 | }
10 | dependencies {
11 | classpath Libs.com_android_tools_build_gradle
12 | classpath Libs.kotlin_gradle_plugin
13 | }
14 | }
15 | plugins {
16 | id("de.fayard.buildSrcVersions") version "0.3.2"
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/mobile/buildSrc/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .gradle/
3 | build/
4 |
--------------------------------------------------------------------------------
/mobile/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 | repositories {
5 | jcenter()
6 | }
7 |
--------------------------------------------------------------------------------
/mobile/buildSrc/src/main/kotlin/Libs.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Generated by https://github.com/jmfayard/buildSrcVersions
3 | *
4 | * Update this file with
5 | * `$ ./gradlew buildSrcVersions` */
6 | object Libs {
7 | /**
8 | * http://developer.android.com/tools/extras/support-library.html */
9 | const val appcompat: String = "androidx.appcompat:appcompat:" + Versions.appcompat
10 |
11 | /**
12 | * http://tools.android.com */
13 | const val constraintlayout: String = "androidx.constraintlayout:constraintlayout:" +
14 | Versions.constraintlayout
15 |
16 | /**
17 | * http://developer.android.com/tools/extras/support-library.html */
18 | const val core_ktx: String = "androidx.core:core-ktx:" + Versions.core_ktx
19 |
20 | const val databinding_adapters: String = "androidx.databinding:databinding-adapters:" +
21 | Versions.androidx_databinding
22 |
23 | /**
24 | * https://developer.android.com/studio */
25 | const val databinding_common: String = "androidx.databinding:databinding-common:" +
26 | Versions.androidx_databinding
27 |
28 | /**
29 | * https://developer.android.com/studio */
30 | const val databinding_compiler: String = "androidx.databinding:databinding-compiler:" +
31 | Versions.androidx_databinding
32 |
33 | const val databinding_runtime: String = "androidx.databinding:databinding-runtime:" +
34 | Versions.androidx_databinding
35 |
36 | /**
37 | * https://developer.android.com/topic/libraries/architecture/index.html */
38 | const val lifecycle_extensions: String = "androidx.lifecycle:lifecycle-extensions:" +
39 | Versions.lifecycle_extensions
40 |
41 | /**
42 | * https://developer.android.com/studio */
43 | const val com_android_tools_build_gradle: String = "com.android.tools.build:gradle:" +
44 | Versions.com_android_tools_build_gradle
45 |
46 | /**
47 | * https://developer.android.com/studio */
48 | const val lint_gradle: String = "com.android.tools.lint:lint-gradle:" + Versions.lint_gradle
49 |
50 | const val play_services_nearby: String = "com.google.android.gms:play-services-nearby:" +
51 | Versions.play_services_nearby
52 |
53 | /**
54 | * http://developer.android.com/tools/extras/support-library.html */
55 | const val material: String = "com.google.android.material:material:" + Versions.material
56 |
57 | /**
58 | * https://github.com/google/gson */
59 | const val gson: String = "com.google.code.gson:gson:" + Versions.gson
60 |
61 | /**
62 | * https://github.com/google/dagger */
63 | const val dagger_android_processor: String = "com.google.dagger:dagger-android-processor:" +
64 | Versions.com_google_dagger
65 |
66 | /**
67 | * https://github.com/google/dagger */
68 | const val dagger_android_support: String = "com.google.dagger:dagger-android-support:" +
69 | Versions.com_google_dagger
70 |
71 | /**
72 | * https://github.com/google/dagger */
73 | const val dagger_compiler: String = "com.google.dagger:dagger-compiler:" +
74 | Versions.com_google_dagger
75 |
76 | const val de_fayard_buildsrcversions_gradle_plugin: String =
77 | "de.fayard.buildSrcVersions:de.fayard.buildSrcVersions.gradle.plugin:" +
78 | Versions.de_fayard_buildsrcversions_gradle_plugin
79 |
80 | /**
81 | * https://kotlinlang.org/ */
82 | const val kotlin_android_extensions_runtime: String =
83 | "org.jetbrains.kotlin:kotlin-android-extensions-runtime:" +
84 | Versions.org_jetbrains_kotlin
85 |
86 | /**
87 | * https://kotlinlang.org/ */
88 | const val kotlin_android_extensions: String =
89 | "org.jetbrains.kotlin:kotlin-android-extensions:" + Versions.org_jetbrains_kotlin
90 |
91 | /**
92 | * https://kotlinlang.org/ */
93 | const val kotlin_annotation_processing_gradle: String =
94 | "org.jetbrains.kotlin:kotlin-annotation-processing-gradle:" +
95 | Versions.org_jetbrains_kotlin
96 |
97 | /**
98 | * https://kotlinlang.org/ */
99 | const val kotlin_gradle_plugin: String = "org.jetbrains.kotlin:kotlin-gradle-plugin:" +
100 | Versions.org_jetbrains_kotlin
101 |
102 | /**
103 | * https://kotlinlang.org/ */
104 | const val kotlin_stdlib_jdk7: String = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:" +
105 | Versions.org_jetbrains_kotlin
106 | }
107 |
--------------------------------------------------------------------------------
/mobile/buildSrc/src/main/kotlin/Versions.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Find which updates are available by running
3 | * `$ ./gradlew buildSrcVersions`
4 | * This will only update the comments.
5 | *
6 | * YOU are responsible for updating manually the dependency version. */
7 | object Versions {
8 | const val appcompat: String = "1.0.2"
9 |
10 | const val constraintlayout: String = "1.1.3"
11 |
12 | const val core_ktx: String = "1.0.2"
13 |
14 | const val androidx_databinding: String = "3.4.2"
15 |
16 | const val lifecycle_extensions: String = "2.0.0"
17 |
18 | const val com_android_tools_build_gradle: String = "3.4.2"
19 |
20 | const val lint_gradle: String = "26.4.2"
21 |
22 | const val play_services_nearby: String = "17.0.0"
23 |
24 | const val material: String = "1.0.0"
25 |
26 | const val gson: String = "2.8.5"
27 |
28 | const val com_google_dagger: String = "2.24"
29 |
30 | const val de_fayard_buildsrcversions_gradle_plugin: String = "0.3.2"
31 |
32 | const val org_jetbrains_kotlin: String = "1.3.41"
33 |
34 | /**
35 | *
36 | * To update Gradle, edit the wrapper file at path:
37 | * ./gradle/wrapper/gradle-wrapper.properties
38 | */
39 | object Gradle {
40 | const val runningVersion: String = "5.1.1"
41 |
42 | const val currentVersion: String = "5.5.1"
43 |
44 | const val nightlyVersion: String = "5.7-20190805220111+0000"
45 |
46 | const val releaseCandidate: String = "5.6-rc-1"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/mobile/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
10 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | # Project-wide Gradle settings.
16 | # IDE (e.g. Android Studio) users:
17 | # Gradle settings configured through the IDE *will override*
18 | # any settings specified in this file.
19 | # For more details on how to configure your build environment visit
20 | # http://www.gradle.org/docs/current/userguide/build_environment.html
21 | # Specifies the JVM arguments used for the daemon process.
22 | # The setting is particularly useful for tweaking memory settings.
23 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
24 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
25 | # When configured, Gradle will run in incubating parallel mode.
26 | # This option should only be used with decoupled projects. More details, visit
27 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
28 | # org.gradle.parallel=true
29 | org.gradle.jvmargs=-Xmx8192m -Dfile.encoding=UTF-8
30 | android.enableBuildCache=true
31 | org.gradle.caching=true
32 | android.useAndroidX=true
33 | android.enableJetifier=true
34 | kotlin.code.style=official
35 | -Dsonar.host.url=http://localhost:9000/
--------------------------------------------------------------------------------
/mobile/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/mobile/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/mobile/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jun 08 20:01:07 EET 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/mobile/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/mobile/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/things/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 |
--------------------------------------------------------------------------------
/things/Readme.md:
--------------------------------------------------------------------------------
1 | ## Android Things Application
2 |
3 | Embedded App is simple as mentioned before. For optional part of speech recognation you can follow below article. Also you could make your own models.
4 |
5 | ### Okey Things
6 | Thanks Nilhcem for showing us how to add speech recognition to Android Things devices.
7 | **Solution #3: The “Open Source” way** used in this project. For more information click [link](http://nilhcem.com/android-things/control-your-devices-through-voice-with-usb-audio-support)
8 |
--------------------------------------------------------------------------------
/things/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/things/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'kotlin-kapt'
5 |
6 | android {
7 | compileSdkVersion 28
8 | defaultConfig {
9 | applicationId "com.mbakgun.things"
10 | minSdkVersion 27
11 | targetSdkVersion 28
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | lintOptions {
22 | disable('AllowBackup', 'GoogleAppIndexingWarning', 'MissingApplicationIcon')
23 | }
24 | android {
25 | compileOptions {
26 | sourceCompatibility 1.8
27 | targetCompatibility 1.8
28 | }
29 | }
30 | }
31 |
32 | dependencies {
33 | //android
34 | compileOnly Libs.androidthings
35 | implementation Libs.lifecycle_extensions
36 | implementation Libs.kotlin_stdlib_jdk7
37 | implementation Libs.room_runtime
38 | kapt Libs.room_compiler
39 | implementation Libs.lifecycle_viewmodel_ktx
40 | implementation Libs.kotlinx_coroutines_core
41 | implementation Libs.kotlinx_coroutines_android
42 | api Libs.play_services_nearby
43 |
44 | //Serial Connection
45 | implementation Libs.usbserial
46 |
47 | //dagger
48 | kapt Libs.dagger_compiler
49 | kapt Libs.dagger_android_processor
50 | implementation Libs.dagger_android_support
51 |
52 | //Gson
53 | implementation Libs.gson
54 |
55 | // Speech Recognation
56 | implementation(name: 'tts', ext: 'aar')
57 | implementation(name: 'models', ext: 'aar')
58 | }
59 |
--------------------------------------------------------------------------------
/things/app/libs/models.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/things/app/libs/models.aar
--------------------------------------------------------------------------------
/things/app/libs/tts.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/things/app/libs/tts.aar
--------------------------------------------------------------------------------
/things/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/things/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/App.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things
2 |
3 | import android.app.Application
4 | import com.mbakgun.things.di.components.DaggerAppComponent
5 | import dagger.android.AndroidInjector
6 | import dagger.android.DispatchingAndroidInjector
7 | import dagger.android.HasAndroidInjector
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Created by burakakgun on 8.06.2019.
12 | */
13 | class App : Application(), HasAndroidInjector {
14 |
15 | @Inject
16 | lateinit var androidInjector: DispatchingAndroidInjector
17 |
18 | override fun onCreate() {
19 | super.onCreate()
20 |
21 | DaggerAppComponent
22 | .builder()
23 | .application(this)
24 | .build()
25 | .inject(this)
26 | }
27 |
28 | override fun androidInjector(): AndroidInjector = androidInjector
29 | }
30 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/data/IrDao.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.data
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Delete
5 | import androidx.room.Insert
6 | import androidx.room.Query
7 | import androidx.room.Update
8 |
9 | /**
10 | * Created by burakakgun on 8.06.2019.
11 | */
12 |
13 | @Dao
14 | interface IrDao {
15 |
16 | @Insert
17 | fun insert(irData: IrData)
18 |
19 | @Delete
20 | fun delete(irData: IrData)
21 |
22 | @Update
23 | fun update(irData: IrData)
24 |
25 | @Query("SELECT * FROM IrRecords where name like :speech LIMIT 1")
26 | fun getByName(speech: String): IrData?
27 |
28 | @get:Query("SELECT * FROM IrRecords")
29 | val getAll: List
30 | }
31 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/data/IrData.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.data
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 |
6 | /**
7 | * Created by burakakgun on 8.06.2019.
8 | */
9 | @Entity(tableName = "IrRecords")
10 | data class IrData(@PrimaryKey(autoGenerate = true) var id: Int = 0, var name: String, var hexCode: String)
11 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/data/IrDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.data
2 |
3 | import androidx.room.Database
4 | import androidx.room.RoomDatabase
5 |
6 | /**
7 | * Created by burakakgun on 8.06.2019.
8 | */
9 | @Database(entities = [IrData::class], version = 1, exportSchema = false)
10 | abstract class IrDatabase : RoomDatabase() {
11 |
12 | abstract fun getIrDao(): IrDao
13 | }
14 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/data/NearbyMessage.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.data
2 |
3 | /**
4 | * Created by burakakgun on 9.06.2019.
5 | */
6 |
7 | enum class NearbyType {
8 | UPDATE, DELETE, GET_ALL, MESSAGE
9 | }
10 |
11 | data class NearbyMessage(val nearbyType: NearbyType, val value: String)
12 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/di/components/AppComponent.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.di.components
2 |
3 | import com.mbakgun.things.App
4 | import com.mbakgun.things.di.modules.ActivityInjectorsModule
5 | import com.mbakgun.things.di.modules.AppModule
6 | import dagger.BindsInstance
7 | import dagger.Component
8 | import dagger.android.support.AndroidSupportInjectionModule
9 | import javax.inject.Singleton
10 |
11 | /**
12 | * Created by burakakgun on 8.06.2019.
13 | */
14 | @Singleton
15 | @Component(
16 | modules = [AndroidSupportInjectionModule::class,
17 | ActivityInjectorsModule::class,
18 | AppModule::class]
19 | )
20 | @SuppressWarnings("unchecked")
21 | interface AppComponent {
22 |
23 | @Component.Builder
24 | interface Builder {
25 | @BindsInstance
26 | fun application(application: App): Builder
27 |
28 | fun build(): AppComponent
29 | }
30 |
31 | fun inject(app: App)
32 | }
33 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/di/modules/ActivityInjectorsModule.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.di.modules
2 |
3 | import com.mbakgun.things.ui.MainActivity
4 | import dagger.Module
5 | import dagger.android.ContributesAndroidInjector
6 |
7 | /**
8 | * Created by burakakgun on 8.06.2019.
9 | */
10 | @Module
11 | abstract class ActivityInjectorsModule {
12 |
13 | @ContributesAndroidInjector
14 | abstract fun mainActivityInjector(): MainActivity
15 | }
16 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/di/modules/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.di.modules
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import androidx.room.Room
6 | import com.mbakgun.things.App
7 | import com.mbakgun.things.data.IrDao
8 | import com.mbakgun.things.data.IrDatabase
9 | import dagger.Module
10 | import dagger.Provides
11 | import javax.inject.Singleton
12 |
13 | /**
14 | * Created by burakakgun on 8.06.2019.
15 | */
16 | @Module
17 | class AppModule {
18 |
19 | @Provides
20 | @Singleton
21 | fun provideApplication(app: App): Application = app
22 |
23 | @Provides
24 | @Singleton
25 | fun provideApplicationContext(app: App): Context = app.applicationContext
26 |
27 | @Singleton
28 | @Provides
29 | fun provideDb(app: Application): IrDatabase {
30 | return Room
31 | .databaseBuilder(app, IrDatabase::class.java, "irDbThings.db")
32 | .fallbackToDestructiveMigration()
33 | .build()
34 | }
35 |
36 | @Singleton
37 | @Provides
38 | fun provideIrDao(db: IrDatabase): IrDao {
39 | return db.getIrDao()
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/ui/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.ui
2 |
3 | import android.os.Bundle
4 | import com.google.gson.Gson
5 | import com.mbakgun.things.data.NearbyMessage
6 | import com.mbakgun.things.data.NearbyType
7 | import com.mbakgun.things.util.NearbyCommunication
8 | import com.mbakgun.things.util.PocketSphinx
9 | import com.mbakgun.things.util.SerialCommunication
10 | import dagger.android.DaggerActivity
11 | import javax.inject.Inject
12 |
13 | class MainActivity : DaggerActivity() {
14 | @Inject
15 | lateinit var serialCommunication: SerialCommunication
16 |
17 | @Inject
18 | lateinit var nearbyCommunication: NearbyCommunication
19 |
20 | @Inject
21 | lateinit var speechRecognizer: PocketSphinx
22 |
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 | super.onCreate(savedInstanceState)
25 | serialCommunication.initSerialConnectionOverUSB()
26 | speechRecognizer.runRecognizerSetup()
27 | }
28 |
29 | fun onSerialDataReceived(data: String) =
30 | nearbyCommunication.sendMessage(
31 | Gson().toJson(NearbyMessage(NearbyType.MESSAGE, data))
32 | )
33 |
34 | fun onNearByDeviceRequestedSerialCommand(data: String) = serialCommunication.sendSerialData(data)
35 |
36 | fun onTextRecognized(recognizedText: String) = serialCommunication.sendVoiceData(recognizedText)
37 |
38 | override fun onResume() {
39 | super.onResume()
40 | nearbyCommunication.connect()
41 | serialCommunication.startUsbConnection()
42 | }
43 |
44 | override fun onStop() {
45 | super.onStop()
46 | serialCommunication.stopUsbConnection()
47 | nearbyCommunication.disconnect()
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/util/NearbyCommunication.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.util
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import androidx.annotation.Nullable
6 | import com.google.android.gms.common.api.GoogleApiClient
7 | import com.google.android.gms.nearby.Nearby
8 | import com.google.android.gms.nearby.connection.AdvertisingOptions
9 | import com.google.android.gms.nearby.connection.ConnectionInfo
10 | import com.google.android.gms.nearby.connection.ConnectionLifecycleCallback
11 | import com.google.android.gms.nearby.connection.ConnectionResolution
12 | import com.google.android.gms.nearby.connection.Payload
13 | import com.google.android.gms.nearby.connection.PayloadCallback
14 | import com.google.android.gms.nearby.connection.PayloadTransferUpdate
15 | import com.google.android.gms.nearby.connection.Strategy
16 | import com.google.gson.Gson
17 | import com.mbakgun.things.R
18 | import com.mbakgun.things.data.IrDao
19 | import com.mbakgun.things.data.IrData
20 | import com.mbakgun.things.data.NearbyMessage
21 | import com.mbakgun.things.data.NearbyType
22 | import com.mbakgun.things.ui.MainActivity
23 | import kotlinx.coroutines.GlobalScope
24 | import kotlinx.coroutines.launch
25 | import java.nio.charset.Charset
26 | import javax.inject.Inject
27 |
28 | /**
29 | * Created by burakakgun on 8.06.2019.
30 | */
31 | @Suppress("DEPRECATION")
32 | class NearbyCommunication @Inject constructor(private val activity: MainActivity, private val irDao: IrDao) {
33 | lateinit var mGoogleApiClient: GoogleApiClient
34 | val mRemotePeerEndpoints = mutableListOf()
35 |
36 | companion object {
37 | private const val TAG = "NearbyCommunication"
38 | }
39 |
40 | init {
41 | mGoogleApiClient = GoogleApiClient.Builder(activity)
42 | .addConnectionCallbacks(object : GoogleApiClient.ConnectionCallbacks {
43 | override fun onConnected(@Nullable bundle: Bundle?) {
44 | Log.d(TAG, "onConnected: advertises on the network as the host")
45 | startAdvertising()
46 | }
47 |
48 | override fun onConnectionSuspended(i: Int) {
49 | Log.d(TAG, "onConnectionSuspended: $i")
50 | mGoogleApiClient.reconnect()
51 | }
52 | })
53 | .addOnConnectionFailedListener { connectionResult -> Log.d(TAG, "onConnectionFailed: $connectionResult") }
54 | .addApi(Nearby.CONNECTIONS_API)
55 | .build()
56 | }
57 |
58 | fun connect() {
59 | if (mGoogleApiClient.isConnected.not()) mGoogleApiClient.connect()
60 | }
61 |
62 | fun disconnect() {
63 | if (mGoogleApiClient.isConnected()) {
64 | Nearby.Connections.stopAdvertising(mGoogleApiClient)
65 | if (mRemotePeerEndpoints.isNotEmpty()) {
66 | Nearby.Connections.sendPayload(
67 | mGoogleApiClient,
68 | mRemotePeerEndpoints,
69 | Payload.fromBytes("Shutting down host".toByteArray())
70 | )
71 | Nearby.Connections.stopAllEndpoints(mGoogleApiClient)
72 | mRemotePeerEndpoints.clear()
73 | }
74 |
75 | mGoogleApiClient.disconnect()
76 | }
77 | }
78 |
79 | fun sendMessage(message: String) {
80 | Log.d(TAG, "About to send message: $message")
81 | Nearby.Connections.sendPayload(
82 | mGoogleApiClient,
83 | mRemotePeerEndpoints,
84 | Payload.fromBytes(message.toByteArray(Charset.forName("UTF-8")))
85 | )
86 | }
87 |
88 | private fun startAdvertising() = Nearby.Connections
89 | .startAdvertising(
90 | mGoogleApiClient, null, activity.getString(R.string.id), object : ConnectionLifecycleCallback() {
91 | override fun onConnectionInitiated(endpointId: String, connectionInfo: ConnectionInfo) {
92 | Log.d(TAG, "onConnectionInitiated. Token: " + connectionInfo.authenticationToken)
93 | Nearby.Connections.acceptConnection(mGoogleApiClient, endpointId, object : PayloadCallback() {
94 | override fun onPayloadTransferUpdate(p0: String, p1: PayloadTransferUpdate) = Unit
95 |
96 | override fun onPayloadReceived(endpointId: String, payload: Payload) {
97 | String(payload.asBytes()!!).apply {
98 | Log.d(TAG, "onPayloadReceived: $this")
99 | val message = Gson().fromJson(this, NearbyMessage::class.java)
100 | when (message.nearbyType) {
101 | NearbyType.UPDATE -> {
102 | val irData = Gson().fromJson(message.value, IrData::class.java)
103 | GlobalScope.launch {
104 | irDao.update(irData)
105 | sendMessage(Gson().toJson(NearbyMessage(NearbyType.MESSAGE, "Updated")))
106 | }
107 | }
108 | NearbyType.DELETE -> {
109 | val irData = Gson().fromJson(message.value, IrData::class.java)
110 | GlobalScope.launch {
111 | irDao.delete(irData)
112 | sendMessage(Gson().toJson(NearbyMessage(NearbyType.MESSAGE, "Deleted")))
113 | }
114 | }
115 | NearbyType.GET_ALL -> {
116 | GlobalScope.launch {
117 | sendMessage(
118 | Gson().toJson(
119 | NearbyMessage(
120 | NearbyType.GET_ALL,
121 | Gson().toJson(irDao.getAll)
122 | )
123 | )
124 | )
125 | }
126 | }
127 | NearbyType.MESSAGE -> activity.onNearByDeviceRequestedSerialCommand(message.value)
128 | }
129 | }
130 | }
131 | })
132 | }
133 |
134 | override fun onConnectionResult(endpointId: String, resolution: ConnectionResolution) {
135 | Log.d(TAG, "onConnectionResult")
136 | if (resolution.status.isSuccess) {
137 | if (!mRemotePeerEndpoints.contains(endpointId)) {
138 | mRemotePeerEndpoints.add(endpointId)
139 | }
140 | Log.d(TAG, "Connected! (endpointId=$endpointId)")
141 | } else {
142 | Log.w(TAG, "Connection to " + endpointId + " failed. Code: " + resolution.status.statusCode)
143 | }
144 | }
145 |
146 | override fun onDisconnected(endpointId: String) {
147 | Log.i(TAG, "onDisconnected: $endpointId")
148 | }
149 | },
150 | AdvertisingOptions(Strategy.P2P_STAR)
151 | )
152 | .setResultCallback { result ->
153 | Log.d(TAG, "startAdvertising:onResult:$result")
154 | if (result.status.isSuccess) {
155 | Log.d(TAG, "Advertising...")
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/util/PocketSphinx.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.util
2 |
3 | import android.util.Log
4 | import com.mbakgun.things.ui.MainActivity
5 | import edu.cmu.pocketsphinx.Assets
6 | import edu.cmu.pocketsphinx.Hypothesis
7 | import edu.cmu.pocketsphinx.RecognitionListener
8 | import edu.cmu.pocketsphinx.SpeechRecognizer
9 | import edu.cmu.pocketsphinx.SpeechRecognizerSetup
10 | import kotlinx.coroutines.Dispatchers
11 | import kotlinx.coroutines.GlobalScope
12 | import kotlinx.coroutines.launch
13 | import java.io.File
14 | import java.io.IOException
15 | import javax.inject.Inject
16 |
17 | class PocketSphinx @Inject constructor(
18 | private val activity: MainActivity
19 | ) : RecognitionListener {
20 |
21 | private var recognizer: SpeechRecognizer? = null
22 |
23 | override fun onBeginningOfSpeech() {
24 | Log.d(TAG, "onBeginningOfSpeech")
25 | }
26 |
27 | override fun onEndOfSpeech() {
28 | Log.d(TAG, "onEndOfSpeech")
29 |
30 | if (recognizer?.searchName != WAKEUP_SEARCH) {
31 | Log.i(TAG, "End of speech. Stop recognizer")
32 | recognizer?.stop()
33 | }
34 | }
35 |
36 | override fun onPartialResult(hypothesis: Hypothesis?) {
37 | if (hypothesis == null) {
38 | return
39 | }
40 | val text = hypothesis.hypstr
41 | if (text == ACTIVATION_KEYPHRASE) {
42 | Log.i(TAG, "Activation keyphrase detected during a partial result")
43 | recognizer?.stop()
44 | } else {
45 | Log.i(TAG, "On partial result: $text")
46 | }
47 | }
48 |
49 | override fun onResult(hypothesis: Hypothesis?) {
50 | if (hypothesis == null) {
51 | return
52 | }
53 | val text = hypothesis.hypstr
54 | Log.i(TAG, "On result: $text")
55 | if (ACTIVATION_KEYPHRASE == text) {
56 | startListeningToAction()
57 | } else {
58 | text?.apply {
59 | activity.onTextRecognized(this)
60 | }
61 | startListeningToActivationPhrase()
62 | }
63 | }
64 |
65 | override fun onError(e: Exception) {
66 | Log.e(TAG, "On error", e)
67 | }
68 |
69 | override fun onTimeout() {
70 | Log.i(TAG, "Timeout!")
71 | recognizer?.stop()
72 | startListeningToActivationPhrase()
73 | }
74 |
75 | fun runRecognizerSetup() {
76 | Log.d(TAG, "Recognizer setup")
77 | GlobalScope.launch(Dispatchers.IO) {
78 | try {
79 | val assets = Assets(activity)
80 | val assetDir = assets.syncAssets()
81 | setupRecognizer(assetDir)
82 | } catch (e: Exception) {
83 | Log.e(TAG, "Failed to initialize recognizer: ${e.localizedMessage}")
84 | }
85 | }
86 | }
87 |
88 | @Throws(IOException::class)
89 | private fun setupRecognizer(assetsDir: File) {
90 | recognizer = SpeechRecognizerSetup.defaultSetup()
91 | .setAcousticModel(File(assetsDir, "en-us-ptm"))
92 | .setDictionary(File(assetsDir, "cmudict-en-us.dict"))
93 | .recognizer
94 | recognizer?.addListener(this)
95 |
96 | // Custom recognizer
97 | recognizer?.addKeyphraseSearch(WAKEUP_SEARCH, ACTIVATION_KEYPHRASE)
98 | recognizer?.addNgramSearch(ACTION_SEARCH, File(assetsDir, "predefined.lm.bin"))
99 | startListeningToAction()
100 | }
101 |
102 | private fun startListeningToActivationPhrase() {
103 | Log.i(TAG, "Start listening for the \"ok things\" keyphrase")
104 | recognizer?.startListening(WAKEUP_SEARCH)
105 | }
106 |
107 | private fun startListeningToAction() {
108 | Log.i(TAG, "Start listening for some actions with a 10secs timeout")
109 | recognizer?.startListening(ACTION_SEARCH, 10000)
110 | }
111 |
112 | companion object {
113 | private val TAG = PocketSphinx::class.java.simpleName
114 | private const val ACTIVATION_KEYPHRASE = "ok things"
115 | private const val WAKEUP_SEARCH = "wakeup"
116 | private const val ACTION_SEARCH = "action"
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/things/app/src/main/java/com/mbakgun/things/util/SerialCommunication.kt:
--------------------------------------------------------------------------------
1 | package com.mbakgun.things.util
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.IntentFilter
7 | import android.hardware.usb.UsbDevice
8 | import android.hardware.usb.UsbDeviceConnection
9 | import android.hardware.usb.UsbManager
10 | import android.util.Log
11 | import android.util.Log.d
12 | import com.felhr.usbserial.UsbSerialDevice
13 | import com.felhr.usbserial.UsbSerialInterface
14 | import com.mbakgun.things.R
15 | import com.mbakgun.things.data.IrDao
16 | import com.mbakgun.things.data.IrData
17 | import com.mbakgun.things.ui.MainActivity
18 | import kotlinx.coroutines.Dispatchers
19 | import kotlinx.coroutines.GlobalScope
20 | import kotlinx.coroutines.launch
21 | import java.io.UnsupportedEncodingException
22 | import java.nio.charset.Charset
23 | import javax.inject.Inject
24 |
25 | /**
26 | * Created by burakakgun on 8.06.2019.
27 | */
28 | class SerialCommunication @Inject constructor(private val activity: MainActivity, private val irDao: IrDao) {
29 |
30 | private var connection: UsbDeviceConnection? = null
31 | private var serialDevice: UsbSerialDevice? = null
32 | private var buffer = ""
33 |
34 | private val usbManager by lazy {
35 | activity.getSystemService(UsbManager::class.java)
36 | }
37 |
38 | fun initSerialConnectionOverUSB() {
39 | val filter = IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED)
40 | activity.registerReceiver(usbDetachedReceiver, filter)
41 | }
42 |
43 | private val usbDetachedReceiver = object : BroadcastReceiver() {
44 | override fun onReceive(context: Context, intent: Intent) {
45 | val action = intent.action
46 | if (UsbManager.ACTION_USB_DEVICE_DETACHED == action) {
47 | val device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
48 | if (device != null && device.vendorId == USB_VENDOR_ID && device.productId == USB_PRODUCT_ID) {
49 | Log.i(TAG, "USB device detached")
50 | stopUsbConnection()
51 | }
52 | }
53 | }
54 | }
55 |
56 | fun startUsbConnection() {
57 | val connectedDevices = usbManager.deviceList
58 | if (connectedDevices.isNotEmpty()) {
59 | for (device in connectedDevices.values) {
60 | if (device.vendorId == USB_VENDOR_ID && device.productId == USB_PRODUCT_ID) {
61 | Log.i(TAG, "Device found: " + device.deviceName)
62 | startSerialConnection(device)
63 | return
64 | }
65 | }
66 | }
67 | Log.w(TAG, "Could not start USB connection - No devices found")
68 | }
69 |
70 | private fun startSerialConnection(device: UsbDevice) {
71 | Log.i(TAG, "Ready to open USB device connection")
72 | connection = usbManager.openDevice(device)
73 | serialDevice = UsbSerialDevice.createUsbSerialDevice(device, connection)
74 | if (serialDevice!!.open()) {
75 | with(serialDevice!!) {
76 | setBaudRate(BAUD_RATE)
77 | setDataBits(UsbSerialInterface.DATA_BITS_8)
78 | setStopBits(UsbSerialInterface.STOP_BITS_1)
79 | setParity(UsbSerialInterface.PARITY_NONE)
80 | setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF)
81 | read(callback)
82 | }
83 | Log.i(TAG, "Serial connection opened")
84 | } else {
85 | Log.w(TAG, "Cannot open serial connection")
86 | }
87 | }
88 |
89 | fun sendSerialData(value: String) {
90 | serialDevice?.write(value.toByteArray())
91 | }
92 |
93 | fun sendVoiceData(speech: String) {
94 | GlobalScope.launch(Dispatchers.IO) {
95 | val value = irDao.getByName(speech)
96 | value?.let {
97 | d("SerialCommunication", "speech sending:$speech")
98 | serialDevice?.write("send:${value.hexCode}".toByteArray())
99 | }
100 | }
101 | }
102 |
103 | fun stopUsbConnection() {
104 | activity.unregisterReceiver(usbDetachedReceiver)
105 | try {
106 | serialDevice?.close()
107 | connection?.close()
108 | } finally {
109 | serialDevice = null
110 | connection = null
111 | }
112 | }
113 |
114 | private val callback = UsbSerialInterface.UsbReadCallback { data ->
115 | try {
116 | val dataUtf8 = String(data, Charset.forName("UTF-8"))
117 | buffer += dataUtf8
118 | var index = 0
119 | while ({
120 | index = buffer.indexOf('\n')
121 | index
122 | }() != -1) {
123 | val dataStr = buffer.substring(0, index + 1).trim { it <= ' ' }
124 | buffer = if (buffer.length == index) "" else buffer.substring(index + 1)
125 |
126 | Log.i(TAG, "Serial data received: $data")
127 | if (dataStr.startsWith("saved")) {
128 | val irData =
129 | IrData(
130 | name = dataStr.substring(SUBSTRING_STARTS, dataStr.indexOf("-")),
131 | hexCode = dataStr.substring(dataStr.indexOf("-") + 1)
132 | )
133 | if (irData.hexCode != "FFFFFFFF") {
134 | // end of button push
135 | GlobalScope.launch {
136 | irDao.insert(irData)
137 | activity.onSerialDataReceived(activity.getString(R.string.saved))
138 | }
139 | } else {
140 | activity.onSerialDataReceived(activity.getString(R.string.try_again))
141 | }
142 | } else {
143 | activity.onSerialDataReceived(dataStr)
144 | }
145 | }
146 | } catch (e: UnsupportedEncodingException) {
147 | Log.e(TAG, "Error receiving USB data", e)
148 | }
149 | }
150 |
151 | companion object {
152 | const val TAG = "SerialCommunication"
153 | const val USB_VENDOR_ID = 6790
154 | const val USB_PRODUCT_ID = 29987
155 | const val BAUD_RATE = 9600
156 | const val SUBSTRING_STARTS = 6 // 'read:' and 'send:'
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/things/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | irremote things
3 | irremote
4 | Command saved
5 | Please try again
6 |
7 |
--------------------------------------------------------------------------------
/things/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/things/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.3.31'
5 | repositories {
6 | google()
7 | jcenter()
8 |
9 | }
10 | dependencies {
11 | classpath Libs.com_android_tools_build_gradle
12 | classpath Libs.kotlin_gradle_plugin
13 | }
14 | }
15 |
16 | plugins {
17 | id("de.fayard.buildSrcVersions") version "0.3.2"
18 | }
19 |
20 | allprojects {
21 | repositories {
22 | google()
23 | jcenter()
24 | maven { url "https://jitpack.io" }
25 | flatDir { dirs 'libs' }
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/things/buildSrc/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .gradle/
3 | build/
4 |
--------------------------------------------------------------------------------
/things/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 | repositories {
5 | jcenter()
6 | }
7 |
--------------------------------------------------------------------------------
/things/buildSrc/src/main/kotlin/Libs.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Generated by https://github.com/jmfayard/buildSrcVersions
3 | *
4 | * Update this file with
5 | * `$ ./gradlew buildSrcVersions` */
6 | object Libs {
7 | /**
8 | * https://developer.android.com/topic/libraries/architecture/index.html */
9 | const val lifecycle_extensions: String = "androidx.lifecycle:lifecycle-extensions:" +
10 | Versions.androidx_lifecycle
11 |
12 | /**
13 | * http://developer.android.com/tools/extras/support-library.html */
14 | const val lifecycle_viewmodel_ktx: String = "androidx.lifecycle:lifecycle-viewmodel-ktx:" +
15 | Versions.androidx_lifecycle
16 |
17 | /**
18 | * https://developer.android.com/topic/libraries/architecture/index.html */
19 | const val room_compiler: String = "androidx.room:room-compiler:" + Versions.androidx_room
20 |
21 | /**
22 | * https://developer.android.com/topic/libraries/architecture/index.html */
23 | const val room_runtime: String = "androidx.room:room-runtime:" + Versions.androidx_room
24 |
25 | /**
26 | * https://developer.android.com/studio */
27 | const val com_android_tools_build_gradle: String = "com.android.tools.build:gradle:" +
28 | Versions.com_android_tools_build_gradle
29 |
30 | /**
31 | * https://developer.android.com/studio */
32 | const val lint_gradle: String = "com.android.tools.lint:lint-gradle:" + Versions.lint_gradle
33 |
34 | /**
35 | * https://github.com/felHR85/UsbSerial */
36 | const val usbserial: String = "com.github.felHR85:UsbSerial:" + Versions.usbserial
37 |
38 | const val play_services_nearby: String = "com.google.android.gms:play-services-nearby:" +
39 | Versions.play_services_nearby
40 |
41 | const val androidthings: String = "com.google.android.things:androidthings:" +
42 | Versions.androidthings
43 |
44 | /**
45 | * https://github.com/google/gson */
46 | const val gson: String = "com.google.code.gson:gson:" + Versions.gson
47 |
48 | /**
49 | * https://github.com/google/dagger */
50 | const val dagger_android_processor: String = "com.google.dagger:dagger-android-processor:" +
51 | Versions.com_google_dagger
52 |
53 | /**
54 | * https://github.com/google/dagger */
55 | const val dagger_android_support: String = "com.google.dagger:dagger-android-support:" +
56 | Versions.com_google_dagger
57 |
58 | /**
59 | * https://github.com/google/dagger */
60 | const val dagger_compiler: String = "com.google.dagger:dagger-compiler:" +
61 | Versions.com_google_dagger
62 |
63 | const val de_fayard_buildsrcversions_gradle_plugin: String =
64 | "de.fayard.buildSrcVersions:de.fayard.buildSrcVersions.gradle.plugin:" +
65 | Versions.de_fayard_buildsrcversions_gradle_plugin
66 |
67 | /**
68 | * https://kotlinlang.org/ */
69 | const val kotlin_android_extensions_runtime: String =
70 | "org.jetbrains.kotlin:kotlin-android-extensions-runtime:" +
71 | Versions.org_jetbrains_kotlin
72 |
73 | /**
74 | * https://kotlinlang.org/ */
75 | const val kotlin_android_extensions: String =
76 | "org.jetbrains.kotlin:kotlin-android-extensions:" + Versions.org_jetbrains_kotlin
77 |
78 | /**
79 | * https://kotlinlang.org/ */
80 | const val kotlin_annotation_processing_gradle: String =
81 | "org.jetbrains.kotlin:kotlin-annotation-processing-gradle:" +
82 | Versions.org_jetbrains_kotlin
83 |
84 | /**
85 | * https://kotlinlang.org/ */
86 | const val kotlin_gradle_plugin: String = "org.jetbrains.kotlin:kotlin-gradle-plugin:" +
87 | Versions.org_jetbrains_kotlin
88 |
89 | /**
90 | * https://kotlinlang.org/ */
91 | const val kotlin_stdlib_jdk7: String = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:" +
92 | Versions.org_jetbrains_kotlin
93 |
94 | /**
95 | * https://github.com/Kotlin/kotlinx.coroutines */
96 | const val kotlinx_coroutines_android: String =
97 | "org.jetbrains.kotlinx:kotlinx-coroutines-android:" + Versions.org_jetbrains_kotlinx
98 |
99 | /**
100 | * https://github.com/Kotlin/kotlinx.coroutines */
101 | const val kotlinx_coroutines_core: String = "org.jetbrains.kotlinx:kotlinx-coroutines-core:" +
102 | Versions.org_jetbrains_kotlinx
103 | }
104 |
--------------------------------------------------------------------------------
/things/buildSrc/src/main/kotlin/Versions.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * Find which updates are available by running
3 | * `$ ./gradlew buildSrcVersions`
4 | * This will only update the comments.
5 | *
6 | * YOU are responsible for updating manually the dependency version. */
7 | object Versions {
8 | const val androidx_lifecycle: String = "2.0.0"
9 |
10 | const val androidx_room: String = "2.1.0"
11 |
12 | const val com_android_tools_build_gradle: String = "3.4.2"
13 |
14 | const val lint_gradle: String = "26.4.2"
15 |
16 | const val usbserial: String = "6.1.0"
17 |
18 | const val play_services_nearby: String = "17.0.0"
19 |
20 | const val androidthings: String = "1.0"
21 |
22 | const val gson: String = "2.8.5"
23 |
24 | const val com_google_dagger: String = "2.24"
25 |
26 | const val de_fayard_buildsrcversions_gradle_plugin: String = "0.3.2"
27 |
28 | const val org_jetbrains_kotlin: String = "1.3.41"
29 |
30 | const val org_jetbrains_kotlinx: String = "1.2.1"
31 |
32 | /**
33 | *
34 | * To update Gradle, edit the wrapper file at path:
35 | * ./gradle/wrapper/gradle-wrapper.properties
36 | */
37 | object Gradle {
38 | const val runningVersion: String = "5.1.1"
39 |
40 | const val currentVersion: String = "5.5.1"
41 |
42 | const val nightlyVersion: String = "5.7-20190805220111+0000"
43 |
44 | const val releaseCandidate: String = "5.6-rc-1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/things/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 | # Project-wide Gradle settings.
20 |
21 | # IDE (e.g. Android Studio) users:
22 | # Gradle settings configured through the IDE *will override*
23 | # any settings specified in this file.
24 |
25 | # For more details on how to configure your build environment visit
26 | # http://www.gradle.org/docs/current/userguide/build_environment.html
27 |
28 | # Specifies the JVM arguments used for the daemon process.
29 | # The setting is particularly useful for tweaking memory settings.
30 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
31 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
32 |
33 | # When configured, Gradle will run in incubating parallel mode.
34 | # This option should only be used with decoupled projects. More details, visit
35 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
36 | # org.gradle.parallel=true
37 |
38 |
39 | org.gradle.jvmargs=-Xmx8192m -Dfile.encoding=UTF-8
40 | android.enableBuildCache=true
41 | org.gradle.caching=true
42 | android.useAndroidX=true
43 | android.enableJetifier=true
44 | kotlin.code.style=official
45 | -Dsonar.host.url=http://localhost:9000/
--------------------------------------------------------------------------------
/things/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbakgun/Android-Things-IR-Remote-Hacker/2a79a6e540618ca3789b5f506a98639c8e0d1e61/things/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/things/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jun 08 14:37:36 EET 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/things/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/things/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------