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