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

Commit adf7c857 authored by Evan Laird's avatar Evan Laird Committed by Android (Google) Code Review
Browse files

Merge "Fix ArrayIndexOOB crash with invalid sim slot"

parents 080619f1 bf6fef3f
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -21,12 +21,15 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.VisibleForTesting;

import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
@@ -206,6 +209,7 @@ public class CarrierTextController {
    protected void updateCarrierText() {
        boolean allSimsMissing = true;
        boolean anySimReadyAndInService = false;
        boolean missingSimsWithSubs = false;
        CharSequence displayText = null;

        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
@@ -252,6 +256,7 @@ public class CarrierTextController {
                // described above.
                displayText = makeCarrierStringOnEmergencyCapable(
                        getMissingSimMessage(), subs.get(0).getCarrierName());
                missingSimsWithSubs = true;
            } else {
                // We don't have a SubscriptionInfo to get the emergency calls only from.
                // Grab it from the old sticky broadcast if possible instead. We can use it
@@ -288,12 +293,14 @@ public class CarrierTextController {
            displayText = getAirplaneModeMessage();
        }

        if (mCarrierTextCallback != null) {
            mCarrierTextCallback.updateCarrierInfo(new CarrierTextCallbackInfo(
        Handler handler = Dependency.get(Dependency.MAIN_HANDLER);
        final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
                displayText,
                displayText.toString().split(mSeparator.toString()),
                    anySimReadyAndInService,
                    subsIds));
                anySimReadyAndInService && !missingSimsWithSubs,
                subsIds);
        if (mCarrierTextCallback != null) {
            handler.post(() -> mCarrierTextCallback.updateCarrierInfo(info));
        }

    }
@@ -487,7 +494,8 @@ public class CarrierTextController {
        public final boolean anySimReady;
        public final int[] subscriptionIds;

        CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
        @VisibleForTesting
        public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
                boolean anySimReady, int[] subscriptionIds) {
            this.carrierText = carrierText;
            this.listOfCarriers = listOfCarriers;
+60 −16
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.R.dimen;
import com.android.systemui.plugins.ActivityStarter;
@@ -134,6 +135,15 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
        mDeviceProvisionedController = deviceProvisionedController;
    }

    @VisibleForTesting
    public QSFooterImpl(Context context, AttributeSet attrs) {
        this(context, attrs,
                Dependency.get(ActivityStarter.class),
                Dependency.get(UserInfoController.class),
                Dependency.get(NetworkController.class),
                Dependency.get(DeviceProvisionedController.class));
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
@@ -476,12 +486,28 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
                mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
    }

    @VisibleForTesting
    protected int getSlotIndex(int subscriptionId) {
        return SubscriptionManager.getSlotIndex(subscriptionId);
    }

    @Override
    public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
        if (info.anySimReady) {
            boolean[] slotSeen = new boolean[SIM_SLOTS];
            if (info.listOfCarriers.length == info.subscriptionIds.length) {
                for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
                int slot = SubscriptionManager.getSlotIndex(info.subscriptionIds[i]);
                    int slot = getSlotIndex(info.subscriptionIds[i]);
                    if (slot >= SIM_SLOTS) {
                        Log.w(TAG, "updateInfoCarrier - slot: " + slot);
                        continue;
                    }
                    if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
                        Log.e(TAG,
                                "Invalid SIM slot index for subscription: "
                                        + info.subscriptionIds[i]);
                        continue;
                    }
                    mInfos[slot].visible = true;
                    slotSeen[slot] = true;
                    mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
@@ -493,16 +519,30 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
                        mCarrierGroups[i].setVisibility(View.GONE);
                    }
                }
            handleUpdateState();
            } else {
                // If there are sims ready but there are not the same number of carrier names as
                // subscription ids, just show the full text in the first slot
                mInfos[0].visible = true;
                mCarrierTexts[0].setText(info.carrierText);
                mCarrierGroups[0].setVisibility(View.VISIBLE);
                for (int i = 1; i < SIM_SLOTS; i++) {
                    mInfos[i].visible = false;
                    mCarrierTexts[i].setText("");
                    mCarrierGroups[i].setVisibility(View.GONE);
                }
            }
        } else {
            mInfos[0].visible = false;
            mInfos[1].visible = false;
            mCarrierTexts[0].setText(info.carrierText);
            mCarrierGroups[0].setVisibility(View.VISIBLE);
            mCarrierGroups[1].setVisibility(View.GONE);
            handleUpdateState();
            for (int i = 1; i < SIM_SLOTS; i++) {
                mInfos[i].visible = false;
                mCarrierTexts[i].setText("");
                mCarrierGroups[i].setVisibility(View.GONE);
            }
        }
        handleUpdateState();
    }

    @Override
    public void setMobileDataIndicators(NetworkController.IconState statusIcon,
@@ -510,9 +550,14 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
            int qsType, boolean activityIn, boolean activityOut,
            String typeContentDescription,
            String description, boolean isWide, int subId, boolean roaming) {
        int slotIndex = SubscriptionManager.getSlotIndex(subId);
        int slotIndex = getSlotIndex(subId);
        if (slotIndex >= SIM_SLOTS) {
            Log.e(TAG, "setMobileDataIndicators - slot: " + slotIndex);
            Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
            return;
        }
        if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
            Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
            return;
        }
        mInfos[slotIndex].visible = statusIcon.visible;
        mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
