blob: 0eeaa9b753820b90378909599509289ab09dd6e6 [file] [log] [blame]
Fabian Kozynskia48d2d02019-02-27 11:36:02 -05001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.qs;
18
19import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
20
21import android.content.Context;
22import android.telephony.SubscriptionManager;
23import android.util.AttributeSet;
24import android.util.Log;
25import android.view.View;
26import android.widget.LinearLayout;
27
28import androidx.annotation.VisibleForTesting;
29
30import com.android.keyguard.CarrierTextController;
31import com.android.systemui.Dependency;
32import com.android.systemui.R;
33import com.android.systemui.statusbar.policy.NetworkController;
34
35import javax.inject.Inject;
36import javax.inject.Named;
37
38/**
39 * Displays Carrier name and network status in QS
40 */
41public class QSCarrierGroup extends LinearLayout implements
42 CarrierTextController.CarrierTextCallback,
43 NetworkController.SignalCallback {
44
45 private static final String TAG = "QSCarrierGroup";
46 /**
47 * Support up to 3 slots which is what's supported by {@link TelephonyManager#getPhoneCount}
48 */
49 private static final int SIM_SLOTS = 3;
50 private final NetworkController mNetworkController;
51
52 private View[] mCarrierDividers = new View[SIM_SLOTS - 1];
53 private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
54 private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS];
55 private CarrierTextController mCarrierTextController;
56
57 private boolean mListening;
58
59 @Inject
60 public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
61 NetworkController networkController) {
62 super(context, attrs);
63 mNetworkController = networkController;
64 }
65
66 @VisibleForTesting
67 public QSCarrierGroup(Context context, AttributeSet attrs) {
68 this(context, attrs,
69 Dependency.get(NetworkController.class));
70 }
71
72 @Override
73 protected void onFinishInflate() {
74 super.onFinishInflate();
75
76 mCarrierGroups[0] = findViewById(R.id.carrier1);
77 mCarrierGroups[1] = findViewById(R.id.carrier2);
78 mCarrierGroups[2] = findViewById(R.id.carrier3);
79
80 mCarrierDividers[0] = findViewById(R.id.qs_carrier_divider1);
81 mCarrierDividers[1] = findViewById(R.id.qs_carrier_divider2);
82
83 for (int i = 0; i < SIM_SLOTS; i++) {
84 mInfos[i] = new CellSignalState();
85 }
86
87 CharSequence separator = mContext.getString(
88 com.android.internal.R.string.kg_text_message_separator);
89 mCarrierTextController = new CarrierTextController(mContext, separator, false, false);
90 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
91 }
92
93 public void setListening(boolean listening) {
94 if (listening == mListening) {
95 return;
96 }
97 mListening = listening;
98 updateListeners();
99 }
100
101 @Override
102 @VisibleForTesting
103 public void onDetachedFromWindow() {
104 setListening(false);
105 super.onDetachedFromWindow();
106 }
107
108 private void updateListeners() {
109 if (mListening) {
110 if (mNetworkController.hasVoiceCallingFeature()) {
111 mNetworkController.addCallback(this);
112 }
113 mCarrierTextController.setListening(this);
114 } else {
115 mNetworkController.removeCallback(this);
116 mCarrierTextController.setListening(null);
117 }
118 }
119
120 private void handleUpdateState() {
121 for (int i = 0; i < SIM_SLOTS; i++) {
122 mCarrierGroups[i].updateState(mInfos[i]);
123 }
Fabian Kozynski4e76d1f2019-02-25 16:30:04 -0500124
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500125 mCarrierDividers[0].setVisibility(
126 mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
127 // This tackles the case of slots 2 being available as well as at least one other.
128 // In that case we show the second divider. Note that if both dividers are visible, it means
129 // all three slots are in use, and that is correct.
130 mCarrierDividers[1].setVisibility(
131 (mInfos[1].visible && mInfos[2].visible)
132 || (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE);
133 }
134
135 @VisibleForTesting
136 protected int getSlotIndex(int subscriptionId) {
137 return SubscriptionManager.getSlotIndex(subscriptionId);
138 }
139
140 @Override
141 public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
142 if (info.anySimReady) {
143 boolean[] slotSeen = new boolean[SIM_SLOTS];
144 if (info.listOfCarriers.length == info.subscriptionIds.length) {
145 for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
146 int slot = getSlotIndex(info.subscriptionIds[i]);
147 if (slot >= SIM_SLOTS) {
148 Log.w(TAG, "updateInfoCarrier - slot: " + slot);
149 continue;
150 }
151 if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
152 Log.e(TAG,
153 "Invalid SIM slot index for subscription: "
154 + info.subscriptionIds[i]);
155 continue;
156 }
157 mInfos[slot].visible = true;
158 slotSeen[slot] = true;
159 mCarrierGroups[slot].setCarrierText(info.listOfCarriers[i].toString().trim());
160 mCarrierGroups[slot].setVisibility(View.VISIBLE);
161 }
162 for (int i = 0; i < SIM_SLOTS; i++) {
163 if (!slotSeen[i]) {
164 mInfos[i].visible = false;
165 mCarrierGroups[i].setVisibility(View.GONE);
166 }
167 }
168 } else {
169 Log.e(TAG, "Carrier information arrays not of same length");
170 }
171 } else {
172 mInfos[0].visible = false;
173 mCarrierGroups[0].setCarrierText(info.carrierText);
174 mCarrierGroups[0].setVisibility(View.VISIBLE);
175 for (int i = 1; i < SIM_SLOTS; i++) {
176 mInfos[i].visible = false;
177 mCarrierGroups[i].setCarrierText("");
178 mCarrierGroups[i].setVisibility(View.GONE);
179 }
180 }
181 handleUpdateState();
182 }
183
184 @Override
185 public void setMobileDataIndicators(NetworkController.IconState statusIcon,
186 NetworkController.IconState qsIcon, int statusType,
187 int qsType, boolean activityIn, boolean activityOut,
188 String typeContentDescription,
189 String description, boolean isWide, int subId, boolean roaming) {
190 int slotIndex = getSlotIndex(subId);
191 if (slotIndex >= SIM_SLOTS) {
192 Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
193 return;
194 }
195 if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
196 Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
197 return;
198 }
199 mInfos[slotIndex].visible = statusIcon.visible;
200 mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
201 mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
202 mInfos[slotIndex].typeContentDescription = typeContentDescription;
203 mInfos[slotIndex].roaming = roaming;
204 handleUpdateState();
205 }
206
207 @Override
208 public void setNoSims(boolean hasNoSims, boolean simDetected) {
209 if (hasNoSims) {
210 for (int i = 0; i < SIM_SLOTS; i++) {
211 mInfos[i].visible = false;
212 }
213 }
214 handleUpdateState();
215 }
216
217 static final class CellSignalState {
218 boolean visible;
219 int mobileSignalIconId;
220 String contentDescription;
221 String typeContentDescription;
222 boolean roaming;
223 }
224}