1 /* 2 * Copyright (C) 2021 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.google.android.car.kitchensink.bluetooth; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothDevice; 21 import android.bluetooth.BluetoothDevicePicker; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.os.Bundle; 27 import android.util.Log; 28 import android.view.LayoutInflater; 29 import android.view.View; 30 import android.view.ViewGroup; 31 import android.widget.Button; 32 import android.widget.TableLayout; 33 import android.widget.TableRow; 34 import android.widget.TextView; 35 import android.widget.Toast; 36 37 import androidx.annotation.Nullable; 38 import androidx.fragment.app.Fragment; 39 40 import com.google.android.car.kitchensink.R; 41 42 import java.util.Set; 43 import java.util.concurrent.Executor; 44 45 public class BluetoothDeviceFragment extends Fragment { 46 private static final String TAG = "CAR.BLUETOOTH.KS"; 47 BluetoothAdapter mBluetoothAdapter; 48 BluetoothDevice mPickedDevice; 49 Executor mExecutor; 50 BluetoothDeviceTypeChecker mDeviceTypeChecker; 51 52 TextView mPickedDeviceText; 53 Button mDevicePicker; 54 TableLayout mTableLayout; 55 56 @Override onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)57 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 58 @Nullable Bundle savedInstanceState) { 59 View v = inflater.inflate(R.layout.bluetooth_devices, container, false); 60 mDeviceTypeChecker = new BluetoothDeviceTypeChecker(getContext(), true); 61 mDevicePicker = v.findViewById(R.id.bluetooth_pick_device); 62 mTableLayout = v.findViewById(R.id.PairedDeviceTable); 63 mExecutor = new ThreadPerTaskExecutor(); 64 65 // Pick a bluetooth device 66 mDevicePicker.setOnClickListener(new View.OnClickListener() { 67 @Override 68 public void onClick(View view) { 69 launchDevicePicker(); 70 } 71 }); 72 73 return v; 74 } 75 76 @Override onResume()77 public void onResume() { 78 super.onResume(); 79 checkAllDevices(); 80 } 81 launchDevicePicker()82 void launchDevicePicker() { 83 IntentFilter filter = new IntentFilter(); 84 filter.addAction(BluetoothDevicePicker.ACTION_DEVICE_SELECTED); 85 getContext().registerReceiver(mPickerReceiver, filter); 86 87 Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH); 88 intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 89 getContext().startActivity(intent); 90 } 91 checkAllDevices()92 void checkAllDevices() { 93 BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 94 if (bluetoothAdapter == null) { 95 Log.w(TAG, "Bluetooth Adapter not available"); 96 return; 97 } 98 mTableLayout.removeAllViews(); 99 Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices(); 100 Context context = getContext(); 101 for (BluetoothDevice device : bondedDevices) { 102 TableRow row = new TableRow(context); 103 TextView deviceName = new TextView(context); 104 deviceName.setText(device.getName()); 105 TextView deviceType = new TextView(context); 106 deviceType.setText(Boolean.toString(mDeviceTypeChecker.isIapDevice(device))); 107 row.addView(deviceName); 108 row.addView(deviceType); 109 mTableLayout.addView(row); 110 } 111 } 112 addDeviceToTable(BluetoothDevice device, String value)113 private void addDeviceToTable(BluetoothDevice device, String value) { 114 getActivity().runOnUiThread(new Runnable() { 115 public void run() { 116 Context context = getContext(); 117 TableRow row = new TableRow(context); 118 TextView deviceName = new TextView(context); 119 TextView deviceValue = new TextView(context); 120 deviceName.setText(device.getName()); 121 deviceValue.setText(value); 122 row.addView(deviceName); 123 row.addView(deviceValue); 124 mTableLayout.addView(row); 125 } 126 }); 127 } 128 129 private final BroadcastReceiver mPickerReceiver = new BroadcastReceiver() { 130 @Override 131 public void onReceive(Context context, Intent intent) { 132 String action = intent.getAction(); 133 Log.v(TAG, "mPickerReceiver got " + action); 134 135 if (BluetoothDevicePicker.ACTION_DEVICE_SELECTED.equals(action)) { 136 final BluetoothDevice device = 137 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 138 Log.v(TAG, "mPickerReceiver got " + device); 139 if (device == null) { 140 Toast.makeText(getContext(), "No device selected", Toast.LENGTH_SHORT).show(); 141 return; 142 } 143 mExecutor.execute(new Runnable() { 144 @Override 145 public void run() { 146 addDeviceToTable(device, 147 Boolean.toString(mDeviceTypeChecker.isIapDevice(device))); 148 Log.w(TAG, "Is iAP" + mDeviceTypeChecker.isIapDevice(device)); 149 } 150 }); 151 Log.w(TAG, "Dispatched"); 152 getContext().unregisterReceiver(mPickerReceiver); 153 } 154 } 155 }; 156 157 private class ThreadPerTaskExecutor implements Executor { execute(Runnable r)158 public void execute(Runnable r) { 159 new Thread(r).start(); 160 } 161 } 162 } 163