• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.systemui.qs;
18 
19 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.provider.Settings;
24 import android.telephony.SubscriptionManager;
25 import android.util.AttributeSet;
26 import android.util.Log;
27 import android.view.View;
28 import android.widget.LinearLayout;
29 
30 import androidx.annotation.VisibleForTesting;
31 
32 import com.android.keyguard.CarrierTextController;
33 import com.android.systemui.Dependency;
34 import com.android.systemui.R;
35 import com.android.systemui.plugins.ActivityStarter;
36 import com.android.systemui.statusbar.policy.NetworkController;
37 
38 import javax.inject.Inject;
39 import javax.inject.Named;
40 
41 /**
42  * Displays Carrier name and network status in QS
43  */
44 public class QSCarrierGroup extends LinearLayout implements
45         CarrierTextController.CarrierTextCallback,
46         NetworkController.SignalCallback, View.OnClickListener {
47 
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;
59     private ActivityStarter mActivityStarter;
60 
61     private boolean mListening;
62 
63     @Inject
QSCarrierGroup(@amedVIEW_CONTEXT) Context context, AttributeSet attrs, NetworkController networkController, ActivityStarter activityStarter)64     public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
65             NetworkController networkController, ActivityStarter activityStarter) {
66         super(context, attrs);
67         mNetworkController = networkController;
68         mActivityStarter = activityStarter;
69     }
70 
71     @VisibleForTesting
QSCarrierGroup(Context context, AttributeSet attrs)72     public QSCarrierGroup(Context context, AttributeSet attrs) {
73         this(context, attrs,
74                 Dependency.get(NetworkController.class),
75                 Dependency.get(ActivityStarter.class));
76     }
77 
78     @Override
onClick(View v)79     public void onClick(View v) {
80         if (!v.isVisibleToUser()) return;
81         mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
82                 Settings.ACTION_WIRELESS_SETTINGS), 0);
83     }
84 
85     @Override
onFinishInflate()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();
98             mCarrierGroups[i].setOnClickListener(this);
99         }
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 
setListening(boolean listening)107     public void setListening(boolean listening) {
108         if (listening == mListening) {
109             return;
110         }
111         mListening = listening;
112         updateListeners();
113     }
114 
115     @Override
116     @VisibleForTesting
onDetachedFromWindow()117     public void onDetachedFromWindow() {
118         setListening(false);
119         super.onDetachedFromWindow();
120     }
121 
updateListeners()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 
handleUpdateState()134     private void handleUpdateState() {
135         for (int i = 0; i < SIM_SLOTS; i++) {
136             mCarrierGroups[i].updateState(mInfos[i]);
137         }
138 
139         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
getSlotIndex(int subscriptionId)150     protected int getSlotIndex(int subscriptionId) {
151         return SubscriptionManager.getSlotIndex(subscriptionId);
152     }
153 
154     @Override
updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info)155     public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
156         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);
180                     }
181                     for (int i = 0; i < SIM_SLOTS; i++) {
182                         if (!slotSeen[i]) {
183                             mInfos[i].visible = false;
184                             mCarrierGroups[i].setVisibility(View.GONE);
185                         }
186                     }
187                 } else {
188                     Log.e(TAG, "Carrier information arrays not of same length");
189                 }
190             } else {
191                 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                 }
199             }
200         }
201         handleUpdateState();
202     }
203 
204     @Override
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)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
setNoSims(boolean hasNoSims, boolean simDetected)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 }
245