• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Manifest;
22 import android.app.settings.SettingsEnums;
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothDevicePicker;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.os.Bundle;
29 import android.os.UserManager;
30 import android.text.TextUtils;
31 import android.util.Log;
32 import android.view.Menu;
33 import android.view.MenuInflater;
34 
35 import androidx.annotation.NonNull;
36 import androidx.annotation.VisibleForTesting;
37 
38 import com.android.settings.R;
39 import com.android.settings.flags.Flags;
40 import com.android.settings.password.PasswordUtils;
41 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
42 import com.android.settingslib.core.AbstractPreferenceController;
43 
44 import java.util.List;
45 
46 /**
47  * BluetoothSettings is the Settings screen for Bluetooth configuration and
48  * connection management.
49  */
50 public final class DevicePickerFragment extends DeviceListPreferenceFragment {
51     private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
52     private static final String TAG = "DevicePickerFragment";
53     private static final String EXTRA_ORIGINAL_SEND_INTENT =
54             "android.bluetooth.extra.DEVICE_PICKER_ORIGINAL_SEND_INTENT";
55 
56     @VisibleForTesting
57     BluetoothProgressCategory mAvailableDevicesCategory;
58     @VisibleForTesting
59     Context mContext;
60     @VisibleForTesting
61     String mLaunchPackage;
62     @VisibleForTesting
63     String mLaunchClass;
64     @VisibleForTesting
65     String mCallingAppPackageName;
66 
67     private boolean mNeedAuth;
68     private boolean mScanAllowed;
69 
DevicePickerFragment()70     public DevicePickerFragment() {
71         super(null /* Not tied to any user restrictions. */);
72     }
73 
74     @Override
initPreferencesFromPreferenceScreen()75     public void initPreferencesFromPreferenceScreen() {
76         Intent intent = getActivity().getIntent();
77         mNeedAuth = intent.getBooleanExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
78         setFilter(intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
79                 BluetoothDevicePicker.FILTER_TYPE_ALL));
80         mLaunchPackage = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE);
81         mLaunchClass = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS);
82         mAvailableDevicesCategory = (BluetoothProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
83     }
84 
85     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)86     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
87         super.onCreateOptionsMenu(menu, inflater);
88     }
89 
90     @Override
getMetricsCategory()91     public int getMetricsCategory() {
92         return SettingsEnums.BLUETOOTH_DEVICE_PICKER;
93     }
94 
95     @Override
onCreate(Bundle savedInstanceState)96     public void onCreate(Bundle savedInstanceState) {
97         super.onCreate(savedInstanceState);
98         getActivity().setTitle(getString(R.string.device_picker));
99         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
100         mScanAllowed = !um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH);
101         mCallingAppPackageName = PasswordUtils.getCallingAppPackageName(
102                 getActivity().getActivityToken());
103         if (!TextUtils.equals(mCallingAppPackageName, mLaunchPackage)) {
104             Log.w(TAG, "sendDevicePickedIntent() launch package name is not equivalent to"
105                     + " calling package name!");
106         }
107         mContext = getContext();
108         setHasOptionsMenu(true);
109     }
110 
111     @Override
onAttach(@onNull Context context)112     public void onAttach(@NonNull Context context) {
113         super.onAttach(context);
114         if (Flags.enableNearbyShareEntrypoint()) {
115             initNearbySharingController();
116         }
117     }
118 
initNearbySharingController()119     private void initNearbySharingController() {
120         Intent sendIntent =
121                 getIntent().getParcelableExtra(EXTRA_ORIGINAL_SEND_INTENT, Intent.class);
122         if (sendIntent == null) {
123             return;
124         }
125         use(NearbySharePreferenceController.class).init(sendIntent);
126     }
127 
128     @Override
onStart()129     public void onStart() {
130         super.onStart();
131         mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
132         removeAllDevices();
133         addCachedDevices();
134         mSelectedDevice = null;
135         if (mScanAllowed) {
136             enableScanning();
137             mAvailableDevicesCategory.setProgress(mBluetoothAdapter.isDiscovering());
138         }
139     }
140 
141     @Override
onStop()142     public void onStop() {
143         // Try disable scanning no matter what, no effect if enableScanning has not been called
144         disableScanning();
145         super.onStop();
146     }
147 
148     @Override
onDestroy()149     public void onDestroy() {
150         super.onDestroy();
151         /* Check if any device was selected, if no device selected
152          * send  ACTION_DEVICE_SELECTED with a null device, otherwise
153          * don't do anything */
154         if (mSelectedDevice == null) {
155             sendDevicePickedIntent(null);
156         }
157     }
158 
159     @Override
onDevicePreferenceClick(BluetoothDevicePreference btPreference)160     public void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
161         disableScanning();
162         LocalBluetoothPreferences.persistSelectedDeviceInPicker(
163                 getActivity(), mSelectedDevice.getAddress());
164         if ((btPreference.getCachedDevice().getBondState() ==
165                 BluetoothDevice.BOND_BONDED) || !mNeedAuth) {
166             sendDevicePickedIntent(mSelectedDevice);
167             finish();
168         } else {
169             super.onDevicePreferenceClick(btPreference);
170         }
171     }
172 
173     @Override
onScanningStateChanged(boolean started)174     public void onScanningStateChanged(boolean started) {
175         super.onScanningStateChanged(started);
176         started |= mScanEnabled;
177         mAvailableDevicesCategory.setProgress(started);
178     }
179 
onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState)180     public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice,
181             int bondState) {
182         BluetoothDevice device = cachedDevice.getDevice();
183         if (!device.equals(mSelectedDevice)) {
184             return;
185         }
186         if (bondState == BluetoothDevice.BOND_BONDED) {
187             sendDevicePickedIntent(device);
188             finish();
189         } else if (bondState == BluetoothDevice.BOND_NONE) {
190             enableScanning();
191         }
192     }
193 
194     @Override
initDevicePreference(BluetoothDevicePreference preference)195     protected void initDevicePreference(BluetoothDevicePreference preference) {
196         super.initDevicePreference(preference);
197         preference.setNeedNotifyHierarchyChanged(true);
198     }
199 
200     @Override
onBluetoothStateChanged(int bluetoothState)201     public void onBluetoothStateChanged(int bluetoothState) {
202         super.onBluetoothStateChanged(bluetoothState);
203 
204         if (bluetoothState == BluetoothAdapter.STATE_ON) {
205             enableScanning();
206         }
207     }
208 
209     @Override
getLogTag()210     protected String getLogTag() {
211         return TAG;
212     }
213 
214     @Override
getPreferenceScreenResId()215     protected int getPreferenceScreenResId() {
216         return R.xml.device_picker;
217     }
218 
219     @Override
createPreferenceControllers(Context context)220     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
221         return null;
222     }
223 
224     @Override
getDeviceListKey()225     public String getDeviceListKey() {
226         return KEY_BT_DEVICE_LIST;
227     }
228 
sendDevicePickedIntent(BluetoothDevice device)229     private void sendDevicePickedIntent(BluetoothDevice device) {
230         Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
231         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
232         if (mLaunchPackage != null && mLaunchClass != null) {
233             if (TextUtils.equals(mCallingAppPackageName, mLaunchPackage)) {
234                 intent.setClassName(mLaunchPackage, mLaunchClass);
235             }
236         }
237 
238         mContext.sendBroadcast(intent, Manifest.permission.BLUETOOTH_CONNECT);
239     }
240 }
241