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