Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / android / CHIPTool / app / src / main / java / com / google / chip / chiptool / provisioning / DeviceProvisioningFragment.kt
1 /*
2  *   Copyright (c) 2020 Project CHIP Authors
3  *   All rights reserved.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  *
17  */
18
19 package com.google.chip.chiptool.provisioning
20
21 import android.bluetooth.BluetoothGatt
22 import android.os.Bundle
23 import android.util.Log
24 import android.view.LayoutInflater
25 import android.view.View
26 import android.view.ViewGroup
27 import android.widget.Toast
28 import androidx.fragment.app.Fragment
29 import com.google.chip.chiptool.ChipClient
30 import com.google.chip.chiptool.GenericChipDeviceListener
31 import com.google.chip.chiptool.R
32 import com.google.chip.chiptool.bluetooth.BluetoothManager
33 import com.google.chip.chiptool.setuppayloadscanner.CHIPDeviceInfo
34 import com.google.chip.chiptool.util.DeviceIdUtil
35 import com.google.chip.chiptool.util.FragmentUtil
36 import kotlinx.coroutines.CoroutineScope
37 import kotlinx.coroutines.Dispatchers
38 import kotlinx.coroutines.ExperimentalCoroutinesApi
39 import kotlinx.coroutines.Job
40 import kotlinx.coroutines.cancel
41 import kotlinx.coroutines.launch
42
43 @ExperimentalCoroutinesApi
44 class DeviceProvisioningFragment : Fragment() {
45
46   private lateinit var deviceInfo: CHIPDeviceInfo
47
48   private var gatt: BluetoothGatt? = null
49
50   private val networkType: ProvisionNetworkType
51     get() = requireNotNull(
52         ProvisionNetworkType.fromName(arguments?.getString(ARG_PROVISION_NETWORK_TYPE))
53     )
54
55   private val scope = CoroutineScope(Dispatchers.Main + Job())
56
57   override fun onCreateView(
58       inflater: LayoutInflater,
59       container: ViewGroup?,
60       savedInstanceState: Bundle?
61   ): View {
62     deviceInfo = checkNotNull(requireArguments().getParcelable(ARG_DEVICE_INFO))
63     return inflater.inflate(R.layout.single_fragment_container, container, false).apply {
64       if (savedInstanceState == null) {
65         startConnectingToDevice()
66       }
67     }
68   }
69
70   override fun onStop() {
71     super.onStop()
72     gatt = null
73     scope.cancel()
74   }
75
76   private fun startConnectingToDevice() {
77     if (gatt != null) {
78       return
79     }
80
81     scope.launch {
82       val deviceController = ChipClient.getDeviceController()
83       val bluetoothManager = BluetoothManager()
84
85       showMessage(
86           R.string.rendezvous_over_ble_scanning_text,
87           deviceInfo.discriminator.toString()
88       )
89       val device = bluetoothManager.getBluetoothDevice(deviceInfo.discriminator) ?: run {
90         showMessage(R.string.rendezvous_over_ble_scanning_failed_text)
91         return@launch
92       }
93
94       showMessage(
95           R.string.rendezvous_over_ble_connecting_text,
96           device.name ?: device.address.toString()
97       )
98       gatt = bluetoothManager.connect(requireContext(), device)
99
100       showMessage(R.string.rendezvous_over_ble_pairing_text)
101       deviceController.setCompletionListener(ConnectionCallback())
102
103       val deviceId = DeviceIdUtil.getNextAvailableId(requireContext())
104       deviceController.pairDevice(gatt, deviceId, deviceInfo.setupPinCode)
105       DeviceIdUtil.setNextAvailableId(requireContext(), deviceId + 1)
106     }
107   }
108
109   private fun showMessage(msgResId: Int, stringArgs: String? = null) {
110     requireActivity().runOnUiThread {
111       val context = requireContext()
112       Toast.makeText(context, context.getString(msgResId, stringArgs), Toast.LENGTH_SHORT)
113           .show()
114     }
115   }
116
117   inner class ConnectionCallback : GenericChipDeviceListener() {
118     override fun onConnectDeviceComplete() {
119       Log.d(TAG, "onConnectDeviceComplete")
120     }
121
122     override fun onStatusUpdate(status: Int) {
123       Log.i(TAG, "Pairing status update: $status");
124
125       if (status == STATUS_NETWORK_PROVISIONING_SUCCESS) {
126         showMessage(R.string.rendezvous_over_ble_provisioning_success_text)
127         FragmentUtil.getHost(this@DeviceProvisioningFragment, Callback::class.java)
128             ?.onPairingComplete()
129       }
130     }
131
132     override fun onNetworkCredentialsRequested() {
133       childFragmentManager.beginTransaction()
134           .add(R.id.fragment_container, EnterNetworkFragment.newInstance(networkType))
135           .commit()
136     }
137
138     override fun onPairingComplete(code: Int) {
139       Log.d(TAG, "onPairingComplete: $code")
140     }
141
142     override fun onPairingDeleted(code: Int) {
143       Log.d(TAG, "onPairingDeleted: $code")
144     }
145
146     override fun onCloseBleComplete() {
147       Log.d(TAG, "onCloseBleComplete")
148     }
149
150     override fun onError(error: Throwable?) {
151       Log.d(TAG, "onError: $error")
152     }
153   }
154
155   /** Callback from [DeviceProvisioningFragment] notifying any registered listeners. */
156   interface Callback {
157     /** Notifies that pairing has been completed. */
158     fun onPairingComplete()
159   }
160
161   companion object {
162     private const val TAG = "DeviceProvisioningFragment"
163     private const val ARG_DEVICE_INFO = "device_info"
164     private const val ARG_PROVISION_NETWORK_TYPE = "provision_network_type"
165     private const val STATUS_NETWORK_PROVISIONING_SUCCESS = 2
166
167     fun newInstance(
168         deviceInfo: CHIPDeviceInfo,
169         networkType: ProvisionNetworkType
170     ): DeviceProvisioningFragment {
171       return DeviceProvisioningFragment().apply {
172         arguments = Bundle(2).apply {
173           putParcelable(ARG_DEVICE_INFO, deviceInfo)
174           putString(ARG_PROVISION_NETWORK_TYPE, networkType.name)
175         }
176       }
177     }
178   }
179 }