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

Commit 97aaa403 authored by Kweku Adams's avatar Kweku Adams Committed by Automerger Merge Worker
Browse files

Merge "Exit doze during an emergency call." into udc-dev am: cfd25ee5

parents e00f19b4 cfd25ee5
Loading
Loading
Loading
Loading
+84 −6
Original line number Diff line number Diff line
@@ -79,6 +79,9 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -146,15 +149,17 @@ import java.util.stream.Collectors;
       label="deep";

       STATE_ACTIVE [
         label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
         label="STATE_ACTIVE\nScreen on OR charging OR alarm going off soon\n"
             + "OR active emergency call",
         color=black,shape=diamond
       ]
       STATE_INACTIVE [
         label="STATE_INACTIVE\nScreen off AND Not charging",color=black,shape=diamond
         label="STATE_INACTIVE\nScreen off AND not charging AND no active emergency call",
         color=black,shape=diamond
       ]
       STATE_QUICK_DOZE_DELAY [
         label="STATE_QUICK_DOZE_DELAY\n"
             + "Screen off AND Not charging\n"
             + "Screen off AND not charging AND no active emergency call\n"
             + "Location, motion detection, and significant motion monitoring turned off",
         color=black,shape=diamond
       ]
@@ -237,11 +242,12 @@ import java.util.stream.Collectors;
       label="light"

       LIGHT_STATE_ACTIVE [
         label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
         label="LIGHT_STATE_ACTIVE\n"
             + "Screen on OR charging OR alarm going off soon OR active emergency call",
         color=black,shape=diamond
       ]
       LIGHT_STATE_INACTIVE [
         label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging",
         label="LIGHT_STATE_INACTIVE\nScreen off AND not charging AND no active emergency call",
         color=black,shape=diamond
       ]
       LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n",color=red,shape=box]
@@ -411,6 +417,7 @@ public class DeviceIdleController extends SystemService
    private static final int ACTIVE_REASON_FROM_BINDER_CALL = 5;
    private static final int ACTIVE_REASON_FORCED = 6;
    private static final int ACTIVE_REASON_ALARM = 7;
    private static final int ACTIVE_REASON_EMERGENCY_CALL = 8;
    @VisibleForTesting
    static final int SET_IDLE_FACTOR_RESULT_UNINIT = -1;
    @VisibleForTesting
