diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index 3fc0abfc97f..e438cbfc6ae 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -34,7 +34,10 @@ import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.Index; import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -205,11 +208,20 @@ public final class BluetoothDevicePreference extends Preference implements void onClicked() { int bondState = mCachedDevice.getBondState(); + final MetricsFeatureProvider metricsFeatureProvider = + FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider(); + if (mCachedDevice.isConnected()) { + metricsFeatureProvider.action(getContext(), + MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT); askDisconnect(); } else if (bondState == BluetoothDevice.BOND_BONDED) { + metricsFeatureProvider.action(getContext(), + MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT); mCachedDevice.connect(true); } else if (bondState == BluetoothDevice.BOND_NONE) { + metricsFeatureProvider.action(getContext(), + MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR); pair(); } } diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java index 83c05608a8a..6db51dfc87c 100644 --- a/src/com/android/settings/bluetooth/BluetoothEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java @@ -27,7 +27,6 @@ import android.provider.Settings; import android.widget.Switch; import android.widget.Toast; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.search.Index; @@ -52,6 +51,7 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh private static final String EVENT_DATA_IS_BT_ON = "is_bluetooth_on"; private static final int EVENT_UPDATE_INDEX = 0; + private final int mMetricsEvent; private Handler mHandler = new Handler() { @Override @@ -77,13 +77,15 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh }; public BluetoothEnabler(Context context, SwitchWidgetController switchWidget, - MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager) { + MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager, + int metricsEvent) { mContext = context; mMetricsFeatureProvider = metricsFeatureProvider; mSwitchWidget = switchWidget; mSwitch = mSwitchWidget.getSwitch(); mSwitchWidget.setListener(this); mValidListener = false; + mMetricsEvent = metricsEvent; if (manager == null) { // Bluetooth is not supported @@ -191,7 +193,7 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh return false; } - mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_BLUETOOTH_TOGGLE, isChecked); + mMetricsFeatureProvider.action(mContext, mMetricsEvent, isChecked); if (mLocalAdapter != null) { boolean status = mLocalAdapter.setBluetoothEnabled(isChecked); diff --git a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java index d9b1bea71b8..f98a2096fd5 100644 --- a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java +++ b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java @@ -18,6 +18,7 @@ package com.android.settings.bluetooth; import android.content.Context; import android.support.v7.preference.PreferenceScreen; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.core.PreferenceController; import com.android.settings.core.lifecycle.LifecycleObserver; import com.android.settings.core.lifecycle.events.OnPause; @@ -54,7 +55,8 @@ public class BluetoothMasterSwitchPreferenceController extends PreferenceControl mBtPreference = (MasterSwitchPreference) screen.findPreference(KEY_TOGGLE_BLUETOOTH); mBluetoothEnabler = new BluetoothEnabler(mContext, new MasterSwitchController(mBtPreference), - FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(), mBluetoothManager); + FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(), mBluetoothManager, + MetricsEvent.ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE); } @Override diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java index acb99a6739e..5679f906f60 100644 --- a/src/com/android/settings/bluetooth/BluetoothSettings.java +++ b/src/com/android/settings/bluetooth/BluetoothSettings.java @@ -153,7 +153,8 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem mSwitchBar = activity.getSwitchBar(); mBluetoothEnabler = new BluetoothEnabler(activity, new SwitchBarController(mSwitchBar), - mMetricsFeatureProvider, Utils.getLocalBtManager(activity)); + mMetricsFeatureProvider, Utils.getLocalBtManager(activity), + MetricsEvent.ACTION_BLUETOOTH_TOGGLE); mBluetoothEnabler.setupSwitchController(); } diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java index 4fa44b44549..037b381a033 100755 --- a/src/com/android/settings/bluetooth/Utils.java +++ b/src/com/android/settings/bluetooth/Utils.java @@ -21,9 +21,12 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.DialogInterface; +import android.support.annotation.VisibleForTesting; import android.widget.Toast; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.Index; import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -84,14 +87,25 @@ public final class Utils { // TODO: wire this up to show connection errors... static void showConnectingError(Context context, String name) { - showError(context, name, R.string.bluetooth_connecting_error_message); + showConnectingError(context, name, getLocalBtManager(context)); + } + + @VisibleForTesting + static void showConnectingError(Context context, String name, LocalBluetoothManager manager) { + FeatureFactory.getFactory(context).getMetricsFeatureProvider().visible(context, + MetricsEvent.VIEW_UNKNOWN, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR); + showError(context, name, R.string.bluetooth_connecting_error_message, manager); } static void showError(Context context, String name, int messageResId) { + showError(context, name, messageResId, getLocalBtManager(context)); + } + + private static void showError(Context context, String name, int messageResId, + LocalBluetoothManager manager) { String message = context.getString(messageResId, name); - LocalBluetoothManager manager = getLocalBtManager(context); Context activity = manager.getForegroundActivity(); - if(manager.isForegroundActivity()) { + if (manager.isForegroundActivity()) { new AlertDialog.Builder(activity) .setTitle(R.string.bluetooth_error_title) .setMessage(message) diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java new file mode 100644 index 00000000000..59151180584 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 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.bluetooth.BluetoothDevice; +import android.content.Context; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class BluetoothDevicePreferenceTest { + + private Context mContext; + @Mock + private CachedBluetoothDevice mCachedBluetoothDevice; + + private FakeFeatureFactory mFakeFeatureFactory; + private MetricsFeatureProvider mMetricsFeatureProvider; + private BluetoothDevicePreference mPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application.getApplicationContext()); + FakeFeatureFactory.setupForTest(mContext); + mFakeFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); + mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider(); + mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice); + } + + @Test + public void onClicked_deviceConnected_shouldLogBluetoothDisconnectEvent() { + when(mCachedBluetoothDevice.isConnected()).thenReturn(true); + + mPreference.onClicked(); + + verify(mMetricsFeatureProvider).action( + mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT); + } + + @Test + public void onClicked_deviceBonded_shouldLogBluetoothConnectEvent() { + when(mCachedBluetoothDevice.isConnected()).thenReturn(false); + when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + + mPreference.onClicked(); + + verify(mMetricsFeatureProvider).action( + mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT); + } + + @Test + public void onClicked_deviceNotBonded_shouldLogBluetoothPairEvent() { + when(mCachedBluetoothDevice.isConnected()).thenReturn(false); + when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE); + when(mCachedBluetoothDevice.startPairing()).thenReturn(true); + + mPreference.onClicked(); + + verify(mMetricsFeatureProvider).action( + mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR); + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java new file mode 100644 index 00000000000..7761afc1076 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 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 com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.widget.MasterSwitchController; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class BluetoothEnablerTest { + + @Mock + private MetricsFeatureProvider mMetricsFeatureProvider; + @Mock + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void onSwitchToggled_shouldLogActionWithSuppliedEvent() { + BluetoothEnabler bluetoothEnabler = new BluetoothEnabler(mContext, + mock(MasterSwitchController.class), mMetricsFeatureProvider, + mock(LocalBluetoothManager.class), 123); + bluetoothEnabler.onSwitchToggled(false); + + verify(mMetricsFeatureProvider).action(mContext, 123, false); + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java new file mode 100644 index 00000000000..5f4b101d060 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017 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 com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class UtilsTest { + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + + private FakeFeatureFactory mFakeFeatureFactory; + private MetricsFeatureProvider mMetricsFeatureProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + FakeFeatureFactory.setupForTest(mContext); + mFakeFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); + mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider(); + } + + @Test + 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)); + } +}