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

Commit f418e9f6 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

DeviceStateMonitor and unit test polish am: d6455281 am: 7f14cc6a

Change-Id: Ib321d7cb82f29c42a86b3cbfe14ee9403c0166ae
parents e79c0a62 7f14cc6a
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -76,9 +76,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;

@@ -258,8 +255,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);
@@ -680,6 +683,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());
    }