QSFooterImpl shows multiple carriers
QSFooter now shows up to two subscriptions with corresponding signal
rate graphic.
Modified CarrierTextCallback to pass an info struct.
Pending design guidelines.
Test: manual using DSDS
Bug: 113343186
Change-Id: Ic98d52ae59139132533a86fcc279a4f64c98c91e
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index 8069ce4..adcb7a1 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -42,8 +42,8 @@
private CarrierTextController.CarrierTextCallback mCarrierTextCallback =
new CarrierTextController.CarrierTextCallback() {
@Override
- public void updateCarrierText(CharSequence carrierText, boolean simsReady) {
- setText(carrierText);
+ public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
+ setText(info.carrierText);
}
@Override
@@ -53,7 +53,7 @@
@Override
public void finishedWakingUp() {
- setSelected(mShouldMarquee);
+ setSelected(true);
}
};
@@ -85,7 +85,6 @@
mShowMissingSim);
mShouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setSelected(mShouldMarquee); // Allow marquee to work.
-
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 3698a6e..2ce6965 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -46,17 +46,11 @@
private static final String TAG = "CarrierTextController";
private final boolean mIsEmergencyCallCapable;
-
private boolean mTelephonyCapable;
-
private boolean mShowMissingSim;
-
private boolean mShowAirplaneMode;
-
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-
private WifiManager mWifiManager;
-
private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
private CarrierTextCallback mCarrierTextCallback;
private Context mContext;
@@ -132,10 +126,8 @@
/**
* Controller that provides updates on text with carriers names or SIM status.
* Used by {@link CarrierText}.
- * @param context
+ *
* @param separator Separator between different parts of the text
- * @param showAirplaneMode
- * @param showMissingSim
*/
public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode,
boolean showMissingSim) {
@@ -186,6 +178,7 @@
/**
* Sets the listening status of this controller. If the callback is null, it is set to
* not listening
+ *
* @param callback Callback to provide text updates
*/
public void setListening(CarrierTextCallback callback) {
@@ -199,7 +192,7 @@
} else {
// Don't listen and clear out the text when the device isn't a phone.
mKeyguardUpdateMonitor = null;
- callback.updateCarrierText("", false);
+ callback.updateCarrierInfo(new CarrierTextCallbackInfo("", null, false, null));
}
} else {
mCarrierTextCallback = null;
@@ -217,9 +210,11 @@
List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
final int numSubs = subs.size();
+ final int[] subsIds = new int[numSubs];
if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs);
for (int i = 0; i < numSubs; i++) {
int subId = subs.get(i).getSubscriptionId();
+ subsIds[i] = subId;
IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
CharSequence carrierName = subs.get(i).getCarrierName();
CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
@@ -294,9 +289,11 @@
}
if (mCarrierTextCallback != null) {
- mCarrierTextCallback.updateCarrierText(displayText, anySimReadyAndInService);
- mCarrierTextCallback.updateCarrierList(
- displayText.toString().split(mSeparator.toString()), anySimReadyAndInService);
+ mCarrierTextCallback.updateCarrierInfo(new CarrierTextCallbackInfo(
+ displayText,
+ displayText.toString().split(mSeparator.toString()),
+ anySimReadyAndInService,
+ subsIds));
}
}
@@ -482,22 +479,31 @@
}
/**
+ * Data structure for passing information to CarrierTextController subscribers
+ */
+ public static final class CarrierTextCallbackInfo {
+ public final CharSequence carrierText;
+ public final CharSequence[] listOfCarriers;
+ public final boolean anySimReady;
+ public final int[] subscriptionIds;
+
+ CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
+ boolean anySimReady, int[] subscriptionIds) {
+ this.carrierText = carrierText;
+ this.listOfCarriers = listOfCarriers;
+ this.anySimReady = anySimReady;
+ this.subscriptionIds = subscriptionIds;
+ }
+ }
+
+ /**
* Callback to communicate to Views
*/
public interface CarrierTextCallback {
/**
- * Provides an updated list of carrier names
- * @param listOfCarriers
- * @param simsReady Whether at least one SIM is ready and with service
+ * Provides updated carrier information.
*/
- default void updateCarrierList(CharSequence[] listOfCarriers, boolean simsReady) {};
-
- /**
- * Provides an updated full carrier text
- * @param carrierText
- * @param simsReady Whether at least one SIM is ready and with service
- */
- default void updateCarrierText(CharSequence carrierText, boolean simsReady) {};
+ default void updateCarrierInfo(CarrierTextCallbackInfo info) {};
/**
* Notifies the View that the device is going to sleep
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index e63f88a..c0ed4b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -30,14 +30,18 @@
import android.graphics.drawable.RippleDrawable;
import android.os.Bundle;
import android.os.UserManager;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -45,7 +49,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.keyguard.CarrierText;
+import com.android.keyguard.CarrierTextController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.settingslib.drawable.UserIconDrawable;
@@ -68,7 +72,11 @@
import javax.inject.Named;
public class QSFooterImpl extends FrameLayout implements QSFooter,
- OnClickListener, OnUserInfoChangedListener, EmergencyListener, SignalCallback {
+ OnClickListener, OnUserInfoChangedListener, EmergencyListener, SignalCallback,
+ CarrierTextController.CarrierTextCallback {
+
+ private static final int SIM_SLOTS = 2;
+ private static final String TAG = "QSFooterImpl";
private final ActivityStarter mActivityStarter;
private final UserInfoController mUserInfoController;
@@ -77,7 +85,6 @@
private SettingsButton mSettingsButton;
protected View mSettingsContainer;
private PageIndicator mPageIndicator;
- private CarrierText mCarrierText;
private boolean mQsDisabled;
private QSPanel mQsPanel;
@@ -99,12 +106,20 @@
private View mActionsContainer;
private View mDragHandle;
- private View mMobileGroup;
- private ImageView mMobileSignal;
- private ImageView mMobileRoaming;
+
+ private View mCarrierDivider;
+ private ViewGroup mMobileFooter;
+ private View[] mMobileGroups = new View[SIM_SLOTS];
+ private ViewGroup[] mCarrierGroups = new ViewGroup[SIM_SLOTS];
+ private TextView[] mCarrierTexts = new TextView[SIM_SLOTS];
+ private ImageView[] mMobileSignals = new ImageView[SIM_SLOTS];
+ private ImageView[] mMobileRoamings = new ImageView[SIM_SLOTS];
+ private final CellSignalState[] mInfos =
+ new CellSignalState[]{new CellSignalState(), new CellSignalState()};
+
private final int mColorForeground;
- private final CellSignalState mInfo = new CellSignalState();
private OnClickListener mExpandClickListener;
+ private CarrierTextController mCarrierTextController;
@Inject
public QSFooterImpl(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -134,10 +149,20 @@
mSettingsContainer = findViewById(R.id.settings_button_container);
mSettingsButton.setOnClickListener(this);
- mMobileGroup = findViewById(R.id.mobile_combo);
- mMobileSignal = findViewById(R.id.mobile_signal);
- mMobileRoaming = findViewById(R.id.mobile_roaming);
- mCarrierText = findViewById(R.id.qs_carrier_text);
+ mMobileFooter = findViewById(R.id.qs_mobile);
+ mCarrierGroups[0] = findViewById(R.id.carrier1);
+ mCarrierGroups[1] = findViewById(R.id.carrier2);
+
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mMobileGroups[i] = mCarrierGroups[i].findViewById(R.id.mobile_combo);
+ mMobileSignals[i] = mCarrierGroups[i].findViewById(R.id.mobile_signal);
+ mMobileRoamings[i] = mCarrierGroups[i].findViewById(R.id.mobile_roaming);
+ mCarrierTexts[i] = mCarrierGroups[i].findViewById(R.id.qs_carrier_text);
+ }
+ mCarrierDivider = findViewById(R.id.qs_carrier_divider);
+ CharSequence separator = mContext.getString(
+ com.android.internal.R.string.kg_text_message_separator);
+ mCarrierTextController = new CarrierTextController(mContext, separator, false, false);
mMultiUserSwitch = findViewById(R.id.multi_user_switch);
mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
@@ -204,8 +229,8 @@
private TouchAnimator createFooterAnimator() {
return new TouchAnimator.Builder()
.addFloat(mDivider, "alpha", 0, 1)
- .addFloat(mCarrierText, "alpha", 0, 0, 1)
- .addFloat(mMobileGroup, "alpha", 0, 1)
+ .addFloat(mMobileFooter, "alpha", 0, 0, 1)
+ .addFloat(mCarrierDivider, "alpha", 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
.addFloat(mDragHandle, "alpha", 1, 0, 0)
.addFloat(mPageIndicator, "alpha", 0, 1)
@@ -332,10 +357,12 @@
mNetworkController.addEmergencyListener(this);
mNetworkController.addCallback(this);
}
+ mCarrierTextController.setListening(this);
} else {
mUserInfoController.removeCallback(this);
mNetworkController.removeEmergencyListener(this);
mNetworkController.removeCallback(this);
+ mCarrierTextController.setListening(null);
}
}
@@ -358,7 +385,8 @@
if (v == mSettingsButton) {
if (!mDeviceProvisionedController.isCurrentUserSetup()) {
// If user isn't setup just unlock the device and dump them back at SUW.
- mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
+ mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
+ });
return;
}
MetricsLogger.action(mContext,
@@ -415,32 +443,64 @@
}
private void handleUpdateState() {
- mMobileGroup.setVisibility(mInfo.visible ? View.VISIBLE : View.GONE);
- if (mInfo.visible) {
- mMobileRoaming.setVisibility(mInfo.roaming ? View.VISIBLE : View.GONE);
- mMobileRoaming.setImageTintList(ColorStateList.valueOf(mColorForeground));
- SignalDrawable d = new SignalDrawable(mContext);
- d.setDarkIntensity(QuickStatusBarHeader.getColorIntensity(mColorForeground));
- mMobileSignal.setImageDrawable(d);
- mMobileSignal.setImageLevel(mInfo.mobileSignalIconId);
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mMobileGroups[i].setVisibility(mInfos[i].visible ? View.VISIBLE : View.GONE);
+ if (mInfos[i].visible) {
+ mMobileRoamings[i].setVisibility(mInfos[i].roaming ? View.VISIBLE : View.GONE);
+ mMobileRoamings[i].setImageTintList(ColorStateList.valueOf(mColorForeground));
+ SignalDrawable d = new SignalDrawable(mContext);
+ d.setDarkIntensity(QuickStatusBarHeader.getColorIntensity(mColorForeground));
+ mMobileSignals[i].setImageDrawable(d);
+ mMobileSignals[i].setImageLevel(mInfos[i].mobileSignalIconId);
- StringBuilder contentDescription = new StringBuilder();
- if (mInfo.contentDescription != null) {
- contentDescription.append(mInfo.contentDescription).append(", ");
+ StringBuilder contentDescription = new StringBuilder();
+ if (mInfos[i].contentDescription != null) {
+ contentDescription.append(mInfos[i].contentDescription).append(", ");
+ }
+ if (mInfos[i].roaming) {
+ contentDescription
+ .append(mContext.getString(R.string.data_connection_roaming))
+ .append(", ");
+ }
+ // TODO: show mobile data off/no internet text for 5 seconds before carrier text
+ if (TextUtils.equals(mInfos[i].typeContentDescription,
+ mContext.getString(R.string.data_connection_no_internet))
+ || TextUtils.equals(mInfos[i].typeContentDescription,
+ mContext.getString(R.string.cell_data_off_content_description))) {
+ contentDescription.append(mInfos[i].typeContentDescription);
+ }
+ mMobileSignals[i].setContentDescription(contentDescription);
}
- if (mInfo.roaming) {
- contentDescription
- .append(mContext.getString(R.string.data_connection_roaming))
- .append(", ");
+ }
+ mCarrierDivider.setVisibility(
+ mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
+ if (info.anySimReady) {
+ boolean[] slotSeen = new boolean[SIM_SLOTS];
+ for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
+ int slot = SubscriptionManager.getSlotIndex(info.subscriptionIds[i]);
+ mInfos[slot].visible = true;
+ slotSeen[slot] = true;
+ mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
+ mCarrierGroups[slot].setVisibility(View.VISIBLE);
}
- // TODO: show mobile data off/no internet text for 5 seconds before carrier text
- if (TextUtils.equals(mInfo.typeContentDescription,
- mContext.getString(R.string.data_connection_no_internet))
- || TextUtils.equals(mInfo.typeContentDescription,
- mContext.getString(R.string.cell_data_off_content_description))) {
- contentDescription.append(mInfo.typeContentDescription);
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ if (!slotSeen[i]) {
+ mInfos[i].visible = false;
+ mCarrierGroups[i].setVisibility(View.GONE);
+ }
}
- mMobileSignal.setContentDescription(contentDescription);
+ handleUpdateState();
+ } 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();
}
}
@@ -450,18 +510,23 @@
int qsType, boolean activityIn, boolean activityOut,
String typeContentDescription,
String description, boolean isWide, int subId, boolean roaming) {
- mInfo.visible = statusIcon.visible;
- mInfo.mobileSignalIconId = statusIcon.icon;
- mInfo.contentDescription = statusIcon.contentDescription;
- mInfo.typeContentDescription = typeContentDescription;
- mInfo.roaming = roaming;
+ int slotIndex = SubscriptionManager.getSlotIndex(subId);
+ if (slotIndex >= SIM_SLOTS) {
+ Log.e(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+ }
+ mInfos[slotIndex].visible = statusIcon.visible;
+ mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
+ mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
+ mInfos[slotIndex].typeContentDescription = typeContentDescription;
+ mInfos[slotIndex].roaming = roaming;
handleUpdateState();
}
@Override
public void setNoSims(boolean hasNoSims, boolean simDetected) {
if (hasNoSims) {
- mInfo.visible = false;
+ mInfos[0].visible = false;
+ mInfos[1].visible = false;
}
handleUpdateState();
}
@@ -473,4 +538,38 @@
String typeContentDescription;
boolean roaming;
}
+
+
+ /**
+ * TextView that changes its ellipsize value with its visibility.
+ */
+ public static class QSCarrierText extends TextView {
+ public QSCarrierText(Context context) {
+ super(context);
+ }
+
+ public QSCarrierText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public QSCarrierText(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public QSCarrierText(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // Only show marquee when visible
+ if (visibility == VISIBLE) {
+ setEllipsize(TextUtils.TruncateAt.MARQUEE);
+ } else {
+ setEllipsize(TextUtils.TruncateAt.END);
+ }
+ }
+ }
}