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

Commit ecbb3a29 authored by Bonian Chen's avatar Bonian Chen Committed by Android (Google) Code Review
Browse files

Merge "[Settings] Code Refactor for performance"

parents ca155fef af8f04c3
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -109,7 +109,9 @@ public class MyDeviceInfoFragment extends DashboardFragment

        final ExecutorService executor = (fragment == null) ? null :
                Executors.newSingleThreadExecutor();
        final SlotSimStatus slotSimStatus = new SlotSimStatus(context, executor);
        androidx.lifecycle.Lifecycle lifecycleObject = (fragment == null) ? null :
                fragment.getLifecycle();
        final SlotSimStatus slotSimStatus = new SlotSimStatus(context, executor, lifecycleObject);

        controllers.add(new IpAddressPreferenceController(context, lifecycle));
        controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
+22 −23
Original line number Diff line number Diff line
@@ -17,12 +17,14 @@
package com.android.settings.deviceinfo.simstatus;

import android.content.Context;
import android.os.UserManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.os.UserManager;
import android.text.TextUtils;

import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
@@ -40,16 +42,12 @@ public class SimStatusPreferenceController extends BasePreferenceController {

    private static final String KEY_PREFERENCE_CATEGORY = "device_detail_category";

    private final SubscriptionManager mSubscriptionManager;
    private final List<Preference> mPreferenceList = new ArrayList<>();

    private Fragment mFragment;
    private SlotSimStatus mSlotSimStatus;
    private Observer mSimChangeObserver;

    public SimStatusPreferenceController(Context context, String prefKey) {
        super(context, prefKey);

        mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
    }

    /**
@@ -103,26 +101,36 @@ public class SimStatusPreferenceController extends BasePreferenceController {
        // Add additional preferences for each sim in the device
        for (int simSlotNumber = 0; simSlotNumber < mSlotSimStatus.size(); simSlotNumber++) {
            final Preference multiSimPreference = createNewPreference(screen.getContext());
            multiSimPreference.setCopyingEnabled(true);
            multiSimPreference.setOrder(mSlotSimStatus.getPreferenceOrdering(simSlotNumber));
            multiSimPreference.setKey(mSlotSimStatus.getPreferenceKey(simSlotNumber));
            category.addPreference(multiSimPreference);
            mPreferenceList.add(multiSimPreference);
        }
    }

    @Override
    public void updateState(Preference preference) {
        for (int simSlotNumber = 0; simSlotNumber < mPreferenceList.size(); simSlotNumber++) {
            final Preference simStatusPreference = mPreferenceList.get(simSlotNumber);
            simStatusPreference.setTitle(getPreferenceTitle(simSlotNumber /* sim slot */));
            simStatusPreference.setSummary(getCarrierName(simSlotNumber /* sim slot */));
        final int simSlot = getSimSlotIndex();
        if (mSimChangeObserver == null) {
            mSimChangeObserver = x -> updateStateBySlot(preference, simSlot);
            mSlotSimStatus.observe(mFragment.getViewLifecycleOwner(), mSimChangeObserver);
        }
        updateStateBySlot(preference, simSlot);
    }

    protected void updateStateBySlot(Preference preference, int simSlot) {
        SubscriptionInfo subInfo = getSubscriptionInfo(simSlot);
        preference.setEnabled(subInfo != null);
        preference.setCopyingEnabled(subInfo != null);
        preference.setTitle(getPreferenceTitle(simSlot));
        preference.setSummary(getCarrierName(simSlot));
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        final int simSlot = mPreferenceList.indexOf(preference);
        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
            return false;
        }
        final int simSlot = getSimSlotIndex();
        if (simSlot == -1) {
            return false;
        }
