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

Commit 68c66ceb authored by Rambo Wang's avatar Rambo Wang Committed by Gerrit Code Review
Browse files

Merge "DeviceStateMonitor and unit test polish"

parents 52770b1c 347835b6
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -79,9 +79,6 @@ public class DeviceStateMonitor extends Handler {
    static final int EVENT_WIFI_CONNECTION_CHANGED      = 7;
    static final int EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH = 8;

    // TODO(b/74006656) load hysteresis values from a property when DeviceStateMonitor starts
    private static final int HYSTERESIS_KBPS = 50;

    private static final int WIFI_UNAVAILABLE = 0;
    private static final int WIFI_AVAILABLE = 1;

@@ -264,8 +261,14 @@ public class DeviceStateMonitor extends Handler {
        mIsTetheringOn = false;
        mIsLowDataExpected = false;

        log("DeviceStateMonitor mIsPowerSaveOn=" + mIsPowerSaveOn + ",mIsScreenOn="
                + mIsScreenOn + ",mIsCharging=" + mIsCharging, false);
        log("DeviceStateMonitor mIsTetheringOn=" + mIsTetheringOn
                + ", mIsScreenOn=" + mIsScreenOn
                + ", mIsCharging=" + mIsCharging
                + ", mIsPowerSaveOn=" + mIsPowerSaveOn
                + ", mIsLowDataExpected=" + mIsLowDataExpected
                + ", mIsWifiConnected=" + mIsWifiConnected
                + ", mIsAlwaysSignalStrengthReportingEnabled="
                + mIsAlwaysSignalStrengthReportingEnabled, false);

        final IntentFilter filter = new IntentFilter();
        filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
@@ -733,6 +736,8 @@ public class DeviceStateMonitor extends Handler {
        ipw.println("mIsLowDataExpected=" + mIsLowDataExpected);
        ipw.println("mUnsolicitedResponseFilter=" + mUnsolicitedResponseFilter);
        ipw.println("mIsWifiConnected=" + mIsWifiConnected);
        ipw.println("mIsAlwaysSignalStrengthReportingEnabled="
                + mIsAlwaysSignalStrengthReportingEnabled);
        ipw.println("Local logs:");
        ipw.increaseIndent();
        mLocalLog.dump(fd, ipw, args);
+222 −39
Original line number Diff line number Diff line
@@ -17,16 +17,23 @@ package com.android.internal.telephony;

import static android.hardware.radio.V1_0.DeviceStateType.CHARGING_STATE;
import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED;
import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.nullable;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;

import static java.util.Arrays.asList;

import android.annotation.IntDef;
import android.content.Intent;
import android.hardware.radio.V1_2.IndicationFilter;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
import android.os.Message;
@@ -34,26 +41,125 @@ import android.test.suitebuilder.annotation.MediumTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

import androidx.test.filters.FlakyTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Map;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class DeviceStateMonitorTest extends TelephonyTest {
    // No indication filter set
    private static final int INDICATION_FILTERS_NONE = 0;

    // All implemented indiation filters set so far
    // which is a subset of IndicationFilter.ALL
    private static final int INDICATION_FILTERS_ALL =
            IndicationFilter.SIGNAL_STRENGTH
            | IndicationFilter.FULL_NETWORK_STATE
            | IndicationFilter.DATA_CALL_DORMANCY_CHANGED
            | IndicationFilter.LINK_CAPACITY_ESTIMATE
            | IndicationFilter.PHYSICAL_CHANNEL_CONFIG;

    // INDICATION_FILTERS_ALL but excludes Indication.SIGNAL_STRENGTH
    private static final int INDICATION_FILTERS_WHEN_TETHERING_ON =
            INDICATION_FILTERS_ALL & ~IndicationFilter.SIGNAL_STRENGTH;
    private static final int INDICATION_FILTERS_WHEN_CHARGING = INDICATION_FILTERS_ALL;
    private static final int INDICATION_FILTERS_WHEN_SCREEN_ON = INDICATION_FILTERS_ALL;

    /** @hide */
    @IntDef(prefix = {"STATE_TYPE_"}, value = {
        STATE_TYPE_RIL_CONNECTED,
        STATE_TYPE_SCREEN,
        STATE_TYPE_POWER_SAVE_MODE,
        STATE_TYPE_CHARGING,
        STATE_TYPE_TETHERING,
        STATE_TYPE_RADIO_AVAILABLE,
        STATE_TYPE_WIFI_CONNECTED,
        STATE_TYPE_ALWAYS_SIGNAL_STRENGTH_REPORTED,
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface StateType {}

    // Keep the same value as correspoinding event
    // See state2Event() for detail
    private static final int STATE_TYPE_RIL_CONNECTED = 0;
    // EVENT_UPDATE_NODE_CHANGED is not here, it will be removed in aosp soon
    private static final int STATE_TYPE_SCREEN = 2;
    private static final int STATE_TYPE_POWER_SAVE_MODE = 3;
    private static final int STATE_TYPE_CHARGING = 4;
    private static final int STATE_TYPE_TETHERING = 5;
    private static final int STATE_TYPE_RADIO_AVAILABLE = 6;
    private static final int STATE_TYPE_WIFI_CONNECTED = 7;
    private static final int STATE_TYPE_ALWAYS_SIGNAL_STRENGTH_REPORTED = 8;

    /** @hide */
    @IntDef(prefix = {"STATE_"}, value = {
        STATE_OFF,
        STATE_ON
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface StateStatus {}

    private static final int STATE_OFF = 0;
    private static final int STATE_ON = 1;

    // The keys are the single IndicationFilter flags,
    // The values are the array of states, when one state turn on, the corresponding
    // IndicationFilter flag should NOT be turned off.
    private static final Map<Integer, int[]> INDICATION_FILTER_2_TRIGGERS = Map.of(
            IndicationFilter.SIGNAL_STRENGTH,             new int[] {
                STATE_TYPE_ALWAYS_SIGNAL_STRENGTH_REPORTED, STATE_TYPE_CHARGING, STATE_TYPE_SCREEN},
            IndicationFilter.FULL_NETWORK_STATE,          new int[] {
                STATE_TYPE_CHARGING, STATE_TYPE_SCREEN, STATE_TYPE_TETHERING},
            IndicationFilter.DATA_CALL_DORMANCY_CHANGED,  new int[] {
                STATE_TYPE_CHARGING, STATE_TYPE_SCREEN, STATE_TYPE_TETHERING},
            IndicationFilter.LINK_CAPACITY_ESTIMATE,      new int[] {
                STATE_TYPE_CHARGING, STATE_TYPE_SCREEN, STATE_TYPE_TETHERING},
            IndicationFilter.PHYSICAL_CHANNEL_CONFIG,     new int[] {
                STATE_TYPE_CHARGING, STATE_TYPE_SCREEN, STATE_TYPE_TETHERING}
    );

    private DeviceStateMonitor mDSM;
    // Given a stateType, return the event type that can change the state
    private int state2Event(@StateType int stateType) {
        // As long as we keep the same value, we can directly return the stateType
        return stateType;
    }

    private void updateState(@StateType int stateType, @StateStatus int stateValue) {
        final int event = state2Event(stateType);
        mDSM.obtainMessage(event, stateValue, 0 /* arg2, not used*/).sendToTarget();
        processAllMessages();
    }

    private void updateAllStatesToOff() {
        updateState(STATE_TYPE_RIL_CONNECTED, STATE_OFF);
        updateState(STATE_TYPE_SCREEN, STATE_OFF);
        updateState(STATE_TYPE_POWER_SAVE_MODE, STATE_OFF);
        updateState(STATE_TYPE_CHARGING, STATE_OFF);
        updateState(STATE_TYPE_TETHERING, STATE_OFF);
        updateState(STATE_TYPE_RADIO_AVAILABLE, STATE_OFF);
        updateState(STATE_TYPE_WIFI_CONNECTED, STATE_OFF);
        updateState(STATE_TYPE_ALWAYS_SIGNAL_STRENGTH_REPORTED, STATE_OFF);
    }

    @Before
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
        mDSM = new DeviceStateMonitor(mPhone);
        processAllMessages();

        // Initialize with ALL states off
        updateAllStatesToOff();

        // eliminate the accumuted impact on Mockito.verify()
        reset(mSimulatedCommandsVerifier);
    }

    @After
@@ -62,7 +168,76 @@ public class DeviceStateMonitorTest extends TelephonyTest {
        super.tearDown();
    }

    @Test @FlakyTest
    /**
     * Verify the behavior of CI.setUnsolResponseFilter().
     * Keeping other state unchanged, when one state change. setUnsolResponseFilter()
     * should be called with right IndicationFilter flag set.
     */
    @Test @MediumTest
    public void testSetUnsolResponseFilter_singleStateChange() {
        for (int indicationFilter : INDICATION_FILTER_2_TRIGGERS.keySet()) {
            for (int state : INDICATION_FILTER_2_TRIGGERS.get(indicationFilter)) {
                verifySetUnsolResponseFilter(state, indicationFilter);
            }
        }
    }

    private void verifySetUnsolResponseFilter(int state, int indicationFilter) {
        reset(mSimulatedCommandsVerifier);
        // In the beginning, all states are off

        // Turn on the state
        updateState(state, STATE_ON);

        // Keep other states off, then specified indication filter should NOT be turn off
        ArgumentCaptor<Integer> acIndicationFilter = ArgumentCaptor.forClass(Integer.class);
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                acIndicationFilter.capture(), nullable(Message.class));
        assertTrue((acIndicationFilter.getValue() & indicationFilter) != 0);

        // Turn off the state again
        updateState(state, STATE_OFF);

        // Keep other states off, then no filter flag is on
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                eq(INDICATION_FILTERS_NONE), nullable(Message.class));
    }

    @Test
    public void testSetUnsolResponseFilter_noReduandantCall() {
        // initially all state off, turn screen on
        updateState(STATE_TYPE_SCREEN, STATE_ON);
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(anyInt(),
                nullable(Message.class));
        reset(mSimulatedCommandsVerifier);

        updateState(STATE_TYPE_CHARGING, STATE_ON);
        verify(mSimulatedCommandsVerifier, never()).setUnsolResponseFilter(anyInt(),
                nullable(Message.class));

        updateState(STATE_TYPE_POWER_SAVE_MODE, STATE_ON);
        verify(mSimulatedCommandsVerifier, never()).setUnsolResponseFilter(anyInt(),
                nullable(Message.class));
    }

    @Test
    public void testScreenOnOff() {
        // screen was off by default, turn it on now
        updateState(STATE_TYPE_SCREEN, STATE_ON);
        processAllMessages();

        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                eq(INDICATION_FILTERS_WHEN_SCREEN_ON), nullable(Message.class));

        // turn screen off
        updateState(STATE_TYPE_SCREEN, STATE_OFF);
        processAllMessages();

        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                eq(INDICATION_FILTERS_NONE), nullable(Message.class));
    }

    @Test
    public void testTethering() {
        // Turn tethering on
        Intent intent = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
@@ -70,8 +245,8 @@ public class DeviceStateMonitorTest extends TelephonyTest {
        mContext.sendBroadcast(intent);
        processAllMessages();

        verify(mSimulatedCommandsVerifier, times(1)).setUnsolResponseFilter(eq(6),
                nullable(Message.class));
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                eq(INDICATION_FILTERS_WHEN_TETHERING_ON), nullable(Message.class));

        // Turn tethering off
        intent = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
@@ -79,21 +254,23 @@ public class DeviceStateMonitorTest extends TelephonyTest {
        mContext.sendBroadcast(intent);
        processAllMessages();

        verify(mSimulatedCommandsVerifier, times(1)).setUnsolResponseFilter(eq(0),
                nullable(Message.class));
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                eq(INDICATION_FILTERS_NONE), nullable(Message.class));

        verify(mSimulatedCommandsVerifier, times(1)).sendDeviceState(eq(LOW_DATA_EXPECTED),
        verify(mSimulatedCommandsVerifier).sendDeviceState(eq(LOW_DATA_EXPECTED),
                eq(true), nullable(Message.class));
    }

    @Test @FlakyTest
    @Test
    public void testCharging() {
        // Charging
        Intent intent = new Intent(BatteryManager.ACTION_CHARGING);
        mContext.sendBroadcast(intent);
        processAllMessages();

        verify(mSimulatedCommandsVerifier, times(1)).sendDeviceState(eq(CHARGING_STATE),
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                eq(INDICATION_FILTERS_WHEN_CHARGING), nullable(Message.class));
        verify(mSimulatedCommandsVerifier).sendDeviceState(eq(CHARGING_STATE),
                eq(true), nullable(Message.class));

        // Not charging
@@ -101,55 +278,61 @@ public class DeviceStateMonitorTest extends TelephonyTest {
        mContext.sendBroadcast(intent);
        processAllMessages();

        verify(mSimulatedCommandsVerifier, times(1)).setUnsolResponseFilter(eq(0),
                nullable(Message.class));

        verify(mSimulatedCommandsVerifier, times(1)).sendDeviceState(eq(LOW_DATA_EXPECTED),
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                eq(INDICATION_FILTERS_NONE), nullable(Message.class));
        verify(mSimulatedCommandsVerifier).sendDeviceState(eq(LOW_DATA_EXPECTED),
                eq(true), nullable(Message.class));

        verify(mSimulatedCommandsVerifier, times(1)).sendDeviceState(eq(CHARGING_STATE),
        verify(mSimulatedCommandsVerifier).sendDeviceState(eq(CHARGING_STATE),
                eq(false), nullable(Message.class));
    }

    @Test @FlakyTest
    @Test
    public void testReset() {
        mDSM.obtainMessage(6).sendToTarget();

        verify(mSimulatedCommandsVerifier, times(1)).setUnsolResponseFilter(eq(-1),
                nullable(Message.class));
        testResetFromEvent(DeviceStateMonitor.EVENT_RIL_CONNECTED);
        testResetFromEvent(DeviceStateMonitor.EVENT_RADIO_AVAILABLE);
    }

    private void sendStates(int screenState, int chargingState, int wifiState) {
        mDSM.obtainMessage(
                DeviceStateMonitor.EVENT_SCREEN_STATE_CHANGED, screenState, 0).sendToTarget();
        mDSM.obtainMessage(
                DeviceStateMonitor.EVENT_CHARGING_STATE_CHANGED, chargingState, 0).sendToTarget();
        mDSM.obtainMessage(
                DeviceStateMonitor.EVENT_WIFI_CONNECTION_CHANGED, wifiState, 0).sendToTarget();
    private void testResetFromEvent(int event) {
        reset(mSimulatedCommandsVerifier);
        mDSM.obtainMessage(event).sendToTarget();
        processAllMessages();

        verify(mSimulatedCommandsVerifier).sendDeviceState(eq(CHARGING_STATE),
                anyBoolean(), nullable(Message.class));
        verify(mSimulatedCommandsVerifier).sendDeviceState(eq(LOW_DATA_EXPECTED),
                anyBoolean(), nullable(Message.class));
        verify(mSimulatedCommandsVerifier).sendDeviceState(eq(POWER_SAVE_MODE),
                anyBoolean(), nullable(Message.class));
        verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(anyInt(),
                nullable(Message.class));
    }

    @Test
    @MediumTest
    public void testWifi() {
        // screen off
        sendStates(0, 0, 0);
    public void testComputeCellInfoMinInternal() {
        // by default, screen is off, charging is off and wifi is off
        assertEquals(
                DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
        // screen off, but charging
        sendStates(0, 1, 0);

        // keep screen off, but turn charging on
        updateState(STATE_TYPE_CHARGING, STATE_ON);
        assertEquals(
                DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
        // screen on, no wifi
        sendStates(1, 0, 0);

        // turn screen on, turn charging off and keep wifi off
        updateState(STATE_TYPE_SCREEN, STATE_ON);
        updateState(STATE_TYPE_CHARGING, STATE_OFF);
        assertEquals(
                DeviceStateMonitor.CELL_INFO_INTERVAL_SHORT_MS, mDSM.computeCellInfoMinInterval());

        // screen on, but on wifi
        sendStates(1, 0, 1);
        updateState(STATE_TYPE_WIFI_CONNECTED, STATE_ON);
        assertEquals(
                DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());

        // screen on, charging
        sendStates(1, 1, 0);
        updateState(STATE_TYPE_WIFI_CONNECTED, STATE_OFF);
        updateState(STATE_TYPE_CHARGING, STATE_OFF);
        assertEquals(
                DeviceStateMonitor.CELL_INFO_INTERVAL_SHORT_MS, mDSM.computeCellInfoMinInterval());
    }