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

Commit d911a095 authored by SongFerng Wang's avatar SongFerng Wang Committed by Android (Google) Code Review
Browse files

Merge "Avoid ANR when UI query network selection state" into tm-qpr-dev

parents 77b98813 88717f2c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
                use(OpenNetworkSelectPagePreferenceController.class).init(mSubId);
        final AutoSelectPreferenceController autoSelectPreferenceController =
                use(AutoSelectPreferenceController.class)
                        .init(mSubId)
                        .init(getLifecycle(), mSubId)
                        .addListener(openNetworkSelectPagePreferenceController);
        use(NetworkPreferenceCategoryController.class).init(mSubId)
                .setChildren(Arrays.asList(autoSelectPreferenceController));
+83 −12
Original line number Diff line number Diff line
@@ -31,9 +31,12 @@ import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
@@ -60,6 +63,9 @@ import java.util.concurrent.atomic.AtomicLong;
public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController
        implements LifecycleObserver{
    private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1);
    private static final String LOG_TAG = "AutoSelectPreferenceController";
    private static final String INTERNAL_LOG_TAG_INIT = "Init";
    private static final String INTERNAL_LOG_TAG_AFTERSET = "AfterSet";

    private final Handler mUiHandler;
    private PreferenceScreen mPreferenceScreen;
@@ -74,6 +80,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
    private AtomicBoolean mUpdatingConfig;
    private int mCacheOfModeStatus;
    private AtomicLong mRecursiveUpdate;
    TelephonyCallbackListener mTelephonyCallbackListener;

    public AutoSelectPreferenceController(Context context, String key) {
        super(context, key);
@@ -88,6 +95,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
                new HandlerExecutor(mUiHandler));
        mAllowedNetworkTypesListener.setAllowedNetworkTypesListener(
                () -> updatePreference());
        mTelephonyCallbackListener = new TelephonyCallbackListener();
    }

    private void updatePreference() {
@@ -104,11 +112,14 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
    @OnLifecycleEvent(ON_START)
    public void onStart() {
        mAllowedNetworkTypesListener.register(mContext, mSubId);
        mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mUiHandler),
                mTelephonyCallbackListener);
    }

    @OnLifecycleEvent(ON_STOP)
    public void onStop() {
        mAllowedNetworkTypesListener.unregister(mContext, mSubId);
        mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallbackListener);
    }

    @Override
@@ -127,12 +138,6 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon

    @Override
    public boolean isChecked() {
        if (!mUpdatingConfig.get()) {
            mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode();
            for (OnNetworkSelectModeListener lsn : mListeners) {
                lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus);
            }
        }
        return mCacheOfModeStatus == TelephonyManager.NETWORK_SELECTION_MODE_AUTO;
    }

@@ -195,12 +200,23 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon

            //Update UI in UI thread
            final long durationMillis = SystemClock.elapsedRealtime() - startMillis;

            mUiHandler.postDelayed(() -> {
                ThreadUtils.postOnBackgroundThread(() -> {
                    queryNetworkSelectionMode(INTERNAL_LOG_TAG_AFTERSET);

                    //Update UI in UI thread
                    mUiHandler.post(() -> {
                        mRecursiveUpdate.getAndIncrement();
                        if (mSwitchPreference != null) {
                            mSwitchPreference.setEnabled(true);
                            mSwitchPreference.setChecked(isChecked());
                        }
                        mRecursiveUpdate.decrementAndGet();
                        updateListenerValue();
                        dismissProgressBar();
                    });
                });
            }, Math.max(MINIMUM_DIALOG_TIME_MILLIS - durationMillis, 0));
        });
    }
@@ -208,7 +224,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
    /**
     * Initialization based on given subscription id.
     **/
    public AutoSelectPreferenceController init(int subId) {
    public AutoSelectPreferenceController init(Lifecycle lifecycle, int subId) {
        mSubId = subId;
        mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
                .createForSubscriptionId(mSubId);
@@ -219,6 +235,19 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
                CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL)
                : false;

        ThreadUtils.postOnBackgroundThread(() -> {
            queryNetworkSelectionMode(INTERNAL_LOG_TAG_INIT);

            //Update UI in UI thread
            mUiHandler.post(() -> {
                if (mSwitchPreference != null) {
                    mRecursiveUpdate.getAndIncrement();
                    mSwitchPreference.setChecked(isChecked());
                    mRecursiveUpdate.decrementAndGet();
                    updateListenerValue();
                }
            });
        });
        return this;
    }

