Settings: Add SMS Mirroring.

Bug: 37546615

Test: Updated Robolectric suite with new unit tests.

Change-Id: I02e1723e1b125b004ff679d6242df14bca4f08ce
This commit is contained in:
Oren Blasberg
2017-07-13 06:55:15 -07:00
parent 84040fdb8b
commit d33dcf13ee
11 changed files with 233 additions and 4 deletions

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FF000000"
android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3zM14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z"/>
</vector>

View File

@@ -7747,6 +7747,9 @@
<!-- Settings item summary for USB preference when set to entering MIDI mode [CHAR LIMIT=NONE] -->
<string name="usb_summary_MIDI">Using device as MIDI</string>
<!-- Settings item title for SMS Mirroring preference [CHAR LIMIT=35] -->
<string name="sms_mirroring_pref">SMS Mirroring</string>
<!-- Settings item title for background check prefs [CHAR LIMIT=35] -->
<string name="background_check_pref">Background check</string>

View File

@@ -38,11 +38,17 @@
android:icon="@drawable/ic_android"
android:order="-4"/>
<Preference
android:key="sms_mirroring"
android:title="@string/sms_mirroring_pref"
android:icon="@drawable/ic_compare_arrows_24dp"
android:order="-3"/>
<Preference
android:key="usb_mode"
android:title="@string/usb_pref"
android:icon="@drawable/ic_usb"
android:order="-3">
android:order="-2">
<intent android:action="android.intent.action.MAIN"
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.deviceinfo.UsbModeChooserActivity"/>

View File

@@ -30,6 +30,7 @@ import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.deviceinfo.UsbBackend;
import com.android.settings.nfc.NfcPreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -81,6 +82,12 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
(SettingsActivity) getActivity());
lifecycle.addObserver(bluetoothPreferenceController);
controllers.add(bluetoothPreferenceController);
SmsMirroringFeatureProvider smsMirroringFeatureProvider =
FeatureFactory.getFactory(context).getSmsMirroringFeatureProvider();
AbstractPreferenceController smsMirroringController =
smsMirroringFeatureProvider.getController(context);
controllers.add(smsMirroringController);
return controllers;
}
@@ -143,6 +150,13 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
keys.add(NfcPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
}
keys.add(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH);
SmsMirroringFeatureProvider smsMirroringFeatureProvider =
FeatureFactory.getFactory(context).getSmsMirroringFeatureProvider();
SmsMirroringPreferenceController smsMirroringController =
smsMirroringFeatureProvider.getController(context);
smsMirroringController.updateNonIndexableKeys(keys);
return keys;
}
};

View File

@@ -0,0 +1,28 @@
/*
* 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.connecteddevice;
import android.content.Context;
public interface SmsMirroringFeatureProvider {
/** Returns whether to show SMS mirroring. */
boolean shouldShowSmsMirroring(Context context);
/** Returns a preference controller for SMS mirroring. */
SmsMirroringPreferenceController getController(Context context);
}

View File

