summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Auto Companion <no-reply@google.com>2021-12-08 09:12:15 -0800
committerDan Harms <danharms@google.com>2021-12-08 10:29:21 -0800
commita34dde2db1dbc86486affc058137d780aad5c89b (patch)
tree4153645045318b9b277a0d0e0892e00b089a18ab
parent6b2e6918ffcc38ee3bf4b801fd2ff4e8c85125a8 (diff)
downloadCompanionDeviceSupport-a34dde2db1dbc86486affc058137d780aad5c89b.tar.gz
Project import generated by Copybara
Included changes: Release-Id: aae-companiondevice-android_20211208.00_RC00 Change-Id: I9f2aeb7c9e7be964084475b5a30313c741e7e7a1
-rw-r--r--companiondevice/AndroidManifest.xml1
-rw-r--r--companiondevice/build.gradle2
-rw-r--r--companiondevice/res/layout-w1240dp-land/suw_companion_qr_code_landing_fragment.xml2
-rw-r--r--companiondevice/res/layout-w1240dp-land/suw_companion_setup_profile_fragment.xml70
-rw-r--r--companiondevice/res/layout/companion_qr_code_landing_fragment.xml2
-rw-r--r--companiondevice/res/layout/suw_companion_setup_profile_fragment.xml62
-rw-r--r--companiondevice/res/values/config.xml1
-rw-r--r--companiondevice/res/values/strings.xml15
-rw-r--r--companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java10
-rw-r--r--companiondevice/src/com/google/android/companiondevicesupport/CompanionQrCodeLandingFragment.java92
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/ConnectedDeviceManager.java2
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/core/FeatureCoordinator.kt8
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/core/MultiProtocolDeviceController.kt106
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/NotificationMsgService.java11
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/BaseNotificationDelegate.java4
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/TelecomUtils.java2
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/Utils.java4
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceService.java9
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorage.java55
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/ui/AssociatedDeviceViewModel.java37
-rw-r--r--libs/connecteddevice/src/com/google/android/connecteddevice/ui/CompanionUriBuilder.kt32
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/ConnectedDeviceManagerTest.java2
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/ChannelResolverTest.kt3
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelTest.kt3
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelV4Test.kt2
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/FeatureCoordinatorTest.kt20
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/MultiProtocolDeviceControllerTest.kt232
-rw-r--r--libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorageTest.java17
28 files changed, 615 insertions, 191 deletions
diff --git a/companiondevice/AndroidManifest.xml b/companiondevice/AndroidManifest.xml
index a377a30..d579588 100644
--- a/companiondevice/AndroidManifest.xml
+++ b/companiondevice/AndroidManifest.xml
@@ -84,6 +84,7 @@
android:resource="@bool/enable_feature_coordinator" />
<meta-data android:name="com.google.android.connecteddevice.supported_oob_channels"
android:resource="@array/supported_oob_channels"/>
+
</service>
<service
android:name="com.google.android.connecteddevice.service.ConnectedDeviceFgUserService"
diff --git a/companiondevice/build.gradle b/companiondevice/build.gradle
index 2f64c1e..5a50a1b 100644
--- a/companiondevice/build.gradle
+++ b/companiondevice/build.gradle
@@ -13,7 +13,7 @@ android {
applicationId "com.google.android.companiondevicesupport"
minSdkVersion 29
targetSdkVersion 30
- versionCode 1117
+ versionCode 1181
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/companiondevice/res/layout-w1240dp-land/suw_companion_qr_code_landing_fragment.xml b/companiondevice/res/layout-w1240dp-land/suw_companion_qr_code_landing_fragment.xml
index 6fdf3bd..c50dbe5 100644
--- a/companiondevice/res/layout-w1240dp-land/suw_companion_qr_code_landing_fragment.xml
+++ b/companiondevice/res/layout-w1240dp-land/suw_companion_qr_code_landing_fragment.xml
@@ -46,7 +46,7 @@
android:layout_marginVertical="?attr/contentMarginVertical"
style="@style/CompanionTitleTextStyle" />
<TextView
- android:id="@+id/add_associated_device_subtitle"
+ android:id="@+id/connect_to_car_instruction"
android:text="@string/add_associated_device_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/companiondevice/res/layout-w1240dp-land/suw_companion_setup_profile_fragment.xml b/companiondevice/res/layout-w1240dp-land/suw_companion_setup_profile_fragment.xml
new file mode 100644
index 0000000..ebb110e
--- /dev/null
+++ b/companiondevice/res/layout-w1240dp-land/suw_companion_setup_profile_fragment.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:layout_marginHorizontal="?attr/pageMarginHorizontal">
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="@integer/suw_title_column_weight"
+ android:paddingVertical="?attr/pageMarginVertical"
+ android:layout_marginEnd="@dimen/suw_column_inner_padding_horizontal">
+ <TextView
+ android:id="@+id/suw_setup_profile_title"
+ android:text="@string/suw_setup_profile_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="left"
+ android:layout_marginVertical="?attr/contentMarginVertical"
+ style="@style/CompanionTitleTextStyle" />
+ <TextView
+ android:id="@+id/suw_setup_profile_content"
+ android:text="@string/suw_setup_profile_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="left"
+ style="@style/CompanionSubtitleTextStyle" />
+ </LinearLayout>
+ <View style="@style/SuwVerticalDividerStyle"/>
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:layout_weight="@integer/suw_content_column_weight"
+ android:layout_marginVertical="?attr/pageMarginVertical"
+ android:layout_marginStart="@dimen/suw_column_inner_padding_horizontal" >
+ <ImageView
+ android:id="@+id/qr_code"
+ android:layout_width="@dimen/qr_code_size"
+ android:layout_height="@dimen/qr_code_size"
+ tools:ignore="ContentDescription" />
+ <TextView
+ android:id="@+id/connect_to_car_instruction"
+ android:text="@string/suw_qr_instruction_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="?attr/contentMarginVertical"
+ android:gravity="center"
+ style="@style/CompanionSubtitleTextStyle" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/companiondevice/res/layout/companion_qr_code_landing_fragment.xml b/companiondevice/res/layout/companion_qr_code_landing_fragment.xml
index ba122f7..55b2356 100644
--- a/companiondevice/res/layout/companion_qr_code_landing_fragment.xml
+++ b/companiondevice/res/layout/companion_qr_code_landing_fragment.xml
@@ -44,7 +44,7 @@
android:layout_marginVertical="?attr/contentMarginVertical"
style="@style/CompanionTitleTextStyle" />
<TextView
- android:id="@+id/add_associated_device_subtitle"
+ android:id="@+id/connect_to_car_instruction"
android:text="@string/add_associated_device_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/companiondevice/res/layout/suw_companion_setup_profile_fragment.xml b/companiondevice/res/layout/suw_companion_setup_profile_fragment.xml
new file mode 100644
index 0000000..a1a12d2
--- /dev/null
+++ b/companiondevice/res/layout/suw_companion_setup_profile_fragment.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:paddingVertical="?attr/pageMarginVertical"
+ android:layout_marginHorizontal="?attr/pageMarginHorizontal">
+ <TextView
+ android:id="@+id/suw_setup_profile_title"
+ android:text="@string/suw_setup_profile_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_marginVertical="?attr/contentMarginVertical"
+ style="@style/CompanionTitleTextStyle" />
+ <TextView
+ android:id="@+id/suw_setup_profile_content"
+ android:text="@string/suw_setup_profile_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ style="@style/CompanionSubtitleTextStyle" />
+ <View
+ android:layout_marginBottom="?attr/companionDividerMargin"
+ style="@style/HorizontalDividerStyle" />
+ <ImageView
+ android:id="@+id/qr_code"
+ android:layout_width="@dimen/qr_code_size"
+ android:layout_height="@dimen/qr_code_size"
+ tools:ignore="ContentDescription" />
+ <TextView
+ android:id="@+id/connect_to_car_instruction"
+ android:text="@string/suw_qr_instruction_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="?attr/contentMarginVertical"
+ android:gravity="center"
+ style="@style/CompanionSubtitleTextStyle" />
+ </LinearLayout>
+</ScrollView>
diff --git a/companiondevice/res/values/config.xml b/companiondevice/res/values/config.xml
index 74d3b93..e2f7b56 100644
--- a/companiondevice/res/values/config.xml
+++ b/companiondevice/res/values/config.xml
@@ -54,4 +54,5 @@
<bool name="enable_feature_coordinator">true</bool>
<bool name="enable_qr_code">false</bool>
+ <bool name="enable_passenger">false</bool>
</resources>
diff --git a/companiondevice/res/values/strings.xml b/companiondevice/res/values/strings.xml
index d583a94..97259ad 100644
--- a/companiondevice/res/values/strings.xml
+++ b/companiondevice/res/values/strings.xml
@@ -184,4 +184,19 @@
<!-- Prefix of the BLE device name. [CHAR LIMIT=20]-->
<string name="ble_device_name_prefix">Vehicle\u00A0</string>
+
+ <!-- QR code uri scheme. -->
+ <string name="uri_scheme" translatable="false">companion</string>
+ <!-- QR code uri authority. -->
+ <string name="uri_authority" translatable="false">demo.companiondevice.com</string>
+ <!-- QR code uri path. -->
+ <string name="uri_path" translatable="false">associate</string>
+
+ <!-- Car SUW setup profile page title. [CHAR LIMIT=40]-->
+ <string name="suw_setup_profile_title">Setup profile with phone</string>
+ <!-- Car SUW setup profile page content. [CHAR LIMIT=200]-->
+ <string name="suw_setup_profile_content">Scan QR code to get started. If you don\'t have a MyCompanion app, you can download it on Google Play and the App Store.</string>
+ <!-- Car SUW setup profile page instructions for user to scan the QR code. [CHAR LIMIT=150]-->
+ <string name="suw_qr_instruction_text">Scan QR code to connect to&lt;br /&gt; &lt;b><xliff:g id="car_name" example="MyVehicle">%1$s</xliff:g>&lt;/b> <xliff:g id="advertised_car_name" example="(Vehicle 0000)">%2$s</xliff:g></string>
+
</resources>
diff --git a/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java b/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java
index e799eb3..5d2e314 100644
--- a/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java
+++ b/companiondevice/src/com/google/android/companiondevicesupport/AssociationActivity.java
@@ -55,6 +55,7 @@ public class AssociationActivity extends FragmentActivity {
private static final String ASSOCIATION_ERROR_FRAGMENT_TAG = "AssociationErrorFragment";
private static final String TURN_ON_BLUETOOTH_DIALOG_TAG = "TurnOnBluetoothDialog";
private static final String EXTRA_AUTH_IS_SETUP_WIZARD = "is_setup_wizard";
+ private static final String EXTRA_AUTH_IS_SETUP_PROFILE = "is_setup_profile_association";
private static final String EXTRA_USE_IMMERSIVE_MODE = "useImmersiveMode";
private static final String EXTRA_HIDE_SKIP_BUTTON = "hide_skip_button";
@@ -62,6 +63,7 @@ public class AssociationActivity extends FragmentActivity {
private CarSetupWizardCompatLayout carSetupWizardLayout;
private AssociatedDeviceViewModel model;
private boolean isStartedForSuw = false;
+ private boolean isStartedForSetupProfile = false;
private boolean isImmersive = false;
private boolean hideSkipButton = false;
@@ -101,6 +103,8 @@ public class AssociationActivity extends FragmentActivity {
return;
}
isStartedForSuw = intent.getBooleanExtra(EXTRA_AUTH_IS_SETUP_WIZARD, /* defaultValue= */ false);
+ isStartedForSetupProfile =
+ intent.getBooleanExtra(EXTRA_AUTH_IS_SETUP_PROFILE, /* defaultValue= */ false);
isImmersive = intent.getBooleanExtra(EXTRA_USE_IMMERSIVE_MODE, /* defaultValue= */ false);
hideSkipButton = intent.getBooleanExtra(EXTRA_HIDE_SKIP_BUTTON, /* defaultValue= */ false);
}
@@ -295,8 +299,12 @@ public class AssociationActivity extends FragmentActivity {
if (fragment != null && fragment.isVisible()) {
return;
}
- fragment = CompanionQrCodeLandingFragment.newInstance(isStartedForSuw);
+ fragment =
+ CompanionQrCodeLandingFragment.newInstance(isStartedForSuw, isStartedForSetupProfile);
launchFragment(fragment, COMPANION_LANDING_FRAGMENT_TAG);
+ if (isStartedForSetupProfile) {
+ showSkipButton();
+ }
}
private void showTurnOnBluetoothFragment() {
diff --git a/companiondevice/src/com/google/android/companiondevicesupport/CompanionQrCodeLandingFragment.java b/companiondevice/src/com/google/android/companiondevicesupport/CompanionQrCodeLandingFragment.java
index cde7c51..200c8e9 100644
--- a/companiondevice/src/com/google/android/companiondevicesupport/CompanionQrCodeLandingFragment.java
+++ b/companiondevice/src/com/google/android/companiondevicesupport/CompanionQrCodeLandingFragment.java
@@ -20,6 +20,7 @@ import static com.google.android.connecteddevice.util.SafeLog.loge;
import android.bluetooth.BluetoothAdapter;
import android.graphics.Bitmap;
+import android.net.Uri;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.text.Html;
@@ -30,27 +31,39 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
+import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
+import com.google.android.connecteddevice.model.StartAssociationResponse;
import com.google.android.connecteddevice.model.TransportProtocols;
import com.google.android.connecteddevice.ui.AssociatedDeviceViewModel;
import com.google.android.connecteddevice.ui.AssociatedDeviceViewModelFactory;
+import com.google.android.connecteddevice.ui.CompanionUriBuilder;
+import com.google.android.connecteddevice.ui.QrCodeGenerator;
import java.util.Arrays;
import java.util.List;
/** Fragment that provides association instructions. */
public class CompanionQrCodeLandingFragment extends Fragment {
private static final String IS_STARTED_FOR_SUW_KEY = "isStartedForSuw";
+ private static final String IS_STARTED_FOR_SETUP_PROFILE_KEY = "isSetupProfile";
private static final String TAG = "CompanionQrCodeLandingFragment";
+ private boolean isStartedForSetupProfile = false;
+ @Nullable private View instructionsView = null;
+ @Nullable private View addButtonView = null;
/**
* Creates a new instance of {@link CompanionQrCodeLandingFragment}.
*
* @param isStartedForSUW If the fragment is created for car setup wizard.
+ * @param isStartedForSetupProfile If the fragment is created for car setup wizard and car profile
+ * setup. This value will take effect only if the {@code isStartedForSUW} is {@code true}.
* @return {@link CompanionQrCodeLandingFragment} instance.
*/
- static CompanionQrCodeLandingFragment newInstance(boolean isStartedForSUW) {
+ static CompanionQrCodeLandingFragment newInstance(
+ boolean isStartedForSUW, boolean isStartedForSetupProfile) {
Bundle bundle = new Bundle();
bundle.putBoolean(IS_STARTED_FOR_SUW_KEY, isStartedForSUW);
+ bundle.putBoolean(IS_STARTED_FOR_SETUP_PROFILE_KEY, isStartedForSetupProfile);
CompanionQrCodeLandingFragment fragment = new CompanionQrCodeLandingFragment();
fragment.setArguments(bundle);
return fragment;
@@ -59,16 +72,25 @@ public class CompanionQrCodeLandingFragment extends Fragment {
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- @LayoutRes
- int layout =
- getArguments().getBoolean(IS_STARTED_FOR_SUW_KEY)
- ? R.layout.suw_companion_qr_code_landing_fragment
- : R.layout.companion_qr_code_landing_fragment;
+ boolean isStartedForSuw = getArguments().getBoolean(IS_STARTED_FOR_SUW_KEY);
+ isStartedForSetupProfile = getArguments().getBoolean(IS_STARTED_FOR_SETUP_PROFILE_KEY);
+ @LayoutRes int layout;
+ if (isStartedForSuw) {
+ if (isStartedForSetupProfile) {
+ layout = R.layout.suw_companion_setup_profile_fragment;
+ } else {
+ layout = R.layout.suw_companion_qr_code_landing_fragment;
+ }
+ } else {
+ layout = R.layout.companion_qr_code_landing_fragment;
+ }
return inflater.inflate(layout, container, false);
}
@Override
public void onViewCreated(View view, Bundle bundle) {
+ instructionsView = view.findViewById(R.id.association_qr_code_instructions);
+ addButtonView = view.findViewById(R.id.add_button_and_divider);
List<String> transportProtocols =
Arrays.asList(getResources().getStringArray(R.array.transport_protocols));
AssociatedDeviceViewModel model =
@@ -79,13 +101,19 @@ public class CompanionQrCodeLandingFragment extends Fragment {
transportProtocols.contains(TransportProtocols.PROTOCOL_SPP),
getResources().getString(R.string.ble_device_name_prefix)))
.get(AssociatedDeviceViewModel.class);
- TextView connectToCarTextView = view.findViewById(R.id.add_associated_device_subtitle);
+
+ TextView connectToCarTextView = view.findViewById(R.id.connect_to_car_instruction);
model
.getAdvertisedCarName()
.observe(/* owner= */ this, carName -> setCarName(connectToCarTextView, carName));
+ model.getAssociationResponse().observe(/* owner= */ this, this::processAssociationResponse);
+ if (isStartedForSetupProfile) {
+ // Directly start advertisement in SUW setup profile association flow.
+ model.startAssociation();
+ return;
+ }
view.findViewById(R.id.add_associated_device_button)
.setOnClickListener(l -> model.startAssociation());
- model.getQrCode().observe(/* owner= */ this, code -> setImageView(code, view));
}
private void setCarName(TextView textView, String carName) {
@@ -102,25 +130,59 @@ public class CompanionQrCodeLandingFragment extends Fragment {
carName = "(" + carName + ")";
}
String bluetoothName = BluetoothAdapter.getDefaultAdapter().getName();
- String connectToCarText = getString(R.string.qr_instruction_text, bluetoothName, carName);
+ int textId =
+ isStartedForSetupProfile ? R.string.suw_qr_instruction_text : R.string.qr_instruction_text;
+ String connectToCarText = getString(textId, bluetoothName, carName);
Spanned styledConnectToCarText = Html.fromHtml(connectToCarText, Html.FROM_HTML_MODE_LEGACY);
textView.setText(styledConnectToCarText);
}
- private void setImageView(Bitmap bitmap, View view) {
- ImageView qrImage = view.findViewById(R.id.qr_code);
- View instruction = view.findViewById(R.id.association_qr_code_instructions);
- View addButton = view.findViewById(R.id.add_button_and_divider);
+ /**
+ * Set the QR code image view when the association response is available. Hide the instruction and
+ * add button if they are not null.
+ *
+ * @param response the association started successfully response.
+ */
+ private void processAssociationResponse(StartAssociationResponse response) {
+ if (response == null) {
+ loge(
+ TAG,
+ "Association response is null during QR code generation when association "
+ + "started successfully, ignore.");
+ return;
+ }
+
+ ImageView qrImage = getView().findViewById(R.id.qr_code);
if (qrImage == null) {
loge(TAG, "No valid ImageView to show QR code.");
return;
}
+
+ Uri uri =
+ new CompanionUriBuilder()
+ .scheme(getResources().getString(R.string.uri_scheme))
+ .authority(getResources().getString(R.string.uri_authority))
+ .appendPath(getResources().getString(R.string.uri_path))
+ .oobData(response.getOobData())
+ .deviceId(response.getDeviceIdentifier())
+ .appendQueryParameter(
+ IS_STARTED_FOR_SETUP_PROFILE_KEY, String.valueOf(isStartedForSetupProfile))
+ .build();
+ Bitmap bitmap =
+ QrCodeGenerator.createQrCode(
+ uri.toString(), getResources().getDimensionPixelSize(R.dimen.qr_code_size));
if (bitmap == null) {
+ loge(TAG, "QR code could not be generated, ignore.");
return;
}
- instruction.setVisibility(View.GONE);
- addButton.setVisibility(View.GONE);
+
qrImage.setImageBitmap(bitmap);
qrImage.setVisibility(View.VISIBLE);
+ if (instructionsView != null) {
+ instructionsView.setVisibility(View.GONE);
+ }
+ if (addButtonView != null) {
+ addButtonView.setVisibility(View.GONE);
+ }
}
}
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/ConnectedDeviceManager.java b/libs/connecteddevice/src/com/google/android/connecteddevice/ConnectedDeviceManager.java
index 18638f8..6cf5668 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/ConnectedDeviceManager.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/ConnectedDeviceManager.java
@@ -138,7 +138,7 @@ public class ConnectedDeviceManager {
this.carBluetoothManager = carBluetoothManager;
this.connectionExecutor = connectionExecutor;
this.carBluetoothManager.registerCallback(generateCarManagerCallback(), callbackExecutor);
- this.storage.setAssociatedDeviceCallback(associatedDeviceCallback);
+ this.storage.registerAssociatedDeviceCallback(associatedDeviceCallback);
this.storageExecutor = storageExecutor;
}
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/core/FeatureCoordinator.kt b/libs/connecteddevice/src/com/google/android/connecteddevice/core/FeatureCoordinator.kt
index f4ca509..0860ace 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/core/FeatureCoordinator.kt
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/core/FeatureCoordinator.kt
@@ -77,7 +77,7 @@ constructor(
init {
controller.registerCallback(createDeviceControllerCallback(), callbackExecutor)
- storage.setAssociatedDeviceCallback(createStorageAssociatedDeviceCallback())
+ storage.registerAssociatedDeviceCallback(createStorageAssociatedDeviceCallback())
}
/** Initiate connections with all enabled [AssociatedDevice]s. */
@@ -283,11 +283,17 @@ constructor(
}
override fun claimAssociatedDevice(deviceId: String) {
+ logd(TAG, "Claiming device $deviceId. Updating storage and disconnecting.")
+ controller.disconnectDevice(UUID.fromString(deviceId))
storage.claimAssociatedDevice(deviceId)
+ controller.initiateConnectionToDevice(UUID.fromString(deviceId))
}
override fun removeAssociatedDeviceClaim(deviceId: String) {
+ logd(TAG, "Removing claim on device $deviceId. Updating storage and disconnecting.")
+ controller.disconnectDevice(UUID.fromString(deviceId))
storage.removeAssociatedDeviceClaim(deviceId)
+ controller.initiateConnectionToDevice(UUID.fromString(deviceId))
}
private fun startAssociationInternal(
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/core/MultiProtocolDeviceController.kt b/libs/connecteddevice/src/com/google/android/connecteddevice/core/MultiProtocolDeviceController.kt
index 66369a3..73c8d9b 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/core/MultiProtocolDeviceController.kt
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/core/MultiProtocolDeviceController.kt
@@ -64,6 +64,8 @@ import java.util.concurrent.atomic.AtomicReference
*
* @property protocols List of supported protocols.
* @property storage Storage necessary to generate reconnect challenge.
+ * @property enablePassenger Whether passenger devices automatically connect. When `true`, newly
+ * associated devices will remain unclaimed by default.
* @property callbackExecutor Executor on which callbacks are executed.
*/
class MultiProtocolDeviceController
@@ -72,8 +74,9 @@ constructor(
private val protocols: Set<ConnectionProtocol>,
private val storage: ConnectedDeviceStorage,
private val oobRunner: OobRunner,
- private val callbackExecutor: Executor = Executors.newSingleThreadExecutor(),
- private val associationServiceUuid: UUID
+ private val associationServiceUuid: UUID,
+ private val enablePassenger: Boolean,
+ private val callbackExecutor: Executor = Executors.newSingleThreadExecutor()
) : DeviceController {
private val connectedRemoteDevices = ConcurrentHashMap<UUID, ConnectedRemoteDevice>()
@@ -84,6 +87,23 @@ constructor(
private val associatedDevices = CopyOnWriteArrayList<AssociatedDevice>()
private val driverDevices = CopyOnWriteArrayList<AssociatedDevice>()
+ private val storageCallback =
+ object : ConnectedDeviceStorage.AssociatedDeviceCallback {
+ override fun onAssociatedDeviceAdded(device: AssociatedDevice) {
+ // Device population is handled locally when a new device is added.
+ }
+
+ override fun onAssociatedDeviceRemoved(device: AssociatedDevice) {
+ logd(TAG, "An associated device has been removed. Repopulating devices from storage.")
+ populateDevices()
+ }
+
+ override fun onAssociatedDeviceUpdated(device: AssociatedDevice) {
+ logd(TAG, "An associated device has been updated. Repopulating devices from storage.")
+ populateDevices()
+ }
+ }
+
override val connectedDevices: List<ConnectedDevice>
get() {
val devices = mutableListOf<ConnectedDevice>()
@@ -114,43 +134,27 @@ constructor(
}
init {
- callbackExecutor.execute {
- while (true) {
- try {
- logd(TAG, "Populating associated devices from storage.")
- associatedDevices.clear()
- driverDevices.clear()
- associatedDevices.addAll(storage.allAssociatedDevices)
- driverDevices.addAll(storage.driverAssociatedDevices)
- break
- } catch (sqliteException: SQLiteCantOpenDatabaseException) {
- loge(
- TAG,
- "Caught transient exception while retrieving devices. Trying again.",
- sqliteException
- )
- try {
- Thread.sleep(ASSOCIATED_DEVICE_RETRY_MS)
- } catch (interrupted: InterruptedException) {
- loge(TAG, "Sleep interrupted.", interrupted)
- break
- }
- }
- }
- logd(TAG, "Devices populated successfully.")
- }
-
- // TODO(b/192656006) Add registration for updates to associated devices to keep in sync
+ storage.registerAssociatedDeviceCallback(storageCallback)
}
override fun start() {
- logd(TAG, "Starting controller.")
- val associatedDevices = storage.driverAssociatedDevices
- for (device in associatedDevices) {
+ logd(TAG, "Starting controller and initiating connections with driver devices.")
+ populateDevices()
+ val driverDevices = storage.driverAssociatedDevices
+ for (device in driverDevices) {
if (device.isConnectionEnabled) {
initiateConnectionToDevice(UUID.fromString(device.deviceId))
}
}
+ if (!enablePassenger) {
+ logd(TAG, "The passenger experience is disabled. Skipping discovery of passenger devices.")
+ return
+ }
+ logd(TAG, "Initiating connections with passenger devices.")
+ val passengerDevices = storage.passengerAssociatedDevices
+ for (device in passengerDevices) {
+ initiateConnectionToDevice(UUID.fromString(device.deviceId))
+ }
}
override fun reset() {
@@ -310,6 +314,34 @@ constructor(
callbacks.remove(callback)
}
+ private fun populateDevices() {
+ callbackExecutor.execute {
+ while (true) {
+ try {
+ logd(TAG, "Populating associated devices from storage.")
+ associatedDevices.clear()
+ driverDevices.clear()
+ associatedDevices.addAll(storage.allAssociatedDevices)
+ driverDevices.addAll(storage.driverAssociatedDevices)
+ logd(TAG, "Devices populated successfully.")
+ break
+ } catch (sqliteException: SQLiteCantOpenDatabaseException) {
+ loge(
+ TAG,
+ "Caught transient exception while retrieving devices. Trying again.",
+ sqliteException
+ )
+ try {
+ Thread.sleep(ASSOCIATED_DEVICE_RETRY_MS)
+ } catch (interrupted: InterruptedException) {
+ loge(TAG, "Sleep interrupted.", interrupted)
+ break
+ }
+ }
+ }
+ }
+ }
+
/**
* Create challenge for connection advertisement.
*
@@ -710,8 +742,14 @@ constructor(
/* deviceName= */ null,
/* isConnectionEnabled= */ true
)
- storage.addAssociatedDeviceForDriver(associatedDevice)
- driverDevices.add(associatedDevice)
+ if (enablePassenger) {
+ logd(TAG, "Saving newly associated device $deviceId as unclaimed.")
+ storage.addAssociatedDeviceForUser(AssociatedDevice.UNCLAIMED_USER_ID, associatedDevice)
+ } else {
+ logd(TAG, "Saving newly associated device $deviceId as a driver's device.")
+ storage.addAssociatedDeviceForDriver(associatedDevice)
+ driverDevices.add(associatedDevice)
+ }
associatedDevices.add(associatedDevice)
}
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/NotificationMsgService.java b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/NotificationMsgService.java
index 497506e..4982181 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/NotificationMsgService.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/NotificationMsgService.java
@@ -31,11 +31,13 @@ import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Binder;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.IBinder;
+import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.RemoteInput;
-import androidx.annotation.Nullable;
import com.google.android.connecteddevice.model.ConnectedDevice;
import com.google.android.connecteddevice.notificationmsg.common.ConversationKey;
import com.google.android.connecteddevice.notificationmsg.proto.NotificationMsg;
@@ -171,6 +173,13 @@ public class NotificationMsgService extends MetaDataService {
* started.
*/
private void sendServiceRunningNotification() {
+ // TODO(b/201677355) A new rule in S restricts
+ // the ability to start foreground services to only active UI
+ // however, this needs to be fixed properly as Assistant needs the foreground service
+ // for replies to work
+ if (VERSION.SDK_INT > VERSION_CODES.R) {
+ return;
+ }
NotificationManager notificationManager = getSystemService(NotificationManager.class);
// Create notification channel for app running notification
NotificationChannel appRunningNotificationChannel =
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 260bbca..803c74a 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
@@ -29,11 +29,11 @@ import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationCompat.Action;
-import androidx.core.graphics.drawable.IconCompat;
-import androidx.annotation.Nullable;
import androidx.core.app.Person;
+import androidx.core.graphics.drawable.IconCompat;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/TelecomUtils.java b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/TelecomUtils.java
index 0705f2f..63a29c7 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/TelecomUtils.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/TelecomUtils.java
@@ -24,9 +24,9 @@ import android.graphics.Canvas;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
-import androidx.annotation.Nullable;
/** Telecom utility methods. */
public class TelecomUtils {
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/Utils.java b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/Utils.java
index 870de69..687fed8 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/Utils.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/notificationmsg/common/Utils.java
@@ -27,12 +27,12 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.google.android.connecteddevice.notificationmsg.proto.NotificationMsg;
import com.google.android.connecteddevice.notificationmsg.proto.NotificationMsg.AvatarIconSync;
import com.google.android.connecteddevice.notificationmsg.proto.NotificationMsg.ConversationNotification;
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceService.java b/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceService.java
index 95c062c..3daa450 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceService.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/service/ConnectedDeviceService.java
@@ -137,6 +137,9 @@ public final class ConnectedDeviceService extends TrunkService {
private static final String META_SUPPORTED_OOB_CHANNELS =
"com.google.android.connecteddevice.supported_oob_channels";
+ private static final String META_ENABLE_PASSENGER =
+ "com.google.android.connecteddevice.enable_passenger";
+
private static final boolean PROXY_ENABLED_BY_DEFAULT = false;
private static final String DEFAULT_RECONNECT_UUID = "000000e0-0000-1000-8000-00805f9b34fb";
@@ -160,6 +163,8 @@ public final class ConnectedDeviceService extends TrunkService {
private static final boolean ENABLE_FEATURE_COORDINATOR_BY_DEFAULT = false;
+ private static final boolean ENABLE_PASSENGER_BY_DEFAULT = false;
+
private static final String[] DEFAULT_TRANSPORT_PROTOCOLS =
{ TransportProtocols.PROTOCOL_BLE_PERIPHERAL };
@@ -275,8 +280,10 @@ public final class ConnectedDeviceService extends TrunkService {
META_SUPPORTED_OOB_CHANNELS,
/* defaultValue= */ new String[0]))));
UUID associationUuid = UUID.fromString(requireMetaString(META_ASSOCIATION_SERVICE_UUID));
+ boolean enablePassenger = getMetaBoolean(META_ENABLE_PASSENGER, ENABLE_PASSENGER_BY_DEFAULT);
DeviceController deviceController =
- new MultiProtocolDeviceController(protocols, storage, oobRunner, associationUuid);
+ new MultiProtocolDeviceController(
+ protocols, storage, oobRunner, associationUuid, enablePassenger);
featureCoordinator = new FeatureCoordinator(deviceController, storage, loggingManager);
logd(TAG, "Wrapping FeatureCoordinator in legacy binders for backwards compatibility.");
connectedDeviceManagerBinder = createConnectedDeviceManagerWrapper();
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorage.java b/libs/connecteddevice/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorage.java
index 3fadd88..389d201 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorage.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorage.java
@@ -28,12 +28,15 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.room.Room;
import com.google.android.connecteddevice.model.AssociatedDevice;
+import com.google.android.connecteddevice.util.ThreadSafeCallbacks;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
@@ -55,11 +58,14 @@ public class ConnectedDeviceStorage {
private final CryptoHelper cryptoHelper;
+ private final Executor callbackExecutor;
+
private SharedPreferences sharedPreferences;
private UUID uniqueId;
- private AssociatedDeviceCallback associatedDeviceCallback;
+ private final ThreadSafeCallbacks<AssociatedDeviceCallback> callbacks =
+ new ThreadSafeCallbacks<>();
public ConnectedDeviceStorage(@NonNull Context context) {
this(
@@ -68,31 +74,30 @@ public class ConnectedDeviceStorage {
Room.databaseBuilder(context, ConnectedDeviceDatabase.class, DATABASE_NAME)
.fallbackToDestructiveMigration()
.build()
- .associatedDeviceDao());
+ .associatedDeviceDao(),
+ Executors.newSingleThreadExecutor());
}
@VisibleForTesting
public ConnectedDeviceStorage(
@NonNull Context context,
@NonNull CryptoHelper cryptoHelper,
- @NonNull AssociatedDeviceDao associatedDeviceDatabase) {
+ @NonNull AssociatedDeviceDao associatedDeviceDatabase,
+ @NonNull Executor callbackExecutor) {
this.context = context;
this.cryptoHelper = cryptoHelper;
this.associatedDeviceDatabase = associatedDeviceDatabase;
+ this.callbackExecutor = callbackExecutor;
}
- /**
- * Set a callback for associated device updates.
- *
- * @param callback {@link AssociatedDeviceCallback} to set.
- */
- public void setAssociatedDeviceCallback(@NonNull AssociatedDeviceCallback callback) {
- associatedDeviceCallback = callback;
+ /** Register an {@link AssociatedDeviceCallback} for associated device updates. */
+ public void registerAssociatedDeviceCallback(@NonNull AssociatedDeviceCallback callback) {
+ callbacks.add(callback, callbackExecutor);
}
- /** Clear the callback for association device callback updates. */
- public void clearAssociationDeviceCallback() {
- associatedDeviceCallback = null;
+ /** Unregister an {@link AssociatedDeviceCallback} from associated device updates. */
+ public void unregisterAssociatedDeviceCallback(@NonNull AssociatedDeviceCallback callback) {
+ callbacks.remove(callback);
}
/**
@@ -377,9 +382,7 @@ public class ConnectedDeviceStorage {
AssociatedDeviceEntity entity =
new AssociatedDeviceEntity(userId, device, /* isConnectionEnabled= */ true);
associatedDeviceDatabase.addOrReplaceAssociatedDevice(entity);
- if (associatedDeviceCallback != null) {
- associatedDeviceCallback.onAssociatedDeviceAdded(device);
- }
+ callbacks.invoke(callback -> callback.onAssociatedDeviceAdded(device));
}
/**
@@ -427,9 +430,7 @@ public class ConnectedDeviceStorage {
private void updateName(AssociatedDeviceEntity entity, String name) {
entity.name = name;
associatedDeviceDatabase.addOrReplaceAssociatedDevice(entity);
- if (associatedDeviceCallback != null) {
- associatedDeviceCallback.onAssociatedDeviceUpdated(entity.toAssociatedDevice());
- }
+ callbacks.invoke(callback -> callback.onAssociatedDeviceUpdated(entity.toAssociatedDevice()));
}
/**
@@ -443,9 +444,7 @@ public class ConnectedDeviceStorage {
return;
}
associatedDeviceDatabase.removeAssociatedDevice(entity);
- if (associatedDeviceCallback != null) {
- associatedDeviceCallback.onAssociatedDeviceRemoved(entity.toAssociatedDevice());
- }
+ callbacks.invoke(callback -> callback.onAssociatedDeviceRemoved(entity.toAssociatedDevice()));
}
/**
@@ -470,9 +469,7 @@ public class ConnectedDeviceStorage {
}
entity.isConnectionEnabled = isConnectionEnabled;
associatedDeviceDatabase.addOrReplaceAssociatedDevice(entity);
- if (associatedDeviceCallback != null) {
- associatedDeviceCallback.onAssociatedDeviceUpdated(entity.toAssociatedDevice());
- }
+ callbacks.invoke(callback -> callback.onAssociatedDeviceUpdated(entity.toAssociatedDevice()));
}
/**
@@ -502,9 +499,7 @@ public class ConnectedDeviceStorage {
entity.userId = ActivityManager.getCurrentUser();
associatedDeviceDatabase.addOrReplaceAssociatedDevice(entity);
- if (associatedDeviceCallback != null) {
- associatedDeviceCallback.onAssociatedDeviceUpdated(entity.toAssociatedDevice());
- }
+ callbacks.invoke(callback -> callback.onAssociatedDeviceUpdated(entity.toAssociatedDevice()));
}
/** Removes the claim on the identified associated device leaving it in an unclaimed state. */
@@ -522,9 +517,7 @@ public class ConnectedDeviceStorage {
entity.userId = AssociatedDevice.UNCLAIMED_USER_ID;
associatedDeviceDatabase.addOrReplaceAssociatedDevice(entity);
- if (associatedDeviceCallback != null) {
- associatedDeviceCallback.onAssociatedDeviceUpdated(entity.toAssociatedDevice());
- }
+ callbacks.invoke(callback -> callback.onAssociatedDeviceUpdated(entity.toAssociatedDevice()));
}
/** Callback for association device related events. */
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/ui/AssociatedDeviceViewModel.java b/libs/connecteddevice/src/com/google/android/connecteddevice/ui/AssociatedDeviceViewModel.java
index d319aec..171ba8c 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/ui/AssociatedDeviceViewModel.java
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/ui/AssociatedDeviceViewModel.java
@@ -28,8 +28,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.net.Uri;
import android.os.ParcelUuid;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -60,12 +58,6 @@ public class AssociatedDeviceViewModel extends AndroidViewModel {
private static final Duration DISCOVERABLE_DURATION = Duration.ofMinutes(2);
- private static final String SCHEME = "https";
-
- private static final String AUTHORITY = "demo.companiondevice.com";
-
- private static final int QR_CODE_SIZE_IN_PIXEL = 200;
-
/** States of association process. */
public enum AssociationState {
NONE,
@@ -82,7 +74,8 @@ public class AssociatedDeviceViewModel extends AndroidViewModel {
private final MutableLiveData<AssociatedDeviceDetails> currentDeviceDetails =
new MutableLiveData<>(null);
private final MutableLiveData<String> advertisedCarName = new MutableLiveData<>(null);
- private final MutableLiveData<Bitmap> bitmap = new MutableLiveData<>(null);
+ private final MutableLiveData<StartAssociationResponse> associationResponse =
+ new MutableLiveData<>(null);
private final MutableLiveData<String> pairingCode = new MutableLiveData<>(null);
private final MutableLiveData<Integer> bluetoothState =
new MutableLiveData<>(BluetoothAdapter.STATE_OFF);
@@ -199,9 +192,10 @@ public class AssociatedDeviceViewModel extends AndroidViewModel {
getApplication().startActivity(intent);
}
- /** Resets the value of {@link #associationState}. */
+ /** Resets the value of {@link #associationState} and {@link #associationResponse}. */
public void resetAssociationState() {
associationState.postValue(AssociationState.NONE);
+ associationResponse.postValue(null);
}
/** Gets the name that is being advertised by the car. */
@@ -209,9 +203,9 @@ public class AssociatedDeviceViewModel extends AndroidViewModel {
return advertisedCarName;
}
- /** Gets the Qr code bitmap. */
- public LiveData<Bitmap> getQrCode() {
- return bitmap;
+ /** Gets the response from a successful request to start association. */
+ public LiveData<StartAssociationResponse> getAssociationResponse() {
+ return associationResponse;
}
/** Gets the generated pairing code. */
@@ -345,6 +339,7 @@ public class AssociatedDeviceViewModel extends AndroidViewModel {
@Override
public void onAssociatedDeviceAdded(@NonNull AssociatedDevice device) {
+ resetAssociationState();
addOrUpdateAssociatedDevice(device);
}
@@ -375,21 +370,7 @@ public class AssociatedDeviceViewModel extends AndroidViewModel {
new IAssociationCallback.Stub() {
@Override
public void onAssociationStartSuccess(StartAssociationResponse response) {
- Uri uri =
- new CompanionUriBuilder()
- .scheme(SCHEME)
- .authority(AUTHORITY)
- .oobData(response.getOobData())
- .deviceId(response.getDeviceIdentifier())
- .build();
-
- Bitmap code = QrCodeGenerator.createQrCode(uri.toString(), QR_CODE_SIZE_IN_PIXEL);
- if (code == null) {
- loge(TAG, "QR code is null, ignore.");
- return;
- }
- bitmap.postValue(code);
-
+ associationResponse.postValue(response);
associationState.postValue(AssociationState.STARTED);
String deviceName = response.getDeviceName();
if (!deviceName.isEmpty()) {
diff --git a/libs/connecteddevice/src/com/google/android/connecteddevice/ui/CompanionUriBuilder.kt b/libs/connecteddevice/src/com/google/android/connecteddevice/ui/CompanionUriBuilder.kt
index 86b5ba8..bff0608 100644
--- a/libs/connecteddevice/src/com/google/android/connecteddevice/ui/CompanionUriBuilder.kt
+++ b/libs/connecteddevice/src/com/google/android/connecteddevice/ui/CompanionUriBuilder.kt
@@ -25,10 +25,10 @@ import com.google.android.connecteddevice.model.OobData
import com.google.protobuf.ByteString
/** Build Uri which will be used to communicate with remote device. */
-class CompanionUriBuilder {
+class CompanionUriBuilder(private val uri: Uri? = null) {
private var oobData: OobData? = null
private var deviceId: ByteArray? = null
- private val builder = Uri.Builder()
+ private val builder: Uri.Builder = uri?.buildUpon() ?: Uri.Builder()
fun scheme(scheme: String) = apply { builder.scheme(scheme) }
fun authority(authority: String) = apply { builder.authority(authority) }
@@ -51,21 +51,23 @@ class CompanionUriBuilder {
fun build(): Uri {
val oobData = this.oobData
- val oobAssociationData = OutOfBandAssociationData.newBuilder().run {
- if (deviceId != null) {
- setDeviceIdentifier(ByteString.copyFrom(deviceId))
- }
- if (oobData != null) {
- val token = OutOfBandAssociationToken.newBuilder().run {
- setEncryptionKey(ByteString.copyFrom(oobData.encryptionKey))
- setIhuIv(ByteString.copyFrom(oobData.ihuIv))
- setMobileIv(ByteString.copyFrom(oobData.mobileIv))
- build()
+ val oobAssociationData =
+ OutOfBandAssociationData.newBuilder().run {
+ if (deviceId != null) {
+ setDeviceIdentifier(ByteString.copyFrom(deviceId))
+ }
+ if (oobData != null) {
+ val token =
+ OutOfBandAssociationToken.newBuilder().run {
+ setEncryptionKey(ByteString.copyFrom(oobData.encryptionKey))
+ setIhuIv(ByteString.copyFrom(oobData.ihuIv))
+ setMobileIv(ByteString.copyFrom(oobData.mobileIv))
+ build()
+ }
+ setToken(token)
}
- setToken(token)
+ build()
}
- build()
- }
builder.appendQueryParameter(
OOB_DATA_PARAMETER_KEY,
Base64.encodeToString(oobAssociationData.toByteArray(), Base64.URL_SAFE)
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/ConnectedDeviceManagerTest.java b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/ConnectedDeviceManagerTest.java
index ff95fe0..873e42c 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/ConnectedDeviceManagerTest.java
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/ConnectedDeviceManagerTest.java
@@ -92,7 +92,7 @@ public class ConnectedDeviceManagerTest {
directExecutor,
directExecutor,
directExecutor);
- verify(mockStorage).setAssociatedDeviceCallback(callbackCaptor.capture());
+ verify(mockStorage).registerAssociatedDeviceCallback(callbackCaptor.capture());
when(mockStorage.getDriverAssociatedDevices()).thenReturn(userDevices);
when(mockStorage.getDriverAssociatedDeviceIds()).thenReturn(userDeviceIds);
associatedDeviceCallback = callbackCaptor.getValue();
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/ChannelResolverTest.kt b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/ChannelResolverTest.kt
index c1ae7b4..9228f86 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/ChannelResolverTest.kt
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/ChannelResolverTest.kt
@@ -93,7 +93,8 @@ class ChannelResolverTest {
.setQueryExecutor(directExecutor())
.build()
val database = connectedDeviceDatabase.associatedDeviceDao()
- spyStorage = spy(ConnectedDeviceStorage(context, Base64CryptoHelper(), database))
+ spyStorage =
+ spy(ConnectedDeviceStorage(context, Base64CryptoHelper(), database, directExecutor()))
whenever(mockStreamFactory.createProtocolStream(any(), any())).thenReturn(mockStream)
whenever(spyStorage.hashWithChallengeSecret(any(), any())).thenReturn(TEST_CHALLENGE_RESPONSE)
channelResolver =
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelTest.kt b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelTest.kt
index e3232dd..3dc968a 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelTest.kt
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelTest.kt
@@ -83,7 +83,8 @@ class MultiProtocolSecureChannelTest {
.setQueryExecutor(directExecutor())
.build()
.associatedDeviceDao()
- spyStorage = spy(ConnectedDeviceStorage(context, Base64CryptoHelper(), database))
+ spyStorage =
+ spy(ConnectedDeviceStorage(context, Base64CryptoHelper(), database, directExecutor()))
whenever(spyStorage.uniqueId).thenReturn(SERVER_DEVICE_ID)
}
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelV4Test.kt b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelV4Test.kt
index cc5e0e3..17927c5 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelV4Test.kt
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/connection/MultiProtocolSecureChannelV4Test.kt
@@ -68,7 +68,7 @@ class MultiProtocolSecureChannelV4Test {
.setQueryExecutor(directExecutor())
.build()
.associatedDeviceDao()
- storage = ConnectedDeviceStorage(context, Base64CryptoHelper(), database)
+ storage = ConnectedDeviceStorage(context, Base64CryptoHelper(), database, directExecutor())
}
@Test
fun processVerificationCodeMessage_oobVerification_verifyOobCode() {
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/FeatureCoordinatorTest.kt b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/FeatureCoordinatorTest.kt
index 23ab293..7cb2bfe 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/FeatureCoordinatorTest.kt
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/FeatureCoordinatorTest.kt
@@ -946,20 +946,24 @@ class FeatureCoordinatorTest {
}
@Test
- fun claimAssociatedDevice_claimsDevice() {
- val deviceId = UUID.randomUUID().toString()
+ fun claimAssociatedDevice_disconnectsAndClaimsDeviceAndInitiatesReconnection() {
+ val deviceId = UUID.randomUUID()
- coordinator.claimAssociatedDevice(deviceId)
+ coordinator.claimAssociatedDevice(deviceId.toString())
- verify(mockStorage).claimAssociatedDevice(deviceId)
+ verify(mockController).disconnectDevice(deviceId)
+ verify(mockStorage).claimAssociatedDevice(deviceId.toString())
+ verify(mockController).initiateConnectionToDevice(deviceId)
}
@Test
- fun removeAssociatedDeviceClaim_removesClaim() {
- val deviceId = UUID.randomUUID().toString()
+ fun removeAssociatedDeviceClaim_disconnectsAndRemovesClaimAndInitiatesReconnection() {
+ val deviceId = UUID.randomUUID()
- coordinator.removeAssociatedDeviceClaim(deviceId)
+ coordinator.removeAssociatedDeviceClaim(deviceId.toString())
- verify(mockStorage).removeAssociatedDeviceClaim(deviceId)
+ verify(mockController).disconnectDevice(deviceId)
+ verify(mockStorage).removeAssociatedDeviceClaim(deviceId.toString())
+ verify(mockController).initiateConnectionToDevice(deviceId)
}
}
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/MultiProtocolDeviceControllerTest.kt b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/MultiProtocolDeviceControllerTest.kt
index d8d07ba..2fae8f9 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/MultiProtocolDeviceControllerTest.kt
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/core/MultiProtocolDeviceControllerTest.kt
@@ -92,15 +92,17 @@ class MultiProtocolDeviceControllerTest {
.setQueryExecutor(directExecutor())
.build()
val database = connectedDeviceDatabase.associatedDeviceDao()
- spyStorage = spy(ConnectedDeviceStorage(context, Base64CryptoHelper(), database))
+ spyStorage =
+ spy(ConnectedDeviceStorage(context, Base64CryptoHelper(), database, directExecutor()))
whenever(spyStorage.hashWithChallengeSecret(any(), any())).thenReturn(TEST_CHALLENGE)
deviceController =
MultiProtocolDeviceController(
protocols,
spyStorage,
mockOobRunner,
- directExecutor(),
- testAssociationServiceUuid
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
)
deviceController.registerCallback(mockCallback, directExecutor())
secureChannel =
@@ -121,13 +123,14 @@ class MultiProtocolDeviceControllerTest {
}
@Test
- fun init_retriesStorageOnException() {
+ fun start_retriesStorageOnException() {
val transientErrorStorage =
object :
ConnectedDeviceStorage(
context,
Base64CryptoHelper(),
- connectedDeviceDatabase.associatedDeviceDao()
+ connectedDeviceDatabase.associatedDeviceDao(),
+ directExecutor()
) {
var attempts = 0
override fun getAllAssociatedDevices(): MutableList<AssociatedDevice> {
@@ -140,17 +143,93 @@ class MultiProtocolDeviceControllerTest {
}
MultiProtocolDeviceController(
- protocols,
- transientErrorStorage,
- mockOobRunner,
- directExecutor(),
- testAssociationServiceUuid
- )
+ protocols,
+ transientErrorStorage,
+ mockOobRunner,
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
+ )
+ .start()
assertThat(transientErrorStorage.attempts).isEqualTo(2)
}
@Test
+ fun start_connectsToPassengerDevicesWhenPassengerEnabled() {
+ val driverId = UUID.randomUUID()
+ val driverDevice =
+ AssociatedDevice(
+ driverId.toString(),
+ /* deviceAddress= */ "",
+ /* deviceName= */ null,
+ /* isConnectionEnabled= */ true
+ )
+ val passengerId = UUID.randomUUID()
+ val passengerDevice =
+ AssociatedDevice(
+ passengerId.toString(),
+ /* deviceAddress= */ "",
+ /* deviceName= */ null,
+ /* isConnectionEnabled= */ true
+ )
+ whenever(spyStorage.driverAssociatedDevices).thenReturn(listOf(driverDevice))
+ whenever(spyStorage.passengerAssociatedDevices).thenReturn(listOf(passengerDevice))
+ whenever(spyStorage.allAssociatedDevices).thenReturn(listOf(driverDevice, passengerDevice))
+ deviceController =
+ MultiProtocolDeviceController(
+ protocols,
+ spyStorage,
+ mockOobRunner,
+ testAssociationServiceUuid,
+ enablePassenger = true,
+ callbackExecutor = directExecutor()
+ )
+
+ deviceController.start()
+
+ verify(testConnectionProtocol).startConnectionDiscovery(eq(driverId), any(), any())
+ verify(testConnectionProtocol).startConnectionDiscovery(eq(passengerId), any(), any())
+ }
+
+ @Test
+ fun start_doesNotConnectToPassengerDevicesWhenPassengerDisabled() {
+ val driverId = UUID.randomUUID()
+ val driverDevice =
+ AssociatedDevice(
+ driverId.toString(),
+ /* deviceAddress= */ "",
+ /* deviceName= */ null,
+ /* isConnectionEnabled= */ true
+ )
+ val passengerId = UUID.randomUUID()
+ val passengerDevice =
+ AssociatedDevice(
+ passengerId.toString(),
+ /* deviceAddress= */ "",
+ /* deviceName= */ null,
+ /* isConnectionEnabled= */ true
+ )
+ whenever(spyStorage.driverAssociatedDevices).thenReturn(listOf(driverDevice))
+ whenever(spyStorage.passengerAssociatedDevices).thenReturn(listOf(passengerDevice))
+ whenever(spyStorage.allAssociatedDevices).thenReturn(listOf(driverDevice, passengerDevice))
+ deviceController =
+ MultiProtocolDeviceController(
+ protocols,
+ spyStorage,
+ mockOobRunner,
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
+ )
+
+ deviceController.start()
+
+ verify(testConnectionProtocol).startConnectionDiscovery(eq(driverId), any(), any())
+ verify(testConnectionProtocol, never()).startConnectionDiscovery(eq(passengerId), any(), any())
+ }
+
+ @Test
fun startAssociation_startedWithoutIdentifier() {
val deviceName = "TestDeviceName"
@@ -274,10 +353,12 @@ class MultiProtocolDeviceControllerTest {
protocols,
spyStorage,
mockOobRunner,
- directExecutor(),
- testAssociationServiceUuid
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
)
deviceController.registerCallback(mockCallback, directExecutor())
+ deviceController.start()
deviceController.initiateConnectionToDevice(deviceId)
argumentCaptor<ConnectionProtocol.DiscoveryCallback>().apply {
verify(testConnectionProtocol).startConnectionDiscovery(any(), any(), capture())
@@ -665,6 +746,95 @@ class MultiProtocolDeviceControllerTest {
}
@Test
+ fun handleSecureChannelMessage_firstMessagePersistsDeviceAsDriverWhenPassengerDisabled() {
+ val deviceName = "TestDeviceName"
+ val deviceId = UUID.randomUUID()
+ val testIdentifier = UUID.randomUUID()
+ val secret = ByteUtils.randomBytes(CHALLENGE_SECRET_BYTES)
+ val testDeviceMessage =
+ DeviceMessage.createOutgoingMessage(
+ null,
+ true,
+ OperationType.CLIENT_MESSAGE,
+ ByteUtils.uuidToBytes(deviceId) + secret
+ )
+ deviceController =
+ MultiProtocolDeviceController(
+ protocols,
+ spyStorage,
+ mockOobRunner,
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
+ )
+
+ deviceController.startAssociation(deviceName, mockAssociationCallback, testIdentifier)
+ argumentCaptor<ConnectionProtocol.DiscoveryCallback>().apply {
+ verify(testConnectionProtocol)
+ .startAssociationDiscovery(eq(deviceName), capture(), eq(testIdentifier))
+ firstValue.onDeviceConnected(UUID.randomUUID().toString())
+ }
+
+ deviceController.handleSecureChannelMessage(
+ testDeviceMessage,
+ deviceController.getConnectedDevice(
+ deviceController.associationPendingDeviceId.get() ?: fail("Null device id.")
+ )
+ ?: fail("Failed to find the device.")
+ )
+
+ argumentCaptor<AssociatedDevice>().apply {
+ verify(spyStorage).addAssociatedDeviceForDriver(capture())
+ assertThat(firstValue.deviceId).isEqualTo(deviceId.toString())
+ }
+ }
+
+ @Test
+ fun handleSecureChannelMessage_firstMessagePersistsDeviceAsUnclaimedWhenPassengerEnabled() {
+ val deviceName = "TestDeviceName"
+ val deviceId = UUID.randomUUID()
+ val testIdentifier = UUID.randomUUID()
+ val secret = ByteUtils.randomBytes(CHALLENGE_SECRET_BYTES)
+ val testDeviceMessage =
+ DeviceMessage.createOutgoingMessage(
+ null,
+ true,
+ OperationType.CLIENT_MESSAGE,
+ ByteUtils.uuidToBytes(deviceId) + secret
+ )
+ deviceController =
+ MultiProtocolDeviceController(
+ protocols,
+ spyStorage,
+ mockOobRunner,
+ testAssociationServiceUuid,
+ enablePassenger = true,
+ callbackExecutor = directExecutor()
+ )
+
+ deviceController.startAssociation(deviceName, mockAssociationCallback, testIdentifier)
+ argumentCaptor<ConnectionProtocol.DiscoveryCallback>().apply {
+ verify(testConnectionProtocol)
+ .startAssociationDiscovery(eq(deviceName), capture(), eq(testIdentifier))
+ firstValue.onDeviceConnected(UUID.randomUUID().toString())
+ }
+
+ deviceController.handleSecureChannelMessage(
+ testDeviceMessage,
+ deviceController.getConnectedDevice(
+ deviceController.associationPendingDeviceId.get() ?: fail("Null device id.")
+ )
+ ?: fail("Failed to find the device.")
+ )
+
+ argumentCaptor<AssociatedDevice>().apply {
+ verify(spyStorage)
+ .addAssociatedDeviceForUser(eq(AssociatedDevice.UNCLAIMED_USER_ID), capture())
+ assertThat(firstValue.deviceId).isEqualTo(deviceId.toString())
+ }
+ }
+
+ @Test
fun connectedDevices_returnsAllConnectedDevices() {
val activeUserDeviceId = UUID.randomUUID()
val activeUserDevice =
@@ -699,12 +869,13 @@ class MultiProtocolDeviceControllerTest {
protocols,
spyStorage,
mockOobRunner,
- directExecutor(),
- testAssociationServiceUuid
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
)
deviceController.registerCallback(mockCallback, directExecutor())
+ deviceController.start()
- deviceController.initiateConnectionToDevice(activeUserDeviceId)
argumentCaptor<ConnectionProtocol.DiscoveryCallback>().apply {
verify(testConnectionProtocol)
.startConnectionDiscovery(eq(activeUserDeviceId), any(), capture())
@@ -793,8 +964,9 @@ class MultiProtocolDeviceControllerTest {
setOf(protocol1, protocol2),
spyStorage,
mockOobRunner,
- directExecutor(),
- testAssociationServiceUuid
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
)
.apply { registerCallback(mockCallback, directExecutor()) }
deviceController.initiateConnectionToDevice(deviceId)
@@ -830,8 +1002,9 @@ class MultiProtocolDeviceControllerTest {
setOf(protocol),
spyStorage,
mockOobRunner,
- directExecutor(),
- testAssociationServiceUuid
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
)
.apply { registerCallback(mockCallback, directExecutor()) }
deviceController.initiateConnectionToDevice(deviceId)
@@ -867,11 +1040,12 @@ class MultiProtocolDeviceControllerTest {
setOf(protocol),
spyStorage,
mockOobRunner,
- directExecutor(),
- testAssociationServiceUuid
+ testAssociationServiceUuid,
+ enablePassenger = false,
+ callbackExecutor = directExecutor()
)
.apply { registerCallback(mockCallback, directExecutor()) }
- deviceController.initiateConnectionToDevice(deviceId)
+ deviceController.start()
argumentCaptor<ConnectionProtocol.DiscoveryCallback>().apply {
verify(protocol).startConnectionDiscovery(any(), any(), capture())
firstValue.onDeviceConnected(testProtocolId)
@@ -994,18 +1168,6 @@ class MultiProtocolDeviceControllerTest {
}
}
- private fun startReconnection() {
- val deviceName = "TestDeviceName"
- val testIdentifier = UUID.randomUUID()
-
- deviceController.startAssociation(deviceName, mockAssociationCallback, testIdentifier)
- argumentCaptor<ConnectionProtocol.DiscoveryCallback>().apply {
- verify(testConnectionProtocol)
- .startAssociationDiscovery(eq(deviceName), capture(), eq(testIdentifier))
- firstValue.onDeviceConnected(UUID.randomUUID().toString())
- }
- }
-
private class Base64CryptoHelper : CryptoHelper {
override fun encrypt(value: ByteArray?): String? = Base64.encodeToString(value, Base64.DEFAULT)
diff --git a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorageTest.java b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorageTest.java
index ecf057e..bdfbe1d 100644
--- a/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorageTest.java
+++ b/libs/connecteddevice/tests/unit/src/com/google/android/connecteddevice/storage/ConnectedDeviceStorageTest.java
@@ -62,7 +62,8 @@ public final class ConnectedDeviceStorageTest {
.build();
AssociatedDeviceDao database = connectedDeviceDatabase.associatedDeviceDao();
- connectedDeviceStorage = new ConnectedDeviceStorage(context, new FakeCryptoHelper(), database);
+ connectedDeviceStorage =
+ new ConnectedDeviceStorage(context, new FakeCryptoHelper(), database, directExecutor());
addedAssociatedDevices = new ArrayList<>();
}
@@ -233,7 +234,7 @@ public final class ConnectedDeviceStorageTest {
@Test
public void setAssociatedDeviceName_issuesCallbackOnNameChange() {
AssociatedDeviceCallback callback = mock(AssociatedDeviceCallback.class);
- connectedDeviceStorage.setAssociatedDeviceCallback(callback);
+ connectedDeviceStorage.registerAssociatedDeviceCallback(callback);
AssociatedDevice device =
new AssociatedDevice(
UUID.randomUUID().toString(),
@@ -299,7 +300,7 @@ public final class ConnectedDeviceStorageTest {
@Test
public void updateAssociatedDeviceName_issuesCallbackOnNameChange() {
AssociatedDeviceCallback callback = mock(AssociatedDeviceCallback.class);
- connectedDeviceStorage.setAssociatedDeviceCallback(callback);
+ connectedDeviceStorage.registerAssociatedDeviceCallback(callback);
AssociatedDevice device =
new AssociatedDevice(
UUID.randomUUID().toString(),
@@ -372,7 +373,7 @@ public final class ConnectedDeviceStorageTest {
@Test
public void addAssociatedDeviceForUser_invokesCallback() {
AssociatedDeviceCallback callback = mock(AssociatedDeviceCallback.class);
- connectedDeviceStorage.setAssociatedDeviceCallback(callback);
+ connectedDeviceStorage.registerAssociatedDeviceCallback(callback);
AssociatedDevice device = addRandomAssociatedDevice(ACTIVE_USER_ID);
@@ -382,7 +383,7 @@ public final class ConnectedDeviceStorageTest {
@Test
public void removeAssociatedDeviceForUser_invokesCallback() {
AssociatedDeviceCallback callback = mock(AssociatedDeviceCallback.class);
- connectedDeviceStorage.setAssociatedDeviceCallback(callback);
+ connectedDeviceStorage.registerAssociatedDeviceCallback(callback);
AssociatedDevice device = addRandomAssociatedDevice(ACTIVE_USER_ID);
connectedDeviceStorage.removeAssociatedDevice(device.getDeviceId());
@@ -393,7 +394,7 @@ public final class ConnectedDeviceStorageTest {
@Test
public void updateAssociatedDeviceName_invokesCallback() {
AssociatedDeviceCallback callback = mock(AssociatedDeviceCallback.class);
- connectedDeviceStorage.setAssociatedDeviceCallback(callback);
+ connectedDeviceStorage.registerAssociatedDeviceCallback(callback);
AssociatedDevice device = addRandomAssociatedDevice(ACTIVE_USER_ID);
String newName = "New Name";
@@ -407,7 +408,7 @@ public final class ConnectedDeviceStorageTest {
@Test
public void claimAssociatedDevice_setsCurrentUserIdOnAssociatedDevice() {
AssociatedDeviceCallback callback = mock(AssociatedDeviceCallback.class);
- connectedDeviceStorage.setAssociatedDeviceCallback(callback);
+ connectedDeviceStorage.registerAssociatedDeviceCallback(callback);
AssociatedDevice device = addRandomAssociatedDevice(AssociatedDevice.UNCLAIMED_USER_ID);
connectedDeviceStorage.claimAssociatedDevice(device.getDeviceId());
@@ -425,7 +426,7 @@ public final class ConnectedDeviceStorageTest {
@Test
public void removeAssociatedDeviceClaim_setsUnclaimedUserIdOnAssociatedDevice() {
AssociatedDeviceCallback callback = mock(AssociatedDeviceCallback.class);
- connectedDeviceStorage.setAssociatedDeviceCallback(callback);
+ connectedDeviceStorage.registerAssociatedDeviceCallback(callback);
AssociatedDevice device = addRandomAssociatedDevice(AssociatedDevice.UNCLAIMED_USER_ID);
connectedDeviceStorage.removeAssociatedDeviceClaim(device.getDeviceId());