Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c63a13c8 authored by Fan Zhang's avatar Fan Zhang
Browse files

Launch customized panic setting intent when configured.

When RRO provides a custom intent package for panic settings and there
is an app to handle it, launch the custom intent instead of the AOSP
version.

Bug: 169946508
Test: robotests
Change-Id: I8479c6e0dd4a90b5a03640035b710ae4ccc7809c
parent 6208cbfd
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -465,6 +465,9 @@
    <!-- Whether to show panic button gesture in Settings -->
    <bool name="config_show_panic_gesture_settings">true</bool>

    <!-- Optional package name if another 1p app wants to take over the panic settings UI -->
    <string name="panic_gesture_settings_package"></string>

    <!-- Whether to show the Preference for Adaptive connectivity -->
    <bool name="config_show_adaptive_connectivity">false</bool>

+3 −0
Original line number Diff line number Diff line
@@ -10996,6 +10996,9 @@
    <!-- Preference title to enable feature for calling emergency services at panic/distress moments[CHAR_LIMIT=60]-->
    <string name="panic_gesture_screen_title">Panic button</string>
    <!-- Preference title to enable feature for calling emergency services at panic/distress moments[CHAR_LIMIT=60]-->
    <string name="panic_gesture_entrypoint_summary">Managed by <xliff:g id="app_name" example="Emergency Info">%1$s</xliff:g></string>
    <!-- Preference summary to enable feature for calling emergency services at panic/distress moments[CHAR_LIMIT=NONE]-->
    <string name="panic_gesture_screen_summary">Start the emergency SOS actions by pressing the power button quickly 5 times.</string>
+79 −4
Original line number Diff line number Diff line
@@ -17,10 +17,16 @@
package com.android.settings.gestures;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;

import com.android.settings.R;

@@ -28,11 +34,19 @@ import com.android.settings.R;
 * Preference controller for emergency sos gesture setting
 */
public class PanicGesturePreferenceController extends GesturePreferenceController {
    private static final String TAG = "PanicGesturePreferenceC";

    @VisibleForTesting
    static final int ON = 1;
    @VisibleForTesting
    static final int OFF = 0;
    @VisibleForTesting
    static final String ACTION_PANIC_SETTINGS =
            "com.android.settings.action.panic_settings";
    @VisibleForTesting
    Intent mIntent;

    private boolean mUseCustomIntent;

    private static final String PREF_KEY_VIDEO = "panic_button_screen_video";

@@ -40,16 +54,38 @@ public class PanicGesturePreferenceController extends GesturePreferenceControlle

    public PanicGesturePreferenceController(Context context, String key) {
        super(context, key);
        final String panicSettingsPackageName = context.getResources().getString(
                R.string.panic_gesture_settings_package);
        if (!TextUtils.isEmpty(panicSettingsPackageName)) {
            mUseCustomIntent = true;
            // Use custom intent if it's configured and system can resolve it.
            final Intent intent = new Intent(ACTION_PANIC_SETTINGS)
                    .setPackage(panicSettingsPackageName);
            if (canResolveIntent(intent)) {
                mIntent = intent;
            }
        }
    }

    private static boolean isGestureAvailable(Context context) {
        return context.getResources()
                .getBoolean(R.bool.config_show_panic_gesture_settings);
    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        if (TextUtils.equals(getPreferenceKey(), preference.getKey()) && mIntent != null) {
            mIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            mContext.startActivity(mIntent);
            return true;
        }
        return super.handlePreferenceTreeClick(preference);
    }

    @Override
    public int getAvailabilityStatus() {
        return isGestureAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
        final boolean isConfigEnabled = mContext.getResources()
                .getBoolean(R.bool.config_show_panic_gesture_settings);

        if (!isConfigEnabled) {
            return UNSUPPORTED_ON_DEVICE;
        }
        return AVAILABLE;
    }