@@ -0,0 +1,31 @@
/*
* 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.connecteddevice;
import android.content.Context;
public class SmsMirroringFeatureProviderImpl implements SmsMirroringFeatureProvider {
@Override
public boolean shouldShowSmsMirroring(Context context) {
return false;
}
@Override
public SmsMirroringPreferenceController getController(Context context) {
return new SmsMirroringPreferenceController(context);
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.connecteddevice;
import android.content.Context;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
public class SmsMirroringPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin {
static final String KEY_SMS_MIRRORING = "sms_mirroring";
private SmsMirroringFeatureProvider mFeatureProvider;
public SmsMirroringPreferenceController(Context context) {
super(context);
mFeatureProvider = FeatureFactory.getFactory(context).getSmsMirroringFeatureProvider();
}
@Override
public boolean isAvailable() {
return mFeatureProvider.shouldShowSmsMirroring(mContext);
}
@Override
public String getPreferenceKey() {
return KEY_SMS_MIRRORING;
}
}

View File

@@ -23,6 +23,7 @@ import android.util.Log;
import com.android.settings.R;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.connecteddevice.SmsMirroringFeatureProvider;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
@@ -103,6 +104,8 @@ public abstract class FeatureFactory {
public abstract DataPlanFeatureProvider getDataPlanFeatureProvider();
public abstract SmsMirroringFeatureProvider getSmsMirroringFeatureProvider();
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);

View File

@@ -29,6 +29,8 @@ import com.android.settings.applications.IPackageManagerWrapperImpl;
import com.android.settings.applications.PackageManagerWrapperImpl;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
import com.android.settings.connecteddevice.SmsMirroringFeatureProvider;
import com.android.settings.connecteddevice.SmsMirroringFeatureProviderImpl;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProviderImpl;
@@ -72,6 +74,7 @@ public class FeatureFactoryImpl extends FeatureFactory {
private UserFeatureProvider mUserFeatureProvider;
private BluetoothFeatureProvider mBluetoothFeatureProvider;
private DataPlanFeatureProvider mDataPlanFeatureProvider;
private SmsMirroringFeatureProvider mSmsMirroringFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -197,4 +200,12 @@ public class FeatureFactoryImpl extends FeatureFactory {
}
return mAssistGestureFeatureProvider;
}
@Override
public SmsMirroringFeatureProvider getSmsMirroringFeatureProvider() {
if (mSmsMirroringFeatureProvider == null) {
mSmsMirroringFeatureProvider = new SmsMirroringFeatureProviderImpl();
}
return mSmsMirroringFeatureProvider;
}
}

View File

@@ -22,16 +22,19 @@ import android.nfc.NfcManager;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.nfc.NfcPreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settingslib.drawer.CategoryKey;
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.RuntimeEnvironment;
@@ -50,19 +53,45 @@ import static org.mockito.Mockito.when;
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ConnectedDeviceDashboardFragmentTest {
@Mock
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
Context mContext;
@Mock
private PackageManager mManager;
private FakeFeatureFactory mFeatureFactory;
private SmsMirroringFeatureProvider mFeatureProvider;
private ConnectedDeviceDashboardFragment mFragment;
private TestSmsMirroringPreferenceController mSmsMirroringPreferenceController;
private static final class TestSmsMirroringPreferenceController
extends SmsMirroringPreferenceController implements PreferenceControllerMixin {
private boolean mIsAvailable;
public TestSmsMirroringPreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
return mIsAvailable;
}
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest(mContext);
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mFeatureProvider = mFeatureFactory.smsMirroringFeatureProvider;
mFragment = new ConnectedDeviceDashboardFragment();
when(mContext.getPackageManager()).thenReturn(mManager);
mSmsMirroringPreferenceController = new TestSmsMirroringPreferenceController(mContext);
when(mFeatureProvider.getController(mContext)).thenReturn(
mSmsMirroringPreferenceController);
}
@Test
@@ -102,12 +131,36 @@ public class ConnectedDeviceDashboardFragmentTest {
assertThat(keys).doesNotContain(NfcPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
}
@Test
public void testSearchIndexProvider_NoSmsMirroring_KeyAdded() {
when(mFeatureProvider.shouldShowSmsMirroring(mContext)).thenReturn(false);
mSmsMirroringPreferenceController.mIsAvailable = false;
final List<String> keys = mFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
mContext);
assertThat(keys).isNotNull();
assertThat(keys).contains(mSmsMirroringPreferenceController.getPreferenceKey());
}
@Test
public void testSearchIndexProvider_SmsMirroring_KeyNotAdded() {
when(mFeatureProvider.shouldShowSmsMirroring(mContext)).thenReturn(true);
mSmsMirroringPreferenceController.mIsAvailable = true;
final List<String> keys = mFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
mContext);
assertThat(keys).isNotNull();
assertThat(keys).doesNotContain(mSmsMirroringPreferenceController.getPreferenceKey());
}
@Test
public void testNonIndexableKeys_existInXmlLayout() {
final Context context = RuntimeEnvironment.application;
when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(false);
final List<String> niks = ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(context);
.getNonIndexableKeys(mContext);
final int xmlId = (new ConnectedDeviceDashboardFragment()).getPreferenceScreenResId();
final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId);
@@ -141,6 +194,7 @@ public class ConnectedDeviceDashboardFragmentTest {
final SummaryLoader summaryLoader = mock(SummaryLoader.class);
when(mContext.getApplicationContext()).thenReturn(mContext);
when(mContext.getSystemService(NFC_SERVICE)).thenReturn(null);
SummaryLoader.SummaryProvider provider =
new ConnectedDeviceDashboardFragment.SummaryProvider(mContext, summaryLoader);

View File

@@ -19,6 +19,7 @@ import android.content.Context;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.connecteddevice.SmsMirroringFeatureProvider;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
@@ -59,6 +60,7 @@ public class FakeFeatureFactory extends FeatureFactory {
public final AssistGestureFeatureProvider assistGestureFeatureProvider;
public final BluetoothFeatureProvider bluetoothFeatureProvider;
public final DataPlanFeatureProvider dataPlanFeatureProvider;
public final SmsMirroringFeatureProvider smsMirroringFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -97,6 +99,7 @@ public class FakeFeatureFactory extends FeatureFactory {
assistGestureFeatureProvider = mock(AssistGestureFeatureProvider.class);
bluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
dataPlanFeatureProvider = mock(DataPlanFeatureProvider.class);
smsMirroringFeatureProvider = mock(SmsMirroringFeatureProvider.class);
}
@Override
@@ -173,4 +176,9 @@ public class FakeFeatureFactory extends FeatureFactory {
public AssistGestureFeatureProvider getAssistGestureFeatureProvider() {
return assistGestureFeatureProvider;
}
@Override
public SmsMirroringFeatureProvider getSmsMirroringFeatureProvider() {
return smsMirroringFeatureProvider;
}
}