diff --git a/res/drawable/ic_call_grey_24dp.xml b/res/drawable/ic_call_grey_24dp.xml new file mode 100644 index 00000000000..960cc8a7b44 --- /dev/null +++ b/res/drawable/ic_call_grey_24dp.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/res/layout/emergency_gesture_number_override_dialog.xml b/res/layout/emergency_gesture_number_override_dialog.xml new file mode 100644 index 00000000000..6ac8ad0433f --- /dev/null +++ b/res/layout/emergency_gesture_number_override_dialog.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 18cdaa06c76..81827f33fc0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11084,6 +11084,22 @@ Play a loud sound before calling + + Call for help + + + Number to call for help + + + %1$s. Tap to change + + + + If you enter a non-emergency number:\n + • Your device must be unlocked to use emergency SOS\n + • Your call may not be answered + + Swipe fingerprint for notifications diff --git a/res/xml/emergency_gesture_settings.xml b/res/xml/emergency_gesture_settings.xml index b1e77c2841c..2e1a2597c07 100644 --- a/res/xml/emergency_gesture_settings.xml +++ b/res/xml/emergency_gesture_settings.xml @@ -40,4 +40,14 @@ app:controller="com.android.settings.gestures.EmergencyGestureSoundPreferenceController" app:allowDividerAbove="true"/> + diff --git a/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreference.java b/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreference.java new file mode 100644 index 00000000000..d481b2eae5b --- /dev/null +++ b/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreference.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 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.content.DialogInterface.BUTTON_POSITIVE; + +import android.content.Context; +import android.content.DialogInterface; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.EditText; + +import androidx.annotation.VisibleForTesting; + +import com.android.settings.R; +import com.android.settingslib.CustomDialogPreferenceCompat; +import com.android.settingslib.emergencynumber.EmergencyNumberUtils; + +/** + * A dialog preference allowing user to provide a phone number to call during emergency gesture. + */ +public class EmergencyGestureNumberOverridePreference extends + CustomDialogPreferenceCompat { + private static final String TAG = "EmergencyGestureNumberO"; + @VisibleForTesting + EditText mEditText; + + private EmergencyNumberUtils mEmergencyNumberUtils; + + public EmergencyGestureNumberOverridePreference(Context context, + AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context); + } + + public EmergencyGestureNumberOverridePreference(Context context, AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + public EmergencyGestureNumberOverridePreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public EmergencyGestureNumberOverridePreference(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mEmergencyNumberUtils = new EmergencyNumberUtils(context); + } + + @Override + public void setNegativeButtonText(int negativeButtonTextResId) { + super.setNegativeButtonText(negativeButtonTextResId); + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + mEditText = view.findViewById(R.id.emergency_gesture_number_override); + final String defaultNumber = mEmergencyNumberUtils.getDefaultPoliceNumber(); + mEditText.setHint(defaultNumber); + final String number = mEmergencyNumberUtils.getPoliceNumber(); + if (!TextUtils.equals(number, defaultNumber)) { + mEditText.setText(number); + } + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == BUTTON_POSITIVE) { + final String input = mEditText.getText().toString(); + if (!TextUtils.isEmpty(input)) { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.EMERGENCY_GESTURE_CALL_NUMBER, input); + } else { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.EMERGENCY_GESTURE_CALL_NUMBER, + mEmergencyNumberUtils.getDefaultPoliceNumber()); + } + } + } +} diff --git a/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreferenceController.java b/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreferenceController.java new file mode 100644 index 00000000000..3dba3f0ac00 --- /dev/null +++ b/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreferenceController.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 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.database.ContentObserver; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.emergencynumber.EmergencyNumberUtils; + +/** + * Preference controller for emergency gesture number override. + */ +public class EmergencyGestureNumberOverridePreferenceController extends BasePreferenceController + implements LifecycleObserver, OnStart, OnStop { + + @VisibleForTesting + EmergencyNumberUtils mEmergencyNumberUtils; + private final Handler mHandler; + private final ContentObserver mSettingsObserver; + private Preference mPreference; + + public EmergencyGestureNumberOverridePreferenceController(Context context, + String preferenceKey) { + super(context, preferenceKey); + mEmergencyNumberUtils = new EmergencyNumberUtils(context); + mHandler = new Handler(Looper.getMainLooper()); + mSettingsObserver = new EmergencyGestureNumberOverrideSettingsObserver(mHandler); + } + + @Override + public int getAvailabilityStatus() { + return mContext.getResources() + .getBoolean(R.bool.config_show_emergency_gesture_settings) ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public CharSequence getSummary() { + return mContext.getString(R.string.emergency_gesture_call_for_help_summary, + mEmergencyNumberUtils.getPoliceNumber()); + } + + @Override + public void onStart() { + mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.EMERGENCY_GESTURE_CALL_NUMBER), false, mSettingsObserver); + } + + @Override + public void onStop() { + mContext.getContentResolver().unregisterContentObserver(mSettingsObserver); + } + + private class EmergencyGestureNumberOverrideSettingsObserver extends ContentObserver { + EmergencyGestureNumberOverrideSettingsObserver(Handler h) { + super(h); + } + + @Override + public void onChange(boolean selfChange) { + if (mPreference != null) { + updateState(mPreference); + } + } + } +} diff --git a/tests/robotests/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreferenceControllerTest.java new file mode 100644 index 00000000000..498c17b798e --- /dev/null +++ b/tests/robotests/src/com/android/settings/gestures/EmergencyGestureNumberOverridePreferenceControllerTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 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.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; + +import androidx.preference.Preference; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settingslib.emergencynumber.EmergencyNumberUtils; + +import org.junit.After; +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.annotation.Config; + + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = SettingsShadowResources.class) +public class EmergencyGestureNumberOverridePreferenceControllerTest { + private static final String PREF_KEY = "test"; + + @Mock + private EmergencyNumberUtils mEmergencyNumberUtils; + private Context mContext; + private EmergencyGestureNumberOverridePreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = ApplicationProvider.getApplicationContext(); + mController = new EmergencyGestureNumberOverridePreferenceController(mContext, PREF_KEY); + } + + @After + public void tearDown() { + SettingsShadowResources.reset(); + } + + @Test + public void getAvailabilityStatus_configIsTrue_shouldReturnAvailable() { + SettingsShadowResources.overrideResource( + R.bool.config_show_emergency_gesture_settings, + Boolean.TRUE); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_configIsFalse_shouldReturnUnsupported() { + SettingsShadowResources.overrideResource( + R.bool.config_show_emergency_gesture_settings, + Boolean.FALSE); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void updateState_shouldLoadNumberFromSettings() { + final Preference preference = new Preference(mContext); + mController.mEmergencyNumberUtils = mEmergencyNumberUtils; + when(mEmergencyNumberUtils.getPoliceNumber()).thenReturn("123"); + + mController.updateState(preference); + + assertThat(preference.getSummary()).isEqualTo( + mContext.getString(R.string.emergency_gesture_call_for_help_summary, "123")); + } + +}