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

Commit 4aad491d authored by Matthew Fritze's avatar Matthew Fritze
Browse files

Polish sos gesture behind the lockscreen

Unlike camera, we only want one intent for the emergency action (rather
than a secure / insecure breakdown). The api startActivity didn't work
behind the keyguard (WAI, I believe) so this CL changes that approach
to start the activity more traditionally.

The existing test is unfortunately removed. In its implementation CL,
[ag/12721582] dupin@ and I discussed the best way to test the action
given we would either check the activity was started with the context
[mContext.startActivity] or from the ActivityStarter
[StatusBar#startActivity]. Unfortunately ActivityStarter doesn't work
for our use case given the Keyguard gets raised (what we're trying to
fix in this CL), so we're left with verifying the injected Context gets
called. In theory we could add a wrapper method and verify it gets
called, but that seems next-to-useless.

Bug: 172278542
Fixes: 171084088
Fixes: 175240607
Test: atest StatusBarTest

Change-Id: Idd855be8d8c9fd35691c32bf88b3b9e2cdbc7b50
parent eab713e3
Loading
Loading
Loading
Loading
+71 −7
Original line number Diff line number Diff line
@@ -574,6 +574,8 @@ public class StatusBar extends SystemUI implements DemoMode,
    private NotificationEntry mDraggedDownEntry;
    private boolean mLaunchCameraWhenFinishedWaking;
    private boolean mLaunchCameraOnFinishedGoingToSleep;
    private boolean mLaunchEmergencyActionWhenFinishedWaking;
    private boolean mLaunchEmergencyActionOnFinishedGoingToSleep;
    private int mLastCameraLaunchSource;
    protected PowerManager.WakeLock mGestureWakeLock;
    private Vibrator mVibrator;
@@ -3844,6 +3846,14 @@ public class StatusBar extends SystemUI implements DemoMode,
                // is correct.
                mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
            }

            if (mLaunchEmergencyActionOnFinishedGoingToSleep) {
                mLaunchEmergencyActionOnFinishedGoingToSleep = false;

                // This gets executed before we will show Keyguard, so post it in order that the
                // state is correct.
                mHandler.post(() -> onEmergencyActionLaunchGestureDetected());
            }
            updateIsKeyguard();
        }

@@ -3890,6 +3900,13 @@ public class StatusBar extends SystemUI implements DemoMode,
                        false /* animate */, mLastCameraLaunchSource);
                mLaunchCameraWhenFinishedWaking = false;
            }
            if (mLaunchEmergencyActionWhenFinishedWaking) {
                mLaunchEmergencyActionWhenFinishedWaking = false;
                Intent emergencyIntent = getEmergencyActionIntent();
                if (emergencyIntent != null) {
                    mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
                }
            }
            updateScrimController();
        }
    };
@@ -4027,20 +4044,65 @@ public class StatusBar extends SystemUI implements DemoMode,

    @Override
    public void onEmergencyActionLaunchGestureDetected() {
        // TODO (b/169793384) Polish the panic gesture to be just like its older brother, camera.
        Intent emergencyIntent = getEmergencyActionIntent();

        if (emergencyIntent == null) {
            Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
            return;
        }

        if (isGoingToSleep()) {
            mLaunchEmergencyActionOnFinishedGoingToSleep = true;
            return;
        }

        if (!mDeviceInteractive) {
            mPowerManager.wakeUp(SystemClock.uptimeMillis(),
                    PowerManager.WAKE_REASON_GESTURE,
                    "com.android.systemui:EMERGENCY_GESTURE");
        }
        // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
        // app-side haptic experimentation.

        if (!mStatusBarKeyguardViewManager.isShowing()) {
            startActivityDismissingKeyguard(emergencyIntent,
                    false /* onlyProvisioned */, true /* dismissShade */,
                    true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0);
            return;
        }

        if (!mDeviceInteractive) {
            // Avoid flickering of the scrim when we instant launch the camera and the bouncer
            // comes on.
            mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
        }

        if (isWakingUpOrAwake()) {
            if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                mStatusBarKeyguardViewManager.reset(true /* hide */);
            }
            mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
            return;
        }
        // We need to defer the emergency action launch until the screen comes on, since otherwise
        // we will dismiss us too early since we are waiting on an activity to be drawn and
        // incorrectly get notified because of the screen on event (which resumes and pauses
        // some activities)
        mLaunchEmergencyActionWhenFinishedWaking = true;
    }

    private @Nullable Intent getEmergencyActionIntent() {
        Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
        PackageManager pm = mContext.getPackageManager();
        ResolveInfo resolveInfo = pm.resolveActivity(emergencyIntent, /*flags=*/0);
        if (resolveInfo == null) {
            // TODO(b/171084088) Upgrade log to wtf when we have default app in main branch.
            Log.d(TAG, "Couldn't find an app to process the emergency intent.");
            return;
            Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
            return null;
        }

        emergencyIntent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName,
                resolveInfo.activityInfo.name));
        emergencyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(emergencyIntent, /*dismissShade=*/true);
        return emergencyIntent;
    }

    boolean isCameraAllowedByAdmin() {
@@ -4100,8 +4162,10 @@ public class StatusBar extends SystemUI implements DemoMode,
            ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
                    ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
            mScrimController.transitionTo(state);
        } else if (isInLaunchTransition() || mLaunchCameraWhenFinishedWaking
        } else if (isInLaunchTransition()
                || mLaunchCameraWhenFinishedWaking
                || launchingAffordanceWithPreview) {
            // TODO(b/170133395) Investigate whether Emergency Gesture flag should be included here.
            mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
        } else if (mBrightnessMirrorVisible) {
            mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
+0 −19
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.fail;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -35,7 +34,6 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -45,7 +43,6 @@ import android.app.StatusBarManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
@@ -87,7 +84,6 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.emergency.EmergencyGesture;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -151,10 +147,8 @@ import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@@ -887,19 +881,6 @@ public class StatusBarTest extends SysuiTestCase {
        verify(mDozeServiceHost).setDozeSuppressed(false);
    }

    @Ignore // TODO (b/175240607) - Figure out if the device will actually dial 911.
    @Test
    public void onEmergencyActionLaunchGesture_launchesEmergencyIntent() {
        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
        StatusBar statusBarSpy = spy(mStatusBar);

        statusBarSpy.onEmergencyActionLaunchGestureDetected();

        verify(statusBarSpy).startActivity(intentCaptor.capture(), eq(true));
        Intent sentIntent = intentCaptor.getValue();
        assertEquals(sentIntent.getAction(), EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
    }

    public static class TestableNotificationInterruptStateProviderImpl extends
            NotificationInterruptStateProviderImpl {