Merge "Fix sysui depending on slow bt calls" into oc-dev

am: 02d5b79cf6

Change-Id: I9a1dbc2f382562fb8ced63fd70f1a5e1674285f0
This commit is contained in:
Jason Monk
2017-06-13 21:44:03 +00:00
committed by android-build-merger
5 changed files with 138 additions and 10 deletions

View File

@@ -179,12 +179,6 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
@Override @Override
public void onBluetoothDevicesChanged() { public void onBluetoothDevicesChanged() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mDetailAdapter.updateItems();
}
});
refreshState(); refreshState();
if (isShowingDetail()) { if (isShowingDetail()) {
mDetailAdapter.updateItems(); mDetailAdapter.updateItems();
@@ -198,6 +192,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
} }
protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback { protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
// We probably won't ever have space in the UI for more than 20 devices, so don't
// get info for them.
private static final int MAX_DEVICES = 20;
private QSDetailItems mItems; private QSDetailItems mItems;
@Override @Override
@@ -260,13 +257,14 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
final Collection<CachedBluetoothDevice> devices = mController.getDevices(); final Collection<CachedBluetoothDevice> devices = mController.getDevices();
if (devices != null) { if (devices != null) {
int connectedDevices = 0; int connectedDevices = 0;
int count = 0;
for (CachedBluetoothDevice device : devices) { for (CachedBluetoothDevice device : devices) {
if (device.getBondState() == BluetoothDevice.BOND_NONE) continue; if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item(); final Item item = new Item();
item.icon = R.drawable.ic_qs_bluetooth_on; item.icon = R.drawable.ic_qs_bluetooth_on;
item.line1 = device.getName(); item.line1 = device.getName();
item.tag = device; item.tag = device;
int state = device.getMaxConnectionState(); int state = mController.getMaxConnectionState(device);
if (state == BluetoothProfile.STATE_CONNECTED) { if (state == BluetoothProfile.STATE_CONNECTED) {
item.icon = R.drawable.ic_qs_bluetooth_connected; item.icon = R.drawable.ic_qs_bluetooth_connected;
item.line2 = mContext.getString(R.string.quick_settings_connected); item.line2 = mContext.getString(R.string.quick_settings_connected);
@@ -280,6 +278,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
} else { } else {
items.add(item); items.add(item);
} }
if (++count == MAX_DEVICES) {
break;
}
} }
} }
mItems.setItems(items.toArray(new Item[items.size()])); mItems.setItems(items.toArray(new Item[items.size()]));

View File

@@ -37,6 +37,9 @@ public interface BluetoothController extends CallbackController<Callback>, Dumpa
void disconnect(CachedBluetoothDevice device); void disconnect(CachedBluetoothDevice device);
boolean canConfigBluetooth(); boolean canConfigBluetooth();
int getMaxConnectionState(CachedBluetoothDevice device);
int getBondState(CachedBluetoothDevice device);
public interface Callback { public interface Callback {
void onBluetoothStateChange(boolean enabled); void onBluetoothStateChange(boolean enabled);
void onBluetoothDevicesChanged(); void onBluetoothDevicesChanged();

View File

@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.policy;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
@@ -33,8 +35,10 @@ import com.android.systemui.Dependency;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.WeakHashMap;
public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback, public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
CachedBluetoothDevice.Callback { CachedBluetoothDevice.Callback {
@@ -44,18 +48,22 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
private final LocalBluetoothManager mLocalBluetoothManager; private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager; private final UserManager mUserManager;
private final int mCurrentUser; private final int mCurrentUser;
private final WeakHashMap<CachedBluetoothDevice, ActuallyCachedState> mCachedState =
new WeakHashMap<>();
private final Handler mBgHandler;
private boolean mEnabled; private boolean mEnabled;
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED; private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
private CachedBluetoothDevice mLastDevice; private CachedBluetoothDevice mLastDevice;
private final H mHandler = new H(); private final H mHandler = new H(Looper.getMainLooper());
private int mState; private int mState;
public BluetoothControllerImpl(Context context, Looper bgLooper) { public BluetoothControllerImpl(Context context, Looper bgLooper) {
mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class); mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class);
mBgHandler = new Handler(bgLooper);
if (mLocalBluetoothManager != null) { if (mLocalBluetoothManager != null) {
mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper)); mLocalBluetoothManager.getEventManager().setReceiverHandler(mBgHandler);
mLocalBluetoothManager.getEventManager().registerCallback(this); mLocalBluetoothManager.getEventManager().registerCallback(this);
onBluetoothStateChanged( onBluetoothStateChanged(
mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState()); mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
@@ -105,6 +113,16 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
return device.getName() + " " + device.getBondState() + " " + device.isConnected(); return device.getName() + " " + device.getBondState() + " " + device.isConnected();
} }
@Override
public int getBondState(CachedBluetoothDevice device) {
return getCachedState(device).mBondState;
}
@Override
public int getMaxConnectionState(CachedBluetoothDevice device) {
return getCachedState(device).mMaxConnectionState;
}
@Override @Override
public void addCallback(Callback cb) { public void addCallback(Callback cb) {
mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget(); mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
@@ -225,12 +243,14 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
@Override @Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
mCachedState.remove(cachedDevice);
updateConnected(); updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED); mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
} }
@Override @Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) { public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
mCachedState.remove(cachedDevice);
updateConnected(); updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED); mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
} }
@@ -243,11 +263,44 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
@Override @Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
mCachedState.remove(cachedDevice);
mLastDevice = cachedDevice; mLastDevice = cachedDevice;
updateConnected(); updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED); mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
} }
private ActuallyCachedState getCachedState(CachedBluetoothDevice device) {
ActuallyCachedState state = mCachedState.get(device);
if (state == null) {
state = new ActuallyCachedState(device, mHandler);
mBgHandler.post(state);
mCachedState.put(device, state);
return state;
}
return state;
}
private static class ActuallyCachedState implements Runnable {
private final WeakReference<CachedBluetoothDevice> mDevice;
private final Handler mUiHandler;
private int mBondState = BluetoothDevice.BOND_NONE;
private int mMaxConnectionState = BluetoothProfile.STATE_DISCONNECTED;
private ActuallyCachedState(CachedBluetoothDevice device, Handler uiHandler) {
mDevice = new WeakReference<>(device);
mUiHandler = uiHandler;
}
@Override
public void run() {
mBondState = mDevice.get().getBondState();
mMaxConnectionState = mDevice.get().getMaxConnectionState();
mUiHandler.removeMessages(H.MSG_PAIRED_DEVICES_CHANGED);
mUiHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
}
private final class H extends Handler { private final class H extends Handler {
private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>(); private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>();
@@ -256,6 +309,10 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
private static final int MSG_ADD_CALLBACK = 3; private static final int MSG_ADD_CALLBACK = 3;
private static final int MSG_REMOVE_CALLBACK = 4; private static final int MSG_REMOVE_CALLBACK = 4;
public H(Looper looper) {
super(looper);
}
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {

View File

@@ -14,16 +14,21 @@
package com.android.systemui.statusbar.policy; package com.android.systemui.statusbar.policy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.os.Looper;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableLooper.RunWithLooper;
import android.util.Log;
import com.android.settingslib.bluetooth.BluetoothEventManager; import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -80,4 +85,56 @@ public class BluetoothControllerImplTest extends SysuiTestCase {
BluetoothAdapter.STATE_DISCONNECTED); BluetoothAdapter.STATE_DISCONNECTED);
assertTrue(mBluetoothControllerImpl.isBluetoothConnected()); assertTrue(mBluetoothControllerImpl.isBluetoothConnected());
} }
@Test
public void testDefaultConnectionState() {
CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
assertEquals(BluetoothProfile.STATE_DISCONNECTED,
mBluetoothControllerImpl.getMaxConnectionState(device));
}
@Test
public void testAsyncBondState() throws Exception {
CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
mBluetoothControllerImpl.addCallback(callback);
// Grab the main looper, we'll need it later.
TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
// Trigger the state getting.
assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
mTestableLooper.processMessages(1);
mainLooper.processAllMessages();
assertEquals(BluetoothDevice.BOND_BONDED, mBluetoothControllerImpl.getBondState(device));
verify(callback).onBluetoothDevicesChanged();
mainLooper.destroy();
}
@Test
public void testAsyncConnectionState() throws Exception {
CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
mBluetoothControllerImpl.addCallback(callback);
// Grab the main looper, we'll need it later.
TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
// Trigger the state getting.
assertEquals(BluetoothProfile.STATE_DISCONNECTED,
mBluetoothControllerImpl.getMaxConnectionState(device));
mTestableLooper.processMessages(1);
mainLooper.processAllMessages();
assertEquals(BluetoothProfile.STATE_CONNECTED,
mBluetoothControllerImpl.getMaxConnectionState(device));
verify(callback).onBluetoothDevicesChanged();
mainLooper.destroy();
}
} }

View File

@@ -83,4 +83,14 @@ public class FakeBluetoothController extends BaseLeakChecker<Callback> implement
public boolean canConfigBluetooth() { public boolean canConfigBluetooth() {
return false; return false;
} }
@Override
public int getMaxConnectionState(CachedBluetoothDevice device) {
return 0;
}
@Override
public int getBondState(CachedBluetoothDevice device) {
return 0;
}
} }