Loading android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java +88 −21 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.pbapclient; import android.accounts.Account; import android.accounts.AccountManager; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetoothPbapClient; Loading @@ -23,15 +25,19 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.provider.CallLog; import android.provider.Settings; import android.util.Log; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.R; import com.android.bluetooth.Utils; import java.lang.IllegalArgumentException; import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import java.util.List; import java.util.Map; /** * Provides Bluetooth Phone Book Access Profile Client profile. Loading @@ -41,7 +47,10 @@ import java.util.List; public class PbapClientService extends ProfileService { private static final boolean DBG = false; private static final String TAG = "PbapClientService"; private PbapClientStateMachine mPbapClientStateMachine; // MAXIMUM_DEVICES set to 10 to prevent an excessive number of simultaneous devices. private static final int MAXIMUM_DEVICES = 10; private Map<BluetoothDevice, PbapClientStateMachine> mPbapClientStateMachineMap = new ConcurrentHashMap<>(); private static PbapClientService sPbapClientService; private PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver(); Loading @@ -67,9 +76,8 @@ public class PbapClientService extends ProfileService { } catch (Exception e) { Log.w(TAG,"Unable to register pbapclient receiver", e); } mPbapClientStateMachine = new PbapClientStateMachine(this, this); removeUncleanAccounts(); setPbapClientService(this); mPbapClientStateMachine.start(); return true; } Loading @@ -80,18 +88,47 @@ public class PbapClientService extends ProfileService { } catch (Exception e) { Log.w(TAG,"Unable to unregister pbapclient receiver", e); } if (mPbapClientStateMachine != null) { mPbapClientStateMachine.doQuit(); for (PbapClientStateMachine pbapClientStateMachine : mPbapClientStateMachineMap.values()) { pbapClientStateMachine.doQuit(); } return true; } @Override protected boolean cleanup() { removeUncleanAccounts(); clearPbapClientService(); return true; } void cleanupDevice(BluetoothDevice device) { Log.w(TAG, "Cleanup device: " + device); synchronized (mPbapClientStateMachineMap) { PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine != null) { mPbapClientStateMachineMap.remove(device); } } } private void removeUncleanAccounts() { // Find all accounts that match the type "pbap" and delete them. AccountManager accountManager = AccountManager.get(this); Account[] accounts = accountManager.getAccountsByType(getString(R.string.pbap_account_type)); Log.w(TAG, "Found " + accounts.length + " unclean accounts"); for (Account acc : accounts) { Log.w(TAG, "Deleting " + acc); // The device ID is the name of the account. accountManager.removeAccountExplicitly(acc); } try { getContentResolver().delete(CallLog.Calls.CONTENT_URI, null, null); } catch (IllegalArgumentException e) { Log.w(TAG, "Call Logs could not be deleted, they may not exist yet."); } } private class PbapBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Loading @@ -103,7 +140,9 @@ public class PbapClientService extends ProfileService { disconnect(device); } } else if(action.equals(Intent.ACTION_USER_UNLOCKED)) { mPbapClientStateMachine.resumeDownload(); for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) { stateMachine.resumeDownload(); } } } } Loading Loading @@ -225,7 +264,7 @@ public class PbapClientService extends ProfileService { private static synchronized void setPbapClientService(PbapClientService instance) { if (instance != null && instance.isAvailable()) { if (DBG) { Log.d(TAG, "setPbapClientService(): set to: " + sPbapClientService); Log.d(TAG, "setPbapClientService(): previously set to: " + sPbapClientService); } sPbapClientService = instance; } else { Loading @@ -247,24 +286,36 @@ public class PbapClientService extends ProfileService { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); Log.d(TAG,"Received request to ConnectPBAPPhonebook " + device.getAddress()); int connectionState = mPbapClientStateMachine.getConnectionState(); if (connectionState == BluetoothProfile.STATE_CONNECTED || connectionState == BluetoothProfile.STATE_CONNECTING) { Log.w(TAG,"Received connect request while already connecting/connected."); if (getPriority(device) <= BluetoothProfile.PRIORITY_OFF) { return false; } if (getPriority(device) > BluetoothProfile.PRIORITY_OFF) { mPbapClientStateMachine.connect(device); synchronized (mPbapClientStateMachineMap) { PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine == null && mPbapClientStateMachineMap.size() < MAXIMUM_DEVICES) { pbapClientStateMachine = new PbapClientStateMachine(this, device); pbapClientStateMachine.start(); mPbapClientStateMachineMap.put(device, pbapClientStateMachine); return true; } } else { Log.w(TAG, "Received connect request while already connecting/connected."); return false; } } } boolean disconnect(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); mPbapClientStateMachine.disconnect(device); PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine != null) { pbapClientStateMachine.disconnect(device); return true; } else { Log.w(TAG, "disconnect() called on unconnected device."); return false; } } public List<BluetoothDevice> getConnectedDevices() { Loading @@ -275,13 +326,29 @@ public class PbapClientService extends ProfileService { private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mPbapClientStateMachine.getDevicesMatchingConnectionStates(states); List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(0); for (Map.Entry<BluetoothDevice, PbapClientStateMachine> stateMachineEntry : mPbapClientStateMachineMap.entrySet()) { int currentDeviceState = stateMachineEntry.getValue().getConnectionState(); for (int state : states) { if (currentDeviceState == state) { deviceList.add(stateMachineEntry.getKey()); break; } } } return deviceList; } int getConnectionState(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mPbapClientStateMachine.getConnectionState(device); PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine == null) { return BluetoothProfile.STATE_DISCONNECTED; } else { return pbapClientStateMachine.getConnectionState(device); } } public boolean setPriority(BluetoothDevice device, int priority) { Loading @@ -308,8 +375,8 @@ public class PbapClientService extends ProfileService { @Override public void dump(StringBuilder sb) { super.dump(sb); if (mPbapClientStateMachine != null) { mPbapClientStateMachine.dump(sb); for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) { stateMachine.dump(sb); } } } android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java +24 −100 Original line number Diff line number Diff line Loading @@ -41,8 +41,6 @@ */ package com.android.bluetooth.pbapclient; import android.accounts.Account; import android.accounts.AccountManager; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothPbapClient; Loading @@ -56,7 +54,6 @@ import android.os.Message; import android.os.ParcelUuid; import android.os.Process; import android.os.UserManager; import android.provider.CallLog; import android.util.Log; import com.android.bluetooth.btservice.ProfileService; Loading @@ -65,7 +62,6 @@ import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import java.lang.IllegalStateException; import java.util.ArrayList; import java.util.List; Loading @@ -74,7 +70,6 @@ final class PbapClientStateMachine extends StateMachine { private static final String TAG = "PbapClientStateMachine"; // Messages for handling connect/disconnect requests. private static final int MSG_CONNECT = 1; private static final int MSG_DISCONNECT = 2; private static final int MSG_SDP_COMPLETE = 9; Loading @@ -98,9 +93,8 @@ final class PbapClientStateMachine extends StateMachine { private State mDisconnecting; // mCurrentDevice may only be changed in Disconnected State. private BluetoothDevice mCurrentDevice = null; private final BluetoothDevice mCurrentDevice; private PbapClientService mService; private Context mContext; private PbapClientConnectionHandler mConnectionHandler; private HandlerThread mHandlerThread = null; private UserManager mUserManager = null; Loading @@ -108,25 +102,24 @@ final class PbapClientStateMachine extends StateMachine { // mMostRecentState maintains previous state for broadcasting transitions. private int mMostRecentState = BluetoothProfile.STATE_DISCONNECTED; PbapClientStateMachine(PbapClientService svc, Context context) { PbapClientStateMachine(PbapClientService svc, BluetoothDevice device) { super(TAG); mService = svc; mContext = context; mCurrentDevice = device; mLock = new Object(); mUserManager = UserManager.get(mContext); mUserManager = UserManager.get(mService); mDisconnected = new Disconnected(); mConnecting = new Connecting(); mDisconnecting = new Disconnecting(); mConnected = new Connected(); removeUncleanAccounts(); addState(mDisconnected); addState(mConnecting); addState(mDisconnecting); addState(mConnected); setInitialState(mDisconnected); setInitialState(mConnecting); } class Disconnected extends State { Loading @@ -136,44 +129,7 @@ final class PbapClientStateMachine extends StateMachine { onConnectionStateChanged(mCurrentDevice, mMostRecentState, BluetoothProfile.STATE_DISCONNECTED); mMostRecentState = BluetoothProfile.STATE_DISCONNECTED; synchronized (mLock) { mCurrentDevice = null; } } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, "Processing MSG " + message.what + " from " + this.getName()); switch (message.what) { case MSG_CONNECT: if (message.obj instanceof BluetoothDevice) { synchronized (mLock) { mCurrentDevice = (BluetoothDevice) message.obj; } transitionTo(mConnecting); } else { Log.w(TAG, "Received CONNECT without valid device"); throw new IllegalStateException("invalid device"); } break; case MSG_DISCONNECT: Log.w(TAG, "Received unexpected disconnect while disconnected."); // It is possible if something crashed for others to think we are connected // already, just remind them. if (message.obj instanceof BluetoothDevice) { onConnectionStateChanged((BluetoothDevice) message.obj, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_DISCONNECTED); } break; default: Log.w(TAG, "Received unexpected message while disconnected."); return NOT_HANDLED; } return HANDLED; quit(); } } Loading @@ -197,9 +153,10 @@ final class PbapClientStateMachine extends StateMachine { mHandlerThread.start(); mConnectionHandler = new PbapClientConnectionHandler.Builder() .setLooper(mHandlerThread.getLooper()) .setContext(mContext) .setContext(mService) .setClientSM(PbapClientStateMachine.this) .setRemoteDevice(mCurrentDevice).build(); .setRemoteDevice(mCurrentDevice) .build(); sendMessageDelayed(MSG_CONNECT_TIMEOUT, CONNECT_TIMEOUT); } Loading @@ -209,8 +166,8 @@ final class PbapClientStateMachine extends StateMachine { if (DBG) Log.d(TAG, "Processing MSG " + message.what + " from " + this.getName()); switch (message.what) { case MSG_DISCONNECT: if (message.obj instanceof BluetoothDevice && ((BluetoothDevice) message.obj).equals(mCurrentDevice)) { if (message.obj instanceof BluetoothDevice && message.obj.equals(mCurrentDevice)) { removeMessages(MSG_CONNECT_TIMEOUT); transitionTo(mDisconnecting); } Loading @@ -227,10 +184,6 @@ final class PbapClientStateMachine extends StateMachine { transitionTo(mDisconnecting); break; case MSG_CONNECT: Log.w(TAG, "Connecting already in progress"); break; case MSG_SDP_COMPLETE: mConnectionHandler.obtainMessage(PbapClientConnectionHandler.MSG_CONNECT, message.obj).sendToTarget(); Loading Loading @@ -275,11 +228,11 @@ final class PbapClientStateMachine extends StateMachine { public void register() { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_SDP_RECORD); mContext.registerReceiver(this, filter); mService.registerReceiver(this, filter); } public void unregister() { mContext.unregisterReceiver(this); mService.unregisterReceiver(this); } } } Loading @@ -306,7 +259,6 @@ final class PbapClientStateMachine extends StateMachine { transitionTo(mDisconnected); break; case MSG_CONNECT: case MSG_DISCONNECT: deferMessage(message); break; Loading Loading @@ -345,14 +297,6 @@ final class PbapClientStateMachine extends StateMachine { public boolean processMessage(Message message) { if (DBG) Log.d(TAG, "Processing MSG " + message.what + " from " + this.getName()); switch (message.what) { case MSG_CONNECT: onConnectionStateChanged(mCurrentDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTED); Log.w(TAG, "Received CONNECT while Connected, ignoring"); break; case MSG_DISCONNECT: if ((message.obj instanceof BluetoothDevice) && ((BluetoothDevice) message.obj).equals(mCurrentDevice)) { Loading Loading @@ -384,34 +328,32 @@ final class PbapClientStateMachine extends StateMachine { intent.putExtra(BluetoothProfile.EXTRA_STATE, state); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); mService.notifyProfileConnectionStateChanged(device, BluetoothProfile.PBAP_CLIENT, state, prevState); } public void connect(BluetoothDevice device) { Log.d(TAG, "Connect Request " + device.getAddress()); sendMessage(MSG_CONNECT, device); } public void disconnect(BluetoothDevice device) { Log.d(TAG, "Disconnect Request " + device); sendMessage(MSG_DISCONNECT, device); } public void resumeDownload() { removeUncleanAccounts(); sendMessage(MSG_RESUME_DOWNLOAD); } void doQuit() { removeUncleanAccounts(); if (mHandlerThread != null) { mHandlerThread.quitSafely(); } quitNow(); } @Override protected void onQuitting() { mService.cleanupDevice(mCurrentDevice); } public int getConnectionState() { IState currentState = getCurrentState(); if (currentState instanceof Disconnected) { Loading @@ -428,8 +370,8 @@ final class PbapClientStateMachine extends StateMachine { } public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { int clientState = -1; BluetoothDevice currentDevice = null; int clientState; BluetoothDevice currentDevice; synchronized (mLock) { clientState = getConnectionState(); currentDevice = getDevice(); Loading Loading @@ -472,25 +414,7 @@ final class PbapClientStateMachine extends StateMachine { } Context getContext() { return mContext; } private void removeUncleanAccounts() { // Find all accounts that match the type "pbap" and delete them. AccountManager accountManager = AccountManager.get(mContext); Account[] accounts = accountManager.getAccountsByType( mContext.getString(R.string.pbap_account_type)); Log.w(TAG, "Found " + accounts.length + " unclean accounts"); for (Account acc : accounts) { Log.w(TAG, "Deleting " + acc); // The device ID is the name of the account. accountManager.removeAccountExplicitly(acc); } try { mContext.getContentResolver().delete(CallLog.Calls.CONTENT_URI, null, null); } catch (IllegalArgumentException e) { // CallLogs could not be deleted, they may not exist yet. } return mService; } public void dump(StringBuilder sb) { Loading Loading
android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java +88 −21 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.pbapclient; import android.accounts.Account; import android.accounts.AccountManager; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetoothPbapClient; Loading @@ -23,15 +25,19 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.provider.CallLog; import android.provider.Settings; import android.util.Log; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.R; import com.android.bluetooth.Utils; import java.lang.IllegalArgumentException; import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import java.util.List; import java.util.Map; /** * Provides Bluetooth Phone Book Access Profile Client profile. Loading @@ -41,7 +47,10 @@ import java.util.List; public class PbapClientService extends ProfileService { private static final boolean DBG = false; private static final String TAG = "PbapClientService"; private PbapClientStateMachine mPbapClientStateMachine; // MAXIMUM_DEVICES set to 10 to prevent an excessive number of simultaneous devices. private static final int MAXIMUM_DEVICES = 10; private Map<BluetoothDevice, PbapClientStateMachine> mPbapClientStateMachineMap = new ConcurrentHashMap<>(); private static PbapClientService sPbapClientService; private PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver(); Loading @@ -67,9 +76,8 @@ public class PbapClientService extends ProfileService { } catch (Exception e) { Log.w(TAG,"Unable to register pbapclient receiver", e); } mPbapClientStateMachine = new PbapClientStateMachine(this, this); removeUncleanAccounts(); setPbapClientService(this); mPbapClientStateMachine.start(); return true; } Loading @@ -80,18 +88,47 @@ public class PbapClientService extends ProfileService { } catch (Exception e) { Log.w(TAG,"Unable to unregister pbapclient receiver", e); } if (mPbapClientStateMachine != null) { mPbapClientStateMachine.doQuit(); for (PbapClientStateMachine pbapClientStateMachine : mPbapClientStateMachineMap.values()) { pbapClientStateMachine.doQuit(); } return true; } @Override protected boolean cleanup() { removeUncleanAccounts(); clearPbapClientService(); return true; } void cleanupDevice(BluetoothDevice device) { Log.w(TAG, "Cleanup device: " + device); synchronized (mPbapClientStateMachineMap) { PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine != null) { mPbapClientStateMachineMap.remove(device); } } } private void removeUncleanAccounts() { // Find all accounts that match the type "pbap" and delete them. AccountManager accountManager = AccountManager.get(this); Account[] accounts = accountManager.getAccountsByType(getString(R.string.pbap_account_type)); Log.w(TAG, "Found " + accounts.length + " unclean accounts"); for (Account acc : accounts) { Log.w(TAG, "Deleting " + acc); // The device ID is the name of the account. accountManager.removeAccountExplicitly(acc); } try { getContentResolver().delete(CallLog.Calls.CONTENT_URI, null, null); } catch (IllegalArgumentException e) { Log.w(TAG, "Call Logs could not be deleted, they may not exist yet."); } } private class PbapBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Loading @@ -103,7 +140,9 @@ public class PbapClientService extends ProfileService { disconnect(device); } } else if(action.equals(Intent.ACTION_USER_UNLOCKED)) { mPbapClientStateMachine.resumeDownload(); for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) { stateMachine.resumeDownload(); } } } } Loading Loading @@ -225,7 +264,7 @@ public class PbapClientService extends ProfileService { private static synchronized void setPbapClientService(PbapClientService instance) { if (instance != null && instance.isAvailable()) { if (DBG) { Log.d(TAG, "setPbapClientService(): set to: " + sPbapClientService); Log.d(TAG, "setPbapClientService(): previously set to: " + sPbapClientService); } sPbapClientService = instance; } else { Loading @@ -247,24 +286,36 @@ public class PbapClientService extends ProfileService { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); Log.d(TAG,"Received request to ConnectPBAPPhonebook " + device.getAddress()); int connectionState = mPbapClientStateMachine.getConnectionState(); if (connectionState == BluetoothProfile.STATE_CONNECTED || connectionState == BluetoothProfile.STATE_CONNECTING) { Log.w(TAG,"Received connect request while already connecting/connected."); if (getPriority(device) <= BluetoothProfile.PRIORITY_OFF) { return false; } if (getPriority(device) > BluetoothProfile.PRIORITY_OFF) { mPbapClientStateMachine.connect(device); synchronized (mPbapClientStateMachineMap) { PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine == null && mPbapClientStateMachineMap.size() < MAXIMUM_DEVICES) { pbapClientStateMachine = new PbapClientStateMachine(this, device); pbapClientStateMachine.start(); mPbapClientStateMachineMap.put(device, pbapClientStateMachine); return true; } } else { Log.w(TAG, "Received connect request while already connecting/connected."); return false; } } } boolean disconnect(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); mPbapClientStateMachine.disconnect(device); PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine != null) { pbapClientStateMachine.disconnect(device); return true; } else { Log.w(TAG, "disconnect() called on unconnected device."); return false; } } public List<BluetoothDevice> getConnectedDevices() { Loading @@ -275,13 +326,29 @@ public class PbapClientService extends ProfileService { private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mPbapClientStateMachine.getDevicesMatchingConnectionStates(states); List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(0); for (Map.Entry<BluetoothDevice, PbapClientStateMachine> stateMachineEntry : mPbapClientStateMachineMap.entrySet()) { int currentDeviceState = stateMachineEntry.getValue().getConnectionState(); for (int state : states) { if (currentDeviceState == state) { deviceList.add(stateMachineEntry.getKey()); break; } } } return deviceList; } int getConnectionState(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mPbapClientStateMachine.getConnectionState(device); PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device); if (pbapClientStateMachine == null) { return BluetoothProfile.STATE_DISCONNECTED; } else { return pbapClientStateMachine.getConnectionState(device); } } public boolean setPriority(BluetoothDevice device, int priority) { Loading @@ -308,8 +375,8 @@ public class PbapClientService extends ProfileService { @Override public void dump(StringBuilder sb) { super.dump(sb); if (mPbapClientStateMachine != null) { mPbapClientStateMachine.dump(sb); for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) { stateMachine.dump(sb); } } }
android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java +24 −100 Original line number Diff line number Diff line Loading @@ -41,8 +41,6 @@ */ package com.android.bluetooth.pbapclient; import android.accounts.Account; import android.accounts.AccountManager; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothPbapClient; Loading @@ -56,7 +54,6 @@ import android.os.Message; import android.os.ParcelUuid; import android.os.Process; import android.os.UserManager; import android.provider.CallLog; import android.util.Log; import com.android.bluetooth.btservice.ProfileService; Loading @@ -65,7 +62,6 @@ import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import java.lang.IllegalStateException; import java.util.ArrayList; import java.util.List; Loading @@ -74,7 +70,6 @@ final class PbapClientStateMachine extends StateMachine { private static final String TAG = "PbapClientStateMachine"; // Messages for handling connect/disconnect requests. private static final int MSG_CONNECT = 1; private static final int MSG_DISCONNECT = 2; private static final int MSG_SDP_COMPLETE = 9; Loading @@ -98,9 +93,8 @@ final class PbapClientStateMachine extends StateMachine { private State mDisconnecting; // mCurrentDevice may only be changed in Disconnected State. private BluetoothDevice mCurrentDevice = null; private final BluetoothDevice mCurrentDevice; private PbapClientService mService; private Context mContext; private PbapClientConnectionHandler mConnectionHandler; private HandlerThread mHandlerThread = null; private UserManager mUserManager = null; Loading @@ -108,25 +102,24 @@ final class PbapClientStateMachine extends StateMachine { // mMostRecentState maintains previous state for broadcasting transitions. private int mMostRecentState = BluetoothProfile.STATE_DISCONNECTED; PbapClientStateMachine(PbapClientService svc, Context context) { PbapClientStateMachine(PbapClientService svc, BluetoothDevice device) { super(TAG); mService = svc; mContext = context; mCurrentDevice = device; mLock = new Object(); mUserManager = UserManager.get(mContext); mUserManager = UserManager.get(mService); mDisconnected = new Disconnected(); mConnecting = new Connecting(); mDisconnecting = new Disconnecting(); mConnected = new Connected(); removeUncleanAccounts(); addState(mDisconnected); addState(mConnecting); addState(mDisconnecting); addState(mConnected); setInitialState(mDisconnected); setInitialState(mConnecting); } class Disconnected extends State { Loading @@ -136,44 +129,7 @@ final class PbapClientStateMachine extends StateMachine { onConnectionStateChanged(mCurrentDevice, mMostRecentState, BluetoothProfile.STATE_DISCONNECTED); mMostRecentState = BluetoothProfile.STATE_DISCONNECTED; synchronized (mLock) { mCurrentDevice = null; } } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, "Processing MSG " + message.what + " from " + this.getName()); switch (message.what) { case MSG_CONNECT: if (message.obj instanceof BluetoothDevice) { synchronized (mLock) { mCurrentDevice = (BluetoothDevice) message.obj; } transitionTo(mConnecting); } else { Log.w(TAG, "Received CONNECT without valid device"); throw new IllegalStateException("invalid device"); } break; case MSG_DISCONNECT: Log.w(TAG, "Received unexpected disconnect while disconnected."); // It is possible if something crashed for others to think we are connected // already, just remind them. if (message.obj instanceof BluetoothDevice) { onConnectionStateChanged((BluetoothDevice) message.obj, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_DISCONNECTED); } break; default: Log.w(TAG, "Received unexpected message while disconnected."); return NOT_HANDLED; } return HANDLED; quit(); } } Loading @@ -197,9 +153,10 @@ final class PbapClientStateMachine extends StateMachine { mHandlerThread.start(); mConnectionHandler = new PbapClientConnectionHandler.Builder() .setLooper(mHandlerThread.getLooper()) .setContext(mContext) .setContext(mService) .setClientSM(PbapClientStateMachine.this) .setRemoteDevice(mCurrentDevice).build(); .setRemoteDevice(mCurrentDevice) .build(); sendMessageDelayed(MSG_CONNECT_TIMEOUT, CONNECT_TIMEOUT); } Loading @@ -209,8 +166,8 @@ final class PbapClientStateMachine extends StateMachine { if (DBG) Log.d(TAG, "Processing MSG " + message.what + " from " + this.getName()); switch (message.what) { case MSG_DISCONNECT: if (message.obj instanceof BluetoothDevice && ((BluetoothDevice) message.obj).equals(mCurrentDevice)) { if (message.obj instanceof BluetoothDevice && message.obj.equals(mCurrentDevice)) { removeMessages(MSG_CONNECT_TIMEOUT); transitionTo(mDisconnecting); } Loading @@ -227,10 +184,6 @@ final class PbapClientStateMachine extends StateMachine { transitionTo(mDisconnecting); break; case MSG_CONNECT: Log.w(TAG, "Connecting already in progress"); break; case MSG_SDP_COMPLETE: mConnectionHandler.obtainMessage(PbapClientConnectionHandler.MSG_CONNECT, message.obj).sendToTarget(); Loading Loading @@ -275,11 +228,11 @@ final class PbapClientStateMachine extends StateMachine { public void register() { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_SDP_RECORD); mContext.registerReceiver(this, filter); mService.registerReceiver(this, filter); } public void unregister() { mContext.unregisterReceiver(this); mService.unregisterReceiver(this); } } } Loading @@ -306,7 +259,6 @@ final class PbapClientStateMachine extends StateMachine { transitionTo(mDisconnected); break; case MSG_CONNECT: case MSG_DISCONNECT: deferMessage(message); break; Loading Loading @@ -345,14 +297,6 @@ final class PbapClientStateMachine extends StateMachine { public boolean processMessage(Message message) { if (DBG) Log.d(TAG, "Processing MSG " + message.what + " from " + this.getName()); switch (message.what) { case MSG_CONNECT: onConnectionStateChanged(mCurrentDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTED); Log.w(TAG, "Received CONNECT while Connected, ignoring"); break; case MSG_DISCONNECT: if ((message.obj instanceof BluetoothDevice) && ((BluetoothDevice) message.obj).equals(mCurrentDevice)) { Loading Loading @@ -384,34 +328,32 @@ final class PbapClientStateMachine extends StateMachine { intent.putExtra(BluetoothProfile.EXTRA_STATE, state); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); mService.notifyProfileConnectionStateChanged(device, BluetoothProfile.PBAP_CLIENT, state, prevState); } public void connect(BluetoothDevice device) { Log.d(TAG, "Connect Request " + device.getAddress()); sendMessage(MSG_CONNECT, device); } public void disconnect(BluetoothDevice device) { Log.d(TAG, "Disconnect Request " + device); sendMessage(MSG_DISCONNECT, device); } public void resumeDownload() { removeUncleanAccounts(); sendMessage(MSG_RESUME_DOWNLOAD); } void doQuit() { removeUncleanAccounts(); if (mHandlerThread != null) { mHandlerThread.quitSafely(); } quitNow(); } @Override protected void onQuitting() { mService.cleanupDevice(mCurrentDevice); } public int getConnectionState() { IState currentState = getCurrentState(); if (currentState instanceof Disconnected) { Loading @@ -428,8 +370,8 @@ final class PbapClientStateMachine extends StateMachine { } public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { int clientState = -1; BluetoothDevice currentDevice = null; int clientState; BluetoothDevice currentDevice; synchronized (mLock) { clientState = getConnectionState(); currentDevice = getDevice(); Loading Loading @@ -472,25 +414,7 @@ final class PbapClientStateMachine extends StateMachine { } Context getContext() { return mContext; } private void removeUncleanAccounts() { // Find all accounts that match the type "pbap" and delete them. AccountManager accountManager = AccountManager.get(mContext); Account[] accounts = accountManager.getAccountsByType( mContext.getString(R.string.pbap_account_type)); Log.w(TAG, "Found " + accounts.length + " unclean accounts"); for (Account acc : accounts) { Log.w(TAG, "Deleting " + acc); // The device ID is the name of the account. accountManager.removeAccountExplicitly(acc); } try { mContext.getContentResolver().delete(CallLog.Calls.CONTENT_URI, null, null); } catch (IllegalArgumentException e) { // CallLogs could not be deleted, they may not exist yet. } return mService; } public void dump(StringBuilder sb) { Loading