summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Auto Companion <no-reply@google.com>2022-04-27 10:01:08 -0700
committerErin Yan <yiranyan@google.com>2022-05-12 18:49:36 +0000
commite1858e69ac1a245dc9d15edfacabb634f00b84b7 (patch)
tree5d0a3ba59bfc32ba2ee21f07b6abc7a2f54bed0f
parent6e80f2f7f920a8aa2c0d3e2372d54b005bf5d2d1 (diff)
downloadCompanionDeviceSupport-e1858e69ac1a245dc9d15edfacabb634f00b84b7.tar.gz
Project import generated by Copybara
Included changes: Release-Id: aae-companiondevice-android_20220427.00_RC00 Change-Id: Ifced9528c51d5d1bdfb310d65dff41c0053a728d
-rw-r--r--companiondevice/build.gradle2
-rw-r--r--companiondevice/res/values/dimens.xml2
-rw-r--r--companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java12
-rw-r--r--libs/connecteddevice/res/values/config.xml2
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/api/CompanionConnector.kt44
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/BaseNotificationDelegate.java7
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceFgUserService.kt2
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/api/CompanionConnectorTest.kt97
8 files changed, 156 insertions, 12 deletions
diff --git a/companiondevice/build.gradle b/companiondevice/build.gradle
index c12b2f5..6dd8f99 100644
--- a/companiondevice/build.gradle
+++ b/companiondevice/build.gradle
@@ -14,7 +14,7 @@ android {
applicationId "com.google.android.companiondevicesupport"
minSdkVersion 29
targetSdkVersion 31
- versionCode 1441
+ versionCode 1477
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/companiondevice/res/values/dimens.xml b/companiondevice/res/values/dimens.xml
index c5f9a79..f98b9a3 100644
--- a/companiondevice/res/values/dimens.xml
+++ b/companiondevice/res/values/dimens.xml
@@ -44,7 +44,7 @@
<!-- Common -->
<dimen name="divider_height">1dp</dimen>
- <dimen name="qr_code_size">200dp</dimen>
+ <dimen name="qr_code_size">300dp</dimen>
<dimen name="instruction_margin">8dp</dimen>
<dimen name="connection_indicator_size">12dp</dimen>
<dimen name="connection_indicator_margin_end">12dp</dimen>
diff --git a/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java b/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java
index 266648a..9ead484 100644
--- a/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java
+++ b/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java
@@ -30,9 +30,11 @@ import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.StrictMode;
import android.os.UserManager;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
@@ -101,6 +103,8 @@ public class AssociationActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
+ // TODO(b/228328725): Remove strict mode change when the violation is resolved.
+ maybeEnableStrictMode();
resolveIntent();
// Set theme before calling super.onCreate(bundle) to avoid recreating activity.
@@ -721,6 +725,14 @@ public class AssociationActivity extends FragmentActivity {
return RemoteFeature.ACTION_ASSOCIATION_SETTING.equals(action);
}
+ private static void maybeEnableStrictMode() {
+ if (!Build.TYPE.equals("user")) {
+ StrictMode.setThreadPolicy(
+ new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().penaltyDialog().build());
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
+ }
+ }
+
/** Dialog fragment to turn on bluetooth. */
public static class TurnOnBluetoothDialogFragment extends DialogFragment {
@Override
diff --git a/libs/connecteddevice/res/values/config.xml b/libs/connecteddevice/res/values/config.xml
index 281973d..4feb25c 100644
--- a/libs/connecteddevice/res/values/config.xml
+++ b/libs/connecteddevice/res/values/config.xml
@@ -17,5 +17,5 @@
<resources>
<!-- Current version of the SDK -->
- <string name="hu_companion_sdk_version" translatable="false">1.3.1</string>
+ <string name="hu_companion_sdk_version" translatable="false">1.3.2</string>
</resources>
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/api/CompanionConnector.kt b/libs/connecteddevice/src/com/google/android/connecteddevice/api/CompanionConnector.kt
index fec1907..69c9e41 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/api/CompanionConnector.kt
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/api/CompanionConnector.kt
@@ -77,6 +77,8 @@ constructor(
private val isPlatformInitialized = AtomicBoolean(false)
+ private val waitingForConnection = AtomicBoolean(false)
+
private val featureCoordinatorAction =
if (isForegroundProcess) {
ACTION_BIND_FEATURE_COORDINATOR_FG
@@ -92,6 +94,7 @@ constructor(
IFeatureCoordinator.Stub.asInterface(service)
?: throw IllegalStateException("Cannot create wrapper of a null feature coordinator.")
logd(TAG, "Feature coordinator is alive: ${featureCoordinator?.asBinder()?.isBinderAlive}")
+ waitingForConnection.set(false)
this@CompanionConnector.onServiceConnected()
}
@@ -100,9 +103,12 @@ constructor(
}
override fun onNullBinding(name: ComponentName) {
- loge(TAG, "Received a null binding for FeatureCoordinator.")
this@CompanionConnector.onNullBinding()
}
+
+ override fun onBindingDied(name: ComponentName?) {
+ this@CompanionConnector.onBindingDied()
+ }
}
private val connectionCallback =
@@ -231,7 +237,13 @@ constructor(
initializePlatform()
return
}
+ if (waitingForConnection.compareAndSet(false, true)) {
+ bindAttempts = 0
+ bindToService()
+ }
+ }
+ private fun bindToService() {
logd(TAG, "Platform is not currently connected. Initiating binding.")
val intent = resolveIntent(featureCoordinatorAction)
@@ -250,17 +262,25 @@ constructor(
bindAttempts++
if (bindAttempts > MAX_BIND_ATTEMPTS) {
loge(TAG, "Failed to bind to service after $bindAttempts attempts. Aborting.")
+ waitingForConnection.set(false)
callback?.onFailedToConnect()
return
}
logw(TAG, "Unable to bind to service with action ${intent.action}. Trying again.")
- retryHandler.postDelayed(::connect, BIND_RETRY_DURATION.toMillis())
+ retryHandler.postDelayed(::bindToService, BIND_RETRY_DURATION.toMillis())
}
override fun disconnect() {
logd(TAG, "Disconnecting from the companion platform.")
val wasConnected = isBound
logd(TAG, "FeatureCoordinator is null: ${featureCoordinator == null} isBound: $isBound")
+ unbindFromService()
+ if (wasConnected) {
+ callback?.onDisconnected()
+ }
+ }
+
+ private fun unbindFromService() {
cleanUpFeatureCoordinator()
retryHandler.removeCallbacksAndMessages(/* token= */ null)
try {
@@ -268,10 +288,7 @@ constructor(
} catch (e: IllegalArgumentException) {
logw(TAG, "Attempted to unbind an already unbound service.")
}
- bindAttempts = 0
- if (wasConnected) {
- callback?.onDisconnected()
- }
+ waitingForConnection.set(false)
}
private fun cleanUpFeatureCoordinator() {
@@ -301,10 +318,14 @@ constructor(
}
override fun binderForAction(action: String): IBinder? {
+ logd(TAG, "Binder for action: $action.")
return when (action) {
ACTION_BIND_FEATURE_COORDINATOR, ACTION_BIND_FEATURE_COORDINATOR_FG ->
featureCoordinator?.asBinder()
- else -> null
+ else -> {
+ loge(TAG, "Binder for unexpected action, returning null binder.")
+ null
+ }
}
}
@@ -634,10 +655,17 @@ constructor(
}
private fun onNullBinding() {
- logd(TAG, "Issuing onFailedToConnect callback after null binding.")
+ loge(TAG, "Received a null binding for FeatureCoordinator. Unbinding service.")
+ unbindFromService()
callback?.onFailedToConnect()
}
+ private fun onBindingDied() {
+ logw(TAG, "FeatureCoordinator binding died. Unbinding service.")
+ unbindFromService()
+ callback?.onDisconnected()
+ }
+
private fun resolveIntent(action: String): Intent? {
val packageManager = context.packageManager
val intent = Intent(action)
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/BaseNotificationDelegate.java b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/BaseNotificationDelegate.java
index 8196328..9b4e787 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/BaseNotificationDelegate.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/BaseNotificationDelegate.java
@@ -85,6 +85,10 @@ public class BaseNotificationDelegate {
public static final String EXTRA_REMOTE_INPUT_KEY =
"com.android.car.messenger.common.REMOTE_INPUT_KEY";
+ /** Used to override default notification large icon. **/
+ private static final String EXTRA_USE_LAUNCHER_ICON =
+ "com.android.car.notification.EXTRA_USE_LAUNCHER_ICON";
+
private static final String REPLY = "Reply";
private static final String MARK_AS_READ = "Mark As Read";
@@ -234,6 +238,9 @@ public class BaseNotificationDelegate {
notificationInfo.messageKeys.size(),
notificationInfo.messageKeys.size()));
+ Bundle avatarBundle = new Bundle();
+ avatarBundle.putBoolean(EXTRA_USE_LAUNCHER_ICON, false);
+ builder.addExtras(avatarBundle);
if (avatarIcon != null) {
builder.setLargeIcon(avatarIcon);
} else if (useLetterTile) {
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceFgUserService.kt b/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceFgUserService.kt
index 5003a4f..114bc9c 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceFgUserService.kt
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceFgUserService.kt
@@ -89,8 +89,8 @@ class ConnectedDeviceFgUserService : TrunkService() {
}
override fun onBind(intent: Intent): IBinder? {
+ logd(TAG, "Service bound. Action: ${intent.action}")
val action = intent.action ?: return null
- logd(TAG, "Service bound. Action: $action")
return connector.binderForAction(action)
}
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/api/CompanionConnectorTest.kt b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/api/CompanionConnectorTest.kt
index b09c7d4..040ea11 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/api/CompanionConnectorTest.kt
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/api/CompanionConnectorTest.kt
@@ -88,6 +88,17 @@ class CompanionConnectorTest {
}
@Test
+ fun connect_bindOnceOnlyForMultipleCalls() {
+ setQueryIntentServicesAnswer(defaultServiceAnswer)
+ val connector = CompanionConnector(context, isForegroundProcess = true)
+
+ connector.connect()
+ connector.connect()
+
+ assertThat(context.bindingActions).containsExactly(ACTION_BIND_FEATURE_COORDINATOR_FG)
+ }
+
+ @Test
fun connect_fgRetriesBindWithRemoteFeatureActionIfFeatureCoordinatorReturnsNullBinding() {
setQueryIntentServicesAnswer(defaultServiceAnswer)
val connector = CompanionConnector(context, isForegroundProcess = true)
@@ -110,6 +121,54 @@ class CompanionConnectorTest {
}
@Test
+ fun connect_canConnectAfterServiceDisconnect() {
+ setQueryIntentServicesAnswer(defaultServiceAnswer)
+ val connector = CompanionConnector(context, isForegroundProcess = true)
+ connector.connect()
+ val connection = context.serviceConnection.firstOrNull()
+ val component = ComponentName(PACKAGE_NAME, BG_NAME)
+ connection?.onServiceConnected(component, mockFeatureCoordinator.asBinder())
+ connection?.onServiceDisconnected(component)
+
+ connector.connect()
+
+ assertThat(context.bindingActions)
+ .containsExactly(ACTION_BIND_FEATURE_COORDINATOR_FG, ACTION_BIND_FEATURE_COORDINATOR_FG)
+ }
+
+ @Test
+ fun connect_canConnectAfterBindingDied() {
+ setQueryIntentServicesAnswer(defaultServiceAnswer)
+ val connector = CompanionConnector(context, isForegroundProcess = true)
+ connector.connect()
+ val connection = context.serviceConnection.firstOrNull()
+ val component = ComponentName(PACKAGE_NAME, BG_NAME)
+ connection?.onServiceConnected(component, mockFeatureCoordinator.asBinder())
+ connection?.onBindingDied(component)
+
+ connector.connect()
+
+ assertThat(context.bindingActions)
+ .containsExactly(ACTION_BIND_FEATURE_COORDINATOR_FG, ACTION_BIND_FEATURE_COORDINATOR_FG)
+ }
+
+ @Test
+ fun connect_canConnectAfterNullBinding() {
+ setQueryIntentServicesAnswer(defaultServiceAnswer)
+ val connector = CompanionConnector(context, isForegroundProcess = true)
+ connector.connect()
+ val connection = context.serviceConnection.firstOrNull()
+ val component = ComponentName(PACKAGE_NAME, BG_NAME)
+ connection?.onServiceConnected(component, mockFeatureCoordinator.asBinder())
+ connection?.onNullBinding(component)
+
+ connector.connect()
+
+ assertThat(context.bindingActions)
+ .containsExactly(ACTION_BIND_FEATURE_COORDINATOR_FG, ACTION_BIND_FEATURE_COORDINATOR_FG)
+ }
+
+ @Test
fun disconnect_invokesOnDisconnectedWhenFeatureCoordinatorConnected() {
setQueryIntentServicesAnswer(defaultServiceAnswer)
val connector =
@@ -181,6 +240,18 @@ class CompanionConnectorTest {
}
@Test
+ fun onDisconnected_invokedWhenServiceBindingDied() {
+ setQueryIntentServicesAnswer(defaultServiceAnswer)
+ val connector =
+ CompanionConnector(context, isForegroundProcess = false).apply { callback = mockCallback }
+
+ connector.connect()
+ context.serviceConnection.firstOrNull()?.onBindingDied(ComponentName(PACKAGE_NAME, BG_NAME))
+
+ verify(mockCallback).onDisconnected()
+ }
+
+ @Test
fun onFailedToConnect_invokedWhenServiceIsNotFound() {
setQueryIntentServicesAnswer(defaultServiceAnswer)
val connector =
@@ -221,6 +292,32 @@ class CompanionConnectorTest {
}
@Test
+ fun unbindService_invokedWhenServiceIsNotFound() {
+ setQueryIntentServicesAnswer(defaultServiceAnswer)
+ val connector =
+ CompanionConnector(context, isForegroundProcess = false).apply { callback = mockCallback }
+
+ connector.connect()
+ val connection = context.serviceConnection.first()
+ connection.onNullBinding(ComponentName(PACKAGE_NAME, FG_NAME))
+
+ assertThat(context.unbindServiceConnection).contains(connection)
+ }
+
+ @Test
+ fun unbindService_invokedWhenServiceBindingDied() {
+ setQueryIntentServicesAnswer(defaultServiceAnswer)
+ val connector =
+ CompanionConnector(context, isForegroundProcess = false).apply { callback = mockCallback }
+
+ connector.connect()
+ val connection = context.serviceConnection.first()
+ connection.onBindingDied(ComponentName(PACKAGE_NAME, FG_NAME))
+
+ assertThat(context.unbindServiceConnection).contains(connection)
+ }
+
+ @Test
fun featureCoordinator_isNotNullAfterServiceConnection() {
setQueryIntentServicesAnswer(defaultServiceAnswer)
val connector = CompanionConnector(context, isForegroundProcess = false)