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.bluetooth.BluetoothDevice;
21 import android.content.Context;
22 import android.support.annotation.VisibleForTesting;
23 import android.text.TextUtils;
24 
25 import com.android.settings.R;
26 import com.android.settings.widget.SummaryUpdater;
27 import com.android.settingslib.bluetooth.BluetoothCallback;
28 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
29 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
30 import com.android.settingslib.bluetooth.LocalBluetoothManager;
31 
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.List;
35 import java.util.Set;
36 
37 /**
38  * Helper class that listeners to bluetooth callback and notify client when there is update in
39  * bluetooth summary info.
40  */
41 public final class BluetoothSummaryUpdater extends SummaryUpdater implements BluetoothCallback {
42 
43     private final LocalBluetoothManager mBluetoothManager;
44     private final LocalBluetoothAdapter mBluetoothAdapter;
45 
46     private boolean mEnabled;
47     private int mConnectionState;
48 
BluetoothSummaryUpdater(Context context, OnSummaryChangeListener listener, LocalBluetoothManager bluetoothManager)49     public BluetoothSummaryUpdater(Context context, OnSummaryChangeListener listener,
50             LocalBluetoothManager bluetoothManager) {
51         super(context, listener);
52         mBluetoothManager = bluetoothManager;
53         mBluetoothAdapter = mBluetoothManager != null
54             ? mBluetoothManager.getBluetoothAdapter() : null;
55     }
56 
57     @Override
onBluetoothStateChanged(int bluetoothState)58     public void onBluetoothStateChanged(int bluetoothState) {
59         mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
60             || bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
61         notifyChangeIfNeeded();
62     }
63 
64     @Override
onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state)65     public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
66         mConnectionState = state;
67         updateConnected();
68         notifyChangeIfNeeded();
69     }
70 
71     @Override
onScanningStateChanged(boolean started)72     public void onScanningStateChanged(boolean started) {
73     }
74 
75     @Override
onDeviceAdded(CachedBluetoothDevice cachedDevice)76     public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
77     }
78 
79     @Override
onDeviceDeleted(CachedBluetoothDevice cachedDevice)80     public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
81     }
82 
83     @Override
onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState)84     public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
85     }
86 
87     @Override
register(boolean listening)88     public void register(boolean listening) {
89         if (mBluetoothAdapter == null) {
90             return;
91         }
92         if (listening) {
93             mEnabled = mBluetoothAdapter.isEnabled();
94             mConnectionState = mBluetoothAdapter.getConnectionState();
95             notifyChangeIfNeeded();
96             mBluetoothManager.getEventManager().registerCallback(this);
97         } else {
98             mBluetoothManager.getEventManager().unregisterCallback(this);
99         }
100     }
101 
102     @Override
getSummary()103     public String getSummary() {
104         if (!mEnabled) {
105             return mContext.getString(R.string.bluetooth_disabled);
106         }
107         switch (mConnectionState) {
108             case BluetoothAdapter.STATE_CONNECTED:
109                 return getConnectedDeviceSummary();
110             case BluetoothAdapter.STATE_CONNECTING:
111                 return mContext.getString(R.string.bluetooth_connecting);
112             case BluetoothAdapter.STATE_DISCONNECTING:
113                 return mContext.getString(R.string.bluetooth_disconnecting);
114             default:
115                 return mContext.getString(R.string.disconnected);
116         }
117     }
118 
updateConnected()119     private void updateConnected() {
120         if (mBluetoothAdapter == null) {
121             return;
122         }
123         // Make sure our connection state is up to date.
124         int state = mBluetoothAdapter.getConnectionState();
125         if (state != mConnectionState) {
126             mConnectionState = state;
127             return;
128         }
129         final Collection<CachedBluetoothDevice> devices = getDevices();
130         if (devices == null) {
131             mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
132             return;
133         }
134         if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
135             CachedBluetoothDevice connectedDevice = null;
136             for (CachedBluetoothDevice device : devices) {
137                 if (device.isConnected()) {
138                     connectedDevice = device;
139                     break;
140                 }
141             }
142             if (connectedDevice == null) {
143                 // If somehow we think we are connected, but have no connected devices, we
144                 // aren't connected.
145                 mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
146             }
147         }
148     }
149 
getDevices()150     private Collection<CachedBluetoothDevice> getDevices() {
151         return mBluetoothManager != null
152             ? mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
153             : null;
154     }
155 
156     @VisibleForTesting
getConnectedDeviceSummary()157     String getConnectedDeviceSummary() {
158         String deviceName = null;
159         int count = 0;
160         final Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
161         if (devices == null || devices.isEmpty()) {
162             return null;
163         }
164 
165         for (BluetoothDevice device : devices) {
166             if (device.isConnected()) {
167                 deviceName = device.getName();
168                 count++;
169                 if (count > 1) {
170                     break;
171                 }
172             }
173         }
174 
175         return count > 1 ? mContext.getString(R.string.bluetooth_connected_multiple_devices_summary)
176                 : mContext.getString(R.string.bluetooth_connected_summary, deviceName);
177     }
178 
179 }
180