From 1fc7629dda695c51289034bb7ad895d20ea80f63 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Tue, 8 Jan 2019 16:20:52 -0800 Subject: [PATCH 1/2] Add layout for advanced BT detail header If device supports metadata, then we display advanced UI in Bluetooth details header. This CL adds layout for this header. In advanced layout, it will show: 1. Device name 2. Left, right and case icon 3. Left, right and case battery level Once API is ready, following CL will get metadata from it and set it to UI. Bug: 122460277 Test: RunSettingsRoboTests Change-Id: Ide044cf9705f350b431b2cb3a9ad82cc4425a17e --- res/layout/advanced_bt_entity_header.xml | 68 ++++++++++++++ res/layout/advanced_bt_entity_sub.xml | 63 +++++++++++++ res/values/strings.xml | 7 ++ res/xml/bluetooth_device_details_fragment.xml | 11 ++- ...ancedBluetoothDetailsHeaderController.java | 88 +++++++++++++++++++ .../BluetoothDetailsButtonsController.java | 2 +- .../bluetooth/BluetoothDetailsController.java | 2 +- .../BluetoothDetailsHeaderController.java | 5 +- .../BluetoothDetailsMacAddressController.java | 2 +- .../BluetoothDetailsProfilesController.java | 2 +- .../BluetoothDeviceDetailsFragment.java | 1 + ...dBluetoothDetailsHeaderControllerTest.java | 59 +++++++++++++ .../BluetoothDetailsHeaderControllerTest.java | 1 - 13 files changed, 303 insertions(+), 8 deletions(-) create mode 100644 res/layout/advanced_bt_entity_header.xml create mode 100644 res/layout/advanced_bt_entity_sub.xml create mode 100644 src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java create mode 100644 tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java diff --git a/res/layout/advanced_bt_entity_header.xml b/res/layout/advanced_bt_entity_header.xml new file mode 100644 index 00000000000..4aadad1fc34 --- /dev/null +++ b/res/layout/advanced_bt_entity_header.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/advanced_bt_entity_sub.xml b/res/layout/advanced_bt_entity_sub.xml new file mode 100644 index 00000000000..07ea8146fad --- /dev/null +++ b/res/layout/advanced_bt_entity_sub.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 35c89234eee..3eb7ccccdd7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10496,6 +10496,13 @@ No Bluetooth devices + + Left + + Right + + Case + Settings Panel diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml index cf9fbf936c7..f485c6a8709 100644 --- a/res/xml/bluetooth_device_details_fragment.xml +++ b/res/xml/bluetooth_device_details_fragment.xml @@ -23,7 +23,16 @@ android:key="bluetooth_device_header" android:layout="@layout/settings_entity_header" android:selectable="false" - settings:allowDividerBelow="true"/> + settings:allowDividerBelow="true" + settings:searchable="false"/> + + pair = BluetoothUtils .getBtClassDrawableWithDescription(mContext, mCachedDevice, - mContext.getResources().getFraction(R.fraction.bt_battery_scale_fraction, 1, 1)); + mContext.getResources().getFraction(R.fraction.bt_battery_scale_fraction, 1, + 1)); String summaryText = mCachedDevice.getConnectionSummary(); // If both the hearing aids are connected, two device status should be shown. // If Second Summary is unavailable, to set it to null. @@ -84,4 +85,4 @@ public class BluetoothDetailsHeaderController extends BluetoothDetailsController public String getPreferenceKey() { return KEY_DEVICE_HEADER; } -} +} \ No newline at end of file diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java b/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java index 987dbe4f050..835961dee5e 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java @@ -62,4 +62,4 @@ public class BluetoothDetailsMacAddressController extends BluetoothDetailsContro } return mFooterPreference.getKey(); } -} +} \ No newline at end of file diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java index 88cebcb331f..5c609e69c44 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java @@ -264,4 +264,4 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll public String getPreferenceKey() { return KEY_PROFILES_GROUP; } -} +} \ No newline at end of file diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java index 6ff4309a4fa..1ddad7be26b 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java @@ -108,6 +108,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment mManager = getLocalBluetoothManager(context); mCachedDevice = getCachedDevice(mDeviceAddress); super.onAttach(context); + use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice); final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory( context).getBluetoothFeatureProvider(context); diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java new file mode 100644 index 00000000000..aa91e37adb4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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 android.content.Context; +import android.graphics.drawable.Drawable; + +import com.android.settings.fuelgauge.BatteryMeterView; +import com.android.settings.testutils.shadow.ShadowEntityHeaderController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowEntityHeaderController.class) +public class AdvancedBluetoothDetailsHeaderControllerTest{ + private static final int BATTERY_LEVEL = 30; + + private Context mContext; + private AdvancedBluetoothDetailsHeaderController mController; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + + mController = new AdvancedBluetoothDetailsHeaderController(mContext, "pref_Key"); + } + + @Test + public void createBatteryIcon_hasCorrectInfo() { + final Drawable drawable = mController.createBtBatteryIcon(mContext, BATTERY_LEVEL); + assertThat(drawable).isInstanceOf(BatteryMeterView.BatteryMeterDrawable.class); + + final BatteryMeterView.BatteryMeterDrawable iconDrawable = + (BatteryMeterView.BatteryMeterDrawable) drawable; + assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL); + } + +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java index 1e780753156..930d9cbe087 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java @@ -50,7 +50,6 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) - @Config(shadows = ShadowEntityHeaderController.class) public class BluetoothDetailsHeaderControllerTest extends BluetoothDetailsControllerTestBase { From 47123c8224cef1d4d691e1cdbb658dfb73abade1 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Wed, 23 Jan 2019 13:00:13 -0800 Subject: [PATCH 2/2] Update BT header using BT metadata As for unthethered headset, get BT data from BT metadata, rather than CachedBluetoothDevice Bug: 122460277 Test: RunSettingsRoboTests Change-Id: Ifb5507cbbce9602726ba272c12d1bf95eff91001 --- ...ancedBluetoothDetailsHeaderController.java | 58 ++++++++++++-- .../BluetoothDetailsButtonsController.java | 8 ++ src/com/android/settings/bluetooth/Utils.java | 27 +++++++ ...dBluetoothDetailsHeaderControllerTest.java | 76 ++++++++++++++++++- .../android/settings/bluetooth/UtilsTest.java | 50 +++++++++++- 5 files changed, 208 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java index 2ecaf503fe1..4b8efd4e371 100644 --- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java +++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java @@ -16,17 +16,20 @@ package com.android.settings.bluetooth; +import android.bluetooth.BluetoothDevice; import android.content.Context; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.VisibleForTesting; +import androidx.core.graphics.drawable.IconCompat; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.fuelgauge.BatteryMeterView; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -37,7 +40,8 @@ import com.android.settingslib.widget.LayoutPreference; */ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceController { - private LayoutPreference mLayoutPreference; + @VisibleForTesting + LayoutPreference mLayoutPreference; private CachedBluetoothDevice mCachedDevice; public AdvancedBluetoothDetailsHeaderController(Context context, String prefKey) { @@ -46,8 +50,9 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont @Override public int getAvailabilityStatus() { - //TODO(b/122460277): decide whether it is available by {@code bluetoothDevice} - return CONDITIONALLY_UNAVAILABLE; + final boolean unthetheredHeadset = Utils.getBooleanMetaData(mCachedDevice.getDevice(), + BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET); + return unthetheredHeadset ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @Override @@ -62,12 +67,28 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont mCachedDevice = cachedBluetoothDevice; } - private void refresh() { + @VisibleForTesting + void refresh() { if (mLayoutPreference != null && mCachedDevice != null) { final TextView title = mLayoutPreference.findViewById(R.id.entity_header_title); title.setText(mCachedDevice.getName()); final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary); summary.setText(mCachedDevice.getConnectionSummary()); + + updateSubLayout(mLayoutPreference.findViewById(R.id.layout_left), + BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON, + BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY, + R.string.bluetooth_left_name); + + updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle), + BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON, + BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY, + R.string.bluetooth_middle_name); + + updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right), + BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON, + BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY, + R.string.bluetooth_right_name); } } @@ -79,10 +100,35 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont drawable.setBatteryLevel(level); drawable.setShowPercent(false); drawable.setBatteryColorFilter(new PorterDuffColorFilter( - Utils.getColorAttrDefaultColor(context, android.R.attr.colorControlNormal), + com.android.settings.Utils.getColorAttrDefaultColor(context, + android.R.attr.colorControlNormal), PorterDuff.Mode.SRC_IN)); return drawable; } + private void updateSubLayout(LinearLayout linearLayout, int iconMetaKey, int batteryMetaKey, + int titleResId) { + if (linearLayout == null) { + return; + } + final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice(); + final String iconUri = Utils.getStringMetaData(bluetoothDevice, iconMetaKey); + if (iconUri != null) { + final ImageView imageView = linearLayout.findViewById(R.id.header_icon); + final IconCompat iconCompat = IconCompat.createWithContentUri(iconUri); + imageView.setImageBitmap(iconCompat.getBitmap()); + } + + final int batteryLevel = Utils.getIntMetaData(bluetoothDevice, batteryMetaKey); + if (batteryLevel != Utils.META_INT_ERROR) { + final ImageView imageView = linearLayout.findViewById(R.id.bt_battery_icon); + imageView.setImageDrawable(createBtBatteryIcon(mContext, batteryLevel)); + final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary); + textView.setText(com.android.settings.Utils.formatPercentage(batteryLevel)); + } + + final TextView textView = linearLayout.findViewById(R.id.header_title); + textView.setText(titleResId); + } } diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java index a7fae1441f9..af150527c4c 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java @@ -16,6 +16,7 @@ package com.android.settings.bluetooth; +import android.bluetooth.BluetoothDevice; import android.content.Context; import androidx.preference.PreferenceFragmentCompat; @@ -43,6 +44,13 @@ public class BluetoothDetailsButtonsController extends BluetoothDetailsControlle mIsConnected = device.isConnected(); } + @Override + public boolean isAvailable() { + final boolean unthetheredHeadset = Utils.getBooleanMetaData(mCachedDevice.getDevice(), + BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET); + return !unthetheredHeadset; + } + private void onForgetButtonPressed() { ForgetDeviceDialogFragment fragment = ForgetDeviceDialogFragment.newInstance(mCachedDevice.getAddress()); diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java index d6e395e0c31..ff4a98fc5ce 100755 --- a/src/com/android/settings/bluetooth/Utils.java +++ b/src/com/android/settings/bluetooth/Utils.java @@ -47,6 +47,8 @@ public final class Utils { static final boolean V = BluetoothUtils.V; // verbose logging static final boolean D = BluetoothUtils.D; // regular logging + public static final int META_INT_ERROR = -1; + private Utils() { } @@ -152,4 +154,29 @@ public final class Utils { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1; } + + public static boolean getBooleanMetaData(BluetoothDevice bluetoothDevice, int key) { + if (bluetoothDevice == null) { + return false; + } + return Boolean.parseBoolean(bluetoothDevice.getMetadata(key)); + } + + public static String getStringMetaData(BluetoothDevice bluetoothDevice, int key) { + if (bluetoothDevice == null) { + return null; + } + return bluetoothDevice.getMetadata(key); + } + + public static int getIntMetaData(BluetoothDevice bluetoothDevice, int key) { + if (bluetoothDevice == null) { + return META_INT_ERROR; + } + try { + return Integer.parseInt(bluetoothDevice.getMetadata(key)); + } catch (NumberFormatException e) { + return META_INT_ERROR; + } + } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java index aa91e37adb4..a74610e1a3d 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java @@ -18,15 +18,27 @@ package com.android.settings.bluetooth; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; import android.content.Context; import android.graphics.drawable.Drawable; +import android.view.LayoutInflater; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; import com.android.settings.fuelgauge.BatteryMeterView; import com.android.settings.testutils.shadow.ShadowEntityHeaderController; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.widget.LayoutPreference; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -34,26 +46,82 @@ import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowEntityHeaderController.class) public class AdvancedBluetoothDetailsHeaderControllerTest{ - private static final int BATTERY_LEVEL = 30; + private static final int BATTERY_LEVEL_MAIN = 30; + private static final int BATTERY_LEVEL_LEFT = 25; + private static final int BATTERY_LEVEL_RIGHT = 45; private Context mContext; + + @Mock + private BluetoothDevice mBluetoothDevice; + @Mock + private CachedBluetoothDevice mCachedDevice; private AdvancedBluetoothDetailsHeaderController mController; + private LayoutPreference mLayoutPreference; @Before public void setUp() { - mContext = RuntimeEnvironment.application; + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; mController = new AdvancedBluetoothDetailsHeaderController(mContext, "pref_Key"); + mController.init(mCachedDevice); + mLayoutPreference = new LayoutPreference(mContext, + LayoutInflater.from(mContext).inflate(R.layout.advanced_bt_entity_header, null)); + mController.mLayoutPreference = mLayoutPreference; + when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice); } @Test public void createBatteryIcon_hasCorrectInfo() { - final Drawable drawable = mController.createBtBatteryIcon(mContext, BATTERY_LEVEL); + final Drawable drawable = mController.createBtBatteryIcon(mContext, BATTERY_LEVEL_MAIN); assertThat(drawable).isInstanceOf(BatteryMeterView.BatteryMeterDrawable.class); final BatteryMeterView.BatteryMeterDrawable iconDrawable = (BatteryMeterView.BatteryMeterDrawable) drawable; - assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL); + assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL_MAIN); + } + + @Test + public void refresh_updateCorrectInfo() { + when(mBluetoothDevice.getMetadata( + BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn( + String.valueOf(BATTERY_LEVEL_LEFT)); + when(mBluetoothDevice.getMetadata( + BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn( + String.valueOf(BATTERY_LEVEL_RIGHT)); + when(mBluetoothDevice.getMetadata( + BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY)).thenReturn( + String.valueOf(BATTERY_LEVEL_MAIN)); + mController.refresh(); + + assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_left), BATTERY_LEVEL_LEFT); + assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_right), BATTERY_LEVEL_RIGHT); + assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_middle), BATTERY_LEVEL_MAIN); + } + + @Test + public void getAvailabilityStatus_unthetheredHeadset_returnAvailable() { + when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)) + .thenReturn("true"); + + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_notUnthetheredHeadset_returnUnavailable() { + when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)) + .thenReturn("false"); + + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.CONDITIONALLY_UNAVAILABLE); + } + + private void assertBatteryLevel(LinearLayout linearLayout, int batteryLevel) { + final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary); + assertThat(textView.getText().toString()).isEqualTo( + com.android.settings.Utils.formatPercentage(batteryLevel)); } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java index 1337f6640e1..51e559f8900 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java @@ -15,6 +15,8 @@ */ package com.android.settings.bluetooth; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -22,6 +24,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothDevice; import android.content.Context; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -40,23 +43,68 @@ import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class UtilsTest { + private static final String STRING_METADATA = "string_metadata"; + private static final String BOOL_METADATA = "true"; + private static final String INT_METADATA = "25"; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; + @Mock + private BluetoothDevice mBluetoothDevice; private MetricsFeatureProvider mMetricsFeatureProvider; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mMetricsFeatureProvider = FakeFeatureFactory.setupForTest().getMetricsFeatureProvider(); } @Test - public void testShowConnectingError_shouldLogBluetoothConnectError() { + public void showConnectingError_shouldLogBluetoothConnectError() { when(mContext.getString(anyInt(), anyString())).thenReturn("testMessage"); Utils.showConnectingError(mContext, "testName", mock(LocalBluetoothManager.class)); verify(mMetricsFeatureProvider).visible(eq(mContext), anyInt(), eq(MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR)); } + + @Test + public void getStringMetaData_hasMetaData_getCorrectMetaData() { + when(mBluetoothDevice.getMetadata( + BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON)).thenReturn(STRING_METADATA); + + assertThat(Utils.getStringMetaData(mBluetoothDevice, + BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON)).isEqualTo(STRING_METADATA); + } + + @Test + public void getIntMetaData_hasMetaData_getCorrectMetaData() { + when(mBluetoothDevice.getMetadata( + BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(INT_METADATA); + + assertThat(Utils.getIntMetaData(mBluetoothDevice, + BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)) + .isEqualTo(Integer.parseInt(INT_METADATA)); + } + + @Test + public void getIntMetaData_invalidMetaData_getErrorCode() { + when(mBluetoothDevice.getMetadata( + BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(STRING_METADATA); + + assertThat(Utils.getIntMetaData(mBluetoothDevice, + BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON)).isEqualTo(Utils.META_INT_ERROR); + } + + @Test + public void getBooleanMetaData_hasMetaData_getCorrectMetaData() { + when(mBluetoothDevice.getMetadata( + BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(BOOL_METADATA); + + assertThat(Utils.getBooleanMetaData(mBluetoothDevice, + BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).isEqualTo(true); + } + }