1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.pandora
18 
19 import android.bluetooth.BluetoothDevice.TRANSPORT_BREDR
20 import android.bluetooth.BluetoothManager
21 import android.bluetooth.BluetoothPan
22 import android.bluetooth.BluetoothProfile
23 import android.content.Context
24 import android.net.TetheringManager
25 import android.net.TetheringManager.TETHERING_BLUETOOTH
26 import android.util.Log
27 import io.grpc.stub.StreamObserver
28 import java.io.Closeable
29 import java.util.concurrent.Executors
30 import kotlinx.coroutines.CoroutineScope
31 import kotlinx.coroutines.Dispatchers
32 import kotlinx.coroutines.cancel
33 import kotlinx.coroutines.flow.MutableStateFlow
34 import kotlinx.coroutines.flow.first
35 import pandora.HostProto.*
36 import pandora.PANGrpc.PANImplBase
37 import pandora.PanProto.*
38 
39 @kotlinx.coroutines.ExperimentalCoroutinesApi
40 class Pan(private val context: Context) : PANImplBase(), Closeable {
41     private val TAG = "PandoraPan"
42     private val mScope: CoroutineScope = CoroutineScope(Dispatchers.Default.limitedParallelism(1))
43 
44     private val bluetoothManager = context.getSystemService(BluetoothManager::class.java)!!
45     private val bluetoothAdapter = bluetoothManager.adapter
46     private val bluetoothPan = getProfileProxy<BluetoothPan>(context, BluetoothProfile.PAN)
47 
48     private var mTetheringEnabled = MutableStateFlow(false)
49 
50     private val mTetheringManager: TetheringManager
51     private val mStartTetheringCallback =
52         object : TetheringManager.StartTetheringCallback {
onTetheringStartednull53             override fun onTetheringStarted() {
54                 Log.i(TAG, "onTetheringStarted")
55                 mTetheringEnabled.value = true
56             }
57 
onTetheringFailednull58             override fun onTetheringFailed(error: Int) {
59                 Log.e(TAG, "onTetheringFailed $error")
60                 mTetheringEnabled.value = false
61             }
62         }
63 
64     init {
65         mTetheringManager = context.getSystemService(TetheringManager::class.java)!!
66     }
67 
closenull68     override fun close() {
69         bluetoothAdapter.closeProfileProxy(BluetoothProfile.PAN, bluetoothPan)
70         mScope.cancel()
71     }
72 
enableTetheringnull73     override fun enableTethering(
74         request: EnableTetheringRequest,
75         responseObserver: StreamObserver<EnableTetheringResponse>
76     ) {
77         grpcUnary<EnableTetheringResponse>(mScope, responseObserver) {
78             Log.i(TAG, "enableTethering")
79             if (mTetheringEnabled.value != true) {
80                 mTetheringManager.startTethering(
81                     TETHERING_BLUETOOTH,
82                     Executors.newSingleThreadExecutor(),
83                     mStartTetheringCallback
84                 )
85                 mTetheringEnabled.first { it == true }
86             }
87             EnableTetheringResponse.newBuilder().build()
88         }
89     }
90 
connectPannull91     override fun connectPan(
92         request: ConnectPanRequest,
93         responseObserver: StreamObserver<ConnectPanResponse>
94     ) {
95         grpcUnary<ConnectPanResponse>(mScope, responseObserver) {
96             Log.i(TAG, "connectPan")
97             val device = request.address.toBluetoothDevice(bluetoothAdapter)
98             bluetoothPan.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED)
99             bluetoothPan.connect(device)
100             ConnectPanResponse.newBuilder()
101                 .setConnection(device.toConnection(TRANSPORT_BREDR))
102                 .build()
103         }
104     }
105 }
106