1 /*
2  * Copyright (C) 2011 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.settings.bluetooth;
18 
19 import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
20 
21 import android.app.settings.SettingsEnums;
22 import android.bluetooth.BluetoothAdapter;
23 import android.bluetooth.BluetoothDevice;
24 import android.bluetooth.BluetoothDevicePicker;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.os.Bundle;
28 import android.os.UserManager;
29 import android.view.Menu;
30 import android.view.MenuInflater;
31 
32 import androidx.annotation.VisibleForTesting;
33 
34 import com.android.settings.R;
35 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
36 import com.android.settingslib.core.AbstractPreferenceController;
37 
38 import java.util.List;
39 
40 /**
41  * BluetoothSettings is the Settings screen for Bluetooth configuration and
42  * connection management.
43  */
44 public final class DevicePickerFragment extends DeviceListPreferenceFragment {
45     private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
46     private static final String TAG = "DevicePickerFragment";
47 
48     @VisibleForTesting
49     BluetoothProgressCategory mAvailableDevicesCategory;
50 
51     private boolean mNeedAuth;
52     private String mLaunchPackage;
53     private String mLaunchClass;
54     private boolean mScanAllowed;
55 
DevicePickerFragment()56     public DevicePickerFragment() {
57         super(null /* Not tied to any user restrictions. */);
58     }
59 
60     @Override
initPreferencesFromPreferenceScreen()61     void initPreferencesFromPreferenceScreen() {
62         Intent intent = getActivity().getIntent();
63         mNeedAuth = intent.getBooleanExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
64         setFilter(intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
65                 BluetoothDevicePicker.FILTER_TYPE_ALL));
66         mLaunchPackage = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE);
67         mLaunchClass = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS);
68         mAvailableDevicesCategory = (BluetoothProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
69     }
70 
71     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)72     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
73         super.onCreateOptionsMenu(menu, inflater);
74     }
75 
76     @Override
getMetricsCategory()77     public int getMetricsCategory() {
78         return SettingsEnums.BLUETOOTH_DEVICE_PICKER;
79     }
80 
81     @Override
onCreate(Bundle savedInstanceState)82     public void onCreate(Bundle savedInstanceState) {
83         super.onCreate(savedInstanceState);
84         getActivity().setTitle(getString(R.string.device_picker));
85         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
86         mScanAllowed = !um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH);
87         setHasOptionsMenu(true);
88     }
89 
90     @Override
onStart()91     public void onStart() {
92         super.onStart();
93         addCachedDevices();
94         mSelectedDevice = null;
95         if (mScanAllowed) {
96             enableScanning();
97             mAvailableDevicesCategory.setProgress(mBluetoothAdapter.isDiscovering());
98         }
99     }
100 
101     @Override
onStop()102     public void onStop() {
103         // Try disable scanning no matter what, no effect if enableScanning has not been called
104         disableScanning();
105         super.onStop();
106     }
107 
108     @Override
onDestroy()109     public void onDestroy() {
110         super.onDestroy();
111         /* Check if any device was selected, if no device selected
112          * send  ACTION_DEVICE_SELECTED with a null device, otherwise
113          * don't do anything */
114         if (mSelectedDevice == null) {
115             sendDevicePickedIntent(null);
116         }
117     }
118 
119     @Override
onDevicePreferenceClick(BluetoothDevicePreference btPreference)120     void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
121         disableScanning();
122         LocalBluetoothPreferences.persistSelectedDeviceInPicker(
123                 getActivity(), mSelectedDevice.getAddress());
124         if ((btPreference.getCachedDevice().getBondState() ==
125                 BluetoothDevice.BOND_BONDED) || !mNeedAuth) {
126             sendDevicePickedIntent(mSelectedDevice);
127             finish();
128         } else {
129             super.onDevicePreferenceClick(btPreference);
130         }
131     }
132 
133     @Override
onScanningStateChanged(boolean started)134     public void onScanningStateChanged(boolean started) {
135         super.onScanningStateChanged(started);
136         started |= mScanEnabled;
137         mAvailableDevicesCategory.setProgress(started);
138     }
139 
onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState)140     public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice,
141             int bondState) {
142         BluetoothDevice device = cachedDevice.getDevice();
143         if (!device.equals(mSelectedDevice)) {
144             return;
145         }
146         if (bondState == BluetoothDevice.BOND_BONDED) {
147             sendDevicePickedIntent(device);
148             finish();
149         } else if (bondState == BluetoothDevice.BOND_NONE) {
150             enableScanning();
151         }
152     }
153 
154     @Override
initDevicePreference(BluetoothDevicePreference preference)155     protected void initDevicePreference(BluetoothDevicePreference preference) {
156         super.initDevicePreference(preference);
157         preference.setNeedNotifyHierarchyChanged(true);
158     }
159 
160     @Override
onBluetoothStateChanged(int bluetoothState)161     public void onBluetoothStateChanged(int bluetoothState) {
162         super.onBluetoothStateChanged(bluetoothState);
163 
164         if (bluetoothState == BluetoothAdapter.STATE_ON) {
165             enableScanning();
166         }
167     }
168 
169     @Override
getLogTag()170     protected String getLogTag() {
171         return TAG;
172     }
173 
174     @Override
getPreferenceScreenResId()175     protected int getPreferenceScreenResId() {
176         return R.xml.device_picker;
177     }
178 
179     @Override
createPreferenceControllers(Context context)180     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
181         return null;
182     }
183 
184     @Override
getDeviceListKey()185     public String getDeviceListKey() {
186         return KEY_BT_DEVICE_LIST;
187     }
188 
sendDevicePickedIntent(BluetoothDevice device)189     private void sendDevicePickedIntent(BluetoothDevice device) {
190         Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
191         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
192         if (mLaunchPackage != null && mLaunchClass != null) {
193             intent.setClassName(mLaunchPackage, mLaunchClass);
194         }
195         getActivity().sendBroadcast(intent);
196     }
197 }
198