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.settingslib.bluetooth;
18 
19 import android.content.Context;
20 import android.os.Handler;
21 import android.os.UserHandle;
22 import android.util.Log;
23 
24 import java.lang.ref.WeakReference;
25 
26 import androidx.annotation.Nullable;
27 import androidx.annotation.RequiresPermission;
28 
29 /**
30  * LocalBluetoothManager provides a simplified interface on top of a subset of
31  * the Bluetooth API. Note that {@link #getInstance} will return null
32  * if there is no Bluetooth adapter on this device, and callers must be
33  * prepared to handle this case.
34  */
35 public class LocalBluetoothManager {
36     private static final String TAG = "LocalBluetoothManager";
37 
38     /** Singleton instance. */
39     private static LocalBluetoothManager sInstance;
40 
41     private final Context mContext;
42 
43     /** If a BT-related activity is in the foreground, this will be it. */
44     private WeakReference<Context> mForegroundActivity;
45 
46     private final LocalBluetoothAdapter mLocalAdapter;
47 
48     private final CachedBluetoothDeviceManager mCachedDeviceManager;
49 
50     /** The Bluetooth profile manager. */
51     private final LocalBluetoothProfileManager mProfileManager;
52 
53     /** The broadcast receiver event manager. */
54     private final BluetoothEventManager mEventManager;
55 
56     @Nullable
getInstance(Context context, BluetoothManagerCallback onInitCallback)57     public static synchronized LocalBluetoothManager getInstance(Context context,
58             BluetoothManagerCallback onInitCallback) {
59         if (sInstance == null) {
60             LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
61             if (adapter == null) {
62                 return null;
63             }
64             // This will be around as long as this process is
65             sInstance = new LocalBluetoothManager(adapter, context, /* handler= */ null,
66                     /* userHandle= */ null);
67             if (onInitCallback != null) {
68                 onInitCallback.onBluetoothManagerInitialized(context.getApplicationContext(),
69                         sInstance);
70             }
71         }
72 
73         return sInstance;
74     }
75 
76     /**
77      * Returns a new instance of {@link LocalBluetoothManager} or null if Bluetooth is not
78      * supported for this hardware. This instance should be globally cached by the caller.
79      */
80     @Nullable
create(Context context, Handler handler)81     public static LocalBluetoothManager create(Context context, Handler handler) {
82         LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
83         if (adapter == null) {
84             return null;
85         }
86         return new LocalBluetoothManager(adapter, context, handler, /* userHandle= */ null);
87     }
88 
89     /**
90      * Returns a new instance of {@link LocalBluetoothManager} or null if Bluetooth is not
91      * supported for this hardware. This instance should be globally cached by the caller.
92      *
93      * <p> Allows to specify a {@link UserHandle} for which to receive bluetooth events.
94      *
95      * <p> Requires {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
96      */
97     @Nullable
98     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
create(Context context, Handler handler, UserHandle userHandle)99     public static LocalBluetoothManager create(Context context, Handler handler,
100             UserHandle userHandle) {
101         LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
102         if (adapter == null) {
103             return null;
104         }
105         return new LocalBluetoothManager(adapter, context, handler,
106                 userHandle);
107     }
108 
LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context, Handler handler, UserHandle userHandle)109     private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context, Handler handler,
110             UserHandle userHandle) {
111         mContext = context.getApplicationContext();
112         mLocalAdapter = adapter;
113         mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, this);
114         mEventManager = new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mContext,
115                 handler, userHandle);
116         mProfileManager = new LocalBluetoothProfileManager(mContext,
117                 mLocalAdapter, mCachedDeviceManager, mEventManager);
118 
119         mProfileManager.updateLocalProfiles();
120         mEventManager.readPairedDevices();
121     }
122 
getBluetoothAdapter()123     public LocalBluetoothAdapter getBluetoothAdapter() {
124         return mLocalAdapter;
125     }
126 
getContext()127     public Context getContext() {
128         return mContext;
129     }
130 
getForegroundActivity()131     public Context getForegroundActivity() {
132         return mForegroundActivity == null
133                 ? null
134                 : mForegroundActivity.get();
135     }
136 
isForegroundActivity()137     public boolean isForegroundActivity() {
138         return mForegroundActivity != null && mForegroundActivity.get() != null;
139     }
140 
setForegroundActivity(Context context)141     public synchronized void setForegroundActivity(Context context) {
142         if (context != null) {
143             Log.d(TAG, "setting foreground activity to non-null context");
144             mForegroundActivity = new WeakReference<>(context);
145         } else {
146             if (mForegroundActivity != null) {
147                 Log.d(TAG, "setting foreground activity to null");
148                 mForegroundActivity = null;
149             }
150         }
151     }
152 
getCachedDeviceManager()153     public CachedBluetoothDeviceManager getCachedDeviceManager() {
154         return mCachedDeviceManager;
155     }
156 
getEventManager()157     public BluetoothEventManager getEventManager() {
158         return mEventManager;
159     }
160 
getProfileManager()161     public LocalBluetoothProfileManager getProfileManager() {
162         return mProfileManager;
163     }
164 
165     public interface BluetoothManagerCallback {
onBluetoothManagerInitialized(Context appContext, LocalBluetoothManager bluetoothManager)166         void onBluetoothManagerInitialized(Context appContext,
167                 LocalBluetoothManager bluetoothManager);
168     }
169 }
170