    @Override
@@ -57,6 +93,32 @@ public class PanicGesturePreferenceController extends GesturePreferenceControlle
        return TextUtils.equals(getPreferenceKey(), "gesture_panic_button");
    }

    @Override
    protected boolean canHandleClicks() {
        return !mUseCustomIntent || mIntent != null;
    }

    @Override
    public CharSequence getSummary() {
        if (mUseCustomIntent) {
            final String packageName = mContext.getResources().getString(
                    R.string.panic_gesture_settings_package);
            try {
                final PackageManager pm = mContext.getPackageManager();
                final ApplicationInfo appInfo = pm.getApplicationInfo(
                        packageName, PackageManager.MATCH_DISABLED_COMPONENTS
                                | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS);
                return mContext.getString(R.string.panic_gesture_entrypoint_summary,
                        appInfo.loadLabel(pm));
            } catch (Exception e) {
                Log.d(TAG, "Failed to get custom summary, falling back.");
                return super.getSummary();
            }
        }

        return super.getSummary();
    }

    @Override
    protected String getVideoPrefKey() {
        return PREF_KEY_VIDEO;
@@ -72,4 +134,17 @@ public class PanicGesturePreferenceController extends GesturePreferenceControlle
        return Settings.Secure.putInt(mContext.getContentResolver(), SECURE_KEY,
                isChecked ? ON : OFF);
    }

    /**
     * Whether or not gesture page content should be suppressed from search.
     */
    public boolean shouldSuppressFromSearch() {
        return mUseCustomIntent;
    }

    private boolean canResolveIntent(Intent intent) {
        final ResolveInfo resolveActivity = mContext.getPackageManager()
                .resolveActivity(intent, 0);
        return resolveActivity != null;
    }
}
+11 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.settings.gestures;

import android.app.settings.SettingsEnums;
import android.content.Context;

import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -47,5 +48,14 @@ public class PanicGestureSettings extends DashboardFragment {
    }

    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
            new BaseSearchIndexProvider(R.xml.panic_gesture_settings);
            new BaseSearchIndexProvider(R.xml.panic_gesture_settings) {
                @Override
                protected boolean isPageSearchEnabled(Context context) {
                    final PanicGesturePreferenceController controller =
                            new PanicGesturePreferenceController(context,
                                    "dummy_panic_gesture_pref_key");
                    return !controller.isAvailable()
                            || controller.shouldSuppressFromSearch();
                }
            };
}
+33 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@ import static com.google.common.truth.Truth.assertThat;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.provider.Settings;

import androidx.test.core.app.ApplicationProvider;
@@ -35,15 +38,22 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPackageManager;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = SettingsShadowResources.class)
public class PanicGesturePreferenceControllerTest {

    private static final String TEST_PKG_NAME = "test_pkg";
    private static final String TEST_CLASS_NAME = "name";
    private static final Intent SETTING_INTENT = new Intent(
            PanicGesturePreferenceController.ACTION_PANIC_SETTINGS).setPackage(TEST_PKG_NAME);

    private Context mContext;
    private ContentResolver mContentResolver;
    private ShadowPackageManager mPackageManager;
    private PanicGesturePreferenceController mController;
    private static final String PREF_KEY = "gesture_panic_button";

@@ -51,6 +61,7 @@ public class PanicGesturePreferenceControllerTest {
    public void setUp() {
        mContext = ApplicationProvider.getApplicationContext();
        mContentResolver = mContext.getContentResolver();
        mPackageManager = Shadows.shadowOf(mContext.getPackageManager());
        mController = new PanicGesturePreferenceController(mContext, PREF_KEY);
    }

@@ -59,6 +70,28 @@ public class PanicGesturePreferenceControllerTest {
        SettingsShadowResources.reset();
    }

    @Test
    public void constructor_hasCustomPackageConfig_shouldSetIntent() {
        final ResolveInfo info = new ResolveInfo();
        info.activityInfo = new ActivityInfo();
        info.activityInfo.packageName = TEST_PKG_NAME;
        info.activityInfo.name = TEST_CLASS_NAME;

        mPackageManager.addResolveInfoForIntent(SETTING_INTENT, info);

        SettingsShadowResources.overrideResource(
                R.bool.config_show_panic_gesture_settings,
                Boolean.TRUE);

        SettingsShadowResources.overrideResource(
                R.string.panic_gesture_settings_package,
                TEST_PKG_NAME);

        mController = new PanicGesturePreferenceController(mContext, PREF_KEY);

        assertThat(mController.mIntent).isNotNull();
    }

    @Test
    public void isAvailable_configIsTrue_shouldReturnTrue() {
        SettingsShadowResources.overrideResource(