@@ -765,6 +772,8 @@ public class DeviceIdleController extends SystemService
        }
    };

    private final EmergencyCallListener mEmergencyCallListener = new EmergencyCallListener();

    /** Post stationary status only to this listener. */
    private void postStationaryStatus(DeviceIdleInternal.StationaryListener listener) {
        mHandler.obtainMessage(MSG_REPORT_STATIONARY_STATUS, listener).sendToTarget();
@@ -2323,6 +2332,39 @@ public class DeviceIdleController extends SystemService
        }
    }

    private class EmergencyCallListener extends TelephonyCallback implements
            TelephonyCallback.OutgoingEmergencyCallListener,
            TelephonyCallback.CallStateListener {
        private volatile boolean mIsEmergencyCallActive;

        @Override
        public void onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber,
                int subscriptionId) {
            mIsEmergencyCallActive = true;
            if (DEBUG) Slog.d(TAG, "onOutgoingEmergencyCall(): subId = " + subscriptionId);
            synchronized (DeviceIdleController.this) {
                mActiveReason = ACTIVE_REASON_EMERGENCY_CALL;
                becomeActiveLocked("emergency call", Process.myUid());
            }
        }

        @Override
        public void onCallStateChanged(int state) {
            if (DEBUG) Slog.d(TAG, "onCallStateChanged(): state is " + state);
            // An emergency call just finished
            if (state == TelephonyManager.CALL_STATE_IDLE && mIsEmergencyCallActive) {
                mIsEmergencyCallActive = false;
                synchronized (DeviceIdleController.this) {
                    becomeInactiveIfAppropriateLocked();
                }
            }
        }

        boolean isEmergencyCallActive() {
            return mIsEmergencyCallActive;
        }
    }

    static class Injector {
        private final Context mContext;
        private ConnectivityManager mConnectivityManager;
@@ -2406,6 +2448,10 @@ public class DeviceIdleController extends SystemService
            return mContext.getSystemService(SensorManager.class);
        }

        TelephonyManager getTelephonyManager() {
            return mContext.getSystemService(TelephonyManager.class);
        }

        ConstraintController getConstraintController(Handler handler,
                DeviceIdleInternal localService) {
            if (mContext.getPackageManager()
@@ -2634,6 +2680,9 @@ public class DeviceIdleController extends SystemService

                mLocalActivityTaskManager.registerScreenObserver(mScreenObserver);

                mInjector.getTelephonyManager().registerTelephonyCallback(
                        JobSchedulerBackgroundThread.getExecutor(), mEmergencyCallListener);

                passWhiteListsToForceAppStandbyTrackerLocked();
                updateInteractivityLocked();
            }
@@ -3435,6 +3484,7 @@ public class DeviceIdleController extends SystemService

        final boolean isScreenBlockingInactive =
                mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked);
        final boolean isEmergencyCallActive = mEmergencyCallListener.isEmergencyCallActive();
        if (DEBUG) {
            Slog.d(TAG, "becomeInactiveIfAppropriateLocked():"
                    + " isScreenBlockingInactive=" + isScreenBlockingInactive
@@ -3442,10 +3492,11 @@ public class DeviceIdleController extends SystemService
                    + ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK
                    + ", mScreenLocked=" + mScreenLocked + ")"
                    + " mCharging=" + mCharging
                    + " emergencyCall=" + isEmergencyCallActive
                    + " mForceIdle=" + mForceIdle
            );
        }
        if (!mForceIdle && (mCharging || isScreenBlockingInactive)) {
        if (!mForceIdle && (mCharging || isScreenBlockingInactive || isEmergencyCallActive)) {
            return;
        }
        // Become inactive and determine if we will ultimately go idle.
@@ -3568,6 +3619,17 @@ public class DeviceIdleController extends SystemService
        }
        EventLogTags.writeDeviceIdleLightStep();

        if (mEmergencyCallListener.isEmergencyCallActive()) {
            // The emergency call should have raised the state to ACTIVE and kept it there,
            // so this method shouldn't be called. Don't proceed further.
            Slog.wtf(TAG, "stepLightIdleStateLocked called when emergency call is active");
            if (mLightState != LIGHT_STATE_ACTIVE) {
                mActiveReason = ACTIVE_REASON_EMERGENCY_CALL;
                becomeActiveLocked("emergency", Process.myUid());
            }
            return;
        }

        switch (mLightState) {
            case LIGHT_STATE_INACTIVE:
                mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
@@ -3650,6 +3712,17 @@ public class DeviceIdleController extends SystemService
        if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
        EventLogTags.writeDeviceIdleStep();

        if (mEmergencyCallListener.isEmergencyCallActive()) {
            // The emergency call should have raised the state to ACTIVE and kept it there,
            // so this method shouldn't be called. Don't proceed further.
            Slog.wtf(TAG, "stepIdleStateLocked called when emergency call is active");
            if (mState != STATE_ACTIVE) {
                mActiveReason = ACTIVE_REASON_EMERGENCY_CALL;
                becomeActiveLocked("emergency", Process.myUid());
            }
            return;
        }

        if (isUpcomingAlarmClock()) {
            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
            if (mState != STATE_ACTIVE) {
@@ -3984,6 +4057,11 @@ public class DeviceIdleController extends SystemService
        }
    }

    @VisibleForTesting
    boolean isEmergencyCallActive() {
        return mEmergencyCallListener.isEmergencyCallActive();
    }

    @GuardedBy("this")
    boolean isOpsInactiveLocked() {
        return mActiveIdleOpCount <= 0 && !mJobsActive && !mAlarmsActive;
+148 −0
Original line number Diff line number Diff line
@@ -86,6 +86,9 @@ import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;

import androidx.test.runner.AndroidJUnit4;

@@ -119,6 +122,8 @@ public class DeviceIdleControllerTest {
    private AnyMotionDetectorForTest mAnyMotionDetector;
    private AppStateTrackerForTest mAppStateTracker;
    private DeviceIdleController.Constants mConstants;
    private TelephonyCallback.OutgoingEmergencyCallListener mEmergencyCallListener;
    private TelephonyCallback.CallStateListener mCallStateListener;
    private InjectorForTest mInjector;

    private MockitoSession mMockingSession;
@@ -140,6 +145,8 @@ public class DeviceIdleControllerTest {
    private Sensor mMotionSensor;
    @Mock
    private SensorManager mSensorManager;
    @Mock
    private TelephonyManager mTelephonyManager;

    class InjectorForTest extends DeviceIdleController.Injector {
        ConnectivityManager connectivityManager;
@@ -231,6 +238,11 @@ public class DeviceIdleControllerTest {
            return constraintController;
        }

        @Override
        TelephonyManager getTelephonyManager() {
            return mTelephonyManager;
        }

        @Override
        boolean useMotionSensor() {
            return true;
@@ -343,6 +355,15 @@ public class DeviceIdleControllerTest {

        // Get the same Constants object that mDeviceIdleController got.
        mConstants = mInjector.getConstants(mDeviceIdleController);

        final ArgumentCaptor<TelephonyCallback> telephonyCallbackCaptor =
                ArgumentCaptor.forClass(TelephonyCallback.class);
        verify(mTelephonyManager)
                .registerTelephonyCallback(any(), telephonyCallbackCaptor.capture());
        mEmergencyCallListener = (TelephonyCallback.OutgoingEmergencyCallListener)
                telephonyCallbackCaptor.getValue();
        mCallStateListener =
                (TelephonyCallback.CallStateListener) telephonyCallbackCaptor.getValue();
    }

    @After
@@ -531,6 +552,16 @@ public class DeviceIdleControllerTest {

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyStateConditions(STATE_ACTIVE);

        // All other conditions allow for going INACTIVE...
        setAlarmSoon(false);
        setChargingOn(false);
        setScreenOn(false);
        // ...except the emergency call.
        setEmergencyCallActive(true);

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyStateConditions(STATE_ACTIVE);
    }

    @Test
@@ -559,6 +590,15 @@ public class DeviceIdleControllerTest {

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);

        // All other conditions allow for going INACTIVE...
        setChargingOn(false);
        setScreenOn(false);
        // ...except the emergency call.
        setEmergencyCallActive(true);

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
    }

    @Test
@@ -569,6 +609,7 @@ public class DeviceIdleControllerTest {
        setAlarmSoon(false);
        setChargingOn(false);
        setScreenOn(false);
        setEmergencyCallActive(false);

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyStateConditions(STATE_INACTIVE);
@@ -613,6 +654,7 @@ public class DeviceIdleControllerTest {

        setChargingOn(false);
        setScreenOn(false);
        setEmergencyCallActive(false);

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyLightStateConditions(LIGHT_STATE_INACTIVE);
@@ -1147,6 +1189,22 @@ public class DeviceIdleControllerTest {
                eq(true));
    }

    @Test
    public void testEmergencyCallEndTriggersInactive() {
        setAlarmSoon(false);
        setChargingOn(false);
        setScreenOn(false);
        setEmergencyCallActive(true);

        verifyStateConditions(STATE_ACTIVE);
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);

        setEmergencyCallActive(false);

        verifyStateConditions(STATE_INACTIVE);
        verifyLightStateConditions(LIGHT_STATE_INACTIVE);
    }

    ///////////////// EXIT conditions ///////////////////

    @Test
@@ -2096,6 +2154,75 @@ public class DeviceIdleControllerTest {
                .onDeviceStationaryChanged(eq(true));
    }

    @Test
    public void testEmergencyEndsIdle() {
        enterDeepState(STATE_ACTIVE);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        enterDeepState(STATE_INACTIVE);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        enterDeepState(STATE_IDLE_PENDING);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        enterDeepState(STATE_SENSING);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        enterDeepState(STATE_LOCATING);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        // Quick doze enabled or not shouldn't affect the end state.
        enterDeepState(STATE_QUICK_DOZE_DELAY);
        setQuickDozeEnabled(true);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        enterDeepState(STATE_QUICK_DOZE_DELAY);
        setQuickDozeEnabled(false);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        enterDeepState(STATE_IDLE);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);

        enterDeepState(STATE_IDLE_MAINTENANCE);
        setEmergencyCallActive(true);
        verifyStateConditions(STATE_ACTIVE);
    }

    @Test
    public void testEmergencyEndsLightIdle() {
        enterLightState(LIGHT_STATE_ACTIVE);
        setEmergencyCallActive(true);
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);

        enterLightState(LIGHT_STATE_INACTIVE);
        setEmergencyCallActive(true);
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);

        enterLightState(LIGHT_STATE_WAITING_FOR_NETWORK);
        setEmergencyCallActive(true);
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);

        enterLightState(LIGHT_STATE_IDLE);
        setEmergencyCallActive(true);
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);

        enterLightState(LIGHT_STATE_IDLE_MAINTENANCE);
        setEmergencyCallActive(true);
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);

        enterLightState(LIGHT_STATE_OVERRIDE);
        setEmergencyCallActive(true);
        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
    }

    private void enterDeepState(int state) {
        switch (state) {
            case STATE_ACTIVE:
@@ -2108,6 +2235,7 @@ public class DeviceIdleControllerTest {
                setQuickDozeEnabled(true);
                setScreenOn(false);
                setChargingOn(false);
                setEmergencyCallActive(false);
                mDeviceIdleController.becomeInactiveIfAppropriateLocked();
                break;
            case STATE_LOCATING:
@@ -2128,6 +2256,7 @@ public class DeviceIdleControllerTest {
                setQuickDozeEnabled(false);
                setScreenOn(false);
                setChargingOn(false);
                setEmergencyCallActive(false);
                mDeviceIdleController.becomeInactiveIfAppropriateLocked();
                int count = 0;
                while (mDeviceIdleController.getState() != state) {
@@ -2159,6 +2288,7 @@ public class DeviceIdleControllerTest {
                enterLightState(LIGHT_STATE_ACTIVE);
                setScreenOn(false);
                setChargingOn(false);
                setEmergencyCallActive(false);
                int count = 0;
                mDeviceIdleController.becomeInactiveIfAppropriateLocked();
                while (mDeviceIdleController.getLightState() != lightState) {
@@ -2177,6 +2307,7 @@ public class DeviceIdleControllerTest {
            case LIGHT_STATE_OVERRIDE:
                setScreenOn(false);
                setChargingOn(false);
                setEmergencyCallActive(false);
                mDeviceIdleController.setLightStateForTest(lightState);
                break;
            default:
@@ -2188,6 +2319,14 @@ public class DeviceIdleControllerTest {
        mDeviceIdleController.updateChargingLocked(on);
    }

    private void setEmergencyCallActive(boolean active) {
        if (active) {
            mEmergencyCallListener.onOutgoingEmergencyCall(mock(EmergencyNumber.class), 0);
        } else {
            mCallStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE);
        }
    }

    private void setScreenLocked(boolean locked) {
        mDeviceIdleController.keyguardShowingLocked(locked);
    }
@@ -2235,6 +2374,7 @@ public class DeviceIdleControllerTest {
                assertFalse(mDeviceIdleController.isCharging());
                assertFalse(mDeviceIdleController.isScreenOn()
                        && !mDeviceIdleController.isKeyguardShowing());
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            case STATE_IDLE_PENDING:
                assertEquals(
@@ -2244,6 +2384,7 @@ public class DeviceIdleControllerTest {
                assertFalse(mDeviceIdleController.isCharging());
                assertFalse(mDeviceIdleController.isScreenOn()
                        && !mDeviceIdleController.isKeyguardShowing());
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            case STATE_SENSING:
                assertEquals(
@@ -2255,6 +2396,7 @@ public class DeviceIdleControllerTest {
                assertFalse(mDeviceIdleController.isCharging());
                assertFalse(mDeviceIdleController.isScreenOn()
                        && !mDeviceIdleController.isKeyguardShowing());
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            case STATE_LOCATING:
                assertEquals(
@@ -2263,6 +2405,7 @@ public class DeviceIdleControllerTest {
                assertFalse(mDeviceIdleController.isCharging());
                assertFalse(mDeviceIdleController.isScreenOn()
                        && !mDeviceIdleController.isKeyguardShowing());
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            case STATE_IDLE:
                if (mDeviceIdleController.hasMotionSensor()) {
@@ -2276,6 +2419,7 @@ public class DeviceIdleControllerTest {
                        && !mDeviceIdleController.isKeyguardShowing());
                // Light state should be OVERRIDE at this point.
                verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            case STATE_IDLE_MAINTENANCE:
                if (mDeviceIdleController.hasMotionSensor()) {
@@ -2287,6 +2431,7 @@ public class DeviceIdleControllerTest {
                assertFalse(mDeviceIdleController.isCharging());
                assertFalse(mDeviceIdleController.isScreenOn()
                        && !mDeviceIdleController.isKeyguardShowing());
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            case STATE_QUICK_DOZE_DELAY:
                // If quick doze is enabled, the motion listener should NOT be active.
@@ -2295,6 +2440,7 @@ public class DeviceIdleControllerTest {
                assertFalse(mDeviceIdleController.isCharging());
                assertFalse(mDeviceIdleController.isScreenOn()
                        && !mDeviceIdleController.isKeyguardShowing());
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            default:
                fail("Conditions for " + stateToString(expectedState) + " unknown.");
@@ -2312,6 +2458,7 @@ public class DeviceIdleControllerTest {
            case LIGHT_STATE_ACTIVE:
                assertTrue(
                        mDeviceIdleController.isCharging() || mDeviceIdleController.isScreenOn()
                                || mDeviceIdleController.isEmergencyCallActive()
                                // Or there's an alarm coming up soon.
                                || SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM
                                > mAlarmManager.getNextWakeFromIdleTime());
@@ -2324,6 +2471,7 @@ public class DeviceIdleControllerTest {
                assertFalse(mDeviceIdleController.isCharging());
                assertFalse(mDeviceIdleController.isScreenOn()
                        && !mDeviceIdleController.isKeyguardShowing());
                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                break;
            default:
                fail("Conditions for " + lightStateToString(expectedLightState) + " unknown.");