Skip to content

Commit

Permalink
refactor sample
Browse files Browse the repository at this point in the history
  • Loading branch information
isaidamier committed Apr 29, 2021
1 parent 36c949d commit 09b1be3
Show file tree
Hide file tree
Showing 22 changed files with 105 additions and 123 deletions.
20 changes: 10 additions & 10 deletions BluetoothLeChat/app/build.gradle
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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"
}
2 changes: 1 addition & 1 deletion BluetoothLeChat/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

<application
android:allowBackup="true"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
package com.example.bluetoothlechat

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.bluetoothlechat.bluetooth.ChatServer

class MainActivity : AppCompatActivity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ object ChatServer {
// hold reference to app context to run the chat server
private var app: Application? = null
private lateinit var bluetoothManager: BluetoothManager

// BluetoothAdapter should never be null if the app is installed from the Play store
// since BLE is required per the <uses-feature> tag in the AndroidManifest.xml.
// If the app is installed on an emulator without bluetooth then the app will crash
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

package com.example.bluetoothlechat.bluetooth

import java.util.*

/**
Expand All @@ -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")

Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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!!
Expand All @@ -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)
Expand All @@ -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)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -64,25 +61,14 @@ class LocationRequiredFragment : Fragment() {
checkLocationPermission()
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
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
Expand All @@ -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)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<DeviceConnectionState> { state ->
when(state) {
when (state) {
is DeviceConnectionState.Connected -> {
val device = state.device
Log.d(TAG, "Gatt connection observer: have device $device")
Expand All @@ -54,7 +55,6 @@ class BluetoothChatFragment : Fragment() {
showDisconnected()
}
}

}

private val connectionRequestObserver = Observer<BluetoothDevice> { device ->
Expand All @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,7 +32,7 @@ class MessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
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)
Expand All @@ -50,8 +49,7 @@ class MessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

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)
}
Expand All @@ -68,7 +66,7 @@ class MessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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!!
Expand Down Expand Up @@ -66,7 +69,7 @@ class DeviceScanFragment : Fragment() {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
): View {
_binding = FragmentDeviceScanBinding.inflate(inflater, container, false)

binding.deviceList.apply {
Expand Down
Loading

0 comments on commit 09b1be3

Please sign in to comment.