@@ -539,7 +584,6 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
        boolean roaming;
    }


    /**
     * TextView that changes its ellipsize value with its visibility.
     */
+121 −0
Original line number Diff line number Diff line
@@ -16,27 +16,35 @@ package com.android.systemui.qs;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.support.test.filters.SmallTest;
import android.telephony.SubscriptionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.View;

import com.android.keyguard.CarrierTextController.CarrierTextCallbackInfo;
import com.android.systemui.R;
import com.android.systemui.R.id;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.utils.leaks.LeakCheckedTest;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -68,4 +76,117 @@ public class QSFooterImplTest extends LeakCheckedTest {
        // Verify Settings wasn't launched.
        verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
    }

    @Test // throws no Exception
    public void testUpdateCarrierText_sameLengts() {
        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
        when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
                new Answer<Integer>() {
                    @Override
                    public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
                        return invocationOnMock.getArgument(0);
                    }
                });

        // listOfCarriers length 1, subscriptionIds length 1, anySims false
        CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{""},
                false,
                new int[]{0});
        spiedFooter.updateCarrierInfo(c1);

        // listOfCarriers length 1, subscriptionIds length 1, anySims true
        CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{""},
                true,
                new int[]{0});
        spiedFooter.updateCarrierInfo(c2);

        // listOfCarriers length 2, subscriptionIds length 2, anySims false
        CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{"", ""},
                false,
                new int[]{0, 1});
        spiedFooter.updateCarrierInfo(c3);

        // listOfCarriers length 2, subscriptionIds length 2, anySims true
        CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{"", ""},
                true,
                new int[]{0, 1});
        spiedFooter.updateCarrierInfo(c4);
    }

    @Test // throws no Exception
    public void testUpdateCarrierText_differentLength() {
        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
        when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
                new Answer<Integer>() {
                    @Override
                    public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
                        return invocationOnMock.getArgument(0);
                    }
                });

        // listOfCarriers length 2, subscriptionIds length 1, anySims false
        CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{"", ""},
                false,
                new int[]{0});
        spiedFooter.updateCarrierInfo(c1);

        // listOfCarriers length 2, subscriptionIds length 1, anySims true
        CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{"", ""},
                true,
                new int[]{0});
        spiedFooter.updateCarrierInfo(c2);

        // listOfCarriers length 1, subscriptionIds length 2, anySims false
        CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{""},
                false,
                new int[]{0, 1});
        spiedFooter.updateCarrierInfo(c3);

        // listOfCarriers length 1, subscriptionIds length 2, anySims true
        CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{""},
                true,
                new int[]{0, 1});
        spiedFooter.updateCarrierInfo(c4);
    }

    @Test // throws no Exception
    public void testUpdateCarrierText_invalidSim() {
        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
        when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
                SubscriptionManager.INVALID_SIM_SLOT_INDEX);
        CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
                "",
                new CharSequence[]{"", ""},
                true,
                new int[]{0, 1});
        spiedFooter.updateCarrierInfo(c4);
    }

    @Test // throws no Exception
    public void testSetMobileDataIndicators_invalidSim() {
        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
        when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
                SubscriptionManager.INVALID_SIM_SLOT_INDEX);
        spiedFooter.setMobileDataIndicators(
                mock(NetworkController.IconState.class),
                mock(NetworkController.IconState.class),
                0, 0, true, true, "", "", true, 0, true);
    }

}