blob: 0c68eb5538ebf8c98c9ba0844892a14fa77902d2 [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.settings.bluetooth;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevicePicker;
import android.car.drivingstate.CarUxRestrictions;
import android.content.Context;
import android.content.Intent;
import com.android.car.settings.R;
import com.android.car.settings.common.FragmentController;
import com.android.car.settings.common.Logger;
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
/**
* Displays a list of Bluetooth devices for the user to select. When a device is selected, a
* {@link BluetoothDevicePicker#ACTION_DEVICE_SELECTED} broadcast is sent containing {@link
* BluetoothDevice#EXTRA_DEVICE}.
*
* <p>This is useful to other application to obtain a device without needing to implement the UI.
* The activity hosting this controller should be launched with an intent as detailed in {@link
* BluetoothDevicePicker#ACTION_LAUNCH}. This controller will filter devices as specified by {@link
* BluetoothDevicePicker#EXTRA_FILTER_TYPE} and deliver the broadcast to the specified {@link
* BluetoothDevicePicker#EXTRA_LAUNCH_PACKAGE} {@link BluetoothDevicePicker#EXTRA_LAUNCH_CLASS}
* component. If authentication is required ({@link BluetoothDevicePicker#EXTRA_NEED_AUTH}), this
* controller will initiate pairing with the device and send the selected broadcast once the device
* successfully pairs. If no device is selected and this controller is destroyed, a broadcast with
* a {@code null} {@link BluetoothDevice#EXTRA_DEVICE} is sent.
*/
public class BluetoothDevicePickerPreferenceController extends
BluetoothScanningDevicesGroupPreferenceController {
private static final Logger LOG = new Logger(BluetoothDevicePickerPreferenceController.class);
private BluetoothDeviceFilter.Filter mFilter;
private boolean mNeedAuth;
private String mLaunchPackage;
private String mLaunchClass;
private CachedBluetoothDevice mSelectedDevice;
public BluetoothDevicePickerPreferenceController(Context context, String preferenceKey,
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
super(context, preferenceKey, fragmentController, uxRestrictions);
}
/**
* Sets the intent with which {@link BluetoothDevicePickerActivity} was launched. The intent
* may contain {@link BluetoothDevicePicker} extras to customize the selection list and specify
* the destination of the selected device. See {@link BluetoothDevicePicker#ACTION_LAUNCH}.
*/
public void setLaunchIntent(Intent intent) {
mNeedAuth = intent.getBooleanExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
mFilter = BluetoothDeviceFilter.getFilter(
intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
BluetoothDevicePicker.FILTER_TYPE_ALL));
mLaunchPackage = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE);
mLaunchClass = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS);
}
@Override
protected void checkInitialized() {
if (mFilter == null) {
throw new IllegalStateException("launch intent must be set");
}
}
@Override
protected BluetoothDeviceFilter.Filter getDeviceFilter() {
return mFilter;
}
@Override
protected void onDeviceClickedInternal(CachedBluetoothDevice cachedDevice) {
mSelectedDevice = cachedDevice;
BluetoothUtils.persistSelectedDeviceInPicker(getContext(), cachedDevice.getAddress());
if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED || !mNeedAuth) {
sendDevicePickedIntent(cachedDevice.getDevice());
getFragmentController().goBack();
return;
}
if (cachedDevice.startPairing()) {
LOG.d("startPairing");
} else {
BluetoothUtils.showError(getContext(), cachedDevice.getName(),
R.string.bluetooth_pairing_error_message);
refreshUi();
}
}
@Override
protected void onStartInternal() {
super.onStartInternal();
mSelectedDevice = null;
}
@Override
protected void onDestroyInternal() {
super.onDestroyInternal();
if (mSelectedDevice == null) {
// Notify that no device was selected.
sendDevicePickedIntent(null);
}
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
super.onDeviceBondStateChanged(cachedDevice, bondState);
if (bondState == BluetoothDevice.BOND_BONDED && cachedDevice.equals(mSelectedDevice)) {
sendDevicePickedIntent(mSelectedDevice.getDevice());
getFragmentController().goBack();
}
}
private void sendDevicePickedIntent(BluetoothDevice device) {
LOG.d("sendDevicePickedIntent device: " + device + " package: " + mLaunchPackage
+ " class: " + mLaunchClass);
Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
if (mLaunchPackage != null && mLaunchClass != null) {
intent.setClassName(mLaunchPackage, mLaunchClass);
}
getContext().sendBroadcast(intent);
}
}