From 09b1be320cd263df015c634f36c75bf88ae6cad0 Mon Sep 17 00:00:00 2001 From: Isai Damier Date: Thu, 29 Apr 2021 16:40:19 -0400 Subject: [PATCH] refactor sample --- BluetoothLeChat/app/build.gradle | 20 +++++------ .../app/src/main/AndroidManifest.xml | 2 +- .../example/bluetoothlechat/MainActivity.kt | 2 +- .../bluetoothlechat/bluetooth/ChatServer.kt | 16 +++++++-- .../bluetoothlechat/bluetooth/Constants.kt | 5 ++- .../bluetooth/EnableBluetoothFragment.kt | 31 +++++++--------- .../bluetooth/LocationRequiredFragment.kt | 35 +++++-------------- .../chat/BluetoothChatFragment.kt | 8 ++--- .../chat/LocalMessageViewHolder.kt | 2 +- .../bluetoothlechat/chat/MessageAdapter.kt | 10 +++--- .../chat/RemoteMessageViewHolder.kt | 2 +- .../scan/DeviceScanFragment.kt | 9 +++-- .../scan/DeviceScanViewModel.kt | 9 +++-- .../scan/DeviceScanViewState.kt | 8 ++--- .../app/src/main/res/layout/activity_main.xml | 5 ++- .../res/layout/fragment_bluetooth_chat.xml | 21 ++++++----- .../main/res/layout/fragment_device_scan.xml | 21 ++++++----- .../res/layout/fragment_enable_bluetooth.xml | 7 ++-- .../res/layout/fragment_location_required.xml | 3 +- .../app/src/main/res/layout/item_device.xml | 2 -- .../app/src/main/res/values/strings.xml | 2 -- BluetoothLeChat/build.gradle | 8 ++--- 22 files changed, 105 insertions(+), 123 deletions(-) diff --git a/BluetoothLeChat/app/build.gradle b/BluetoothLeChat/app/build.gradle index fb7fcbee..2bd6c82f 100644 --- a/BluetoothLeChat/app/build.gradle +++ b/BluetoothLeChat/app/build.gradle @@ -1,11 +1,11 @@ /* - * Copyright 2020 Google LLC + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -54,13 +54,13 @@ android { dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.3.1' - implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha08' - implementation 'androidx.activity:activity-ktx:1.2.0-alpha08' + implementation 'androidx.core:core-ktx:1.3.2' + implementation 'androidx.fragment:fragment-ktx:1.3.3' + implementation 'androidx.activity:activity-ktx:1.3.0-alpha07' implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.1' - implementation 'androidx.recyclerview:recyclerview:1.1.0' - implementation "androidx.navigation:navigation-fragment-ktx:2.3.0" - implementation "androidx.navigation:navigation-ui-ktx:2.3.0" + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.recyclerview:recyclerview:1.2.0' + implementation "androidx.navigation:navigation-fragment-ktx:2.3.5" + implementation "androidx.navigation:navigation-ui-ktx:2.3.5" } \ No newline at end of file diff --git a/BluetoothLeChat/app/src/main/AndroidManifest.xml b/BluetoothLeChat/app/src/main/AndroidManifest.xml index 99596546..8a00a879 100644 --- a/BluetoothLeChat/app/src/main/AndroidManifest.xml +++ b/BluetoothLeChat/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ tag in the AndroidManifest.xml. // If the app is installed on an emulator without bluetooth then the app will crash @@ -248,7 +249,15 @@ object ChatServer { offset: Int, value: ByteArray? ) { - super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value) + super.onCharacteristicWriteRequest( + device, + requestId, + characteristic, + preparedWrite, + responseNeeded, + offset, + value + ) if (characteristic.uuid == MESSAGE_UUID) { gattServer?.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null) val message = value?.toString(Charsets.UTF_8) @@ -265,7 +274,10 @@ object ChatServer { super.onConnectionStateChange(gatt, status, newState) val isSuccess = status == BluetoothGatt.GATT_SUCCESS val isConnected = newState == BluetoothProfile.STATE_CONNECTED - Log.d(TAG, "onConnectionStateChange: Client $gatt success: $isSuccess connected: $isConnected") + Log.d( + TAG, + "onConnectionStateChange: Client $gatt success: $isSuccess connected: $isConnected" + ) // try to send a message to the other device as a test if (isSuccess && isConnected) { // discover services diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/Constants.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/Constants.kt index bf6f1a6e..95fba96f 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/Constants.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/Constants.kt @@ -15,6 +15,7 @@ */ package com.example.bluetoothlechat.bluetooth + import java.util.* /** @@ -25,7 +26,7 @@ import java.util.* * * Bluetooth requires a certain format for UUIDs associated with Services. * The official specification can be found here: - * [://www.bluetooth.org/en-us/specification/assigned-numbers/service-discovery][https] + * [https://www.bluetooth.org/en-us/specification/assigned-numbers/service-discovery] */ val SERVICE_UUID: UUID = UUID.fromString("0000b81d-0000-1000-8000-00805f9b34fb") @@ -38,5 +39,3 @@ val MESSAGE_UUID: UUID = UUID.fromString("7db3e235-3608-41f3-a03c-955fcbd2ea4b") * UUID to confirm device connection */ val CONFIRM_UUID: UUID = UUID.fromString("36d4dc5c-814b-4097-a5a6-b93b39085928") - -const val REQUEST_ENABLE_BT = 1 diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/EnableBluetoothFragment.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/EnableBluetoothFragment.kt index e19582a8..2546cf27 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/EnableBluetoothFragment.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/EnableBluetoothFragment.kt @@ -22,6 +22,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController @@ -31,6 +32,7 @@ import com.example.bluetoothlechat.databinding.FragmentEnableBluetoothBinding class EnableBluetoothFragment : Fragment() { private var _binding: FragmentEnableBluetoothBinding? = null + // This property is only valid between onCreateView and onDestroyView. private val binding get() = _binding!! @@ -42,6 +44,13 @@ class EnableBluetoothFragment : Fragment() { } } + private val startForResultEnableBluetooth = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == Activity.RESULT_OK) { + ChatServer.startServer(requireActivity().application) + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ChatServer.requestEnableBluetooth.observe(this, bluetoothEnableObserver) @@ -51,32 +60,16 @@ class EnableBluetoothFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { _binding = FragmentEnableBluetoothBinding.inflate(inflater, container, false) binding.errorAction.setOnClickListener { - // Prompt user to turn on Bluetooth (logic continues in onActivityResult()). + // Prompt user to turn on Bluetooth (logic continues in registerForActivityResult()). val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) - startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT) + startForResultEnableBluetooth.launch(enableBtIntent) } return binding.root } - override fun onActivityResult( - requestCode: Int, - resultCode: Int, - data: Intent? - ) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - REQUEST_ENABLE_BT -> { - if (resultCode == Activity.RESULT_OK) { - ChatServer.startServer(requireActivity().application) - } - super.onActivityResult(requestCode, resultCode, data) - } - else -> super.onActivityResult(requestCode, resultCode, data) - } - } } \ No newline at end of file diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/LocationRequiredFragment.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/LocationRequiredFragment.kt index ad48c46b..ec9e2735 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/LocationRequiredFragment.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/bluetooth/LocationRequiredFragment.kt @@ -18,19 +18,16 @@ package com.example.bluetoothlechat.bluetooth import android.Manifest import android.content.pm.PackageManager import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.example.bluetoothlechat.R import com.example.bluetoothlechat.databinding.FragmentLocationRequiredBinding -private const val TAG = "LocationRequiredFrag" -private const val LOCATION_REQUEST_CODE = 0 - // Fragment responsible for checking if the app has the ACCESS_FINE_LOCATION permission. // This permission is required when using the BLE APIs so the user must grant permission // to the app before viewing the BluetoothChatFragment or DeviceListFragment @@ -44,7 +41,7 @@ class LocationRequiredFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { _binding = FragmentLocationRequiredBinding.inflate(inflater, container, false) // hide the error messages while checking the permissions @@ -64,25 +61,14 @@ class LocationRequiredFragment : Fragment() { checkLocationPermission() } - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - Log.d(TAG, "onRequestPermissionsResult: ") - when(requestCode) { - LOCATION_REQUEST_CODE -> { - if (grantResults.isNotEmpty() && - grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // Navigate to the chat fragment - findNavController().navigate(R.id.action_start_chat) - } else { - showError() - } + private val startForResultRequestPermission = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { + if (it) { + findNavController().navigate(R.id.action_start_chat) + } else { + showError() } } - } private fun showError() { binding.locationErrorMessage.visibility = View.VISIBLE @@ -99,10 +85,7 @@ class LocationRequiredFragment : Fragment() { // Navigate to the chat fragment findNavController().navigate(R.id.action_start_chat) } else { - requestPermissions( - arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), - LOCATION_REQUEST_CODE - ) + startForResultRequestPermission.launch(Manifest.permission.ACCESS_FINE_LOCATION) } } } \ No newline at end of file diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/BluetoothChatFragment.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/BluetoothChatFragment.kt index bb5fe4c4..290c058a 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/BluetoothChatFragment.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/BluetoothChatFragment.kt @@ -27,9 +27,9 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager -import com.example.bluetoothlechat.bluetooth.Message import com.example.bluetoothlechat.R import com.example.bluetoothlechat.bluetooth.ChatServer +import com.example.bluetoothlechat.bluetooth.Message import com.example.bluetoothlechat.databinding.FragmentBluetoothChatBinding import com.example.bluetoothlechat.gone import com.example.bluetoothlechat.visible @@ -39,12 +39,13 @@ private const val TAG = "BluetoothChatFragment" class BluetoothChatFragment : Fragment() { private var _binding: FragmentBluetoothChatBinding? = null + // this property is valid between onCreateView and onDestroyView. private val binding: FragmentBluetoothChatBinding get() = _binding!! private val deviceConnectionObserver = Observer { state -> - when(state) { + when (state) { is DeviceConnectionState.Connected -> { val device = state.device Log.d(TAG, "Gatt connection observer: have device $device") @@ -54,7 +55,6 @@ class BluetoothChatFragment : Fragment() { showDisconnected() } } - } private val connectionRequestObserver = Observer { device -> @@ -77,7 +77,7 @@ class BluetoothChatFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { _binding = FragmentBluetoothChatBinding.inflate(inflater, container, false) Log.d(TAG, "chatWith: set adapter $adapter") diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/LocalMessageViewHolder.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/LocalMessageViewHolder.kt index 3283a556..e454adef 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/LocalMessageViewHolder.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/LocalMessageViewHolder.kt @@ -18,8 +18,8 @@ package com.example.bluetoothlechat.chat import android.view.View import android.widget.TextView import androidx.recyclerview.widget.RecyclerView -import com.example.bluetoothlechat.bluetooth.Message import com.example.bluetoothlechat.R +import com.example.bluetoothlechat.bluetooth.Message class LocalMessageViewHolder(view: View) : RecyclerView.ViewHolder(view) { diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/MessageAdapter.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/MessageAdapter.kt index 5b38f161..9cb1bf62 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/MessageAdapter.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/MessageAdapter.kt @@ -19,9 +19,8 @@ import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.example.bluetoothlechat.bluetooth.Message import com.example.bluetoothlechat.R -import java.lang.IllegalArgumentException +import com.example.bluetoothlechat.bluetooth.Message private const val TAG = "MessageAdapter" private const val REMOTE_MESSAGE = 0 @@ -33,7 +32,7 @@ class MessageAdapter : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { Log.d(TAG, "onCreateViewHolder: ") val inflater = LayoutInflater.from(parent.context) - return when(viewType) { + return when (viewType) { REMOTE_MESSAGE -> { val view = inflater.inflate(R.layout.item_remote_message, parent, false) RemoteMessageViewHolder(view) @@ -50,8 +49,7 @@ class MessageAdapter : RecyclerView.Adapter() { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { Log.d(TAG, "onBindViewHolder: ") - val message = messages[position] - when(message) { + when (val message = messages[position]) { is Message.RemoteMessage -> { (holder as RemoteMessageViewHolder).bind(message) } @@ -68,7 +66,7 @@ class MessageAdapter : RecyclerView.Adapter() { override fun getItemViewType(position: Int): Int { Log.d(TAG, "getItemViewType: ") - return when(messages[position]) { + return when (messages[position]) { is Message.RemoteMessage -> REMOTE_MESSAGE is Message.LocalMessage -> LOCAL_MESSAGE } diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/RemoteMessageViewHolder.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/RemoteMessageViewHolder.kt index dc6fa825..94b1d544 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/RemoteMessageViewHolder.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/chat/RemoteMessageViewHolder.kt @@ -18,8 +18,8 @@ package com.example.bluetoothlechat.chat import android.view.View import android.widget.TextView import androidx.recyclerview.widget.RecyclerView -import com.example.bluetoothlechat.bluetooth.Message import com.example.bluetoothlechat.R +import com.example.bluetoothlechat.bluetooth.Message class RemoteMessageViewHolder(view: View) : RecyclerView.ViewHolder(view) { diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanFragment.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanFragment.kt index 4e58b4aa..ec61a262 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanFragment.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanFragment.kt @@ -26,17 +26,20 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager -import com.example.bluetoothlechat.* +import com.example.bluetoothlechat.R import com.example.bluetoothlechat.bluetooth.ChatServer import com.example.bluetoothlechat.databinding.FragmentDeviceScanBinding +import com.example.bluetoothlechat.exhaustive +import com.example.bluetoothlechat.gone import com.example.bluetoothlechat.scan.DeviceScanViewState.* +import com.example.bluetoothlechat.visible private const val TAG = "DeviceScanFragment" -const val GATT_KEY = "gatt_bundle_key" class DeviceScanFragment : Fragment() { private var _binding: FragmentDeviceScanBinding? = null + // This property is only valid between onCreateView and onDestroyView. private val binding get() = _binding!! @@ -66,7 +69,7 @@ class DeviceScanFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { _binding = FragmentDeviceScanBinding.inflate(inflater, container, false) binding.deviceList.apply { diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewModel.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewModel.kt index c5a8f0fa..c1fa06df 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewModel.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewModel.kt @@ -16,9 +16,11 @@ package com.example.bluetoothlechat.scan import android.app.Application -import android.bluetooth.* +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice import android.bluetooth.le.* import android.os.Handler +import android.os.Looper import android.os.ParcelUuid import android.util.Log import androidx.lifecycle.AndroidViewModel @@ -29,6 +31,7 @@ import com.example.bluetoothlechat.scan.DeviceScanViewState.* private const val TAG = "DeviceScanViewModel" + // 30 second scan period private const val SCAN_PERIOD = 30000L @@ -66,7 +69,7 @@ class DeviceScanViewModel(app: Application) : AndroidViewModel(app) { stopScanning() } - fun startScan() { + private fun startScan() { // If advertisement is not supported on this device then other devices will not be able to // discover and connect to it. if (!adapter.isMultipleAdvertisementSupported) { @@ -81,7 +84,7 @@ class DeviceScanViewModel(app: Application) : AndroidViewModel(app) { _viewState.value = ActiveScan // Stop scanning after the scan period - Handler().postDelayed({ stopScanning() }, SCAN_PERIOD) + Handler(Looper.myLooper()!!).postDelayed({ stopScanning() }, SCAN_PERIOD) // Kick off a new scan scanCallback = DeviceScanCallback() diff --git a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewState.kt b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewState.kt index f048a7c7..f684b4ec 100644 --- a/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewState.kt +++ b/BluetoothLeChat/app/src/main/java/com/example/bluetoothlechat/scan/DeviceScanViewState.kt @@ -18,8 +18,8 @@ package com.example.bluetoothlechat.scan import android.bluetooth.BluetoothDevice sealed class DeviceScanViewState { - object ActiveScan: DeviceScanViewState() - class ScanResults(val scanResults: Map): DeviceScanViewState() - class Error(val message: String): DeviceScanViewState() - object AdvertisementNotSupported: DeviceScanViewState() + object ActiveScan : DeviceScanViewState() + class ScanResults(val scanResults: Map) : DeviceScanViewState() + class Error(val message: String) : DeviceScanViewState() + object AdvertisementNotSupported : DeviceScanViewState() } \ No newline at end of file diff --git a/BluetoothLeChat/app/src/main/res/layout/activity_main.xml b/BluetoothLeChat/app/src/main/res/layout/activity_main.xml index f279db81..709dabdd 100644 --- a/BluetoothLeChat/app/src/main/res/layout/activity_main.xml +++ b/BluetoothLeChat/app/src/main/res/layout/activity_main.xml @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -27,4 +26,4 @@ android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph" /> - \ No newline at end of file + \ No newline at end of file diff --git a/BluetoothLeChat/app/src/main/res/layout/fragment_bluetooth_chat.xml b/BluetoothLeChat/app/src/main/res/layout/fragment_bluetooth_chat.xml index 685a163a..1714b3dc 100644 --- a/BluetoothLeChat/app/src/main/res/layout/fragment_bluetooth_chat.xml +++ b/BluetoothLeChat/app/src/main/res/layout/fragment_bluetooth_chat.xml @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -23,21 +22,21 @@ android:id="@+id/not_connected_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="vertical" - android:layout_gravity="center"> + android:layout_gravity="center" + android:orientation="vertical"> + android:text="@string/no_connected_device_message" />