@@ -228,6 +257,39 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
        return this;
    }

    private void queryNetworkSelectionMode(String tag) {
        mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode();
        Log.d(LOG_TAG, tag + ": query command done. mCacheOfModeStatus: " + mCacheOfModeStatus);
    }

    @VisibleForTesting
    void updateUiAutoSelectValue(ServiceState status) {
        if (status == null) {
            return;
        }
        if (!mUpdatingConfig.get()) {
            int networkSelectionMode = status.getIsManualSelection()
                    ? TelephonyManager.NETWORK_SELECTION_MODE_MANUAL
                    : TelephonyManager.NETWORK_SELECTION_MODE_AUTO;
            if (mCacheOfModeStatus == networkSelectionMode) {
                return;
            }
            mCacheOfModeStatus = networkSelectionMode;
            Log.d(LOG_TAG, "updateUiAutoSelectValue: mCacheOfModeStatus: " + mCacheOfModeStatus);

            mRecursiveUpdate.getAndIncrement();
            updateState(mSwitchPreference);
            mRecursiveUpdate.decrementAndGet();
            updateListenerValue();
        }
    }

    private void updateListenerValue() {
        for (OnNetworkSelectModeListener lsn : mListeners) {
            lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus);
        }
    }

    private void showAutoSelectProgressBar() {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(mContext);
@@ -258,4 +320,13 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
    public interface OnNetworkSelectModeListener {
        void onNetworkSelectModeUpdated(int mode);
    }

    private class TelephonyCallbackListener extends TelephonyCallback
            implements TelephonyCallback.ServiceStateListener {

        @Override
        public void onServiceStateChanged(ServiceState serviceState) {
            updateUiAutoSelectValue(serviceState);
        }
    }
}
+49 −4
Original line number Diff line number Diff line
@@ -28,9 +28,11 @@ import android.app.ProgressDialog;
import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;

import androidx.lifecycle.Lifecycle;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -61,6 +63,10 @@ public class AutoSelectPreferenceControllerTest {
    private CarrierConfigCache mCarrierConfigCache;
    @Mock
    private ProgressDialog mProgressDialog;
    @Mock
    private ServiceState mTestServiceState;
    @Mock
    private Lifecycle mLifecycle;

    private PersistableBundle mCarrierConfig;
    private AutoSelectPreferenceController mController;
@@ -88,7 +94,16 @@ public class AutoSelectPreferenceControllerTest {
        mController = new AutoSelectPreferenceController(mContext, "auto_select");
        mController.mProgressDialog = mProgressDialog;
        mController.mSwitchPreference = mSwitchPreference;
        mController.init(SUB_ID);
        mController.init(mLifecycle, SUB_ID);
        sleepAfterInit();
    }

    private void sleepAfterInit() {
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            fail("Sleep timeout " + e);
        }
    }

    @Test
@@ -111,7 +126,8 @@ public class AutoSelectPreferenceControllerTest {

    @Test
    public void updateState_isRoaming_enabled() {
        when(mTelephonyManager.getServiceState().getRoaming()).thenReturn(true);
        when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState);
        when(mTestServiceState.getRoaming()).thenReturn(true);

        mController.updateState(mSwitchPreference);

@@ -120,7 +136,8 @@ public class AutoSelectPreferenceControllerTest {

    @Test
    public void updateState_notRoamingWithAutoSelectOn_disabled() {
        when(mTelephonyManager.getServiceState().getRoaming()).thenReturn(false);
        when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState);
        when(mTestServiceState.getRoaming()).thenReturn(false);
        doReturn(OPERATOR_NAME).when(mTelephonyManager).getSimOperatorName();

        mController.updateState(mSwitchPreference);
@@ -136,6 +153,34 @@ public class AutoSelectPreferenceControllerTest {
        when(mCarrierConfigCache.getConfigForSubId(SUB_ID)).thenReturn(null);

        // Should not crash
        mController.init(SUB_ID);
        mController.init(mLifecycle, SUB_ID);
    }

    @Test
    public void updateUiAutoSelectValue_serviceStateGetIsManualSelection_isCheckedFalse() {
        when(mTelephonyManager.getNetworkSelectionMode()).thenReturn(
                TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
        when(mTestServiceState.getIsManualSelection()).thenReturn(true);
        mController.init(mLifecycle, SUB_ID);
        sleepAfterInit();

        mController.updateUiAutoSelectValue(mTestServiceState);

        assertThat(mController.isChecked()).isFalse();
        assertThat(mSwitchPreference.isChecked()).isFalse();
    }

    @Test
    public void updateUiAutoSelectValue_serviceStateGetIsAutoSelection_isCheckedTrue() {
        when(mTelephonyManager.getNetworkSelectionMode()).thenReturn(
                TelephonyManager.NETWORK_SELECTION_MODE_MANUAL);
        when(mTestServiceState.getIsManualSelection()).thenReturn(false);
        mController.init(mLifecycle, SUB_ID);
        sleepAfterInit();

        mController.updateUiAutoSelectValue(mTestServiceState);

        assertThat(mController.isChecked()).isTrue();
        assertThat(mSwitchPreference.isChecked()).isTrue();
    }
}