blob: 4571ef3ef4efb29cbb2ef06770f36eff884ed86c [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;
Fabian Kozynskib1aee812019-04-04 14:17:48 -040022import android.content.Intent;
23import android.provider.Settings;
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050024import android.telephony.SubscriptionManager;
25import android.util.AttributeSet;
26import android.util.Log;
27import android.view.View;
28import android.widget.LinearLayout;
29
30import androidx.annotation.VisibleForTesting;
31
32import com.android.keyguard.CarrierTextController;
33import com.android.systemui.Dependency;
34import com.android.systemui.R;
Fabian Kozynskib1aee812019-04-04 14:17:48 -040035import com.android.systemui.plugins.ActivityStarter;
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050036import com.android.systemui.statusbar.policy.NetworkController;
37
38import javax.inject.Inject;
39import javax.inject.Named;
40
41/**
42 * Displays Carrier name and network status in QS
43 */
44public class QSCarrierGroup extends LinearLayout implements
45 CarrierTextController.CarrierTextCallback,
Fabian Kozynskib1aee812019-04-04 14:17:48 -040046 NetworkController.SignalCallback, View.OnClickListener {
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050047
48 private static final String TAG = "QSCarrierGroup";
49 /**
50 * Support up to 3 slots which is what's supported by {@link TelephonyManager#getPhoneCount}
51 */
52 private static final int SIM_SLOTS = 3;
53 private final NetworkController mNetworkController;
54
55 private View[] mCarrierDividers = new View[SIM_SLOTS - 1];
56 private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
57 private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS];
58 private CarrierTextController mCarrierTextController;
Fabian Kozynskib1aee812019-04-04 14:17:48 -040059 private ActivityStarter mActivityStarter;
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050060
61 private boolean mListening;
62
63 @Inject
64 public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
Fabian Kozynskib1aee812019-04-04 14:17:48 -040065 NetworkController networkController, ActivityStarter activityStarter) {
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050066 super(context, attrs);
67 mNetworkController = networkController;
Fabian Kozynskib1aee812019-04-04 14:17:48 -040068 mActivityStarter = activityStarter;
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050069 }
70
71 @VisibleForTesting
72 public QSCarrierGroup(Context context, AttributeSet attrs) {
73 this(context, attrs,
Fabian Kozynskib1aee812019-04-04 14:17:48 -040074 Dependency.get(NetworkController.class),
75 Dependency.get(ActivityStarter.class));
76 }
77
78 @Override
79 public void onClick(View v) {
Fabian Kozynski1bdb0b92019-04-26 10:25:30 -040080 if (!v.isVisibleToUser()) return;
Fabian Kozynskib1aee812019-04-04 14:17:48 -040081 mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
82 Settings.ACTION_WIRELESS_SETTINGS), 0);
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050083 }
84
85 @Override
86 protected void onFinishInflate() {
87 super.onFinishInflate();
88
89 mCarrierGroups[0] = findViewById(R.id.carrier1);
90 mCarrierGroups[1] = findViewById(R.id.carrier2);
91 mCarrierGroups[2] = findViewById(R.id.carrier3);
92
93 mCarrierDividers[0] = findViewById(R.id.qs_carrier_divider1);
94 mCarrierDividers[1] = findViewById(R.id.qs_carrier_divider2);
95
96 for (int i = 0; i < SIM_SLOTS; i++) {
97 mInfos[i] = new CellSignalState();
Fabian Kozynskib1aee812019-04-04 14:17:48 -040098 mCarrierGroups[i].setOnClickListener(this);
Fabian Kozynskia48d2d02019-02-27 11:36:02 -050099 }
100
101 CharSequence separator = mContext.getString(
102 com.android.internal.R.string.kg_text_message_separator);
103 mCarrierTextController = new CarrierTextController(mContext, separator, false, false);
104 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
105 }
106
107 public void setListening(boolean listening) {
108 if (listening == mListening) {
109 return;
110 }
111 mListening = listening;
112 updateListeners();
113 }
114
115 @Override
116 @VisibleForTesting
117 public void onDetachedFromWindow() {
118 setListening(false);
119 super.onDetachedFromWindow();
120 }
121
122 private void updateListeners() {
123 if (mListening) {
124 if (mNetworkController.hasVoiceCallingFeature()) {
125 mNetworkController.addCallback(this);
126 }
127 mCarrierTextController.setListening(this);
128 } else {
129 mNetworkController.removeCallback(this);
130 mCarrierTextController.setListening(null);
131 }
132 }
133
134 private void handleUpdateState() {
135 for (int i = 0; i < SIM_SLOTS; i++) {
136 mCarrierGroups[i].updateState(mInfos[i]);
137 }
Fabian Kozynski4e76d1f2019-02-25 16:30:04 -0500138
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500139 mCarrierDividers[0].setVisibility(
140 mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
141 // This tackles the case of slots 2 being available as well as at least one other.
142 // In that case we show the second divider. Note that if both dividers are visible, it means
143 // all three slots are in use, and that is correct.
144 mCarrierDividers[1].setVisibility(
145 (mInfos[1].visible && mInfos[2].visible)
146 || (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE);
147 }
148
149 @VisibleForTesting
150 protected int getSlotIndex(int subscriptionId) {
151 return SubscriptionManager.getSlotIndex(subscriptionId);
152 }
153
154 @Override
155 public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
Fabian Kozynskib38edbb2019-04-12 12:20:13 -0400156 if (info.airplaneMode) {
157 setVisibility(View.GONE);
158 } else {
159 setVisibility(View.VISIBLE);
160 if (info.anySimReady) {
161 boolean[] slotSeen = new boolean[SIM_SLOTS];
162 if (info.listOfCarriers.length == info.subscriptionIds.length) {
163 for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
164 int slot = getSlotIndex(info.subscriptionIds[i]);
165 if (slot >= SIM_SLOTS) {
166 Log.w(TAG, "updateInfoCarrier - slot: " + slot);
167 continue;
168 }
169 if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
170 Log.e(TAG,
171 "Invalid SIM slot index for subscription: "
172 + info.subscriptionIds[i]);
173 continue;
174 }
175 mInfos[slot].visible = true;
176 slotSeen[slot] = true;
177 mCarrierGroups[slot].setCarrierText(
178 info.listOfCarriers[i].toString().trim());
179 mCarrierGroups[slot].setVisibility(View.VISIBLE);
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500180 }
Fabian Kozynskib38edbb2019-04-12 12:20:13 -0400181 for (int i = 0; i < SIM_SLOTS; i++) {
182 if (!slotSeen[i]) {
183 mInfos[i].visible = false;
184 mCarrierGroups[i].setVisibility(View.GONE);
185 }
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500186 }
Fabian Kozynskib38edbb2019-04-12 12:20:13 -0400187 } else {
188 Log.e(TAG, "Carrier information arrays not of same length");
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500189 }
190 } else {
Fabian Kozynskib38edbb2019-04-12 12:20:13 -0400191 mInfos[0].visible = false;
192 mCarrierGroups[0].setCarrierText(info.carrierText);
193 mCarrierGroups[0].setVisibility(View.VISIBLE);
194 for (int i = 1; i < SIM_SLOTS; i++) {
195 mInfos[i].visible = false;
196 mCarrierGroups[i].setCarrierText("");
197 mCarrierGroups[i].setVisibility(View.GONE);
198 }
Fabian Kozynskia48d2d02019-02-27 11:36:02 -0500199 }
200 }
201 handleUpdateState();
202 }
203
204 @Override
205 public void setMobileDataIndicators(NetworkController.IconState statusIcon,
206 NetworkController.IconState qsIcon, int statusType,
207 int qsType, boolean activityIn, boolean activityOut,
208 String typeContentDescription,
209 String description, boolean isWide, int subId, boolean roaming) {
210 int slotIndex = getSlotIndex(subId);
211 if (slotIndex >= SIM_SLOTS) {
212 Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
213 return;
214 }
215 if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
216 Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
217 return;
218 }
219 mInfos[slotIndex].visible = statusIcon.visible;
220 mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
221 mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
222 mInfos[slotIndex].typeContentDescription = typeContentDescription;
223 mInfos[slotIndex].roaming = roaming;
224 handleUpdateState();
225 }
226
227 @Override
228 public void setNoSims(boolean hasNoSims, boolean simDetected) {
229 if (hasNoSims) {
230 for (int i = 0; i < SIM_SLOTS; i++) {
231 mInfos[i].visible = false;
232 }
233 }
234 handleUpdateState();
235 }
236
237 static final class CellSignalState {
238 boolean visible;
239 int mobileSignalIconId;
240 String contentDescription;
241 String typeContentDescription;
242 boolean roaming;
243 }
244}