1 /* 2 * Copyright 2018 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.car.settings.bluetooth; 18 19 import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; 20 21 import android.bluetooth.BluetoothDevice; 22 import android.car.drivingstate.CarUxRestrictions; 23 import android.content.Context; 24 25 import com.android.car.settings.R; 26 import com.android.car.settings.common.FragmentController; 27 import com.android.car.settings.common.Logger; 28 import com.android.internal.util.ArrayUtils; 29 import com.android.settingslib.bluetooth.BluetoothDeviceFilter; 30 import com.android.settingslib.bluetooth.BluetoothDeviceFilter.Filter; 31 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 32 33 /** 34 * Displays a list of unbonded (unpaired) Bluetooth devices. This controller also sets the 35 * Bluetooth adapter to discovery mode and begins scanning for discoverable devices for as long as 36 * the preference group is shown. Clicking on a device will start the pairing process. Discovery 37 * and scanning are halted while a device is pairing. Users with the {@link 38 * DISALLOW_CONFIG_BLUETOOTH} restriction cannot pair devices. 39 */ 40 public class BluetoothUnbondedDevicesPreferenceController extends 41 BluetoothScanningDevicesGroupPreferenceController { 42 43 private final Filter mUnbondedDeviceTypeFilter = new UnbondedDeviceTypeFilter(); 44 45 private static final Logger LOG = new Logger( 46 BluetoothUnbondedDevicesPreferenceController.class); 47 BluetoothUnbondedDevicesPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)48 public BluetoothUnbondedDevicesPreferenceController(Context context, String preferenceKey, 49 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 50 super(context, preferenceKey, fragmentController, uxRestrictions); 51 } 52 53 @Override getDeviceFilter()54 protected BluetoothDeviceFilter.Filter getDeviceFilter() { 55 return mUnbondedDeviceTypeFilter; 56 } 57 58 @Override onDeviceClickedInternal(CachedBluetoothDevice cachedDevice)59 protected void onDeviceClickedInternal(CachedBluetoothDevice cachedDevice) { 60 if (cachedDevice.startPairing()) { 61 LOG.d("startPairing"); 62 // Indicate that this client (vehicle) would like access to contacts (PBAP) and messages 63 // (MAP) if there is a server which permits it (usually a phone). 64 cachedDevice.getDevice().setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED); 65 cachedDevice.getDevice().setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED); 66 } else { 67 BluetoothUtils.showError(getContext(), cachedDevice.getName(), 68 R.string.bluetooth_pairing_error_message); 69 refreshUi(); 70 } 71 } 72 73 @Override getAvailabilityStatus()74 protected int getAvailabilityStatus() { 75 int availabilityStatus = super.getAvailabilityStatus(); 76 if (availabilityStatus == AVAILABLE 77 && getUserManager().hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)) { 78 return DISABLED_FOR_PROFILE; 79 } 80 return availabilityStatus; 81 } 82 83 /** Filter that matches only unbonded devices with specific device types. */ 84 private class UnbondedDeviceTypeFilter implements Filter { matches(BluetoothDevice device)85 public boolean matches(BluetoothDevice device) { 86 int[] unbondedMajorClassFilter = getContext() 87 .getResources() 88 .getIntArray(R.array.config_unbonded_device_filter_allowlist); 89 boolean matches = device.getBondState() != BluetoothDevice.BOND_BONDED; 90 if (matches && unbondedMajorClassFilter.length > 0) { 91 matches = device.getBluetoothClass() != null 92 && ArrayUtils.contains( 93 unbondedMajorClassFilter, 94 device.getBluetoothClass().getMajorDeviceClass()); 95 } 96 return matches; 97 } 98 } 99 } 100