• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 android.bluetooth.BluetoothAdapter;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 
25 import androidx.annotation.VisibleForTesting;
26 
27 import com.android.settingslib.utils.ThreadUtils;
28 
29 /** Helper class, intended to be used by an Activity, to keep the local Bluetooth adapter in
30  *  discoverable mode indefinitely. By default setting the scan mode to
31  *  BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE will time out after some time, but some
32  *  Bluetooth settings pages would like to keep the device discoverable as long as the page is
33  *  visible. */
34 public class AlwaysDiscoverable extends BroadcastReceiver {
35     private static final String TAG = "AlwaysDiscoverable";
36 
37     private Context mContext;
38     private BluetoothAdapter mBluetoothAdapter;
39     private IntentFilter mIntentFilter;
40 
41     @VisibleForTesting
42     boolean mStarted;
43 
AlwaysDiscoverable(Context context)44     public AlwaysDiscoverable(Context context) {
45         mContext = context;
46         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
47         mIntentFilter = new IntentFilter();
48         mIntentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
49     }
50 
51     /** After calling start(), consumers should make a matching call to stop() when they no longer
52      * wish to enforce discoverable mode. */
start()53     public void start() {
54         if (mStarted) {
55             return;
56         }
57         mContext.registerReceiver(this, mIntentFilter,
58                 Context.RECEIVER_EXPORTED_UNAUDITED);
59         mStarted = true;
60         ThreadUtils.postOnBackgroundThread(() -> {
61             if (mBluetoothAdapter.getScanMode()
62                     != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
63                 mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
64             }
65         });
66     }
67 
stop()68     public void stop() {
69         if (!mStarted) {
70             return;
71         }
72         mContext.unregisterReceiver(this);
73         mStarted = false;
74         ThreadUtils.postOnBackgroundThread(
75                 () -> mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
76     }
77 
78     @Override
onReceive(Context context, Intent intent)79     public void onReceive(Context context, Intent intent) {
80         String action = intent.getAction();
81         if (action != BluetoothAdapter.ACTION_SCAN_MODE_CHANGED) {
82             return;
83         }
84         ThreadUtils.postOnBackgroundThread(() -> {
85             if (mBluetoothAdapter.getScanMode()
86                     != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
87                 mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
88             }
89         });
90     }
91 }
92