diff --git a/app/build.gradle b/app/build.gradle index 47424e1..d741207 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,8 +26,8 @@ android { minSdkVersion 21 targetSdkVersion 27 - versionCode 20 - versionName "2.4.3" + versionCode 21 + versionName "2.4.4" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" javaCompileOptions { @@ -134,15 +134,16 @@ android { project.ext { appcompat_version = '27.1.1' aac_version = '1.0.0' + room_version = '1.0.0' ioio_version = '5.07' gms_maps_version = '15.0.1' gms_location_version = '15.0.1' firebase_core_version = '15.0.2' firebase_crash_version = '15.0.2' - firebase_perf_version = '15.1.0' + firebase_perf_version = '15.2.0' firebase_crashlytics_version = '2.9.1' retrofit_version = '2.4.0' - anko_version = '0.10.4' + anko_version = '0.10.5' kodein_version = '4.1.0' leak_version = '1.5.4' runner_version = '1.0.1' @@ -223,11 +224,11 @@ dependencies { implementation "io.reactivex.rxjava2:rxkotlin:$rxkotlin_version" // Room - kapt "android.arch.persistence.room:compiler:$aac_version" - implementation "android.arch.persistence.room:runtime:$aac_version" - implementation "android.arch.lifecycle:common-java8:$aac_version" - implementation "android.arch.persistence.room:rxjava2:$aac_version" - testImplementation "android.arch.persistence.room:testing:$aac_version" + kapt "android.arch.persistence.room:compiler:$room_version" + implementation "android.arch.persistence.room:runtime:$room_version" + implementation "android.arch.lifecycle:common-java8:$room_version" + implementation "android.arch.persistence.room:rxjava2:$room_version" + testImplementation "android.arch.persistence.room:testing:$room_version" // LiveData implementation "android.arch.lifecycle:extensions:$aac_lifecycle_version" @@ -236,6 +237,8 @@ dependencies { // Anko implementation "org.jetbrains.anko:anko-commons:$anko_version" implementation "org.jetbrains.anko:anko-design:$anko_version" + implementation "org.jetbrains.anko:anko-appcompat-v7:$anko_version" + implementation "org.jetbrains.anko:anko-sdk25:$anko_version" // OpenCSV implementation "com.opencsv:opencsv:$opencsv_version" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a413ebb..b9e13f9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,7 +52,7 @@ + android:value="${fabric_api_key}"/> 1) { diff --git a/app/src/main/java/science/apolline/view/activity/SettingsActivity.kt b/app/src/main/java/science/apolline/view/activity/SettingsActivity.kt index a34373b..3a503c9 100644 --- a/app/src/main/java/science/apolline/view/activity/SettingsActivity.kt +++ b/app/src/main/java/science/apolline/view/activity/SettingsActivity.kt @@ -79,7 +79,8 @@ class SettingsActivity : AppCompatPreferenceActivity() { // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. - bindPreferenceSummaryToValue(findPreference("device_name"), STRING) + bindPreferenceSummaryToValue(findPreference("sensor_name"), STRING) + bindPreferenceSummaryToValue(findPreference("sensor_mac_address"), STRING) bindPreferenceSummaryToValue(findPreference("device_uuid"), STRING) // bindPreferenceSummaryToValue(findPreference("example_list")) } diff --git a/app/src/main/java/science/apolline/view/activity/SplashScreen.kt b/app/src/main/java/science/apolline/view/activity/SplashScreen.kt index ef753a0..e5e4e83 100644 --- a/app/src/main/java/science/apolline/view/activity/SplashScreen.kt +++ b/app/src/main/java/science/apolline/view/activity/SplashScreen.kt @@ -12,6 +12,7 @@ import android.graphics.PorterDuff import android.os.Bundle import android.os.CountDownTimer import android.preference.PreferenceManager +import android.support.annotation.IdRes import android.support.v4.content.ContextCompat import science.apolline.R import kotlinx.android.synthetic.main.content_splash_screen.* @@ -19,6 +20,7 @@ import com.szugyi.circlemenu.view.CircleImageView import android.widget.Toast import android.view.View import android.view.animation.RotateAnimation +import android.widget.EditText import com.fondesa.kpermissions.extension.listeners import com.github.ivbaranov.rxbluetooth.RxBluetooth import com.github.salomonbrys.kodein.instance @@ -42,9 +44,11 @@ class SplashScreen : RootActivity(), AnkoLogger { private lateinit var mDisposable: CompositeDisposable private var mDetectedDevices = hashMapOf() private lateinit var mPrefs: SharedPreferences - private var EXTRA_DEVICE_ADDRESS: String = "fffffff-ffff-ffff-ffff-ffffffffffff" private var mIsLocationPermissionGranted = false + private var EXTRA_DEVICE_ADDRESS: String = "fffffff-ffff-ffff-ffff-ffffffffffff" + private var SENSOR_MAC_ADDRESS: String = "ff-ff-ff-ff-ff-ff" + private val mRequestLocationPermission by lazy { permissionsBuilder(Manifest.permission.ACCESS_FINE_LOCATION) .build() @@ -54,10 +58,11 @@ class SplashScreen : RootActivity(), AnkoLogger { super.onCreate(savedInstanceState) mPrefs = PreferenceManager.getDefaultSharedPreferences(applicationContext) EXTRA_DEVICE_ADDRESS = mPrefs.getString("device_uuid", "ffffffff-ffff-ffff-ffff-ffffffffffff") + SENSOR_MAC_ADDRESS = mPrefs.getString("sensor_mac_address", "ff-ff-ff-ff-ff-ff") mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter() mDisposable = CompositeDisposable() - mIsLocationPermissionGranted = CheckUtility.isWifiNetworkConnected(applicationContext) + mIsLocationPermissionGranted = CheckUtility.isWifiNetworkConnected(this) setContentView(R.layout.activity_splash_screen) ripple_scan_view.clipToOutline = true @@ -117,10 +122,12 @@ class SplashScreen : RootActivity(), AnkoLogger { .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.computation()) .subscribe { device -> - addDeviceToCircleView(device) + addDeviceToCircleView(device, isBounded = isBoundedDevice(device)) } ) + + mDisposable.add(mRxBluetoothClient.observeBondState() .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.computation()) @@ -136,37 +143,39 @@ class SplashScreen : RootActivity(), AnkoLogger { info("device bound state BOND_BONDED: " + event.bluetoothDevice.name) if (event.bluetoothDevice.name.toString().toLowerCase().contains(regex = "^ioio.".toRegex())) { + + val deviceMacAddress = event.bluetoothDevice!!.address.toString() val intent = Intent(this, MainActivity::class.java) - startActivity(intent) - finish() - } - } - else -> { + if (deviceMacAddress != SENSOR_MAC_ADDRESS) { + var sensorNameEditText: EditText? = null - } + alert { + title = "New sensor name" + customView { + sensorNameEditText = editText { + id = Id.alert_new_sensor + hint = "A-00" + padding = dip(20) + } + } - } - }) + yesButton { + val sensorName = sensorNameEditText!!.text.toString() + mPrefs.edit().putString("sensor_mac_address", deviceMacAddress) + .putString("sensor_name", sensorName) + .apply() + startActivity(intent) + finish() + } - mDisposable.add(mRxBluetoothClient.observeBondState() - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.computation()) - .subscribe { event -> - when (event.state) { - BluetoothDevice.BOND_NONE -> { - info("device bound state BOND_NONE: " + event.bluetoothDevice.name) - } - BluetoothDevice.BOND_BONDING -> { - info("device bound state BOND_BONDING: " + event.bluetoothDevice.name) - } - BluetoothDevice.BOND_BONDED -> { - info("device bound state BOND_BONDED: " + event.bluetoothDevice.name) + noButton { - if (event.bluetoothDevice.name.toString().toLowerCase().contains(regex = "^ioio.".toRegex())) { - val intent = Intent(this, MainActivity::class.java) - startActivity(intent) - finish() + } + + + }.show() + } } } @@ -176,7 +185,6 @@ class SplashScreen : RootActivity(), AnkoLogger { } }) - } override fun onStop() { @@ -210,28 +218,62 @@ class SplashScreen : RootActivity(), AnkoLogger { // if (circle_layout.tag != null) { val view = circle_layout.selectedItem if (view is CircleImageView) { - Toasty.info(applicationContext, "Default PIN code for IOIO sensor is: 4545", Toast.LENGTH_LONG, true).show() mBluetoothAdapter!!.cancelDiscovery() selected_device_name_textview.text = view.name val deviceName = view.name val device = mDetectedDevices[deviceName] val boundedDevices = mBluetoothAdapter!!.bondedDevices - if (boundedDevices.size > 0) { - if (boundedDevices.contains(device)) { - val intent = Intent(this, MainActivity::class.java) +// if (boundedDevices.size > 0) { + if (boundedDevices.contains(device)) { + val deviceMacAddress = device!!.address.toString() + val intent = Intent(this, MainActivity::class.java) + + if (deviceMacAddress != SENSOR_MAC_ADDRESS) { + var sensorNameEditText: EditText? = null + alert { + title = "New sensor name" + customView { + sensorNameEditText = editText { + id = Id.alert_new_sensor + hint = "A-00" + padding = dip(20) + } + } + + yesButton { + val sensorName = sensorNameEditText!!.text.toString() + mPrefs.edit().putString("sensor_mac_address", deviceMacAddress) + .putString("sensor_name", sensorName) + .apply() + startActivity(intent) + finish() + } + + noButton { + + } + + + }.show() + + } else { startActivity(intent) finish() } + + } else { + Toasty.info(applicationContext, "Default PIN code for IOIO sensor is: 4545", Toast.LENGTH_LONG, true).show() device!!.createBond() } + // } } } - private fun addDeviceToCircleView(device: BluetoothDevice?) { + private fun addDeviceToCircleView(device: BluetoothDevice?, isBounded: Boolean) { var isCompatible = false if (device != null) { @@ -251,45 +293,45 @@ class SplashScreen : RootActivity(), AnkoLogger { when (device.bluetoothClass.majorDeviceClass) { BluetoothClass.Device.Major.AUDIO_VIDEO -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_audio_video, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_audio_video, isCompatible, isBounded) } BluetoothClass.Device.Major.COMPUTER -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_computer, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_computer, isCompatible, isBounded) } BluetoothClass.Device.Major.HEALTH -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_health, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_health, isCompatible, isBounded) } BluetoothClass.Device.Major.IMAGING -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_imaging, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_imaging, isCompatible, isBounded) } BluetoothClass.Device.Major.MISC -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_misc, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_misc, isCompatible, isBounded) } BluetoothClass.Device.Major.NETWORKING -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_netwoking, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_netwoking, isCompatible, isBounded) } BluetoothClass.Device.Major.PERIPHERAL -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_peripheral, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_peripheral, isCompatible, isBounded) } BluetoothClass.Device.Major.TOY -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_toy, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_toy, isCompatible, isBounded) } BluetoothClass.Device.Major.PHONE -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_phone, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_phone, isCompatible, isBounded) } BluetoothClass.Device.Major.WEARABLE -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_wear, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_wear, isCompatible, isBounded) } else -> { - onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_uncategorized, isCompatible) + onAddClick(circle_layout, nameOrcode, R.drawable.ic_device_bluetooth_uncategorized, isCompatible, isBounded) } } @@ -298,6 +340,11 @@ class SplashScreen : RootActivity(), AnkoLogger { } + private fun isBoundedDevice(device: BluetoothDevice?): Boolean { + val boundedDevices = mBluetoothAdapter!!.bondedDevices + return boundedDevices.contains(device) + } + private fun initBoundedDevices() { val boundedDevices = mBluetoothAdapter!!.bondedDevices @@ -307,8 +354,7 @@ class SplashScreen : RootActivity(), AnkoLogger { if (boundedDevices.size > 0) { boundedDevices.forEach { device -> - - addDeviceToCircleView(device) + addDeviceToCircleView(device, isBounded = isBoundedDevice(device)) if (device.name.toString().toLowerCase().contains(regex = "^ioio.".toRegex())) { currentCompatibleSensor = device @@ -316,22 +362,22 @@ class SplashScreen : RootActivity(), AnkoLogger { } } - if (sensorCounter == 1) { - - mDisposable.add(mRxBluetoothClient.observeConnectDevice(currentCompatibleSensor, currentCompatibleSensor!!.uuids[0].uuid) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.computation()) - .subscribe { event -> - if (event.isConnected) { - val intent = Intent(this, MainActivity::class.java) - startActivity(intent) - finish() - } - }) - - } else { - info("There is multiple IOIO Paired sensors, please choose one") - } +// if (sensorCounter == 1) { +// +// mDisposable.add(mRxBluetoothClient.observeConnectDevice(currentCompatibleSensor, currentCompatibleSensor!!.uuids[0].uuid) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribeOn(Schedulers.computation()) +// .subscribe { event -> +// if (event.isConnected) { +// val intent = Intent(this, MainActivity::class.java) +// startActivity(intent) +// finish() +// } +// }) +// +// } else { +// info("There is multiple IOIO Paired sensors, please choose one") +// } } else { info("No bounded devices") @@ -339,12 +385,18 @@ class SplashScreen : RootActivity(), AnkoLogger { } - private fun onAddClick(view: View, name: String, drawableId: Int, compatible: Boolean) { + private fun onAddClick(view: View, name: String, drawableId: Int, compatible: Boolean, bounded: Boolean) { if (compatible) { val newMenu = CircleImageView(this) val currentDrawable = ContextCompat.getDrawable(this, drawableId) val willBeWhite = currentDrawable!!.constantState.newDrawable() - newMenu.setBackgroundResource(R.drawable.circle_menu_shape_item) + + if (bounded) { + newMenu.setBackgroundResource(R.drawable.circle_menu_shape_item_bounded) + } else { + newMenu.setBackgroundResource(R.drawable.circle_menu_shape_item) + } + willBeWhite.mutate().setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP) newMenu.setPadding(20, 20, 20, 20) newMenu.setImageDrawable(willBeWhite) @@ -370,6 +422,7 @@ class SplashScreen : RootActivity(), AnkoLogger { onAccepted { mIsLocationPermissionGranted = true Toasty.success(applicationContext, "ACCESS_FINE_LOCATION granted.", Toast.LENGTH_SHORT, true).show() +// checkBlueToothState() } onDenied { @@ -400,6 +453,7 @@ class SplashScreen : RootActivity(), AnkoLogger { noButton { request.detachAllListeners() } + }.show() } @@ -453,5 +507,10 @@ class SplashScreen : RootActivity(), AnkoLogger { private const val REQUEST_CODE_ENABLE_BLUETOOTH = 101 } + object Id { + @IdRes + val alert_new_sensor = View.generateViewId() + } + } diff --git a/app/src/main/res/drawable-land/circle_menu_shape_item_bounded.xml b/app/src/main/res/drawable-land/circle_menu_shape_item_bounded.xml new file mode 100644 index 0000000..b82b168 --- /dev/null +++ b/app/src/main/res/drawable-land/circle_menu_shape_item_bounded.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/circle_menu_shape_item_bounded.xml b/app/src/main/res/drawable/circle_menu_shape_item_bounded.xml new file mode 100644 index 0000000..4e9131b --- /dev/null +++ b/app/src/main/res/drawable/circle_menu_shape_item_bounded.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8db194e..d4e2812 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,8 +138,11 @@ 2 - Device name - Apolline00 + Sensor name + Apolline00 + + Sensor MAC Address + ff-ff-ff-ff-ff-ff Device UUID ffffffff-ffff-ffff-ffff-ffffffffffff diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml index ffbce75..62f6756 100644 --- a/app/src/main/res/xml/pref_general.xml +++ b/app/src/main/res/xml/pref_general.xml @@ -10,13 +10,18 @@ + android:title="@string/pref_title_sensor_name" /> + +