• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.internal.telephony;
18 
19 import android.annotation.NonNull;
20 import android.os.Handler;
21 import android.os.Message;
22 import android.os.PersistableBundle;
23 import android.os.Registrant;
24 import android.os.RegistrantList;
25 import android.telephony.AnomalyReporter;
26 import android.telephony.CarrierConfigManager;
27 import android.telephony.ServiceState;
28 import android.telephony.TelephonyDisplayInfo;
29 import android.telephony.TelephonyManager;
30 import android.util.IndentingPrintWriter;
31 import android.util.LocalLog;
32 import android.util.Pair;
33 
34 import com.android.internal.telephony.flags.FeatureFlags;
35 import com.android.telephony.Rlog;
36 
37 import java.io.FileDescriptor;
38 import java.io.PrintWriter;
39 import java.util.Set;
40 import java.util.UUID;
41 
42 import javax.sip.InvalidArgumentException;
43 
44 /**
45  * The DisplayInfoController updates and broadcasts all changes to {@link TelephonyDisplayInfo}.
46  * It manages all the information necessary for display purposes. Clients can register for display
47  * info changes via {@link #registerForTelephonyDisplayInfoChanged} and obtain the current
48  * TelephonyDisplayInfo via {@link #getTelephonyDisplayInfo}.
49  */
50 public class DisplayInfoController extends Handler {
51     private final String mLogTag;
52     private final LocalLog mLocalLog = new LocalLog(128);
53 
54     private static final Set<Pair<Integer, Integer>> VALID_DISPLAY_INFO_SET = Set.of(
55             // LTE
56             Pair.create(TelephonyManager.NETWORK_TYPE_LTE,
57                     TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA),
58             Pair.create(TelephonyManager.NETWORK_TYPE_LTE,
59                     TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO),
60             Pair.create(TelephonyManager.NETWORK_TYPE_LTE,
61                     TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA),
62             Pair.create(TelephonyManager.NETWORK_TYPE_LTE,
63                     TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED),
64 
65             // NR
66             Pair.create(TelephonyManager.NETWORK_TYPE_NR,
67                     TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED)
68             );
69 
70     /** Event for service state changed (roaming). */
71     private static final int EVENT_SERVICE_STATE_CHANGED = 1;
72     /** Event for carrier config changed. */
73     private static final int EVENT_CARRIER_CONFIG_CHANGED = 2;
74 
75     @NonNull private final Phone mPhone;
76     @NonNull private final NetworkTypeController mNetworkTypeController;
77     @NonNull private final RegistrantList mTelephonyDisplayInfoChangedRegistrants =
78             new RegistrantList();
79     @NonNull private final FeatureFlags mFeatureFlags;
80     @NonNull private TelephonyDisplayInfo mTelephonyDisplayInfo;
81     @NonNull private ServiceState mServiceState;
82     @NonNull private PersistableBundle mConfigs;
83 
DisplayInfoController(@onNull Phone phone, @NonNull FeatureFlags featureFlags)84     public DisplayInfoController(@NonNull Phone phone, @NonNull FeatureFlags featureFlags) {
85         mPhone = phone;
86         mFeatureFlags = featureFlags;
87         mLogTag = "DIC-" + mPhone.getPhoneId();
88         mServiceState = mPhone.getServiceStateTracker().getServiceState();
89         mConfigs = new PersistableBundle();
90         CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class);
91         try {
92             if (ccm != null) {
93                 mConfigs = ccm.getConfigForSubId(mPhone.getSubId(),
94                         CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL);
95             }
96         } catch (Exception ignored) {
97             // CarrierConfigLoader might not be available yet.
98             // Once it's available, configs will be updated through the listener.
99         }
100         mPhone.getServiceStateTracker()
101                 .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
102         if (ccm != null) {
103             ccm.registerCarrierConfigChangeListener(Runnable::run,
104                     (slotIndex, subId, carrierId, specificCarrierId) -> {
105                         if (slotIndex == mPhone.getPhoneId()) {
106                             obtainMessage(EVENT_CARRIER_CONFIG_CHANGED).sendToTarget();
107                         }
108                     });
109         }
110         mTelephonyDisplayInfo = new TelephonyDisplayInfo(
111                 TelephonyManager.NETWORK_TYPE_UNKNOWN,
112                 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
113                 false, false, false);
114         mNetworkTypeController = new NetworkTypeController(phone, this, featureFlags);
115         // EVENT_UPDATE will transition from DefaultState to the current state
116         // and update the TelephonyDisplayInfo based on the current state.
117         mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE);
118 
119         // To Support Satellite bandwidth constrained data capability status at telephony
120         // display info
121         log("register for satellite network callback");
122         mNetworkTypeController.registerForSatelliteNetwork();
123     }
124 
125     /**
126      * @return the current TelephonyDisplayInfo
127      */
getTelephonyDisplayInfo()128     @NonNull public TelephonyDisplayInfo getTelephonyDisplayInfo() {
129         return mTelephonyDisplayInfo;
130     }
131 
132     /**
133      * Update TelephonyDisplayInfo based on network type and override network type, received from
134      * NetworkTypeController.
135      */
updateTelephonyDisplayInfo()136     public void updateTelephonyDisplayInfo() {
137         if (mNetworkTypeController != null && mServiceState != null) {
138             TelephonyDisplayInfo newDisplayInfo = new TelephonyDisplayInfo(
139                     mNetworkTypeController.getDataNetworkType(),
140                     mNetworkTypeController.getOverrideNetworkType(),
141                     isRoaming(),
142                     mServiceState.isUsingNonTerrestrialNetwork(),
143                     mNetworkTypeController.getSatelliteConstrainedData());
144             if (!newDisplayInfo.equals(mTelephonyDisplayInfo)) {
145                 logl("TelephonyDisplayInfo changed from " + mTelephonyDisplayInfo + " to "
146                         + newDisplayInfo);
147                 validateDisplayInfo(newDisplayInfo);
148                 mTelephonyDisplayInfo = newDisplayInfo;
149                 mTelephonyDisplayInfoChangedRegistrants.notifyRegistrants();
150                 mPhone.notifyDisplayInfoChanged(mTelephonyDisplayInfo);
151             }
152         } else {
153             loge("Found null object");
154         }
155     }
156 
157     /**
158      * Determine the roaming status for icon display only.
159      * If this is {@code true}, the roaming indicator will be shown, and if this is {@code false},
160      * the roaming indicator will not be shown.
161      * To get the actual roaming status, use {@link ServiceState#getRoaming()} instead.
162      *
163      * @return Whether the device is considered roaming for display purposes.
164      */
isRoaming()165     private boolean isRoaming() {
166         boolean roaming = mServiceState.getRoaming();
167         if (roaming && !mConfigs.getBoolean(CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL)) {
168             logl("Override roaming for display due to carrier configs.");
169             roaming = false;
170         }
171         return roaming;
172     }
173 
174     /**
175      * Validate the display info and trigger anomaly report if needed.
176      *
177      * @param displayInfo The display info to validate.
178      */
validateDisplayInfo(@onNull TelephonyDisplayInfo displayInfo)179     private void validateDisplayInfo(@NonNull TelephonyDisplayInfo displayInfo) {
180         try {
181             if (displayInfo.getNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) {
182                 throw new InvalidArgumentException("LTE_CA is not a valid network type.");
183             }
184             if (displayInfo.getNetworkType() < TelephonyManager.NETWORK_TYPE_UNKNOWN
185                     && displayInfo.getNetworkType() > TelephonyManager.NETWORK_TYPE_NR) {
186                 throw new InvalidArgumentException("Invalid network type "
187                         + displayInfo.getNetworkType());
188             }
189             if (displayInfo.getOverrideNetworkType()
190                     != TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
191                     && !VALID_DISPLAY_INFO_SET.contains(Pair.create(displayInfo.getNetworkType(),
192                     displayInfo.getOverrideNetworkType()))) {
193                 throw new InvalidArgumentException("Invalid network type override "
194                         + TelephonyDisplayInfo.overrideNetworkTypeToString(
195                                 displayInfo.getOverrideNetworkType())
196                         + " for " + TelephonyManager.getNetworkTypeName(
197                                 displayInfo.getNetworkType()));
198             }
199         } catch (InvalidArgumentException e) {
200             logel(e.getMessage());
201             AnomalyReporter.reportAnomaly(UUID.fromString("3aa92a2c-94ed-46a0-a744-d6b1dfec2a56"),
202                     e.getMessage(), mPhone.getCarrierId());
203         }
204     }
205 
206     /**
207      * Register for TelephonyDisplayInfo changed.
208      * @param h Handler to notify
209      * @param what msg.what when the message is delivered
210      * @param obj msg.obj when the message is delivered
211      */
registerForTelephonyDisplayInfoChanged(Handler h, int what, Object obj)212     public void registerForTelephonyDisplayInfoChanged(Handler h, int what, Object obj) {
213         Registrant r = new Registrant(h, what, obj);
214         mTelephonyDisplayInfoChangedRegistrants.add(r);
215     }
216 
217     /**
218      * Unregister for TelephonyDisplayInfo changed.
219      * @param h Handler to notify
220      */
unregisterForTelephonyDisplayInfoChanged(Handler h)221     public void unregisterForTelephonyDisplayInfoChanged(Handler h) {
222         mTelephonyDisplayInfoChangedRegistrants.remove(h);
223     }
224 
225     @Override
handleMessage(@onNull Message msg)226     public void handleMessage(@NonNull Message msg) {
227         switch (msg.what) {
228             case EVENT_SERVICE_STATE_CHANGED:
229                 mServiceState = mPhone.getServiceStateTracker().getServiceState();
230                 log("ServiceState updated, isRoaming=" + mServiceState.getRoaming());
231                 updateTelephonyDisplayInfo();
232                 break;
233             case EVENT_CARRIER_CONFIG_CHANGED:
234                 mConfigs = mPhone.getContext().getSystemService(CarrierConfigManager.class)
235                         .getConfigForSubId(mPhone.getSubId(),
236                                 CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL);
237                 log("Carrier configs updated: " + mConfigs);
238                 updateTelephonyDisplayInfo();
239                 break;
240         }
241     }
242 
243     /**
244      * Log debug messages.
245      * @param s debug messages
246      */
log(@onNull String s)247     private void log(@NonNull String s) {
248         Rlog.d(mLogTag, s);
249     }
250 
251     /**
252      * Log error messages.
253      * @param s error messages
254      */
loge(@onNull String s)255     private void loge(@NonNull String s) {
256         Rlog.e(mLogTag, s);
257     }
258 
259     /**
260      * Log debug messages and also log into the local log.
261      * @param s debug messages
262      */
logl(@onNull String s)263     private void logl(@NonNull String s) {
264         log(s);
265         mLocalLog.log(s);
266     }
267 
268     /**
269      * Log error messages and also log into the local log.
270      * @param s debug messages
271      */
logel(@onNull String s)272     private void logel(@NonNull String s) {
273         loge(s);
274         mLocalLog.log(s);
275     }
276 
277     /**
278      * Dump the current state.
279      */
dump(FileDescriptor fd, PrintWriter printWriter, String[] args)280     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
281         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
282         pw.println("DisplayInfoController:");
283         pw.println(" mPhone=" + mPhone.getPhoneName());
284         pw.println(" mTelephonyDisplayInfo=" + mTelephonyDisplayInfo.toString());
285         pw.flush();
286         pw.println("Local logs:");
287         pw.increaseIndent();
288         mLocalLog.dump(fd, pw, args);
289         pw.decreaseIndent();
290         pw.println(" ***************************************");
291         mNetworkTypeController.dump(fd, pw, args);
292         pw.flush();
293     }
294 }
295