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