diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 5c3dc8f2763..4efd4e064a6 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -1095,4 +1095,17 @@ no + + @string/prevent_ringing_option_vibrate + @string/prevent_ringing_option_mute + @string/prevent_ringing_option_none + + + + + 1 + 2 + 0 + + diff --git a/res/values/strings.xml b/res/values/strings.xml index f0d41b51c19..6a77d2727ed 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9564,6 +9564,23 @@ + + Prevent ringing + + Press Power & Volume Up together + + Vibrate + + Mute + + Do nothing + + Vibrate all calls and notifications + + Mute all calls and notifications + + Do nothing + Network details diff --git a/res/xml/gestures.xml b/res/xml/gestures.xml index f136ec75ee7..7083a3116b8 100644 --- a/res/xml/gestures.xml +++ b/res/xml/gestures.xml @@ -50,4 +50,9 @@ android:title="@string/ambient_display_pickup_title" android:fragment="com.android.settings.gestures.PickupGestureSettings" /> + + diff --git a/res/xml/prevent_ringing_gesture_settings.xml b/res/xml/prevent_ringing_gesture_settings.xml new file mode 100644 index 00000000000..10732fce884 --- /dev/null +++ b/res/xml/prevent_ringing_gesture_settings.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/gestures/GestureSettings.java b/src/com/android/settings/gestures/GestureSettings.java index 1efac5bd6f9..b3f8b798bb0 100644 --- a/src/com/android/settings/gestures/GestureSettings.java +++ b/src/com/android/settings/gestures/GestureSettings.java @@ -44,6 +44,7 @@ public class GestureSettings extends DashboardFragment { private static final String KEY_DOUBLE_TWIST = "gesture_double_twist_input_summary"; private static final String KEY_DOUBLE_TAP_SCREEN = "gesture_double_tap_screen_input_summary"; private static final String KEY_PICK_UP = "gesture_pick_up_input_summary"; + private static final String KEY_PREVENT_RINGING = "gesture_prevent_ringing_summary"; private AmbientDisplayConfiguration mAmbientDisplayConfig; @@ -86,6 +87,8 @@ public class GestureSettings extends DashboardFragment { ambientDisplayConfiguration, UserHandle.myUserId(), KEY_PICK_UP)); controllers.add(new DoubleTapScreenPreferenceController(context, lifecycle, ambientDisplayConfiguration, UserHandle.myUserId(), KEY_DOUBLE_TAP_SCREEN)); + controllers.add(new PreventRingingPreferenceController( + context, lifecycle, UserHandle.myUserId(), KEY_PREVENT_RINGING)); return controllers; } diff --git a/src/com/android/settings/gestures/PreventRingingGestureSettings.java b/src/com/android/settings/gestures/PreventRingingGestureSettings.java new file mode 100644 index 00000000000..9897b48d126 --- /dev/null +++ b/src/com/android/settings/gestures/PreventRingingGestureSettings.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2018 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.gestures; + +import android.content.Context; +import android.os.UserHandle; +import android.provider.SearchIndexableResource; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class PreventRingingGestureSettings extends DashboardFragment { + + private static final String TAG = "RingingGestureSettings"; + private static final String KEY_PREVENT_RINGING = "gesture_prevent_ringing"; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.SETTINGS_PREVENT_RINGING; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.prevent_ringing_gesture_settings; + } + + @Override + public int getHelpResource() { + return 0; + } + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getLifecycle()); + } + + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle) { + final List controllers = new ArrayList<>(); + controllers.add(new PreventRingingPreferenceController(context, lifecycle, + UserHandle.myUserId(), KEY_PREVENT_RINGING)); + return controllers; + } + + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.prevent_ringing_gesture_settings; + return Arrays.asList(sir); + } + + @Override + public List createPreferenceControllers( + Context context) { + return buildPreferenceControllers(context, null /* lifecycle */); + } + }; + +} diff --git a/src/com/android/settings/gestures/PreventRingingPreferenceController.java b/src/com/android/settings/gestures/PreventRingingPreferenceController.java new file mode 100644 index 00000000000..3255c9262d9 --- /dev/null +++ b/src/com/android/settings/gestures/PreventRingingPreferenceController.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2018 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.gestures; + +import static android.provider.Settings.Secure.VOLUME_HUSH_GESTURE; +import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE; +import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; +import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE; + +import android.annotation.UserIdInt; +import android.content.Context; +import android.os.Bundle; +import android.provider.Settings; +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.widget.VideoPreference; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnCreate; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; +import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState; + +public class PreventRingingPreferenceController extends AbstractPreferenceController + implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener, + LifecycleObserver, OnResume, OnPause, OnCreate, OnSaveInstanceState { + + private static final String PREF_KEY_VIDEO = "gesture_prevent_ringing_video"; + private final String mPrefKey; + @VisibleForTesting + static final String KEY_VIDEO_PAUSED = "key_video_paused"; + + private VideoPreference mVideoPreference; + @VisibleForTesting + boolean mVideoPaused; + + private final String SECURE_KEY = VOLUME_HUSH_GESTURE; + + @UserIdInt + private final int mUserId; + + public PreventRingingPreferenceController(Context context, Lifecycle lifecycle, + @UserIdInt int userId, String key) { + super(context); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + mUserId = userId; + mPrefKey = key; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + if (isAvailable()) { + mVideoPreference = (VideoPreference) screen.findPreference(getVideoPrefKey()); + } + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (preference != null) { + if (preference instanceof ListPreference) { + ListPreference pref = (ListPreference) preference; + int value = Settings.Secure.getInt( + mContext.getContentResolver(), SECURE_KEY, VOLUME_HUSH_VIBRATE); + switch (value) { + case VOLUME_HUSH_VIBRATE: + pref.setValue(String.valueOf(value)); + break; + case VOLUME_HUSH_MUTE: + pref.setValue(String.valueOf(value)); + break; + default: + pref.setValue(String.valueOf(VOLUME_HUSH_OFF)); + } + } + } + } + + @Override + public CharSequence getSummary() { + int value = Settings.Secure.getInt( + mContext.getContentResolver(), SECURE_KEY, VOLUME_HUSH_VIBRATE); + int summary; + switch (value) { + case VOLUME_HUSH_VIBRATE: + summary = R.string.prevent_ringing_option_vibrate_summary; + break; + case VOLUME_HUSH_MUTE: + summary = R.string.prevent_ringing_option_mute_summary; + break; + default: + summary = R.string.prevent_ringing_option_none_summary; + } + return mContext.getString(summary); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + if (savedInstanceState != null) { + mVideoPaused = savedInstanceState.getBoolean(KEY_VIDEO_PAUSED, false); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putBoolean(KEY_VIDEO_PAUSED, mVideoPaused); + } + + @Override + public void onPause() { + if (mVideoPreference != null) { + mVideoPaused = mVideoPreference.isVideoPaused(); + mVideoPreference.onViewInvisible(); + } + } + + @Override + public void onResume() { + if (mVideoPreference != null) { + mVideoPreference.onViewVisible(mVideoPaused); + } + } + + @Override + public boolean isAvailable() { + return mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled); + } + + protected String getVideoPrefKey() { + return PREF_KEY_VIDEO; + } + + @Override + public String getPreferenceKey() { + return mPrefKey; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + int value = Integer.parseInt((String) newValue); + Settings.Secure.putInt(mContext.getContentResolver(), SECURE_KEY, value); + preference.setSummary(getSummary()); + return true; + } +} diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingGestureSettingsTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingGestureSettingsTest.java new file mode 100644 index 00000000000..47bb4706838 --- /dev/null +++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingGestureSettingsTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 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.gestures; + +import static com.google.common.truth.Truth.assertThat; + +import android.provider.SearchIndexableResource; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +public class PreventRingingGestureSettingsTest { + + private PreventRingingGestureSettings mSettings; + + @Before + public void setUp() { + mSettings = new PreventRingingGestureSettings(); + } + + @Test + public void testSearchIndexProvider_shouldIndexResource() { + final List indexRes = + PreventRingingGestureSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex( + RuntimeEnvironment.application, true /* enabled */); + + assertThat(indexRes).isNotNull(); + assertThat(indexRes.get(0).xmlResId).isEqualTo(mSettings.getPreferenceScreenResId()); + } +} diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java new file mode 100644 index 00000000000..d92e0e05d1c --- /dev/null +++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2018 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.gestures; + +import static android.provider.Settings.Secure.VOLUME_HUSH_GESTURE; +import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE; +import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; +import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE; + +import static com.google.common.truth.Truth.assertThat; + +import static junit.framework.Assert.assertEquals; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.provider.Settings; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; + +import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.settings.R; +import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; +import com.android.settings.search.InlinePayload; +import com.android.settings.search.InlineSwitchPayload; +import com.android.settings.search.ResultPayload; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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; + +@RunWith(SettingsRobolectricTestRunner.class) +public class PreventRingingPreferenceControllerTest { + + private static final String KEY_PICK_UP = "gesture_prevent_ringing"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + + private PreventRingingPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new PreventRingingPreferenceController( + mContext, null, 0, KEY_PICK_UP); + } + + @Test + public void testIsAvailable_configIsTrue_shouldReturnTrue() { + when(mContext.getResources().getBoolean( + com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void testIsAvailable_configIsFalse_shouldReturnFalse() { + when(mContext.getResources().getBoolean( + com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(false); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void testGetSummary_mute() { + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, + Settings.Secure.VOLUME_HUSH_MUTE); + assertEquals(mContext.getString(R.string.prevent_ringing_option_mute_summary), + mController.getSummary()); + } + + @Test + public void testGetSummary_vibrate() { + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, + Settings.Secure.VOLUME_HUSH_VIBRATE); + assertEquals(mContext.getString(R.string.prevent_ringing_option_vibrate_summary), + mController.getSummary()); + } + @Test + public void testGetSummary_other() { + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, + 7); + assertEquals(mContext.getString(R.string.prevent_ringing_option_none_summary), + mController.getSummary()); + } + + @Test + public void testUpdateState_mute() { + ListPreference pref = mock(ListPreference.class); + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, + Settings.Secure.VOLUME_HUSH_MUTE); + mController.updateState(pref); + verify(pref).setValue(String.valueOf(Settings.Secure.VOLUME_HUSH_MUTE)); + } + + @Test + public void testUpdateState_vibrate() { + ListPreference pref = mock(ListPreference.class); + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, + Settings.Secure.VOLUME_HUSH_VIBRATE); + mController.updateState(pref); + verify(pref).setValue(String.valueOf(Settings.Secure.VOLUME_HUSH_VIBRATE)); + } + + @Test + public void testUpdateState_other() { + ListPreference pref = mock(ListPreference.class); + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, + 7); + mController.updateState(pref); + verify(pref).setValue(String.valueOf(Settings.Secure.VOLUME_HUSH_OFF)); + } + + @Test + public void testUpdateState_parentPage() { + Preference pref = mock(Preference.class); + // verify no exception + mController.updateState(pref); + } + + @Test + public void testOnPreferenceChange() { + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, + 7); + + mController.onPreferenceChange(mock(Preference.class), String.valueOf(VOLUME_HUSH_MUTE)); + + assertEquals(VOLUME_HUSH_MUTE, Settings.Secure.getInt(mContext.getContentResolver(), + VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF)); + } +}