diff --git a/res/layout/companion_apps_remove_button_widget.xml b/res/layout/companion_apps_remove_button_widget.xml
new file mode 100644
index 00000000000..a3c229537ac
--- /dev/null
+++ b/res/layout/companion_apps_remove_button_widget.xml
@@ -0,0 +1,24 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/preference_companion_app.xml b/res/layout/preference_companion_app.xml
new file mode 100644
index 00000000000..22712753b2f
--- /dev/null
+++ b/res/layout/preference_companion_app.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b471d0fb559..7bc760a9c6f 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -205,6 +205,9 @@
21dp
16dp
+
+ 20dp
+
1px
16dp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 19f892e5525..41f76e8f974 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1815,6 +1815,10 @@
Device\'s Bluetooth address: %1$s
Forget device?
+
+ Remove association
+
+ Disconnect App?
Your phone will no longer be paired with %1$s
@@ -1822,12 +1826,16 @@
Your tablet will no longer be paired with %1$s
Your device will no longer be paired with %1$s
+
+ %1$s app will no longer connect to your %2$s
%1$s will no longer be paired with any device linked to this account
Forget device
+
+ Disconnect app
Connect to\u2026
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 94052b67213..5084d4d481a 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -44,6 +44,9 @@
settings:allowDividerBelow="true"
settings:allowDividerAbove="true"/>
+
+
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsController.java
new file mode 100644
index 00000000000..f2a94ba7440
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsController.java
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.bluetooth;
+
+import static com.android.internal.util.CollectionUtils.filter;
+
+import android.companion.Association;
+import android.companion.CompanionDeviceManager;
+import android.companion.ICompanionDeviceManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import com.google.common.base.Objects;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+
+/**
+ * This class adds Companion Device app rows to launch the app or remove the associations
+ */
+public class BluetoothDetailsCompanionAppsController extends BluetoothDetailsController {
+ public static final String KEY_DEVICE_COMPANION_APPS = "device_companion_apps";
+ private static final String LOG_TAG = "BTCompanionController";
+
+ private CachedBluetoothDevice mCachedDevice;
+
+ @VisibleForTesting
+ PreferenceCategory mProfilesContainer;
+
+ @VisibleForTesting
+ CompanionDeviceManager mCompanionDeviceManager;
+
+ @VisibleForTesting
+ PackageManager mPackageManager;
+
+ public BluetoothDetailsCompanionAppsController(Context context,
+ PreferenceFragmentCompat fragment, CachedBluetoothDevice device, Lifecycle lifecycle) {
+ super(context, fragment, device, lifecycle);
+ mCachedDevice = device;
+ mCompanionDeviceManager = context.getSystemService(CompanionDeviceManager.class);
+ mPackageManager = context.getPackageManager();
+ lifecycle.addObserver(this);
+ }
+
+ @Override
+ protected void init(PreferenceScreen screen) {
+ mProfilesContainer = screen.findPreference(getPreferenceKey());
+ mProfilesContainer.setLayoutResource(R.layout.preference_companion_app);
+ }
+
+ private List getAssociations(String address) {
+ return filter(
+ mCompanionDeviceManager.getAllAssociations(),
+ a -> Objects.equal(address, a.getDeviceMacAddress()));
+ }
+
+ private static void removePreference(PreferenceCategory container, String packageName) {
+ Preference preference = container.findPreference(packageName);
+ if (preference != null) {
+ container.removePreference(preference);
+ }
+ }
+
+ private void removeAssociationDialog(String packageName, String address,
+ PreferenceCategory container, CharSequence appName, Context context) {
+ DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ removeAssociation(packageName, address, container);
+ }
+ };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+
+ builder.setPositiveButton(
+ R.string.bluetooth_companion_app_remove_association_confirm_button,
+ dialogClickListener)
+ .setNegativeButton(android.R.string.cancel, dialogClickListener)
+ .setTitle(R.string.bluetooth_companion_app_remove_association_dialog_title)
+ .setMessage(mContext.getString(
+ R.string.bluetooth_companion_app_body, appName, mCachedDevice.getName()))
+ .show();
+ }
+
+ private static void removeAssociation(String packageName, String address,
+ PreferenceCategory container) {
+ try {
+ java.util.Objects.requireNonNull(ICompanionDeviceManager.Stub.asInterface(
+ ServiceManager.getService(
+ Context.COMPANION_DEVICE_SERVICE))).disassociate(
+ address, packageName);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+
+ removePreference(container, packageName);
+ }
+
+ private CharSequence getAppName(String packageName) {
+ CharSequence appName = null;
+ try {
+ appName = mPackageManager.getApplicationLabel(
+ mPackageManager.getApplicationInfo(packageName, 0));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Package Not Found", e);
+ }
+
+ return appName;
+ }
+
+ private List getPreferencesNeedToShow(String address, PreferenceCategory container) {
+ List preferencesToRemove = new ArrayList<>();
+ Set packages = getAssociations(address)
+ .stream().map(Association::getPackageName)
+ .collect(Collectors.toSet());
+
+ for (int i = 0; i < container.getPreferenceCount(); i++) {
+ String preferenceKey = container.getPreference(i).getKey();
+ if (packages.isEmpty() || !packages.contains(preferenceKey)) {
+ preferencesToRemove.add(preferenceKey);
+ }
+ }
+
+ for (String preferenceName : preferencesToRemove) {
+ removePreference(container, preferenceName);
+ }
+
+ return packages.stream()
+ .filter(p -> container.findPreference(p) == null)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Refreshes the state of the preferences for all the associations, possibly adding or
+ * removing preferences as needed.
+ */
+ @Override
+ protected void refresh() {
+ updatePreferences(mContext, mCachedDevice.getAddress(), mProfilesContainer);
+ }
+
+ /**
+ * Add preferences for each association for the bluetooth device
+ */
+ public void updatePreferences(Context context,
+ String address, PreferenceCategory container) {
+ Set addedPackages = new HashSet<>();
+
+ for (String packageName : getPreferencesNeedToShow(address, container)) {
+ CharSequence appName = getAppName(packageName);
+
+ if (TextUtils.isEmpty(appName) || !addedPackages.add(packageName)) {
+ continue;
+ }
+
+ Drawable removeIcon = context.getResources().getDrawable(R.drawable.ic_clear);
+ CompanionAppWidgetPreference preference = new CompanionAppWidgetPreference(
+ removeIcon,
+ v -> removeAssociationDialog(packageName, address, container, appName, context),
+ context
+ );
+
+ Drawable appIcon;
+
+ try {
+ appIcon = mPackageManager.getApplicationIcon(packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Icon Not Found", e);
+ continue;
+ }
+ Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
+ preference.setIcon(appIcon);
+ preference.setTitle(appName.toString());
+ preference.setOnPreferenceClickListener(v -> {
+ context.startActivity(intent);
+ return true;
+ });
+
+ preference.setKey(packageName);
+ preference.setVisible(true);
+ container.addPreference(preference);
+ }
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_DEVICE_COMPANION_APPS;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index a8812475ace..4980ba313fb 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -185,6 +185,8 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
lifecycle, mManager));
controllers.add(new BluetoothDetailsButtonsController(context, this, mCachedDevice,
lifecycle));
+ controllers.add(new BluetoothDetailsCompanionAppsController(context, this,
+ mCachedDevice, lifecycle));
controllers.add(new BluetoothDetailsProfilesController(context, this, mManager,
mCachedDevice, lifecycle));
controllers.add(new BluetoothDetailsMacAddressController(context, this, mCachedDevice,
diff --git a/src/com/android/settings/bluetooth/CompanionAppWidgetPreference.java b/src/com/android/settings/bluetooth/CompanionAppWidgetPreference.java
new file mode 100644
index 00000000000..cd0643373d6
--- /dev/null
+++ b/src/com/android/settings/bluetooth/CompanionAppWidgetPreference.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.ImageButton;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+/**
+ * A custom preference for companion device apps. Added a button for association removal
+ */
+public class CompanionAppWidgetPreference extends Preference {
+ private Drawable mWidgetIcon;
+ private View.OnClickListener mWidgetListener;
+ private int mImageButtonPadding;
+
+ public CompanionAppWidgetPreference(Drawable widgetIcon, View.OnClickListener widgetListener,
+ Context context) {
+ super(context);
+ mWidgetIcon = widgetIcon;
+ mWidgetListener = widgetListener;
+ mImageButtonPadding = context.getResources().getDimensionPixelSize(
+ R.dimen.bluetooth_companion_app_widget);
+ setWidgetLayoutResource(R.layout.companion_apps_remove_button_widget);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ ImageButton imageButton = (ImageButton) holder.findViewById(R.id.remove_button);
+ imageButton.setPadding(
+ mImageButtonPadding, mImageButtonPadding, mImageButtonPadding, mImageButtonPadding);
+ imageButton.setColorFilter(getContext().getColor(android.R.color.darker_gray));
+ imageButton.setImageDrawable(mWidgetIcon);
+ imageButton.setOnClickListener(mWidgetListener);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
new file mode 100644
index 00000000000..3f49938412b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.companion.Association;
+import android.companion.CompanionDeviceManager;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothDetailsCompanionAppsControllerTest extends
+ BluetoothDetailsControllerTestBase {
+ private static final String PACKAGE_NAME_ONE = "com.google.android.deskclock";
+ private static final String PACKAGE_NAME_TWO = "com.google.android.calculator";
+ private static final String PACKAGE_NAME_THREE = "com.google.android.GoogleCamera";
+ private static final CharSequence APP_NAME_ONE = "deskclock";
+ private static final CharSequence APP_NAME_TWO = "calculator";
+ private static final CharSequence APP_NAME_THREE = "GoogleCamera";
+
+ @Mock
+ private CompanionDeviceManager mCompanionDeviceManager;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private BluetoothDetailsCompanionAppsController mController;
+ private PreferenceCategory mProfiles;
+ private List mPackages;
+ private List mAppNames;
+ private List mAssociations;
+
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ mPackages = Arrays.asList(PACKAGE_NAME_ONE, PACKAGE_NAME_TWO, PACKAGE_NAME_THREE);
+ mAppNames = Arrays.asList(APP_NAME_ONE, APP_NAME_TWO, APP_NAME_THREE);
+ mProfiles = spy(new PreferenceCategory(mContext));
+ mAssociations = new ArrayList<>();
+ when(mCompanionDeviceManager.getAllAssociations()).thenReturn(mAssociations);
+ when(mProfiles.getPreferenceManager()).thenReturn(mPreferenceManager);
+ setupDevice(mDeviceConfig);
+ mController =
+ new BluetoothDetailsCompanionAppsController(mContext, mFragment, mCachedDevice,
+ mLifecycle);
+ mController.mCompanionDeviceManager = mCompanionDeviceManager;
+ mController.mPackageManager = mPackageManager;
+ mController.mProfilesContainer = mProfiles;
+ mProfiles.setKey(mController.getPreferenceKey());
+ mScreen.addPreference(mProfiles);
+ }
+
+ private void setupFakeLabelAndInfo(String packageName, CharSequence appName) {
+ ApplicationInfo appInfo = mock(ApplicationInfo.class);
+ try {
+ when(mPackageManager.getApplicationInfo(packageName, 0)).thenReturn(appInfo);
+ when(mPackageManager.getApplicationLabel(appInfo)).thenReturn(appName);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void addFakeAssociation(String packageName, CharSequence appName) {
+ setupFakeLabelAndInfo(packageName, appName);
+ Association association = new Association(
+ 0, mCachedDevice.getAddress(), packageName, "", true, System.currentTimeMillis());
+ mAssociations.add(association);
+ showScreen(mController);
+ }
+
+ private Preference getPreference(int index) {
+ PreferenceCategory preferenceCategory = mProfiles.findPreference(
+ mController.getPreferenceKey());
+ return Objects.requireNonNull(preferenceCategory).getPreference(index);
+ }
+
+ private void removeAssociation(String packageName) {
+ mAssociations = mAssociations.stream()
+ .filter(a -> !a.getPackageName().equals(packageName))
+ .collect(Collectors.toList());
+
+ when(mCompanionDeviceManager.getAllAssociations()).thenReturn(mAssociations);
+
+ showScreen(mController);
+ }
+
+ @Test
+ public void addOneAssociation_preferenceShouldBeAdded() {
+ addFakeAssociation(PACKAGE_NAME_ONE, APP_NAME_ONE);
+
+ Preference preferenceOne = getPreference(0);
+
+ assertThat(preferenceOne.getClass()).isEqualTo(CompanionAppWidgetPreference.class);
+ assertThat(preferenceOne.getKey()).isEqualTo(PACKAGE_NAME_ONE);
+ assertThat(preferenceOne.getTitle()).isEqualTo(APP_NAME_ONE.toString());
+ assertThat(mProfiles.getPreferenceCount()).isEqualTo(1);
+
+ removeAssociation(PACKAGE_NAME_ONE);
+
+ assertThat(mProfiles.getPreferenceCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void removeOneAssociation_preferenceShouldBeRemoved() {
+ addFakeAssociation(PACKAGE_NAME_ONE, APP_NAME_ONE);
+
+ removeAssociation(PACKAGE_NAME_ONE);
+
+ assertThat(mProfiles.getPreferenceCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void addMultipleAssociations_preferencesShouldBeAdded() {
+ for (int i = 0; i < mPackages.size(); i++) {
+ addFakeAssociation(mPackages.get(i), mAppNames.get(i));
+
+ Preference preference = getPreference(i);
+
+ assertThat(preference.getClass()).isEqualTo(CompanionAppWidgetPreference.class);
+ assertThat(preference.getKey()).isEqualTo(mPackages.get(i));
+ assertThat(preference.getTitle()).isEqualTo(mAppNames.get(i).toString());
+ assertThat(mProfiles.getPreferenceCount()).isEqualTo(i + 1);
+ }
+ }
+
+ @Test
+ public void removeMultipleAssociations_preferencesShouldBeRemoved() {
+ for (int i = 0; i < mPackages.size(); i++) {
+ addFakeAssociation(mPackages.get(i), mAppNames.get(i).toString());
+ }
+
+ for (int i = 0; i < mPackages.size(); i++) {
+ removeAssociation(mPackages.get(i));
+
+ assertThat(mProfiles.getPreferenceCount()).isEqualTo(mPackages.size() - i - 1);
+
+ if (i == mPackages.size() - 1) {
+ break;
+ }
+
+ assertThat(getPreference(0).getKey()).isEqualTo(mPackages.get(i + 1));
+ assertThat(getPreference(0).getTitle()).isEqualTo(mAppNames.get(i + 1).toString());
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/CompanionAppWidgetPreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/CompanionAppWidgetPreferenceTest.java
new file mode 100644
index 00000000000..8ee3ef78d81
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/CompanionAppWidgetPreferenceTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+
+import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowAlertDialogCompat.class})
+public class CompanionAppWidgetPreferenceTest {
+ private static final String TITLE_ONE = "Test Title 1";
+ private static final String TITLE_TWO = "Test Title 1";
+ private static final String KEY_ONE = "Test Key 1";
+ private static final String KEY_TWO = "Test Key 1";
+
+ private Context mContext;
+ private Drawable mWidgetIconOne;
+ private Drawable mWidgetIconTwo;
+ private Drawable mAppIconOne;
+ private Drawable mAppIconTwo;
+
+ @Mock
+ private View.OnClickListener mWidgetListenerOne;
+ @Mock
+ private View.OnClickListener mWidgetListenerTwo;
+
+ private List mPreferenceContainer;
+
+ @Before
+ public void setUp() {
+ mPreferenceContainer = new ArrayList<>();
+ Context context = spy(RuntimeEnvironment.application.getApplicationContext());
+ mContext = new ContextThemeWrapper(context, R.style.Theme_Settings);
+ mWidgetIconOne = mock(Drawable.class);
+ mAppIconOne = mock(Drawable.class);
+ mWidgetListenerOne = mock(View.OnClickListener.class);
+ mWidgetIconTwo = mock(Drawable.class);
+ mAppIconTwo = mock(Drawable.class);
+ mWidgetListenerTwo = mock(View.OnClickListener.class);
+ }
+
+ private void setUpPreferenceContainer(Drawable widgetIcon, Drawable appIcon,
+ View.OnClickListener listener, String title, String key) {
+ CompanionAppWidgetPreference preference = new CompanionAppWidgetPreference(
+ widgetIcon, listener, mContext);
+ preference.setIcon(appIcon);
+ preference.setTitle(title);
+ preference.setKey(key);
+ mPreferenceContainer.add(preference);
+ }
+
+ @Test
+ public void setUpPreferenceContainer_preferenceShouldBeAdded() {
+ setUpPreferenceContainer(
+ mWidgetIconOne, mAppIconOne, mWidgetListenerOne, TITLE_ONE, KEY_ONE);
+
+ assertThat(mPreferenceContainer.get(0).getIcon()).isEqualTo(mAppIconOne);
+ assertThat(mPreferenceContainer.get(0).getKey()).isEqualTo(KEY_ONE);
+ assertThat(mPreferenceContainer.get(0).getTitle()).isEqualTo(TITLE_ONE);
+
+ setUpPreferenceContainer(
+ mWidgetIconTwo, mAppIconTwo, mWidgetListenerTwo, TITLE_TWO, KEY_TWO);
+
+ assertThat(mPreferenceContainer.get(1).getIcon()).isEqualTo(mAppIconTwo);
+ assertThat(mPreferenceContainer.get(1).getKey()).isEqualTo(KEY_TWO);
+ assertThat(mPreferenceContainer.get(1).getTitle()).isEqualTo(TITLE_TWO);
+ }
+}