Synchronize get/set of BluetoothMapClient
Change-Id: Ib8386c290c961bb0081c74801838bc2f34586a31
Fix: 135629708
Test: manual
diff --git a/res/values/config.xml b/res/values/config.xml
index 56cb667..0696f07 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -18,4 +18,7 @@
<!-- Whether existing messages should be loaded. Recommended to turn off if head-unit's and
BT-paired phone's clocks are not synced.-->
<bool name="config_loadExistingMessages">false</bool>
+ <!-- Whether app should attempt to reconnect to Bluetooth MAP profile, once MAP is
+ disconnected. -->
+ <bool name="config_reconnectToMap">true</bool>
</resources>
diff --git a/src/com/android/car/messenger/MessengerDelegate.java b/src/com/android/car/messenger/MessengerDelegate.java
index 6328905..643a58d 100644
--- a/src/com/android/car/messenger/MessengerDelegate.java
+++ b/src/com/android/car/messenger/MessengerDelegate.java
@@ -7,6 +7,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
+import android.bluetooth.BluetoothProfile;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
@@ -34,6 +35,7 @@
import com.android.car.messenger.bluetooth.BluetoothHelper;
import com.android.car.messenger.bluetooth.BluetoothMonitor;
import com.android.car.messenger.log.L;
+import com.android.internal.annotations.GuardedBy;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
@@ -53,8 +55,10 @@
private static final String TAG = "CM.MessengerDelegate";
// Static user name for building a MessagingStyle.
private static final String STATIC_USER_NAME = "STATIC_USER_NAME";
+ private static final Object mMapClientLock = new Object();
private final Context mContext;
+ @GuardedBy("mMapClientLock")
private BluetoothMapClient mBluetoothMapClient;
private NotificationManager mNotificationManager;
private final SmsDatabaseHandler mSmsDatabaseHandler;
@@ -112,12 +116,14 @@
public void onDeviceConnected(BluetoothDevice device) {
L.d(TAG, "Device connected: \t%s", device.getAddress());
mBTDeviceAddressToConnectionTimestamp.put(device.getAddress(), System.currentTimeMillis());
- if (mBluetoothMapClient != null && mShouldLoadExistingMessages) {
- mBluetoothMapClient.getUnreadMessages(device);
- } else {
- // onDeviceConnected should be sent by BluetoothMapClient, so log if we run into this
- // strange case.
- L.e(TAG, "BluetoothMapClient is null after connecting to device.");
+ synchronized (mMapClientLock) {
+ if (mBluetoothMapClient != null && mShouldLoadExistingMessages) {
+ mBluetoothMapClient.getUnreadMessages(device);
+ } else {
+ // onDeviceConnected should be sent by BluetoothMapClient, so log if we run into
+ // this strange case.
+ L.e(TAG, "BluetoothMapClient is null after connecting to device.");
+ }
}
}
@@ -131,24 +137,36 @@
@Override
public void onMapConnected(BluetoothMapClient client) {
- if (mBluetoothMapClient == client) {
- return;
- }
+ List<BluetoothDevice> connectedDevices;
+ synchronized (mMapClientLock) {
+ if (mBluetoothMapClient == client) {
+ return;
+ }
- if (mBluetoothMapClient != null) {
- mBluetoothMapClient.close();
- }
+ if (mBluetoothMapClient != null) {
+ mBluetoothMapClient.close();
+ }
- mBluetoothMapClient = client;
- for (BluetoothDevice device : client.getConnectedDevices()) {
- onDeviceConnected(device);
+ mBluetoothMapClient = client;
+ connectedDevices = mBluetoothMapClient.getConnectedDevices();
+ }
+ if (connectedDevices != null) {
+ for (BluetoothDevice device : connectedDevices) {
+ onDeviceConnected(device);
+ }
}
}
@Override
public void onMapDisconnected(int profile) {
- mBluetoothMapClient = null;
cleanupMessagesAndNotifications(key -> true);
+ synchronized (mMapClientLock) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ adapter.closeProfileProxy(BluetoothProfile.MAP_CLIENT, mBluetoothMapClient);
+ }
+ mBluetoothMapClient = null;
+ }
}
@Override
@@ -159,24 +177,27 @@
protected void sendMessage(SenderKey senderKey, String messageText) {
boolean success = false;
// Even if the device is not connected, try anyway so that the reply in enqueued.
- if (mBluetoothMapClient != null) {
- NotificationInfo notificationInfo = mNotificationInfos.get(senderKey);
- if (notificationInfo == null) {
- L.w(TAG, "No notificationInfo found for senderKey: %s", senderKey);
- } else if (notificationInfo.mSenderContactUri == null) {
- L.w(TAG, "Do not have contact URI for sender!");
- } else {
- Uri recipientUris[] = {Uri.parse(notificationInfo.mSenderContactUri)};
+ synchronized (mMapClientLock) {
+ if (mBluetoothMapClient != null) {
+ NotificationInfo notificationInfo = mNotificationInfos.get(senderKey);
+ if (notificationInfo == null) {
+ L.w(TAG, "No notificationInfo found for senderKey: %s", senderKey);
+ } else if (notificationInfo.mSenderContactUri == null) {
+ L.w(TAG, "Do not have contact URI for sender!");
+ } else {
+ Uri[] recipientUris = {Uri.parse(notificationInfo.mSenderContactUri)};
- final int requestCode = senderKey.hashCode();
+ final int requestCode = senderKey.hashCode();
- Intent intent = new Intent(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
- PendingIntent sentIntent = PendingIntent.getBroadcast(mContext, requestCode, intent,
- PendingIntent.FLAG_ONE_SHOT);
+ Intent intent = new Intent(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
+ PendingIntent sentIntent = PendingIntent.getBroadcast(mContext, requestCode,
+ intent,
+ PendingIntent.FLAG_ONE_SHOT);
- success = BluetoothHelper.sendMessage(mBluetoothMapClient,
- senderKey.getDeviceAddress(), recipientUris, messageText,
- sentIntent, null);
+ success = BluetoothHelper.sendMessage(mBluetoothMapClient,
+ senderKey.getDeviceAddress(), recipientUris, messageText,
+ sentIntent, null);
+ }
}
}
@@ -299,8 +320,10 @@
protected void cleanup() {
cleanupMessagesAndNotifications(key -> true);
- if (mBluetoothMapClient != null) {
- mBluetoothMapClient.close();
+ synchronized (mMapClientLock) {
+ if (mBluetoothMapClient != null) {
+ mBluetoothMapClient.close();
+ }
}
}
@@ -426,7 +449,10 @@
}
BluetoothDevice device = adapter.getRemoteDevice(deviceAddress);
- return mBluetoothMapClient.isUploadingSupported(device);
+ synchronized (mMapClientLock) {
+ return (mBluetoothMapClient != null) && mBluetoothMapClient.isUploadingSupported(
+ device);
+ }
}
/**
diff --git a/src/com/android/car/messenger/bluetooth/BluetoothMonitor.java b/src/com/android/car/messenger/bluetooth/BluetoothMonitor.java
index 7640c1c..0015ebc 100644
--- a/src/com/android/car/messenger/bluetooth/BluetoothMonitor.java
+++ b/src/com/android/car/messenger/bluetooth/BluetoothMonitor.java
@@ -9,11 +9,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources.NotFoundException;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.car.messenger.R;
import com.android.car.messenger.log.L;
import java.util.HashSet;
@@ -153,6 +155,17 @@
private void onMapDisconnected(int profile) {
mListeners.forEach(listener -> listener.onMapDisconnected(profile));
+ boolean shouldReconnectToMap = false;
+ try {
+ shouldReconnectToMap = mContext.getResources().getBoolean(
+ R.bool.config_loadExistingMessages);
+ } catch (NotFoundException e) {
+ // Should only happen for robolectric unit tests
+ L.e(TAG, e, "Could not find loadExistingMessages config");
+ }
+ if (shouldReconnectToMap) {
+ connectToMap();
+ }
}
private void onSdpRecord(BluetoothDevice device, boolean supportsReply) {