Move logic from QSCarrierGroup into Controller.

This removes the injection into the QSCarrierGroup view
and moves it into an associated controller instead.

Controllers are added for QSCarrierGroup, QSContainer,
and QuickStatusBarHeader, though only QSCarrierGroup does
any heavy lifting at the moment. The other controllers are
parent controllers that are needed to ensure everything is
cleanly initialized when the view is inflated.

Bug: 144503618
Test: atest SystemUITests && manual
Change-Id: Iee539b492581f84b25811a9ae2d60426b49b075d
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java
new file mode 100644
index 0000000..1bfe1b1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.telephony.SubscriptionManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.CarrierTextController;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.utils.leaks.LeakCheckedTest;
+import com.android.systemui.utils.os.FakeHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class QSCarrierGroupControllerTest extends LeakCheckedTest {
+
+    private QSCarrierGroupController mQSCarrierGroupController;
+    private NetworkController.SignalCallback mSignalCallback;
+    private CarrierTextController.CarrierTextCallback mCallback;
+    @Mock
+    private QSCarrierGroup mQSCarrierGroup;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private NetworkController mNetworkController;
+    @Mock
+    private CarrierTextController.Builder mCarrierTextControllerBuilder;
+    @Mock
+    private CarrierTextController mCarrierTextController;
+    private TestableLooper mTestableLooper;
+
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+        mTestableLooper = TestableLooper.get(this);
+        Handler handler = new FakeHandler(TestableLooper.get(this).getLooper());
+
+        when(mNetworkController.hasVoiceCallingFeature()).thenReturn(true);
+        doAnswer(invocation -> mSignalCallback = invocation.getArgument(0))
+                .when(mNetworkController)
+                .addCallback(any(NetworkController.SignalCallback.class));
+
+        when(mCarrierTextControllerBuilder.setShowAirplaneMode(anyBoolean()))
+                .thenReturn(mCarrierTextControllerBuilder);
+        when(mCarrierTextControllerBuilder.setShowMissingSim(anyBoolean()))
+                .thenReturn(mCarrierTextControllerBuilder);
+        when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextController);
+
+        doAnswer(invocation -> mCallback = invocation.getArgument(0))
+                .when(mCarrierTextController)
+                .setListening(any(CarrierTextController.CarrierTextCallback.class));
+
+        when(mQSCarrierGroup.getNoSimTextView()).thenReturn(new TextView(mContext));
+        when(mQSCarrierGroup.getCarrier1View()).thenReturn(mock(QSCarrier.class));
+        when(mQSCarrierGroup.getCarrier2View()).thenReturn(mock(QSCarrier.class));
+        when(mQSCarrierGroup.getCarrier3View()).thenReturn(mock(QSCarrier.class));
+        when(mQSCarrierGroup.getCarrierDivider1()).thenReturn(new View(mContext));
+        when(mQSCarrierGroup.getCarrierDivider2()).thenReturn(new View(mContext));
+
+        mQSCarrierGroupController = new QSCarrierGroupController.Builder(
+                mActivityStarter, handler, TestableLooper.get(this).getLooper(),
+                mNetworkController, mCarrierTextControllerBuilder)
+                .setQSCarrierGroup(mQSCarrierGroup)
+                .build();
+
+        mQSCarrierGroupController.setListening(true);
+    }
+
+    @Test // throws no Exception
+    public void testUpdateCarrierText_sameLengths() {
+        QSCarrierGroupController spiedCarrierGroupController =
+                Mockito.spy(mQSCarrierGroupController);
+        when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer(
+                (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0));
+
+        // listOfCarriers length 1, subscriptionIds length 1, anySims false
+        CarrierTextController.CarrierTextCallbackInfo
+                c1 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                false,
+                new int[]{0});
+        mCallback.updateCarrierInfo(c1);
+
+        // listOfCarriers length 1, subscriptionIds length 1, anySims true
+        CarrierTextController.CarrierTextCallbackInfo
+                c2 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                true,
+                new int[]{0});
+        mCallback.updateCarrierInfo(c2);
+
+        // listOfCarriers length 2, subscriptionIds length 2, anySims false
+        CarrierTextController.CarrierTextCallbackInfo
+                c3 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                false,
+                new int[]{0, 1});
+        mCallback.updateCarrierInfo(c3);
+
+        // listOfCarriers length 2, subscriptionIds length 2, anySims true
+        CarrierTextController.CarrierTextCallbackInfo
+                c4 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                true,
+                new int[]{0, 1});
+        mCallback.updateCarrierInfo(c4);
+
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test // throws no Exception
+    public void testUpdateCarrierText_differentLength() {
+        QSCarrierGroupController spiedCarrierGroupController =
+                Mockito.spy(mQSCarrierGroupController);
+        when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer(
+                (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0));
+
+        // listOfCarriers length 2, subscriptionIds length 1, anySims false
+        CarrierTextController.CarrierTextCallbackInfo
+                c1 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                false,
+                new int[]{0});
+        mCallback.updateCarrierInfo(c1);
+
+        // listOfCarriers length 2, subscriptionIds length 1, anySims true
+        CarrierTextController.CarrierTextCallbackInfo
+                c2 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                true,
+                new int[]{0});
+        mCallback.updateCarrierInfo(c2);
+
+        // listOfCarriers length 1, subscriptionIds length 2, anySims false
+        CarrierTextController.CarrierTextCallbackInfo
+                c3 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                false,
+                new int[]{0, 1});
+        mCallback.updateCarrierInfo(c3);
+
+        // listOfCarriers length 1, subscriptionIds length 2, anySims true
+        CarrierTextController.CarrierTextCallbackInfo
+                c4 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                true,
+                new int[]{0, 1});
+        mCallback.updateCarrierInfo(c4);
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test // throws no Exception
+    public void testUpdateCarrierText_invalidSim() {
+        QSCarrierGroupController spiedCarrierGroupController =
+                Mockito.spy(mQSCarrierGroupController);
+        when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn(
+                SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+
+        CarrierTextController.CarrierTextCallbackInfo
+                c4 = new CarrierTextController.CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                true,
+                new int[]{0, 1});
+        mCallback.updateCarrierInfo(c4);
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test // throws no Exception
+    public void testSetMobileDataIndicators_invalidSim() {
+        mSignalCallback.setMobileDataIndicators(
+                mock(NetworkController.IconState.class),
+                mock(NetworkController.IconState.class),
+                0, 0, true, true, "", "", true, 0, true);
+    }
+}