Home | History | Annotate | Download | only in bluetooth
      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.bluetooth.BluetoothAdapter;
     20 import android.bluetooth.BluetoothDevice;
     21 import android.bluetooth.BluetoothProfile;
     22 import android.bluetooth.le.BluetoothLeScanner;
     23 import android.content.Context;
     24 import android.os.ParcelUuid;
     25 import android.util.Log;
     26 
     27 import java.util.List;
     28 import java.util.Set;
     29 
     30 /**
     31  * LocalBluetoothAdapter provides an interface between the Settings app
     32  * and the functionality of the local {@link BluetoothAdapter}, specifically
     33  * those related to state transitions of the adapter itself.
     34  *
     35  * <p>Connection and bonding state changes affecting specific devices
     36  * are handled by {@link CachedBluetoothDeviceManager},
     37  * {@link BluetoothEventManager}, and {@link LocalBluetoothProfileManager}.
     38  */
     39 public class LocalBluetoothAdapter {
     40     private static final String TAG = "LocalBluetoothAdapter";
     41 
     42     /** This class does not allow direct access to the BluetoothAdapter. */
     43     private final BluetoothAdapter mAdapter;
     44 
     45     private LocalBluetoothProfileManager mProfileManager;
     46 
     47     private static LocalBluetoothAdapter sInstance;
     48 
     49     private int mState = BluetoothAdapter.ERROR;
     50 
     51     private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
     52 
     53     private long mLastScan;
     54 
     55     private LocalBluetoothAdapter(BluetoothAdapter adapter) {
     56         mAdapter = adapter;
     57     }
     58 
     59     void setProfileManager(LocalBluetoothProfileManager manager) {
     60         mProfileManager = manager;
     61     }
     62 
     63     /**
     64      * Get the singleton instance of the LocalBluetoothAdapter. If this device
     65      * doesn't support Bluetooth, then null will be returned. Callers must be
     66      * prepared to handle a null return value.
     67      * @return the LocalBluetoothAdapter object, or null if not supported
     68      */
     69     static synchronized LocalBluetoothAdapter getInstance() {
     70         if (sInstance == null) {
     71             BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
     72             if (adapter != null) {
     73                 sInstance = new LocalBluetoothAdapter(adapter);
     74             }
     75         }
     76 
     77         return sInstance;
     78     }
     79 
     80     // Pass-through BluetoothAdapter methods that we can intercept if necessary
     81 
     82     public void cancelDiscovery() {
     83         mAdapter.cancelDiscovery();
     84     }
     85 
     86     public boolean enable() {
     87         return mAdapter.enable();
     88     }
     89 
     90     public boolean disable() {
     91         return mAdapter.disable();
     92     }
     93 
     94     public String getAddress() {
     95         return mAdapter.getAddress();
     96     }
     97 
     98     void getProfileProxy(Context context,
     99             BluetoothProfile.ServiceListener listener, int profile) {
    100         mAdapter.getProfileProxy(context, listener, profile);
    101     }
    102 
    103     public Set<BluetoothDevice> getBondedDevices() {
    104         return mAdapter.getBondedDevices();
    105     }
    106 
    107     public String getName() {
    108         return mAdapter.getName();
    109     }
    110 
    111     public int getScanMode() {
    112         return mAdapter.getScanMode();
    113     }
    114 
    115     public BluetoothLeScanner getBluetoothLeScanner() {
    116         return mAdapter.getBluetoothLeScanner();
    117     }
    118 
    119     public int getState() {
    120         return mAdapter.getState();
    121     }
    122 
    123     public ParcelUuid[] getUuids() {
    124         return mAdapter.getUuids();
    125     }
    126 
    127     public boolean isDiscovering() {
    128         return mAdapter.isDiscovering();
    129     }
    130 
    131     public boolean isEnabled() {
    132         return mAdapter.isEnabled();
    133     }
    134 
    135     public int getConnectionState() {
    136         return mAdapter.getConnectionState();
    137     }
    138 
    139     public void setDiscoverableTimeout(int timeout) {
    140         mAdapter.setDiscoverableTimeout(timeout);
    141     }
    142 
    143     public long getDiscoveryEndMillis() {
    144         return mAdapter.getDiscoveryEndMillis();
    145     }
    146 
    147     public void setName(String name) {
    148         mAdapter.setName(name);
    149     }
    150 
    151     public void setScanMode(int mode) {
    152         mAdapter.setScanMode(mode);
    153     }
    154 
    155     public boolean setScanMode(int mode, int duration) {
    156         return mAdapter.setScanMode(mode, duration);
    157     }
    158 
    159     public void startScanning(boolean force) {
    160         // Only start if we're not already scanning
    161         if (!mAdapter.isDiscovering()) {
    162             if (!force) {
    163                 // Don't scan more than frequently than SCAN_EXPIRATION_MS,
    164                 // unless forced
    165                 if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
    166                     return;
    167                 }
    168 
    169                 // If we are playing music, don't scan unless forced.
    170                 A2dpProfile a2dp = mProfileManager.getA2dpProfile();
    171                 if (a2dp != null && a2dp.isA2dpPlaying()) {
    172                     return;
    173                 }
    174                 A2dpSinkProfile a2dpSink = mProfileManager.getA2dpSinkProfile();
    175                 if ((a2dpSink != null) && (a2dpSink.isA2dpPlaying())){
    176                     return;
    177                 }
    178             }
    179 
    180             if (mAdapter.startDiscovery()) {
    181                 mLastScan = System.currentTimeMillis();
    182             }
    183         }
    184     }
    185 
    186     public void stopScanning() {
    187         if (mAdapter.isDiscovering()) {
    188             mAdapter.cancelDiscovery();
    189         }
    190     }
    191 
    192     public synchronized int getBluetoothState() {
    193         // Always sync state, in case it changed while paused
    194         syncBluetoothState();
    195         return mState;
    196     }
    197 
    198     void setBluetoothStateInt(int state) {
    199         synchronized(this) {
    200             if (mState == state) {
    201                 return;
    202             }
    203             mState = state;
    204         }
    205 
    206         if (state == BluetoothAdapter.STATE_ON) {
    207             // if mProfileManager hasn't been constructed yet, it will
    208             // get the adapter UUIDs in its constructor when it is.
    209             if (mProfileManager != null) {
    210                 mProfileManager.setBluetoothStateOn();
    211             }
    212         }
    213     }
    214 
    215     // Returns true if the state changed; false otherwise.
    216     boolean syncBluetoothState() {
    217         int currentState = mAdapter.getState();
    218         if (currentState != mState) {
    219             setBluetoothStateInt(mAdapter.getState());
    220             return true;
    221         }
    222         return false;
    223     }
    224 
    225     public boolean setBluetoothEnabled(boolean enabled) {
    226         boolean success = enabled
    227                 ? mAdapter.enable()
    228                 : mAdapter.disable();
    229 
    230         if (success) {
    231             setBluetoothStateInt(enabled
    232                 ? BluetoothAdapter.STATE_TURNING_ON
    233                 : BluetoothAdapter.STATE_TURNING_OFF);
    234         } else {
    235             if (Utils.V) {
    236                 Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
    237                         "success for enabled: " + enabled);
    238             }
    239 
    240             syncBluetoothState();
    241         }
    242         return success;
    243     }
    244 
    245     public BluetoothDevice getRemoteDevice(String address) {
    246         return mAdapter.getRemoteDevice(address);
    247     }
    248 
    249     public int getMaxConnectedAudioDevices() {
    250         return mAdapter.getMaxConnectedAudioDevices();
    251     }
    252 
    253     public List<Integer> getSupportedProfiles() {
    254         return mAdapter.getSupportedProfiles();
    255     }
    256 }
    257