summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/keyguard/CarrierTextController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java294
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java331
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java)102
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java4
11 files changed, 577 insertions, 330 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 06aba405fa3e..d66a53cd9012 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -24,6 +24,7 @@ import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
@@ -42,11 +43,14 @@ import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainResources;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import java.util.List;
import java.util.Objects;
+import javax.inject.Inject;
+
/**
* Controller that generates text including the carrier names and/or the status of all the SIM
* interfaces in the device. Through a callback, the updates can be retrieved either as a list or
@@ -598,6 +602,35 @@ public class CarrierTextController {
return mContext.getText(carrierHelpTextId);
}
+ public static class Builder {
+ private final Context mContext;
+ private final String mSeparator;
+ private boolean mShowAirplaneMode;
+ private boolean mShowMissingSim;
+
+ @Inject
+ public Builder(Context context, @MainResources Resources resources) {
+ mContext = context;
+ mSeparator = resources.getString(
+ com.android.internal.R.string.kg_text_message_separator);
+ }
+
+
+ public Builder setShowAirplaneMode(boolean showAirplaneMode) {
+ mShowAirplaneMode = showAirplaneMode;
+ return this;
+ }
+
+ public Builder setShowMissingSim(boolean showMissingSim) {
+ mShowMissingSim = showMissingSim;
+ return this;
+ }
+
+ public CarrierTextController build() {
+ return new CarrierTextController(
+ mContext, mSeparator, mShowAirplaneMode, mShowMissingSim);
+ }
+ }
/**
* Data structure for passing information to CarrierTextController subscribers
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
index 4501b8f0a469..4c7d82e99d06 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
@@ -73,7 +73,7 @@ public class QSCarrier extends LinearLayout {
mColorForegroundIntensity = QuickStatusBarHeader.getColorIntensity(colorForeground);
}
- public void updateState(QSCarrierGroup.CellSignalState state) {
+ public void updateState(QSCarrierGroupController.CellSignalState state) {
mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
if (state.visible) {
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
index 5742787b39bc..346c75da6a89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
@@ -16,309 +16,43 @@
package com.android.systemui.qs;
-import static com.android.systemui.Dependency.BG_HANDLER;
-import static com.android.systemui.Dependency.MAIN_LOOPER;
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
-import android.annotation.MainThread;
import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.telephony.SubscriptionManager;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
-import androidx.annotation.VisibleForTesting;
-
-import com.android.keyguard.CarrierTextController;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.MainLooper;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.policy.NetworkController;
-
-import java.util.function.Consumer;
-
-import javax.inject.Inject;
-import javax.inject.Named;
/**
* Displays Carrier name and network status in QS
*/
-public class QSCarrierGroup extends LinearLayout implements
- NetworkController.SignalCallback, View.OnClickListener {
-
- private static final String TAG = "QSCarrierGroup";
- /**
- * Support up to 3 slots which is what's supported by {@link TelephonyManager#getPhoneCount}
- */
- private static final int SIM_SLOTS = 3;
- private final NetworkController mNetworkController;
- private final Handler mBgHandler;
- private final H mMainHandler;
-
- private View[] mCarrierDividers = new View[SIM_SLOTS - 1];
- private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
- private TextView mNoSimTextView;
- private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS];
- private CarrierTextController mCarrierTextController;
- private CarrierTextController.CarrierTextCallback mCallback;
- private ActivityStarter mActivityStarter;
-
- private boolean mListening;
-
- @Inject
- public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- NetworkController networkController, ActivityStarter activityStarter,
- @BgHandler Handler handler,
- @MainLooper Looper looper) {
- super(context, attrs);
- mNetworkController = networkController;
- mActivityStarter = activityStarter;
- mBgHandler = handler;
- mMainHandler = new H(looper, this::handleUpdateCarrierInfo, this::handleUpdateState);
- mCallback = new Callback(mMainHandler);
- }
-
- @VisibleForTesting
- protected CarrierTextController.CarrierTextCallback getCallback() {
- return mCallback;
- }
-
- @VisibleForTesting
+public class QSCarrierGroup extends LinearLayout {
public QSCarrierGroup(Context context, AttributeSet attrs) {
- this(context, attrs,
- Dependency.get(NetworkController.class),
- Dependency.get(ActivityStarter.class),
- Dependency.get(BG_HANDLER),
- Dependency.get(MAIN_LOOPER));
- }
-
- @Override
- public void onClick(View v) {
- if (!v.isVisibleToUser()) return;
- mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
- Settings.ACTION_WIRELESS_SETTINGS), 0);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mCarrierGroups[0] = findViewById(R.id.carrier1);
- mCarrierGroups[1] = findViewById(R.id.carrier2);
- mCarrierGroups[2] = findViewById(R.id.carrier3);
-
- mCarrierDividers[0] = findViewById(R.id.qs_carrier_divider1);
- mCarrierDividers[1] = findViewById(R.id.qs_carrier_divider2);
-
- mNoSimTextView = findViewById(R.id.no_carrier_text);
-
- for (int i = 0; i < SIM_SLOTS; i++) {
- mInfos[i] = new CellSignalState();
- mCarrierGroups[i].setOnClickListener(this);
- }
- mNoSimTextView.setOnClickListener(this);
-
- CharSequence separator = mContext.getString(
- com.android.internal.R.string.kg_text_message_separator);
- mCarrierTextController = new CarrierTextController(mContext, separator, false, false);
- setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
-
- public void setListening(boolean listening) {
- if (listening == mListening) {
- return;
- }
- mListening = listening;
- mBgHandler.post(this::updateListeners);
- }
-
- @Override
- @VisibleForTesting
- public void onDetachedFromWindow() {
- setListening(false);
- super.onDetachedFromWindow();
- }
-
- private void updateListeners() {
- if (mListening) {
- if (mNetworkController.hasVoiceCallingFeature()) {
- mNetworkController.addCallback(this);
- }
- mCarrierTextController.setListening(mCallback);
- } else {
- mNetworkController.removeCallback(this);
- mCarrierTextController.setListening(null);
- }
- }
-
- @MainThread
- private void handleUpdateState() {
- if (!mMainHandler.getLooper().isCurrentThread()) {
- mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
- return;
- }
-
- for (int i = 0; i < SIM_SLOTS; i++) {
- mCarrierGroups[i].updateState(mInfos[i]);
- }
-
- mCarrierDividers[0].setVisibility(
- mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
- // This tackles the case of slots 2 being available as well as at least one other.
- // In that case we show the second divider. Note that if both dividers are visible, it means
- // all three slots are in use, and that is correct.
- mCarrierDividers[1].setVisibility(
- (mInfos[1].visible && mInfos[2].visible)
- || (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE);
- }
-
- @VisibleForTesting
- protected int getSlotIndex(int subscriptionId) {
- return SubscriptionManager.getSlotIndex(subscriptionId);
+ super(context, attrs);
}
- @MainThread
- private void handleUpdateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
- if (!mMainHandler.getLooper().isCurrentThread()) {
- mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget();
- return;
- }
-
- mNoSimTextView.setVisibility(View.GONE);
- if (!info.airplaneMode && 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 = 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;
- mCarrierGroups[slot].setCarrierText(
- info.listOfCarriers[i].toString().trim());
- mCarrierGroups[slot].setVisibility(View.VISIBLE);
- }
- for (int i = 0; i < SIM_SLOTS; i++) {
- if (!slotSeen[i]) {
- mInfos[i].visible = false;
- mCarrierGroups[i].setVisibility(View.GONE);
- }
- }
- } else {
- Log.e(TAG, "Carrier information arrays not of same length");
- }
- } else {
- // No sims or airplane mode (but not WFC). Do not show QSCarrierGroup, instead just show
- // info.carrierText in a different view.
- for (int i = 0; i < SIM_SLOTS; i++) {
- mInfos[i].visible = false;
- mCarrierGroups[i].setCarrierText("");
- mCarrierGroups[i].setVisibility(View.GONE);
- }
- mNoSimTextView.setText(info.carrierText);
- mNoSimTextView.setVisibility(View.VISIBLE);
- }
- handleUpdateState(); // handleUpdateCarrierInfo is always called from main thread.
+ TextView getNoSimTextView() {
+ return findViewById(R.id.no_carrier_text);
}
- @Override
- public void setMobileDataIndicators(NetworkController.IconState statusIcon,
- NetworkController.IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut,
- String typeContentDescription,
- String description, boolean isWide, int subId, boolean roaming) {
- int slotIndex = getSlotIndex(subId);
- if (slotIndex >= SIM_SLOTS) {
- 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;
- mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
- mInfos[slotIndex].typeContentDescription = typeContentDescription;
- mInfos[slotIndex].roaming = roaming;
- mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ QSCarrier getCarrier1View() {
+ return findViewById(R.id.carrier1);
}
- @Override
- public void setNoSims(boolean hasNoSims, boolean simDetected) {
- if (hasNoSims) {
- for (int i = 0; i < SIM_SLOTS; i++) {
- mInfos[i].visible = false;
- }
- }
- mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ QSCarrier getCarrier2View() {
+ return findViewById(R.id.carrier2);
}
- static final class CellSignalState {
- boolean visible;
- int mobileSignalIconId;
- String contentDescription;
- String typeContentDescription;
- boolean roaming;
+ QSCarrier getCarrier3View() {
+ return findViewById(R.id.carrier3);
}
- private static class H extends Handler {
- private Consumer<CarrierTextController.CarrierTextCallbackInfo> mUpdateCarrierInfo;
- private Runnable mUpdateState;
- static final int MSG_UPDATE_CARRIER_INFO = 0;
- static final int MSG_UPDATE_STATE = 1;
-
- H(Looper looper,
- Consumer<CarrierTextController.CarrierTextCallbackInfo> updateCarrierInfo,
- Runnable updateState) {
- super(looper);
- mUpdateCarrierInfo = updateCarrierInfo;
- mUpdateState = updateState;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE_CARRIER_INFO:
- mUpdateCarrierInfo.accept(
- (CarrierTextController.CarrierTextCallbackInfo) msg.obj);
- break;
- case MSG_UPDATE_STATE:
- mUpdateState.run();
- break;
- default:
- super.handleMessage(msg);
- }
- }
+ View getCarrierDivider1() {
+ return findViewById(R.id.qs_carrier_divider1);
}
- private static class Callback implements CarrierTextController.CarrierTextCallback {
- private H mMainHandler;
-
- Callback(H handler) {
- mMainHandler = handler;
- }
-
- @Override
- public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
- mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget();
- }
+ View getCarrierDivider2() {
+ return findViewById(R.id.qs_carrier_divider2);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java
new file mode 100644
index 000000000000..ac94858cff27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java
@@ -0,0 +1,331 @@
+/*
+ * 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 android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+
+import android.annotation.MainThread;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.keyguard.CarrierTextController;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.MainLooper;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+import java.util.function.Consumer;
+
+import javax.inject.Inject;
+
+public class QSCarrierGroupController {
+ private static final String TAG = "QSCarrierGroup";
+
+ /**
+ * Support up to 3 slots which is what's supported by {@link TelephonyManager#getPhoneCount}
+ */
+ private static final int SIM_SLOTS = 3;
+
+ private final ActivityStarter mActivityStarter;
+ private final Handler mBgHandler;
+ private final NetworkController mNetworkController;
+ private final CarrierTextController mCarrierTextController;
+ private final TextView mNoSimTextView;
+ private final H mMainHandler;
+ private final Callback mCallback;
+ private boolean mListening;
+ private final CellSignalState[] mInfos =
+ new CellSignalState[SIM_SLOTS];
+ private View[] mCarrierDividers = new View[SIM_SLOTS - 1];
+ private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
+
+ private final NetworkController.SignalCallback mSignalCallback =
+ new NetworkController.SignalCallback() {
+ @Override
+ public void setMobileDataIndicators(NetworkController.IconState statusIcon,
+ NetworkController.IconState qsIcon, int statusType, int qsType,
+ boolean activityIn, boolean activityOut, String typeContentDescription,
+ String description, boolean isWide, int subId, boolean roaming) {
+ int slotIndex = getSlotIndex(subId);
+ if (slotIndex >= SIM_SLOTS) {
+ 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;
+ mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
+ mInfos[slotIndex].typeContentDescription = typeContentDescription;
+ mInfos[slotIndex].roaming = roaming;
+ mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ }
+
+ @Override
+ public void setNoSims(boolean hasNoSims, boolean simDetected) {
+ if (hasNoSims) {
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mInfos[i].visible = false;
+ }
+ }
+ mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ }
+ };
+
+ private static class Callback implements CarrierTextController.CarrierTextCallback {
+ private H mHandler;
+
+ Callback(H handler) {
+ mHandler = handler;
+ }
+
+ @Override
+ public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
+ mHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget();
+ }
+ }
+
+ private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter,
+ @BgHandler Handler bgHandler, @MainLooper Looper mainLooper,
+ NetworkController networkController,
+ CarrierTextController.Builder carrierTextControllerBuilder) {
+ mActivityStarter = activityStarter;
+ mBgHandler = bgHandler;
+ mNetworkController = networkController;
+ mCarrierTextController = carrierTextControllerBuilder
+ .setShowAirplaneMode(false)
+ .setShowMissingSim(false)
+ .build();
+
+ View.OnClickListener onClickListener = v -> {
+ if (!v.isVisibleToUser()) {
+ return;
+ }
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ new Intent(Settings.ACTION_WIRELESS_SETTINGS), 0);
+ };
+ view.setOnClickListener(onClickListener);
+ mNoSimTextView = view.getNoSimTextView();
+ mNoSimTextView.setOnClickListener(onClickListener);
+ mMainHandler = new H(mainLooper, this::handleUpdateCarrierInfo, this::handleUpdateState);
+ mCallback = new Callback(mMainHandler);
+
+
+ mCarrierGroups[0] = view.getCarrier1View();
+ mCarrierGroups[1] = view.getCarrier2View();
+ mCarrierGroups[2] = view.getCarrier3View();
+
+ mCarrierDividers[0] = view.getCarrierDivider1();
+ mCarrierDividers[1] = view.getCarrierDivider2();
+
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mInfos[i] = new CellSignalState();
+ mCarrierGroups[i].setOnClickListener(onClickListener);
+ }
+ view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+ view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ setListening(false);
+ }
+ });
+ }
+
+ @VisibleForTesting
+ protected int getSlotIndex(int subscriptionId) {
+ return SubscriptionManager.getSlotIndex(subscriptionId);
+ }
+
+ public void setListening(boolean listening) {
+ if (listening == mListening) {
+ return;
+ }
+ mListening = listening;
+
+ mBgHandler.post(this::updateListeners);
+ }
+
+ private void updateListeners() {
+ if (mListening) {
+ if (mNetworkController.hasVoiceCallingFeature()) {
+ mNetworkController.addCallback(mSignalCallback);
+ }
+ mCarrierTextController.setListening(mCallback);
+ } else {
+ mNetworkController.removeCallback(mSignalCallback);
+ mCarrierTextController.setListening(null);
+ }
+ }
+
+
+ @MainThread
+ private void handleUpdateState() {
+ if (!mMainHandler.getLooper().isCurrentThread()) {
+ mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ return;
+ }
+
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mCarrierGroups[i].updateState(mInfos[i]);
+ }
+
+ mCarrierDividers[0].setVisibility(
+ mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
+ // This tackles the case of slots 2 being available as well as at least one other.
+ // In that case we show the second divider. Note that if both dividers are visible, it means
+ // all three slots are in use, and that is correct.
+ mCarrierDividers[1].setVisibility(
+ (mInfos[1].visible && mInfos[2].visible)
+ || (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE);
+ }
+
+ @MainThread
+ private void handleUpdateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
+ if (!mMainHandler.getLooper().isCurrentThread()) {
+ mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget();
+ return;
+ }
+
+ mNoSimTextView.setVisibility(View.GONE);
+ if (!info.airplaneMode && 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 = 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;
+ mCarrierGroups[slot].setCarrierText(
+ info.listOfCarriers[i].toString().trim());
+ mCarrierGroups[slot].setVisibility(View.VISIBLE);
+ }
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ if (!slotSeen[i]) {
+ mInfos[i].visible = false;
+ mCarrierGroups[i].setVisibility(View.GONE);
+ }
+ }
+ } else {
+ Log.e(TAG, "Carrier information arrays not of same length");
+ }
+ } else {
+ // No sims or airplane mode (but not WFC). Do not show QSCarrierGroup, instead just show
+ // info.carrierText in a different view.
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mInfos[i].visible = false;
+ mCarrierGroups[i].setCarrierText("");
+ mCarrierGroups[i].setVisibility(View.GONE);
+ }
+ mNoSimTextView.setText(info.carrierText);
+ mNoSimTextView.setVisibility(View.VISIBLE);
+ }
+ handleUpdateState(); // handleUpdateCarrierInfo is always called from main thread.
+ }
+
+ private static class H extends Handler {
+ private Consumer<CarrierTextController.CarrierTextCallbackInfo> mUpdateCarrierInfo;
+ private Runnable mUpdateState;
+ static final int MSG_UPDATE_CARRIER_INFO = 0;
+ static final int MSG_UPDATE_STATE = 1;
+
+ H(Looper looper,
+ Consumer<CarrierTextController.CarrierTextCallbackInfo> updateCarrierInfo,
+ Runnable updateState) {
+ super(looper);
+ mUpdateCarrierInfo = updateCarrierInfo;
+ mUpdateState = updateState;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_CARRIER_INFO:
+ mUpdateCarrierInfo.accept(
+ (CarrierTextController.CarrierTextCallbackInfo) msg.obj);
+ break;
+ case MSG_UPDATE_STATE:
+ mUpdateState.run();
+ break;
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ }
+
+ static final class CellSignalState {
+ boolean visible;
+ int mobileSignalIconId;
+ String contentDescription;
+ String typeContentDescription;
+ boolean roaming;
+ }
+
+ public static class Builder {
+ private QSCarrierGroup mView;
+ private final ActivityStarter mActivityStarter;
+ private final Handler mHandler;
+ private final Looper mLooper;
+ private final NetworkController mNetworkController;
+ private final CarrierTextController.Builder mCarrierTextControllerBuilder;
+
+ @Inject
+ public Builder(ActivityStarter activityStarter, @BgHandler Handler handler,
+ @MainLooper Looper looper, NetworkController networkController,
+ CarrierTextController.Builder carrierTextControllerBuilder) {
+ mActivityStarter = activityStarter;
+ mHandler = handler;
+ mLooper = looper;
+ mNetworkController = networkController;
+ mCarrierTextControllerBuilder = carrierTextControllerBuilder;
+ }
+
+ Builder setQSCarrierGroup(QSCarrierGroup view) {
+ mView = view;
+ return this;
+ }
+
+ public QSCarrierGroupController build() {
+ return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
+ mNetworkController, mCarrierTextControllerBuilder);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
new file mode 100644
index 000000000000..fa3328417bd6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.android.systemui.R;
+
+import javax.inject.Inject;
+
+public class QSContainerImplController {
+ private final QSContainerImpl mView;
+ private final QuickStatusBarHeaderController mQuickStatusBarHeaderController;
+
+ private QSContainerImplController(QSContainerImpl view,
+ QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) {
+ mView = view;
+ mQuickStatusBarHeaderController = quickStatusBarHeaderControllerBuilder
+ .setQuickStatusBarHeader(mView.findViewById(R.id.header)).build();
+ }
+
+ public void setListening(boolean listening) {
+ mQuickStatusBarHeaderController.setListening(listening);
+ }
+
+ public static class Builder {
+ private final QuickStatusBarHeaderController.Builder mQuickStatusBarHeaderControllerBuilder;
+ private QSContainerImpl mView;
+
+ @Inject
+ public Builder(
+ QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) {
+ mQuickStatusBarHeaderControllerBuilder = quickStatusBarHeaderControllerBuilder;
+ }
+
+ public Builder setQSContainerImpl(QSContainerImpl view) {
+ mView = view;
+ return this;
+ }
+
+ public QSContainerImplController build() {
+ return new QSContainerImplController(mView, mQuickStatusBarHeaderControllerBuilder);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index ccc836f50c7b..5b09267a9e68 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -18,7 +18,6 @@ import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
@@ -81,6 +80,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final InjectionInflationController mInjectionInflater;
+ private final QSContainerImplController.Builder mQSContainerImplControllerBuilder;
private final QSTileHost mHost;
private boolean mShowCollapsedOnKeyguard;
private boolean mLastKeyguardAndExpanded;
@@ -90,15 +90,16 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
* during state transitions which often call into us.
*/
private int mState;
+ private QSContainerImplController mQSContainerImplController;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
- InjectionInflationController injectionInflater,
- Context context,
- QSTileHost qsTileHost,
- StatusBarStateController statusBarStateController, CommandQueue commandQueue) {
+ InjectionInflationController injectionInflater, QSTileHost qsTileHost,
+ StatusBarStateController statusBarStateController, CommandQueue commandQueue,
+ QSContainerImplController.Builder qsContainerImplControllerBuilder) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mInjectionInflater = injectionInflater;
+ mQSContainerImplControllerBuilder = qsContainerImplControllerBuilder;
commandQueue.observe(getLifecycle(), this);
mHost = qsTileHost;
mStatusBarStateController = statusBarStateController;
@@ -121,6 +122,11 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mFooter = view.findViewById(R.id.qs_footer);
mContainer = view.findViewById(id.quick_settings_container);
+ mQSContainerImplController = mQSContainerImplControllerBuilder
+ .setQSContainerImpl((QSContainerImpl) view)
+ .build();
+
+
mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter);
mQSAnimator = new QSAnimator(this,
mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
@@ -340,6 +346,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
public void setListening(boolean listening) {
if (DEBUG) Log.d(TAG, "setListening " + listening);
mListening = listening;
+ mQSContainerImplController.setListening(listening);
mHeader.setListening(listening);
mFooter.setListening(listening);
mQSPanel.setListening(mListening, mQsExpanded);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 19af235b4f68..02e8f5909793 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -549,7 +549,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
}
mHeaderQsPanel.setListening(listening);
mListening = listening;
- mCarrierGroup.setListening(mListening);
if (listening) {
mZenController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
new file mode 100644
index 000000000000..867677a46a58
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.android.systemui.R;
+
+import javax.inject.Inject;
+
+public class QuickStatusBarHeaderController {
+ private final QuickStatusBarHeader mView;
+ private final QSCarrierGroupController mQSCarrierGroupController;
+
+ private QuickStatusBarHeaderController(QuickStatusBarHeader view,
+ QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
+ mView = view;
+ mQSCarrierGroupController = qsCarrierGroupControllerBuilder
+ .setQSCarrierGroup(mView.findViewById(R.id.carrier_group))
+ .build();
+ }
+
+ public void setListening(boolean listening) {
+ mQSCarrierGroupController.setListening(listening);
+ // TODO: move mView.setListening logic into here.
+ mView.setListening(listening);
+ }
+
+
+ public static class Builder {
+ private final QSCarrierGroupController.Builder mQSCarrierGroupControllerBuilder;
+ private QuickStatusBarHeader mView;
+
+ @Inject
+ public Builder(QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
+ mQSCarrierGroupControllerBuilder = qsCarrierGroupControllerBuilder;
+ }
+
+ public Builder setQuickStatusBarHeader(QuickStatusBarHeader view) {
+ mView = view;
+ return this;
+ }
+
+ public QuickStatusBarHeaderController build() {
+ return new QuickStatusBarHeaderController(mView, mQSCarrierGroupControllerBuilder);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index 60d76789ff63..6976649ec497 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -27,7 +27,6 @@ import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.dagger.SystemUIRootComponent;
-import com.android.systemui.qs.QSCarrierGroup;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
@@ -135,11 +134,6 @@ public class InjectionInflationController {
NotificationPanelView createPanelView();
/**
- * Creates the QSCarrierGroup
- */
- QSCarrierGroup createQSCarrierGroup();
-
- /**
* Creates the Shelf.
*/
NotificationShelf creatNotificationShelf();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java
index a2a20a9538fc..1bfe1b10299b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupControllerTest.java
@@ -16,7 +16,10 @@
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;
@@ -24,55 +27,89 @@ import android.os.Handler;
import android.telephony.SubscriptionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextController;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
+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.invocation.InvocationOnMock;
+import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
-public class QSCarrierGroupTest extends LeakCheckedTest {
+public class QSCarrierGroupControllerTest extends LeakCheckedTest {
- private QSCarrierGroup mCarrierGroup;
+ 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);
- mDependency.injectTestDependency(
- Dependency.BG_HANDLER, new Handler(mTestableLooper.getLooper()));
- mDependency.injectTestDependency(Dependency.MAIN_LOOPER, mTestableLooper.getLooper());
- mTestableLooper.runWithLooper(
- () -> mCarrierGroup = (QSCarrierGroup) LayoutInflater.from(mContext).inflate(
- R.layout.qs_carrier_group, null));
- mCallback = mCarrierGroup.getCallback();
+ 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() {
- QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup);
- when(spiedCarrierGroup.getSlotIndex(anyInt())).thenAnswer(
- new Answer<Integer>() {
- @Override
- public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
- return invocationOnMock.getArgument(0);
- }
- });
+ 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
@@ -115,14 +152,10 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
@Test // throws no Exception
public void testUpdateCarrierText_differentLength() {
- QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup);
- when(spiedCarrierGroup.getSlotIndex(anyInt())).thenAnswer(
- new Answer<Integer>() {
- @Override
- public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
- return invocationOnMock.getArgument(0);
- }
- });
+ 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
@@ -164,9 +197,11 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
@Test // throws no Exception
public void testUpdateCarrierText_invalidSim() {
- QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup);
- when(spiedCarrierGroup.getSlotIndex(anyInt())).thenReturn(
+ QSCarrierGroupController spiedCarrierGroupController =
+ Mockito.spy(mQSCarrierGroupController);
+ when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn(
SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+
CarrierTextController.CarrierTextCallbackInfo
c4 = new CarrierTextController.CarrierTextCallbackInfo(
"",
@@ -179,10 +214,7 @@ public class QSCarrierGroupTest extends LeakCheckedTest {
@Test // throws no Exception
public void testSetMobileDataIndicators_invalidSim() {
- QSCarrierGroup spiedCarrierGroup = Mockito.spy(mCarrierGroup);
- when(spiedCarrierGroup.getSlotIndex(anyInt())).thenReturn(
- SubscriptionManager.INVALID_SIM_SLOT_INDEX);
- spiedCarrierGroup.setMobileDataIndicators(
+ mSignalCallback.setMobileDataIndicators(
mock(NetworkController.IconState.class),
mock(NetworkController.IconState.class),
0, 0, true, true, "", "", true, 0, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 6cebb1206efe..800456228e84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -147,9 +147,9 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class),
commandQueue),
new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
- context,
mock(QSTileHost.class),
mock(StatusBarStateController.class),
- commandQueue);
+ commandQueue,
+ mock(QSContainerImplController.Builder.class));
}
}