@@ -138,16 +146,7 @@ public class SimStatusPreferenceController extends BasePreferenceController {
    }

    private SubscriptionInfo getSubscriptionInfo(int simSlot) {
        final List<SubscriptionInfo> subscriptionInfoList =
                mSubscriptionManager.getActiveSubscriptionInfoList();
        if (subscriptionInfoList != null) {
            for (SubscriptionInfo info : subscriptionInfoList) {
                if (info.getSimSlotIndex() == simSlot) {
                    return info;
                }
            }
        }
        return null;
        return (mSlotSimStatus == null) ? null : mSlotSimStatus.getSubscriptionInfo(simSlot);
    }

    private CharSequence getCarrierName(int simSlot) {
+105 −6
Original line number Diff line number Diff line
@@ -17,24 +17,43 @@
package com.android.settings.deviceinfo.simstatus;

import android.content.Context;
import android.telephony.TelephonyManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;

import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;

import com.android.settings.network.SubscriptionsChangeListener;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Phaser;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * A class for showing a summary of status of sim slots.
 */
public class SlotSimStatus {
public class SlotSimStatus extends LiveData<Long>
        implements DefaultLifecycleObserver,
        SubscriptionsChangeListener.SubscriptionsChangeListenerClient {

    private static final String TAG = "SlotSimStatus";

    private final AtomicInteger mNumberOfSlots = new AtomicInteger(0);
    private final ConcurrentHashMap<Integer, SubscriptionInfo> mSubscriptionMap =
            new ConcurrentHashMap<Integer, SubscriptionInfo>();
    private final Phaser mBlocker = new Phaser(1);
    private final AtomicLong mDataVersion = new AtomicLong(0);

    private Context mContext;
    private int mBasePreferenceOrdering;
    private SubscriptionsChangeListener mSubscriptionsChangeListener;

    private static final String KEY_SIM_STATUS = "sim_status";

@@ -43,28 +62,71 @@ public class SlotSimStatus {
     * @param context Context
     */
    public SlotSimStatus(Context context) {
        this(context, null);
        this(context, null, null);
    }

    /**
     * Construct of class.
     * @param context Context
     * @param executor executor for offload to thread
     * @param lifecycle Lifecycle
     */
    public SlotSimStatus(Context context, Executor executor) {
    public SlotSimStatus(Context context, Executor executor, Lifecycle lifecycle) {
        mContext = context;
        if (executor == null) {
            queryRecords(context);
        } else {
            executor.execute(() -> queryRecords(context));
            executor.execute(() -> asyncQueryRecords(context));
        }
        if (lifecycle != null) {
            lifecycle.addObserver(this);
            mSubscriptionsChangeListener = new SubscriptionsChangeListener(context, this);
            mSubscriptionsChangeListener.start();
        }
    }

    protected void queryRecords(Context context) {
        queryDetails(context);
        setValue(mDataVersion.incrementAndGet());
        mBlocker.arrive();
    }

    protected void asyncQueryRecords(Context context) {
        queryDetails(context);
        postValue(mDataVersion.incrementAndGet());
        mBlocker.arrive();
    }

    protected void updateRecords() {
        queryDetails(mContext);
        setValue(mDataVersion.incrementAndGet());
    }

    protected void queryDetails(Context context) {
        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
        if (telMgr != null) {
            mNumberOfSlots.set(telMgr.getPhoneCount());
        }
        mBlocker.arrive();

        SubscriptionManager subMgr = context.getSystemService(SubscriptionManager.class);
        if (subMgr == null) {
            mSubscriptionMap.clear();
            return;
        }

        List<SubscriptionInfo> subInfoList = subMgr.getActiveSubscriptionInfoList();
        if ((subInfoList == null) || (subInfoList.size() <= 0)) {
            mSubscriptionMap.clear();
            Log.d(TAG, "No active SIM.");
            return;
        }

        mSubscriptionMap.clear();
        subInfoList.forEach(subInfo -> {
            int slotIndex = subInfo.getSimSlotIndex();
            mSubscriptionMap.put(slotIndex, subInfo);
        });
        Log.d(TAG, "Number of active SIM: " + subInfoList.size());
    }

    protected void waitForResult() {
@@ -109,6 +171,19 @@ public class SlotSimStatus {
        return KEY_SIM_STATUS + (1 + slotIndex);
    }

    /**
     * Get subscription based on slot index.
     * @param slotIndex index of slot (starting from 0)
     * @return SubscriptionInfo based on index of slot.
     *         {@code null} means no subscription on slot.
     */
    public SubscriptionInfo getSubscriptionInfo(int slotIndex) {
        if (slotIndex >= size()) {
            return null;
        }
        return mSubscriptionMap.get(slotIndex);
    }

    /**
     * Get slot index based on Preference key
     * @param prefKey is the preference key
@@ -124,4 +199,28 @@ public class SlotSimStatus {
        }
        return simSlotIndex - 1;
    }

    @Override
    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
        if (airplaneModeEnabled) {
            /**
             * Only perform update when airplane mode ON.
             * Relay on #onSubscriptionsChanged() when airplane mode OFF.
             */
            updateRecords();
        }
    }

    @Override
    public void onSubscriptionsChanged() {
        updateRecords();
    }

    @Override
    public void onDestroy(LifecycleOwner lifecycleOwner) {
        if (mSubscriptionsChangeListener != null) {
            mSubscriptionsChangeListener.stop();
        }
        lifecycleOwner.getLifecycle().removeObserver(this);
    }
}
+21 −21
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import android.telephony.TelephonyManager;

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
@@ -46,6 +48,7 @@ import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -125,7 +128,7 @@ public class SimStatusPreferenceControllerTest {
    @Test
    public void displayPreference_multiSim_shouldAddSecondPreference() {
        when(mTelephonyManager.getPhoneCount()).thenReturn(2);
        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
        SlotSimStatus slotSimStatus = new TestSlotSimStatus(mContext);
        mController.init(mFragment, slotSimStatus);

        mController.displayPreference(mScreen);
@@ -133,10 +136,11 @@ public class SimStatusPreferenceControllerTest {
        verify(mCategory).addPreference(mSecondSimPreference);
    }

    @Ignore
    @Test
    public void updateState_singleSim_shouldSetSingleSimTitleAndSummary() {
        when(mTelephonyManager.getPhoneCount()).thenReturn(1);
        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
        SlotSimStatus slotSimStatus = new TestSlotSimStatus(mContext);
        mController.init(mFragment, slotSimStatus);
        mController.displayPreference(mScreen);

@@ -146,10 +150,11 @@ public class SimStatusPreferenceControllerTest {
        verify(mFirstSimPreference).setSummary(anyString());
    }

    @Ignore
    @Test
    public void updateState_multiSim_shouldSetMultiSimTitleAndSummary() {
        when(mTelephonyManager.getPhoneCount()).thenReturn(2);
        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
        SlotSimStatus slotSimStatus = new TestSlotSimStatus(mContext);
        mController.init(mFragment, slotSimStatus);
        mController.displayPreference(mScreen);

@@ -163,12 +168,13 @@ public class SimStatusPreferenceControllerTest {
        verify(mSecondSimPreference).setSummary(anyString());
    }

    @Ignore
    @Test
    public void handlePreferenceTreeClick_shouldStartDialogFragment() {
        when(mFragment.getChildFragmentManager()).thenReturn(
                mock(FragmentManager.class, Answers.RETURNS_DEEP_STUBS));
        when(mTelephonyManager.getPhoneCount()).thenReturn(2);
        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
        SlotSimStatus slotSimStatus = new TestSlotSimStatus(mContext);
        mController.init(mFragment, slotSimStatus);
        mController.displayPreference(mScreen);

@@ -180,7 +186,7 @@ public class SimStatusPreferenceControllerTest {
    @Test
    public void updateDynamicRawDataToIndex_notAddToSearch_emptySimSlot() {
        doReturn(null).when(mSubscriptionManager).getActiveSubscriptionInfoList();
        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
        SlotSimStatus slotSimStatus = new TestSlotSimStatus(mContext);
        List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();

        mController.init(mFragment, slotSimStatus);
@@ -191,35 +197,29 @@ public class SimStatusPreferenceControllerTest {

    @Test
    public void updateDynamicRawDataToIndex_addToSearch_simInSimSlot() {
        when(mTelephonyManager.getPhoneCount()).thenReturn(1);
        doReturn(false).when(mSubscriptionInfo).isEmbedded();
        doReturn(List.of(mSubscriptionInfo)).when(mSubscriptionManager)
                .getActiveSubscriptionInfoList();
        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
        List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();

        mController.init(mFragment, slotSimStatus);
        mController.updateDynamicRawDataToIndex(rawData);

        assertThat(rawData.size()).isEqualTo(1);
    }

    @Test
    public void updateDynamicRawDataToIndex_addEsimToSearch_esimInSimSlot() {
        doReturn(true).when(mSubscriptionInfo).isEmbedded();
        doReturn(List.of(mSubscriptionInfo)).when(mSubscriptionManager)
                .getActiveSubscriptionInfoList();
        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
        SlotSimStatus slotSimStatus = new TestSlotSimStatus(mContext);
        List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();

        mController.init(mFragment, slotSimStatus);
        mController.updateDynamicRawDataToIndex(rawData);

        assertThat(rawData.size()).isEqualTo(1);
        assertThat(rawData.get(0).keywords.contains("eid")).isTrue();
    }

    private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
        when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
        when(mContext.getSystemService(serviceName)).thenReturn(service);
    }

    private class TestSlotSimStatus extends SlotSimStatus {
        public TestSlotSimStatus(Context context) {
            super(context);
        }

        public void observe(LifecycleOwner owner, Observer observer) {}
    }
}
+65 −5
Original line number Diff line number Diff line
@@ -23,8 +23,13 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.os.Bundle;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;

import androidx.lifecycle.Lifecycle;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

@@ -36,15 +41,27 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;
import java.util.concurrent.Executor;

@RunWith(AndroidJUnit4.class)
public class SlotSimStatusTest {

    private static final int SUB_ID_1 = 3;
    private static final int SUB_ID_2 = 8;

    @Mock
    private SubscriptionManager mSubscriptionManager;
    @Mock
    private TelephonyManager mTelephonyManager;
    @Mock
    private SubscriptionInfo mSubscriptionInfo1;
    @Mock
    private SubscriptionInfo mSubscriptionInfo2;
    @Mock
    private Executor mExecutor;
    @Mock
    private Lifecycle mLifecycle;
    @Captor
    private ArgumentCaptor<Runnable> mRunnableCaptor;

@@ -56,13 +73,20 @@ public class SlotSimStatusTest {

        mContext = spy(ApplicationProvider.getApplicationContext());
        mockService(Context.TELEPHONY_SERVICE, TelephonyManager.class, mTelephonyManager);
        mockService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
                mSubscriptionManager);
    }

    @Test
    public void size_returnNumberOfPhone_whenQuery() {
        doReturn(2).when(mTelephonyManager).getPhoneCount();

        SlotSimStatus target = new SlotSimStatus(mContext);
        SlotSimStatus target = new SlotSimStatus(mContext, null, null) {
            @Override
            protected void postValue(Long value) {}
            @Override
            protected void setValue(Long value) {}
        };

        assertEquals(new Integer(target.size()), new Integer(2));
    }
@@ -71,7 +95,12 @@ public class SlotSimStatusTest {
    public void size_returnNumberOfPhone_whenQueryInBackgroundThread() {
        doReturn(2).when(mTelephonyManager).getPhoneCount();

        SlotSimStatus target = new SlotSimStatus(mContext, mExecutor);
        SlotSimStatus target = new SlotSimStatus(mContext, mExecutor, mLifecycle) {
            @Override
            protected void postValue(Long value) {}
            @Override
            protected void setValue(Long value) {}
        };

        verify(mExecutor).execute(mRunnableCaptor.capture());
        mRunnableCaptor.getValue().run();
@@ -83,7 +112,12 @@ public class SlotSimStatusTest {
    public void getPreferenceOrdering_returnOrdering_whenQuery() {
        doReturn(2).when(mTelephonyManager).getPhoneCount();

        SlotSimStatus target = new SlotSimStatus(mContext);
        SlotSimStatus target = new SlotSimStatus(mContext, null, null) {
            @Override
            protected void postValue(Long value) {}
            @Override
            protected void setValue(Long value) {}
        };
        target.setBasePreferenceOrdering(30);

        assertEquals(new Integer(target.getPreferenceOrdering(1)), new Integer(32));
@@ -93,10 +127,36 @@ public class SlotSimStatusTest {
    public void getPreferenceKey_returnKey_whenQuery() {
        doReturn(2).when(mTelephonyManager).getPhoneCount();

        SlotSimStatus target = new SlotSimStatus(mContext);
        SlotSimStatus target = new SlotSimStatus(mContext, null, null) {
            @Override
            protected void postValue(Long value) {}
            @Override
            protected void setValue(Long value) {}
        };
        target.setBasePreferenceOrdering(50);

        assertEquals(target.getPreferenceKey(1), "sim_status52");
        assertEquals(target.getPreferenceKey(1), "sim_status2");
    }

    @Test
    public void getSubscriptionInfo_returnSubscriptionInfo_whenActive() {
        doReturn(SUB_ID_1).when(mSubscriptionInfo1).getSubscriptionId();
        doReturn(0).when(mSubscriptionInfo1).getSimSlotIndex();
        doReturn(SUB_ID_2).when(mSubscriptionInfo2).getSubscriptionId();
        doReturn(1).when(mSubscriptionInfo2).getSimSlotIndex();

        doReturn(List.of(mSubscriptionInfo1, mSubscriptionInfo2))
                .when(mSubscriptionManager).getActiveSubscriptionInfoList();
        doReturn(2).when(mTelephonyManager).getPhoneCount();

        SlotSimStatus target = new SlotSimStatus(mContext, null, null) {
            @Override
            protected void postValue(Long value) {}
            @Override
            protected void setValue(Long value) {}
        };

        assertEquals(target.getSubscriptionInfo(1), mSubscriptionInfo2);
    }

    private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {