• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.telephony.qns;
18 
19 import static com.android.telephony.qns.DataConnectionStatusTracker.STATE_CONNECTED;
20 import static com.android.telephony.qns.DataConnectionStatusTracker.STATE_HANDOVER;
21 import static com.android.telephony.qns.QnsConstants.INVALID_ID;
22 
23 import android.annotation.IntDef;
24 import android.net.NetworkCapabilities;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.SystemClock;
29 import android.telephony.AccessNetworkConstants;
30 import android.telephony.Annotation;
31 import android.telephony.TelephonyManager;
32 import android.util.Log;
33 import android.util.Pair;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.telephony.qns.DataConnectionStatusTracker.DataConnectionChangedInfo;
37 
38 import java.io.PrintWriter;
39 import java.util.ArrayList;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.concurrent.ConcurrentHashMap;
44 
45 /**
46  * Prevents HO pingpong between Cellular and IWLAN. Provide Throttling for certain cause. Provide
47  * Handover not allowed policy.
48  */
49 class RestrictManager {
50     private final String mLogTag;
51     private final boolean mDebugFlag = true;
52     static final int RESTRICT_TYPE_GUARDING = 1;
53     static final int RESTRICT_TYPE_THROTTLING = 2;
54     static final int RESTRICT_TYPE_HO_NOT_ALLOWED = 3;
55     static final int RESTRICT_TYPE_NON_PREFERRED_TRANSPORT = 4;
56     static final int RESTRICT_TYPE_RTP_LOW_QUALITY = 5;
57     static final int RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL = 6;
58     static final int RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL = 7;
59     static final int RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL = 8;
60     static final int RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL = 9;
61     static final int RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL = 10;
62 
63     @IntDef(
64             value = {
65                 RESTRICT_TYPE_GUARDING,
66                 RESTRICT_TYPE_THROTTLING,
67                 RESTRICT_TYPE_HO_NOT_ALLOWED,
68                 RESTRICT_TYPE_NON_PREFERRED_TRANSPORT,
69                 RESTRICT_TYPE_RTP_LOW_QUALITY,
70                 RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL,
71                 RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL,
72                 RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL,
73                 RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL,
74                 RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL,
75             })
76     @interface RestrictType {}
77 
78     static final int RELEASE_EVENT_DISCONNECT = 1;
79     static final int RELEASE_EVENT_WIFI_AP_CHANGED = 2;
80     static final int RELEASE_EVENT_WFC_PREFER_MODE_CHANGED = 3;
81     static final int RELEASE_EVENT_CALL_END = 4;
82     static final int RELEASE_EVENT_IMS_NOT_SUPPORT_RAT = 5;
83 
84     @IntDef(
85             value = {
86                 RELEASE_EVENT_DISCONNECT,
87                 RELEASE_EVENT_WIFI_AP_CHANGED,
88                 RELEASE_EVENT_WFC_PREFER_MODE_CHANGED,
89                 RELEASE_EVENT_CALL_END,
90                 RELEASE_EVENT_IMS_NOT_SUPPORT_RAT,
91             })
92     @interface ReleaseEvent {}
93 
94     private static final int EVENT_DATA_CONNECTION_CHANGED = 3001;
95     private static final int EVENT_CALL_STATE_CHANGED = 3002;
96     private static final int EVENT_SRVCC_STATE_CHANGED = 3003;
97     private static final int EVENT_IMS_REGISTRATION_STATE_CHANGED = 3004;
98     private static final int EVENT_LOW_RTP_QUALITY_REPORTED = 3006;
99     private static final int EVENT_RELEASE_RESTRICTION = 3008;
100     protected static final int EVENT_INITIAL_DATA_CONNECTION_FAIL_RETRY_TIMER_EXPIRED = 3009;
101     private static final int EVENT_WIFI_RTT_BACKHAUL_CHECK_STATUS = 3010;
102 
103     @VisibleForTesting static final int GUARDING_TIMER_HANDOVER_INIT = 30000;
104 
105     static final HashMap<Integer, int[]> sReleaseEventMap =
106             new HashMap<Integer, int[]>() {
107                 {
108                     put(
109                             RESTRICT_TYPE_GUARDING,
110                             new int[] {
111                                 RELEASE_EVENT_DISCONNECT, RELEASE_EVENT_WFC_PREFER_MODE_CHANGED
112                             });
113                     put(
114                             RESTRICT_TYPE_RTP_LOW_QUALITY,
115                             new int[] {RELEASE_EVENT_CALL_END, RELEASE_EVENT_WIFI_AP_CHANGED});
116                     put(RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL, new int[] {RELEASE_EVENT_CALL_END});
117                     put(
118                             RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL,
119                             new int[] {
120                                 RELEASE_EVENT_DISCONNECT, RELEASE_EVENT_IMS_NOT_SUPPORT_RAT
121                             });
122                     put(
123                             RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL,
124                             new int[] {
125                                 RELEASE_EVENT_DISCONNECT,
126                                 RELEASE_EVENT_WIFI_AP_CHANGED,
127                                 RELEASE_EVENT_WFC_PREFER_MODE_CHANGED,
128                                 RELEASE_EVENT_IMS_NOT_SUPPORT_RAT
129                             });
130                     put(
131                             RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL,
132                             new int[] {
133                                 RELEASE_EVENT_DISCONNECT,
134                                 RELEASE_EVENT_WIFI_AP_CHANGED,
135                                 RELEASE_EVENT_IMS_NOT_SUPPORT_RAT
136                             });
137                 }
138             };
139     private static final int[] ignorableRestrictionsOnSingleRat =
140             new int[] {
141                 RESTRICT_TYPE_GUARDING,
142                 RESTRICT_TYPE_RTP_LOW_QUALITY,
143                 RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL,
144                 RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL,
145                 RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL,
146                 RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL
147             };
148 
149     private QnsCarrierConfigManager mQnsCarrierConfigManager;
150     private QnsTelephonyListener mTelephonyListener;
151     private QnsEventDispatcher mQnsEventDispatcher;
152     @VisibleForTesting Handler mHandler;
153 
154     @QnsConstants.CellularCoverage
155     int mCellularCoverage; // QnsConstants.COVERAGE_HOME or QnsConstants.COVERAGE_ROAM
156 
157     int mCellularAccessNetwork;
158 
159     @VisibleForTesting QnsRegistrant mRestrictInfoRegistrant;
160     private DataConnectionStatusTracker mDataConnectionStatusTracker;
161     private CellularNetworkStatusTracker mCellularNetworkStatusTracker;
162     private QnsCallStatusTracker mQnsCallStatusTracker;
163     private QnsCallStatusTracker.ActiveCallTracker mActiveCallTracker;
164     private QnsImsManager mQnsImsManager;
165     private QnsTimer mQnsTimer;
166     private WifiBackhaulMonitor mWifiBackhaulMonitor;
167     private QnsMetrics mQnsMetrics;
168     private int mNetCapability;
169     private int mSlotId;
170     private int mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
171     private int mLastEvaluatedTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
172     private int mWfcPreference;
173     private int mWfcRoamingPreference;
174     private int mCounterForIwlanRestrictionInCall;
175     private int mRetryCounterOnDataConnectionFail;
176     private int mFallbackCounterOnDataConnectionFail;
177     private boolean mIsRttStatusCheckRegistered = false;
178     private int mLastDataConnectionTransportType;
179     private int mFallbackTimerId = -1;
180     private boolean mIsTimerRunningOnDataConnectionFail = false;
181     private Pair<Integer, Long> mDeferredThrottlingEvent = null;
182 
183     /** IMS call type */
184     @QnsConstants.QnsCallType private int mImsCallType;
185     /** Call state from TelephonyCallback.CallStateListener */
186     @Annotation.CallState private int mCallState;
187 
188     private Map<Integer, RestrictInfo> mRestrictInfos = new ConcurrentHashMap<>();
189     private Map<Restriction, Integer> mRestrictionTimers = new ConcurrentHashMap<>();
190 
191     private class RestrictManagerHandler extends Handler {
RestrictManagerHandler(Looper l)192         RestrictManagerHandler(Looper l) {
193             super(l);
194         }
195 
196         @Override
handleMessage(Message message)197         public void handleMessage(Message message) {
198             QnsAsyncResult ar;
199             int transportType;
200             Log.d(mLogTag, "handleMessage : " + message.what);
201             switch (message.what) {
202                 case EVENT_DATA_CONNECTION_CHANGED:
203                     ar = (QnsAsyncResult) message.obj;
204                     onDataConnectionChanged((DataConnectionChangedInfo) ar.mResult);
205                     break;
206 
207                 case EVENT_CALL_STATE_CHANGED:
208                     ar = (QnsAsyncResult) message.obj;
209                     int callState = (int) ar.mResult;
210                     onCallStateChanged(callState, mTransportType, mCellularAccessNetwork);
211                     break;
212 
213                 case EVENT_SRVCC_STATE_CHANGED:
214                     ar = (QnsAsyncResult) message.obj;
215                     int srvccState = (int) ar.mResult;
216                     onSrvccStateChanged(srvccState);
217                     break;
218 
219                 case EVENT_LOW_RTP_QUALITY_REPORTED:
220                     ar = (QnsAsyncResult) message.obj;
221                     int reason = (int) ar.mResult;
222                     Log.d(mLogTag, "EVENT_LOW_RTP_QUALITY_REPORTED reason: " + reason);
223                     onLowRtpQualityEvent(reason);
224                     break;
225 
226                 case EVENT_IMS_REGISTRATION_STATE_CHANGED:
227                     ar = (QnsAsyncResult) message.obj;
228                     onImsRegistrationStateChanged((QnsImsManager.ImsRegistrationState) ar.mResult);
229                     break;
230 
231                 case EVENT_RELEASE_RESTRICTION:
232                     transportType = message.arg1;
233                     Restriction restriction = (Restriction) message.obj;
234                     Log.d(
235                             mLogTag,
236                             "EVENT_RELEASE_RESTRICTION : "
237                                     + QnsConstants.transportTypeToString(transportType)
238                                     + " "
239                                     + restrictTypeToString(restriction.mRestrictType));
240                     if (restriction
241                             == mRestrictInfos
242                                     .get(transportType)
243                                     .getRestrictionMap()
244                                     .get(restriction.mRestrictType)) {
245                         releaseRestriction(transportType, restriction.mRestrictType);
246                         mQnsTimer.unregisterTimer(mRestrictionTimers
247                                 .getOrDefault(restriction, INVALID_ID));
248                         mRestrictionTimers.remove(restriction);
249                     }
250                     break;
251 
252                 case EVENT_INITIAL_DATA_CONNECTION_FAIL_RETRY_TIMER_EXPIRED:
253                     Log.d(
254                             mLogTag,
255                             "Initial Data Connection fail timer expired"
256                                     + mIsTimerRunningOnDataConnectionFail);
257 
258                     mQnsTimer.unregisterTimer(mFallbackTimerId);
259                     if (mIsTimerRunningOnDataConnectionFail) {
260                         int currTransportType = message.arg1;
261                         fallbackToOtherTransportOnDataConnectionFail(currTransportType);
262                     }
263                     break;
264 
265                 case EVENT_WIFI_RTT_BACKHAUL_CHECK_STATUS:
266                     ar = (QnsAsyncResult) message.obj;
267                     boolean rttCheckStatus = (boolean) ar.mResult;
268                     if (!rttCheckStatus) { // rtt Backhaul check failed
269                         Log.d(mLogTag, "Rtt check status received:Fail");
270                         onWlanRttFail();
271                     }
272                     break;
273 
274                 case QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_ONLY:
275                     onWfcModeChanged(QnsConstants.WIFI_ONLY, QnsConstants.COVERAGE_HOME);
276                     break;
277                 case QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED:
278                     onWfcModeChanged(QnsConstants.CELL_PREF, QnsConstants.COVERAGE_HOME);
279                     break;
280 
281                 case QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED:
282                     onWfcModeChanged(QnsConstants.WIFI_PREF, QnsConstants.COVERAGE_HOME);
283                     break;
284 
285                 case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY:
286                     onWfcModeChanged(QnsConstants.WIFI_ONLY, QnsConstants.COVERAGE_ROAM);
287                     break;
288 
289                 case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED:
290                     onWfcModeChanged(QnsConstants.CELL_PREF, QnsConstants.COVERAGE_ROAM);
291                     break;
292 
293                 case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED:
294                     onWfcModeChanged(QnsConstants.WIFI_PREF, QnsConstants.COVERAGE_ROAM);
295                     break;
296 
297                 case QnsEventDispatcher.QNS_EVENT_APM_ENABLED:
298                 case QnsEventDispatcher.QNS_EVENT_WFC_DISABLED:
299                 case QnsEventDispatcher.QNS_EVENT_WIFI_DISABLING:
300                     if (mFallbackCounterOnDataConnectionFail > 0) {
301                         Log.d(mLogTag, "Reset Fallback Counter on APM On/WFC off/Wifi Off");
302                         mFallbackCounterOnDataConnectionFail = 0;
303                     }
304 
305                     if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS
306                             && hasRestrictionType(
307                                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
308                                     RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL)) {
309 
310                         releaseRestriction(
311                                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
312                                 RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL);
313                     }
314                     break;
315                 default:
316                     break;
317             }
318         }
319     }
320 
321     class LowRtpQualityRestriction extends Restriction{
322         private int mReason;
LowRtpQualityRestriction(int type, int[] releaseEvents, int restrictTime, int reason)323         LowRtpQualityRestriction(int type, int[] releaseEvents, int restrictTime, int reason) {
324             super(type, releaseEvents, restrictTime);
325             mReason = reason;
326         }
getReason()327         int getReason() {
328             return mReason;
329         }
330     }
331 
332     class Restriction {
333         private final int mRestrictType;
334         final ArrayList<Integer> mReleaseEventList;
335         long mReleaseTime;
336 
Restriction(int type, int[] releaseEvents, long restrictTime)337         Restriction(int type, int[] releaseEvents, long restrictTime) {
338             mRestrictType = type;
339             if (restrictTime == 0) {
340                 mReleaseTime = 0;
341             } else {
342                 mReleaseTime = restrictTime + SystemClock.elapsedRealtime();
343                 if (restrictTime > 0 && mReleaseTime < 0) {
344                     mReleaseTime = Long.MAX_VALUE;
345                 }
346             }
347             if (releaseEvents != null && releaseEvents.length > 0) {
348                 mReleaseEventList = new ArrayList<>();
349                 for (int i : releaseEvents) {
350                     mReleaseEventList.add(i);
351                 }
352             } else {
353                 mReleaseEventList = null;
354             }
355         }
356 
needRelease(int event)357         boolean needRelease(int event) {
358             if (mReleaseEventList == null) {
359                 return false;
360             }
361             for (Integer i : mReleaseEventList) {
362                 if (event == i.intValue()) {
363                     return true;
364                 }
365             }
366             return false;
367         }
368 
updateRestrictTime(long timeMillis)369         void updateRestrictTime(long timeMillis) {
370             mReleaseTime = SystemClock.elapsedRealtime() + timeMillis;
371             if (timeMillis > 0 && mReleaseTime < 0) {
372                 mReleaseTime = Long.MAX_VALUE;
373             }
374         }
375 
376         @Override
toString()377         public String toString() {
378             StringBuilder builder = new StringBuilder();
379             builder.append("[RESTRICTION type:").append(restrictTypeToString(mRestrictType));
380             builder.append(" releaseEvents:( ");
381             if (mReleaseEventList != null) {
382                 for (Integer i : mReleaseEventList) {
383                     builder.append(i).append(" ");
384                 }
385             }
386             builder.append(") remainedTimeMillis:");
387             if (mReleaseTime == 0) {
388                 builder.append("N/A");
389             } else {
390                 long remain = mReleaseTime - SystemClock.elapsedRealtime();
391                 builder.append(remain);
392             }
393             builder.append("]");
394             return builder.toString();
395         }
396     }
397 
398     class RestrictInfo {
399         private int mTransportMode; // AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
400         private HashMap<Integer, Restriction> mRestrictionMap = new HashMap<>();
401 
RestrictInfo(int transportMode)402         RestrictInfo(int transportMode) {
403             mTransportMode = transportMode;
404         }
405 
getRestrictionMap()406         HashMap<Integer, Restriction> getRestrictionMap() {
407             return mRestrictionMap;
408         }
409 
isRestricted()410         boolean isRestricted() {
411             return mRestrictionMap.size() != 0;
412         }
413 
414         /**
415          * This method returns if the restriction info has given restriction type.
416          *
417          * @param restrictType integer value of restriction type.
418          * @return true if restrictinfo has the restriction; otherwise false.
419          */
hasRestrictionType(@estrictType int restrictType)420         boolean hasRestrictionType(@RestrictType int restrictType) {
421             return mRestrictionMap.get(restrictType) != null;
422         }
423 
424         @Override
toString()425         public String toString() {
426             StringBuilder builder = new StringBuilder();
427             builder.append("RestrictInfo[")
428                     .append(QnsConstants.transportTypeToString(mTransportMode))
429                     .append("] : ");
430             if (isRestricted()) {
431                 for (Restriction restriction : mRestrictionMap.values()) {
432                     builder.append(restriction.toString()).append(" ");
433                 }
434             } else {
435                 builder.append("No restriction");
436             }
437             return builder.toString();
438         }
439     }
440 
RestrictManager( QnsComponents qnsComponents, Looper loop, int netCapability, DataConnectionStatusTracker dcst, int slotId)441     RestrictManager(
442             QnsComponents qnsComponents,
443             Looper loop,
444             int netCapability,
445             DataConnectionStatusTracker dcst,
446             int slotId) {
447         mRestrictInfos.put(
448                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
449                 new RestrictInfo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN));
450         mRestrictInfos.put(
451                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
452                 new RestrictInfo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN));
453         mSlotId = slotId;
454         mLogTag =
455                 RestrictManager.class.getSimpleName()
456                         + "_"
457                         + mSlotId
458                         + "_"
459                         + QnsUtils.getNameOfNetCapability(netCapability);
460         mTelephonyListener = qnsComponents.getQnsTelephonyListener(mSlotId);
461         mQnsEventDispatcher = qnsComponents.getQnsEventDispatcher(mSlotId);
462         mQnsCarrierConfigManager = qnsComponents.getQnsCarrierConfigManager(mSlotId);
463         mQnsTimer = qnsComponents.getQnsTimer();
464         mHandler = new RestrictManagerHandler(loop);
465         mNetCapability = netCapability;
466         mDataConnectionStatusTracker = dcst;
467         mQnsCallStatusTracker = qnsComponents.getQnsCallStatusTracker(mSlotId);
468         mActiveCallTracker = qnsComponents.getQnsCallStatusTracker(mSlotId).getActiveCallTracker();
469         mQnsMetrics = qnsComponents.getQnsMetrics();
470         mDataConnectionStatusTracker.registerDataConnectionStatusChanged(
471                 mHandler, EVENT_DATA_CONNECTION_CHANGED);
472         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
473             mTelephonyListener.registerCallStateListener(
474                     mHandler, EVENT_CALL_STATE_CHANGED, null, true);
475             mTelephonyListener.registerSrvccStateListener(
476                     mHandler, EVENT_SRVCC_STATE_CHANGED, null);
477         }
478         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
479             mQnsImsManager = qnsComponents.getQnsImsManager(mSlotId);
480             mQnsImsManager.registerImsRegistrationStatusChanged(
481                     mHandler, EVENT_IMS_REGISTRATION_STATE_CHANGED);
482             mWifiBackhaulMonitor = qnsComponents.getWifiBackhaulMonitor(mSlotId);
483         }
484 
485         // check if we can pass "mQnsImsManager"
486         mWfcPreference = QnsUtils.getWfcMode(qnsComponents.getQnsImsManager(mSlotId), false);
487         mWfcRoamingPreference = QnsUtils.getWfcMode(qnsComponents.getQnsImsManager(mSlotId), true);
488 
489         List<Integer> events = new ArrayList<>();
490         events.add(QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_ONLY);
491         events.add(QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED);
492         events.add(QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED);
493         events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY);
494         events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED);
495         events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED);
496         events.add(QnsEventDispatcher.QNS_EVENT_APM_ENABLED);
497         events.add(QnsEventDispatcher.QNS_EVENT_WFC_DISABLED);
498         events.add(QnsEventDispatcher.QNS_EVENT_WIFI_DISABLING);
499         mQnsEventDispatcher.registerEvent(events, mHandler);
500 
501         mCellularNetworkStatusTracker = qnsComponents.getCellularNetworkStatusTracker(mSlotId);
502         restrictNonPreferredTransport();
503     }
504 
clearRestrictions()505     void clearRestrictions() {
506         mRestrictInfos.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getRestrictionMap().clear();
507         mRestrictInfos.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).getRestrictionMap().clear();
508     }
509 
close()510     void close() {
511         mDataConnectionStatusTracker.unRegisterDataConnectionStatusChanged(mHandler);
512         if (mIsRttStatusCheckRegistered
513                 && mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
514             mIsRttStatusCheckRegistered = false;
515             mWifiBackhaulMonitor.unRegisterForRttStatusChange(mHandler);
516         }
517 
518         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
519             mTelephonyListener.unregisterCallStateChanged(mHandler);
520             mTelephonyListener.unregisterSrvccStateChanged(mHandler);
521         }
522         mQnsEventDispatcher.unregisterEvent(mHandler);
523         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS
524                 || mNetCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
525             if (mActiveCallTracker != null) {
526                 mActiveCallTracker.unregisterLowMediaQualityListener(mHandler);
527             }
528         }
529         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
530             mQnsImsManager.unregisterImsRegistrationStatusChanged(mHandler);
531         }
532         mRestrictionTimers.clear();
533     }
534 
onWfcModeChanged(int prefMode, @QnsConstants.CellularCoverage int coverage)535     private void onWfcModeChanged(int prefMode, @QnsConstants.CellularCoverage int coverage) {
536         Log.d(mLogTag, "onWfcModeChanged  prefMode :" + prefMode + "  coverage:" + coverage);
537         if (coverage == QnsConstants.COVERAGE_HOME) {
538             mWfcPreference = prefMode;
539         } else if (coverage == QnsConstants.COVERAGE_ROAM) {
540             mWfcRoamingPreference = prefMode;
541         }
542         if (mCellularCoverage == coverage) {
543             if (prefMode == QnsConstants.CELL_PREF) {
544                 processReleaseEvent(
545                         AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
546                         RELEASE_EVENT_WFC_PREFER_MODE_CHANGED);
547             }
548             if (prefMode == QnsConstants.WIFI_PREF || prefMode == QnsConstants.WIFI_ONLY) {
549                 processReleaseEvent(
550                         AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
551                         RELEASE_EVENT_WFC_PREFER_MODE_CHANGED);
552             }
553         }
554         checkIfCancelNonPreferredRestriction(getPreferredTransportType());
555     }
556 
557     @VisibleForTesting
restrictNonPreferredTransport()558     void restrictNonPreferredTransport() {
559         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS
560                 && !mCellularNetworkStatusTracker.isAirplaneModeEnabled()) {
561             Log.d(mLogTag, "Restrict non-preferred transport at power up");
562             int transportType = getPreferredTransportType();
563             int waitingTimer =
564                     mQnsCarrierConfigManager.getWaitingTimerForPreferredTransportOnPowerOn(
565                             transportType);
566             if (waitingTimer != QnsConstants.KEY_DEFAULT_VALUE) {
567                 int preventTransportType = QnsUtils.getOtherTransportType(transportType);
568                 Log.d(
569                         mLogTag,
570                         "prevent "
571                                 + QnsConstants.transportTypeToString(preventTransportType)
572                                 + " "
573                                 + waitingTimer
574                                 + " milli seconds");
575                 addRestriction(
576                         preventTransportType,
577                         RESTRICT_TYPE_NON_PREFERRED_TRANSPORT,
578                         sReleaseEventMap.get(RESTRICT_TYPE_NON_PREFERRED_TRANSPORT),
579                         waitingTimer);
580             }
581         }
582     }
583 
checkIfCancelNonPreferredRestriction(int transportType)584     private void checkIfCancelNonPreferredRestriction(int transportType) {
585         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
586             releaseRestriction(transportType, RESTRICT_TYPE_NON_PREFERRED_TRANSPORT);
587         }
588     }
589 
getPreferredTransportType()590     private int getPreferredTransportType() {
591         int transportType;
592         int preference = mWfcPreference;
593         if (mCellularCoverage == QnsConstants.COVERAGE_ROAM) {
594             preference = mWfcRoamingPreference;
595         }
596         if (preference == QnsConstants.WIFI_PREF || preference == QnsConstants.WIFI_ONLY) {
597             transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
598         } else {
599             transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
600         }
601         return transportType;
602     }
603 
onCallStateChanged(int callState, int transportType, int cellularAn)604     private void onCallStateChanged(int callState, int transportType, int cellularAn) {
605         Log.d(
606                 mLogTag,
607                 "onCallStateChanged :"
608                         + callState
609                         + " transport:"
610                         + transportType
611                         + " cellularAN:"
612                         + cellularAn);
613         mCallState = callState;
614         if (callState != TelephonyManager.CALL_STATE_IDLE) {
615             if (transportType != AccessNetworkConstants.TRANSPORT_TYPE_WLAN
616                     && cellularAn != AccessNetworkConstants.AccessNetworkType.EUTRAN
617                     && cellularAn != AccessNetworkConstants.AccessNetworkType.NGRAN) {
618                 onCsCallStarted();
619             }
620         } else {
621             releaseRestriction(
622                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
623                     RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL);
624         }
625     }
626 
onSrvccStateChanged(int srvccState)627     private void onSrvccStateChanged(int srvccState) {
628         Log.d(mLogTag, "onSrvccStateChanged :" + srvccState);
629         if (mImsCallType != QnsConstants.CALL_TYPE_IDLE
630                 && srvccState == TelephonyManager.SRVCC_STATE_HANDOVER_STARTED) {
631             addRestriction(
632                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
633                     RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL,
634                     sReleaseEventMap.get(RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL),
635                     0);
636         } else if (mCallState == TelephonyManager.CALL_STATE_IDLE
637                 || srvccState == TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED
638                 || srvccState == TelephonyManager.SRVCC_STATE_HANDOVER_FAILED) {
639             releaseRestriction(
640                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
641                     RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL);
642         }
643     }
644 
onCsCallStarted()645     private void onCsCallStarted() {
646         if (!mQnsCarrierConfigManager.allowImsOverIwlanCellularLimitedCase()) {
647             addRestriction(
648                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
649                     RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL,
650                     sReleaseEventMap.get(RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL),
651                     0);
652         }
653     }
654 
655     @VisibleForTesting
onLowRtpQualityEvent(@nsConstants.RtpLowQualityReason int reason)656     void onLowRtpQualityEvent(@QnsConstants.RtpLowQualityReason int reason) {
657         int lowRtpQualityRestrictTime =
658                 mQnsCarrierConfigManager.getHoRestrictedTimeOnLowRTPQuality(mTransportType);
659         if ((mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
660                         || mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
661                 && lowRtpQualityRestrictTime > 0
662                 && (mImsCallType == QnsConstants.CALL_TYPE_VOICE
663                     || mImsCallType == QnsConstants.CALL_TYPE_EMERGENCY)) {
664             if (reason > 0) {
665                 Restriction restriction =
666                         new LowRtpQualityRestriction(RESTRICT_TYPE_RTP_LOW_QUALITY,
667                                 sReleaseEventMap.get(RESTRICT_TYPE_RTP_LOW_QUALITY),
668                                 lowRtpQualityRestrictTime,
669                                 reason);
670                 // If current report has 'no RTP reason' and previous report at previous
671                 // transport type doesn't have 'no RTP reason', let's move back to previous
672                 // transport type.
673                 if ((reason & 1 << QnsConstants.RTP_LOW_QUALITY_REASON_NO_RTP) != 0) {
674                     releaseRestriction(QnsUtils.getOtherTransportType(mTransportType),
675                             RESTRICT_TYPE_GUARDING, true);
676                     HashMap<Integer, Restriction> restrictionMap = mRestrictInfos
677                             .get(QnsUtils.getOtherTransportType(mTransportType))
678                             .getRestrictionMap();
679                     Restriction restrictionOtherSide = restrictionMap.get(
680                             RESTRICT_TYPE_RTP_LOW_QUALITY);
681                     if (restrictionOtherSide != null
682                             && restrictionOtherSide instanceof LowRtpQualityRestriction) {
683                         int reasonOtherSide =
684                                 ((LowRtpQualityRestriction) restrictionOtherSide).getReason();
685                         if ((reasonOtherSide & 1 << QnsConstants.RTP_LOW_QUALITY_REASON_NO_RTP)
686                                 == 0) {
687                             releaseRestriction(QnsUtils.getOtherTransportType(mTransportType),
688                                     RESTRICT_TYPE_RTP_LOW_QUALITY, true);
689                         }
690                     }
691                 }
692                 // If both transport have low RTP quality restriction, let ANE do final decision.
693                 addRestriction(mTransportType, restriction, lowRtpQualityRestrictTime);
694 
695                 if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
696                     int fallbackReason = mQnsCarrierConfigManager.getQnsIwlanHoRestrictReason();
697                     if (fallbackReason == QnsConstants.FALLBACK_REASON_RTP_OR_WIFI
698                             || fallbackReason == QnsConstants.FALLBACK_REASON_RTP_ONLY) {
699                         increaseCounterToRestrictIwlanInCall();
700                     }
701                 }
702             } else {
703                 if (hasRestrictionType(mTransportType, RESTRICT_TYPE_RTP_LOW_QUALITY)) {
704                     releaseRestriction(mTransportType, RESTRICT_TYPE_RTP_LOW_QUALITY);
705                 }
706             }
707         }
708     }
709 
710     @VisibleForTesting
onDataConnectionChanged(DataConnectionChangedInfo status)711     void onDataConnectionChanged(DataConnectionChangedInfo status) {
712         int dataConnectionState = status.getState();
713         if (dataConnectionState == STATE_CONNECTED || dataConnectionState == STATE_HANDOVER) {
714             mTransportType = status.getTransportType();
715         } else {
716             mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
717         }
718 
719         Log.d(mLogTag, "onDataConnectionChanged transportType:" + status);
720         switch (status.getEvent()) {
721             case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED:
722                 processDataConnectionDisconnected();
723                 break;
724             case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_STARTED:
725                 processDataConnectionStarted(status.getTransportType());
726                 break;
727             case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED:
728                 processDataConnectionConnected(mTransportType);
729                 break;
730             case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED:
731                 processDataConnectionHandoverStarted();
732                 break;
733             case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS:
734                 processDataConnectionHandoverSuccess();
735                 break;
736             case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED:
737                 processDataConnectionHandoverFailed(mTransportType);
738                 break;
739             case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_FAILED:
740                 processDataConnectionFailed(status.getTransportType());
741                 break;
742             default:
743                 Log.d(mLogTag, "unknown DataConnectionChangedEvent:");
744                 break;
745         }
746     }
747 
processDataConnectionConnected(int transportType)748     private void processDataConnectionConnected(int transportType) {
749         // Since HO hysterisis Guard timer is expected
750         checkToCancelInitialPdnConnectionFailFallback();
751         clearInitialPdnConnectionFailFallbackRestriction();
752 
753         checkIfCancelNonPreferredRestriction(QnsUtils.getOtherTransportType(transportType));
754         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
755             if (mLastEvaluatedTransportType == AccessNetworkConstants.TRANSPORT_TYPE_INVALID
756                     || transportType == mLastEvaluatedTransportType) {
757                 processHandoverGuardingOperation(transportType);
758             } else {
759                 Log.d(
760                         mLogTag,
761                         "DataConnectionConnected, but transport type is different,"
762                                 + " Handover init may follow");
763             }
764         }
765     }
766 
clearInitialPdnConnectionFailFallbackRestriction()767     private void clearInitialPdnConnectionFailFallbackRestriction() {
768         mFallbackCounterOnDataConnectionFail = 0;
769         if (hasRestrictionType(
770                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
771                 RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL)) {
772             releaseRestriction(
773                     AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
774                     RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL);
775         }
776         if (hasRestrictionType(
777                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
778                 RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL)) {
779             releaseRestriction(
780                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
781                     RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL);
782         }
783     }
784 
checkToCancelInitialPdnConnectionFailFallback()785     private void checkToCancelInitialPdnConnectionFailFallback() {
786         Log.d(mLogTag, "clear Initial PDN Connection fail Timer checks");
787 
788         mIsTimerRunningOnDataConnectionFail = false;
789         mRetryCounterOnDataConnectionFail = 0;
790 
791         mQnsTimer.unregisterTimer(mFallbackTimerId);
792     }
793 
processDataConnectionDisconnected()794     private void processDataConnectionDisconnected() {
795         processReleaseEvent(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, RELEASE_EVENT_DISCONNECT);
796         processReleaseEvent(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, RELEASE_EVENT_DISCONNECT);
797         mCounterForIwlanRestrictionInCall = 0;
798         if (mDeferredThrottlingEvent != null) {
799             long delayMillis =
800                     mDeferredThrottlingEvent.second - QnsUtils.getSystemElapsedRealTime();
801             if (delayMillis > 0) {
802                 if (mDebugFlag) Log.d(mLogTag, "onDisconnected, process deferred Throttling event");
803                 addRestriction(
804                         mDeferredThrottlingEvent.first,
805                         RESTRICT_TYPE_THROTTLING,
806                         sReleaseEventMap.get(RESTRICT_TYPE_THROTTLING),
807                         delayMillis);
808             }
809             mDeferredThrottlingEvent = null;
810         }
811     }
812 
processDataConnectionStarted(int currTransportType)813     private void processDataConnectionStarted(int currTransportType) {
814         if (mLastDataConnectionTransportType != currTransportType) {
815             Log.d(
816                     mLogTag,
817                     "clear Initial PDN Connection fallback checks for last transport type:"
818                             + mLastDataConnectionTransportType);
819             checkToCancelInitialPdnConnectionFailFallback();
820 
821             if (hasRestrictionType(
822                     mLastDataConnectionTransportType,
823                     RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL)) {
824                 Log.d(
825                         mLogTag,
826                         "PreIncrement_Fallback Counter : " + mFallbackCounterOnDataConnectionFail);
827                 mFallbackCounterOnDataConnectionFail += 1;
828             }
829             mLastDataConnectionTransportType = currTransportType;
830         }
831     }
832 
processDataConnectionHandoverStarted()833     private void processDataConnectionHandoverStarted() {
834         if ((mTransportType != AccessNetworkConstants.TRANSPORT_TYPE_INVALID)
835                 && !hasRestrictionType(mTransportType, RestrictManager.RESTRICT_TYPE_GUARDING)) {
836             startGuarding(GUARDING_TIMER_HANDOVER_INIT, mTransportType);
837         }
838     }
839 
processDataConnectionHandoverSuccess()840     private void processDataConnectionHandoverSuccess() {
841         // Handover Guarding Timer operation
842         processHandoverGuardingOperation(mTransportType);
843 
844         // update LowRtpQualityListener
845         if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
846                 || mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
847             // Return to the transport type restricted by low RTP. It may be singleRAT case, release
848             // the restriction.
849             releaseRestriction(mTransportType, RESTRICT_TYPE_RTP_LOW_QUALITY);
850         }
851     }
852 
processDataConnectionHandoverFailed(int transportType)853     private void processDataConnectionHandoverFailed(int transportType) {
854         cancelGuarding(transportType);
855     }
856 
processHandoverGuardingOperation(int transportType)857     private void processHandoverGuardingOperation(int transportType) {
858         int guardingTransport = QnsUtils.getOtherTransportType(transportType);
859         int delayMillis = getGuardingTimeMillis(guardingTransport, mImsCallType);
860         int minimumGuardingTimer = mQnsCarrierConfigManager.getMinimumHandoverGuardingTimer();
861         if (delayMillis == 0 && minimumGuardingTimer > 0) {
862             delayMillis = minimumGuardingTimer;
863         }
864 
865         if (delayMillis > 0) {
866             startGuarding(delayMillis, guardingTransport);
867         } else {
868             cancelGuarding(guardingTransport);
869         }
870     }
871 
processDataConnectionFailed(int dataConnectionTransportType)872     private void processDataConnectionFailed(int dataConnectionTransportType) {
873         if (mCellularNetworkStatusTracker != null
874                 && !mCellularNetworkStatusTracker.isAirplaneModeEnabled()) {
875             Log.d(mLogTag, "Initiate data connection fail Fallback support check");
876             checkFallbackOnDataConnectionFail(dataConnectionTransportType);
877         } else {
878             checkToCancelInitialPdnConnectionFailFallback();
879         }
880     }
881 
checkFallbackOnDataConnectionFail(int transportType)882     private void checkFallbackOnDataConnectionFail(int transportType) {
883         int[] fallbackConfigOnInitDataFail =
884                 mQnsCarrierConfigManager.getInitialDataConnectionFallbackConfig(mNetCapability);
885 
886         Log.d(
887                 mLogTag,
888                 "FallbackConfig set is :"
889                         + fallbackConfigOnInitDataFail[0]
890                         + ":"
891                         + fallbackConfigOnInitDataFail[1]
892                         + ":"
893                         + fallbackConfigOnInitDataFail[2]);
894 
895         if ((fallbackConfigOnInitDataFail != null && fallbackConfigOnInitDataFail[0] == 1)
896                 && !hasRestrictionType(
897                         transportType, RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL)
898                 && (fallbackConfigOnInitDataFail[3] == 0
899                         || mFallbackCounterOnDataConnectionFail
900                                 < fallbackConfigOnInitDataFail[3])) {
901             Log.d(
902                     mLogTag,
903                     "FallbackCount: "
904                             + fallbackConfigOnInitDataFail[3]
905                             + "_"
906                             + mFallbackCounterOnDataConnectionFail);
907             enableFallbackRetryCountCheckOnInitialPdnFail(
908                     transportType, fallbackConfigOnInitDataFail[1]);
909             enableFallbackRetryTimerCheckOnInitialPdnFail(
910                     transportType, fallbackConfigOnInitDataFail[2]);
911         }
912     }
913 
enableFallbackRetryTimerCheckOnInitialPdnFail( int transportType, int fallbackRetryTimer)914     private void enableFallbackRetryTimerCheckOnInitialPdnFail(
915             int transportType, int fallbackRetryTimer) {
916         Log.d(
917                 mLogTag,
918                 "Start Initial Data Connection fail retry_timer On TransportType"
919                         + fallbackRetryTimer
920                         + "_"
921                         + QnsConstants.transportTypeToString(transportType));
922         if (fallbackRetryTimer > 0 && !mIsTimerRunningOnDataConnectionFail) {
923             Message msg =
924                     mHandler.obtainMessage(
925                             EVENT_INITIAL_DATA_CONNECTION_FAIL_RETRY_TIMER_EXPIRED,
926                             transportType,
927                             0,
928                             null);
929             mFallbackTimerId = mQnsTimer.registerTimer(msg, fallbackRetryTimer);
930             mIsTimerRunningOnDataConnectionFail = true;
931         }
932     }
933 
enableFallbackRetryCountCheckOnInitialPdnFail( int transportType, int fallbackRetryCount)934     private void enableFallbackRetryCountCheckOnInitialPdnFail(
935             int transportType, int fallbackRetryCount) {
936         Log.d(
937                 mLogTag,
938                 "Start Initial Data Connection fail retry_count On TransportType"
939                         + fallbackRetryCount
940                         + "_"
941                         + mRetryCounterOnDataConnectionFail
942                         + "_"
943                         + QnsConstants.transportTypeToString(transportType));
944         if (fallbackRetryCount > 0) {
945             if (mRetryCounterOnDataConnectionFail == fallbackRetryCount) {
946                 fallbackToOtherTransportOnDataConnectionFail(transportType);
947             } else {
948                 mRetryCounterOnDataConnectionFail += 1;
949             }
950         }
951     }
952 
fallbackToOtherTransportOnDataConnectionFail(int currTransportType)953     private void fallbackToOtherTransportOnDataConnectionFail(int currTransportType) {
954 
955         checkToCancelInitialPdnConnectionFailFallback();
956 
957         addRestriction(
958                 currTransportType,
959                 RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL,
960                 sReleaseEventMap.get(RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL),
961                 mQnsCarrierConfigManager.getFallbackGuardTimerOnInitialConnectionFail(
962                         mNetCapability));
963     }
964 
965     @VisibleForTesting
onImsRegistrationStateChanged(QnsImsManager.ImsRegistrationState event)966     void onImsRegistrationStateChanged(QnsImsManager.ImsRegistrationState event) {
967         Log.d(
968                 mLogTag,
969                 "onImsRegistrationStateChanged["
970                         + QnsConstants.transportTypeToString(mTransportType)
971                         + "] transportType["
972                         + QnsConstants.transportTypeToString(event.getTransportType())
973                         + "] RegistrationState["
974                         + QnsConstants.imsRegistrationEventToString(event.getEvent())
975                         + "]");
976         int prefMode =
977                 mCellularCoverage == QnsConstants.COVERAGE_HOME
978                         ? mWfcPreference
979                         : mWfcRoamingPreference;
980 
981         registerRttStatusCheckEvent();
982 
983         switch (event.getEvent()) {
984             case QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED:
985                 onImsUnregistered(event, mTransportType, prefMode);
986                 break;
987             case QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED:
988                 onImsHoRegisterFailed(event, mTransportType, prefMode);
989                 break;
990             case QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED:
991                 Log.d(
992                         mLogTag,
993                         "On Ims Registered: "
994                                 + QnsConstants.transportTypeToString(event.getTransportType()));
995                 if (event.getTransportType() == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
996                         && hasRestrictionType(
997                                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
998                                 RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL)) {
999                     releaseRestriction(
1000                             AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
1001                             RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL);
1002                 }
1003                 break;
1004             default:
1005                 break;
1006         }
1007     }
1008 
registerRttStatusCheckEvent()1009     private void registerRttStatusCheckEvent() {
1010         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
1011 
1012             if (mWifiBackhaulMonitor.isRttCheckEnabled()) {
1013                 if (!mIsRttStatusCheckRegistered) {
1014                     mIsRttStatusCheckRegistered = true;
1015                     mWifiBackhaulMonitor.registerForRttStatusChange(
1016                             mHandler, EVENT_WIFI_RTT_BACKHAUL_CHECK_STATUS);
1017                 }
1018             } else {
1019                 if (mIsRttStatusCheckRegistered) {
1020                     mIsRttStatusCheckRegistered = false;
1021                     mWifiBackhaulMonitor.unRegisterForRttStatusChange(mHandler);
1022                 }
1023             }
1024         }
1025     }
1026 
onImsUnregistered( QnsImsManager.ImsRegistrationState event, int transportType, int prefMode)1027     private void onImsUnregistered(
1028             QnsImsManager.ImsRegistrationState event, int transportType, int prefMode) {
1029         if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
1030             int fallbackTimeMillis =
1031                     mQnsCarrierConfigManager.getFallbackTimeImsUnregistered(
1032                             event.getReasonInfo().getCode(), prefMode);
1033             if (fallbackTimeMillis > 0
1034                     && mQnsCarrierConfigManager.isAccessNetworkAllowed(
1035                             mCellularAccessNetwork, NetworkCapabilities.NET_CAPABILITY_IMS)) {
1036                 fallbackToWwanForImsRegistration(fallbackTimeMillis);
1037             }
1038         }
1039     }
1040 
onImsHoRegisterFailed( QnsImsManager.ImsRegistrationState event, int transportType, int prefMode)1041     private void onImsHoRegisterFailed(
1042             QnsImsManager.ImsRegistrationState event, int transportType, int prefMode) {
1043         if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
1044                 && transportType == event.getTransportType()) {
1045             int fallbackTimeMillis =
1046                     mQnsCarrierConfigManager.getFallbackTimeImsHoRegisterFailed(
1047                             event.getReasonInfo().getCode(), prefMode);
1048             if (fallbackTimeMillis > 0
1049                     && mQnsCarrierConfigManager.isAccessNetworkAllowed(
1050                             mCellularAccessNetwork, NetworkCapabilities.NET_CAPABILITY_IMS)) {
1051                 fallbackToWwanForImsRegistration(fallbackTimeMillis);
1052             }
1053         }
1054     }
1055 
onWlanRttFail()1056     protected void onWlanRttFail() {
1057         Log.d(mLogTag, "start RTT Fallback:");
1058         int fallbackTimeMillis = mQnsCarrierConfigManager.getWlanRttFallbackHystTimer();
1059         if (fallbackTimeMillis > 0
1060                 && mQnsCarrierConfigManager.isAccessNetworkAllowed(
1061                         mCellularAccessNetwork, NetworkCapabilities.NET_CAPABILITY_IMS)) {
1062 
1063             fallbackToWwanForImsRegistration(
1064                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
1065                     RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL,
1066                     fallbackTimeMillis);
1067         }
1068     }
1069 
fallbackToWwanForImsRegistration(int fallbackTimeMillis)1070     private void fallbackToWwanForImsRegistration(int fallbackTimeMillis) {
1071         fallbackToWwanForImsRegistration(
1072                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
1073                 RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL,
1074                 fallbackTimeMillis);
1075     }
1076 
fallbackToWwanForImsRegistration( int transportType, int restrictType, int fallbackTimeMillis)1077     private void fallbackToWwanForImsRegistration(
1078             int transportType, int restrictType, int fallbackTimeMillis) {
1079         Log.d(mLogTag, "release ignorable restrictions on WWAN to fallback.");
1080         for (int restriction : ignorableRestrictionsOnSingleRat) {
1081             releaseRestriction(QnsUtils.getOtherTransportType(transportType), restriction, false);
1082         }
1083         addRestriction(
1084                 transportType,
1085                 restrictType,
1086                 sReleaseEventMap.get(restrictType),
1087                 fallbackTimeMillis);
1088     }
1089 
1090     /** Update Last notified transport type from ANE which owns this RestrictManager */
updateLastNotifiedTransportType(@ccessNetworkConstants.TransportType int transportType)1091     void updateLastNotifiedTransportType(@AccessNetworkConstants.TransportType int transportType) {
1092         if (mDebugFlag) {
1093             Log.d(
1094                     mLogTag,
1095                     "updateLastEvaluatedTransportType: "
1096                             + QnsConstants.transportTypeToString(transportType));
1097         }
1098         mLastEvaluatedTransportType = transportType;
1099         if (mDataConnectionStatusTracker.isActiveState() && mTransportType != transportType) {
1100             startGuarding(GUARDING_TIMER_HANDOVER_INIT,
1101                     QnsUtils.getOtherTransportType(transportType));
1102         }
1103     }
1104 
1105     @VisibleForTesting
setCellularCoverage(@nsConstants.CellularCoverage int coverage)1106     void setCellularCoverage(@QnsConstants.CellularCoverage int coverage) {
1107         Log.d(mLogTag, "setCellularCoverage:" + QnsConstants.coverageToString(coverage));
1108         mCellularCoverage = coverage;
1109         checkIfCancelNonPreferredRestriction(getPreferredTransportType());
1110     }
1111 
setQnsCallType(@nsConstants.QnsCallType int callType)1112     protected void setQnsCallType(@QnsConstants.QnsCallType int callType) {
1113         if (callType != mImsCallType) {
1114             updateGuardingTimerConditionOnCallState(mImsCallType, callType);
1115         }
1116 
1117         mImsCallType = callType;
1118 
1119         Log.d(mLogTag, "setQnsCallType: " + QnsConstants.callTypeToString(callType));
1120         if (callType == QnsConstants.CALL_TYPE_IDLE) {
1121             Log.d(mLogTag, "Call end. init mCounterForIwlanRestrictionInCall");
1122             mCounterForIwlanRestrictionInCall = 0;
1123 
1124             processReleaseEvent(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, RELEASE_EVENT_CALL_END);
1125             processReleaseEvent(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, RELEASE_EVENT_CALL_END);
1126             unregisterLowRtpQualityEvent();
1127         } else {
1128             registerLowRtpQualityEvent();
1129         }
1130     }
1131 
updateGuardingTimerConditionOnCallState(int prevCallType, int newCallType)1132     private void updateGuardingTimerConditionOnCallState(int prevCallType, int newCallType) {
1133         int currGuardingTransport = QnsUtils.getOtherTransportType(mTransportType);
1134         if (mRestrictInfos.get(currGuardingTransport) == null) return;
1135 
1136         HashMap<Integer, Restriction> restrictionMap =
1137                 mRestrictInfos.get(currGuardingTransport).getRestrictionMap();
1138         Restriction restriction = restrictionMap.get(RESTRICT_TYPE_GUARDING);
1139 
1140         if (restriction != null) {
1141             int prevCallTypeMillis = getGuardingTimeMillis(currGuardingTransport, prevCallType);
1142             if (prevCallTypeMillis == 0) {
1143                 return; // We don't need to update minimum guarding timer.
1144             }
1145             int newCallTypeMillis =
1146                     getGuardingTimeMillis(
1147                             currGuardingTransport, newCallType); // new Call type timer
1148             if (newCallTypeMillis == prevCallTypeMillis) return;
1149 
1150             if (newCallTypeMillis != 0) {
1151                 // remaining time on current call type
1152                 long prevCallTypeRemainingMillis =
1153                         restriction.mReleaseTime - SystemClock.elapsedRealtime();
1154                 int guardTimerElapsed = prevCallTypeMillis - (int) prevCallTypeRemainingMillis;
1155                 int newGuardTimer = newCallTypeMillis - guardTimerElapsed;
1156 
1157                 if (mDebugFlag) {
1158                     Log.d(
1159                             mLogTag,
1160                             "Prev Call Type Guarding millis:"
1161                                     + prevCallTypeMillis
1162                                     + "Prev Call type remaining millis:"
1163                                     + prevCallTypeRemainingMillis
1164                                     + "New Call type Guarding millis:"
1165                                     + newCallTypeMillis
1166                                     + "Guard timer Elapsed:"
1167                                     + guardTimerElapsed
1168                                     + "New Guard timer to set:"
1169                                     + newGuardTimer);
1170                 }
1171                 if (newGuardTimer > 0) {
1172                     startGuarding(newGuardTimer, currGuardingTransport);
1173                     return;
1174                 }
1175             }
1176             cancelGuarding(currGuardingTransport);
1177         }
1178     }
1179 
1180     @VisibleForTesting
setCellularAccessNetwork(int accessNetwork)1181     void setCellularAccessNetwork(int accessNetwork) {
1182         mCellularAccessNetwork = accessNetwork;
1183         Log.d(mLogTag, "Current Cellular Network:" + mCellularAccessNetwork);
1184         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS
1185                 && !mQnsCarrierConfigManager.isAccessNetworkAllowed(
1186                         accessNetwork, mNetCapability)) {
1187             processReleaseEvent(
1188                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN, RELEASE_EVENT_IMS_NOT_SUPPORT_RAT);
1189         }
1190     }
1191 
addRestriction(int transport, Restriction restrictObj, long timeMillis)1192     void addRestriction(int transport, Restriction restrictObj, long timeMillis) {
1193         boolean needNotify = false;
1194         HashMap<Integer, Restriction> restrictionMap =
1195                 mRestrictInfos.get(transport).getRestrictionMap();
1196         Restriction restriction = restrictionMap.get(restrictObj.mRestrictType);
1197         Log.d(
1198                 mLogTag,
1199                 "addRestriction["
1200                         + QnsConstants.transportTypeToString(transport)
1201                         + "] "
1202                         + restrictTypeToString(restrictObj.mRestrictType)
1203                         + " was restrict:"
1204                         + (restriction != null)
1205                         + " timeMillis:" + timeMillis);
1206         if (restriction == null) {
1207             restriction = restrictObj;
1208             restrictionMap.put(restrictObj.mRestrictType, restriction);
1209             Log.d(
1210                     mLogTag,
1211                     "addRestriction["
1212                             + QnsConstants.transportTypeToString(transport)
1213                             + "] "
1214                             + restriction);
1215             needNotify = true;
1216         } else {
1217             if (timeMillis > 0) {
1218                 restriction.updateRestrictTime(timeMillis);
1219                 removeReleaseRestrictionMessage(restriction);
1220             }
1221             Log.d(
1222                     mLogTag,
1223                     "updateRestriction["
1224                             + QnsConstants.transportTypeToString(transport)
1225                             + "] "
1226                             + restriction);
1227         }
1228         if (timeMillis > 0) {
1229             sendReleaseRestrictionMessage(transport, restriction);
1230         }
1231         if (needNotify) {
1232             notifyRestrictInfoChanged();
1233         }
1234     }
1235 
addRestriction(int transport, int type, int[] releaseEvents, long timeMillis)1236     void addRestriction(int transport, int type, int[] releaseEvents, long timeMillis) {
1237         boolean needNotify = false;
1238         HashMap<Integer, Restriction> restrictionMap =
1239                 mRestrictInfos.get(transport).getRestrictionMap();
1240         Restriction restriction = restrictionMap.get(type);
1241         Log.d(
1242                 mLogTag,
1243                 "addRestriction["
1244                         + QnsConstants.transportTypeToString(transport)
1245                         + "] "
1246                         + restrictTypeToString(type)
1247                         + " was restrict:"
1248                         + (restriction != null)
1249                         + " timeMillis:" + timeMillis);
1250         if (restriction == null) {
1251             restriction = new Restriction(type, releaseEvents, timeMillis);
1252             restrictionMap.put(type, restriction);
1253             Log.d(
1254                     mLogTag,
1255                     "addRestriction["
1256                             + QnsConstants.transportTypeToString(transport)
1257                             + "] "
1258                             + restriction);
1259             needNotify = true;
1260         } else {
1261             if (timeMillis > 0) {
1262                 restriction.updateRestrictTime(timeMillis);
1263                 removeReleaseRestrictionMessage(restriction);
1264             }
1265             Log.d(
1266                     mLogTag,
1267                     "updateRestriction["
1268                             + QnsConstants.transportTypeToString(transport)
1269                             + "] "
1270                             + restriction);
1271         }
1272         if (timeMillis > 0) {
1273             sendReleaseRestrictionMessage(transport, restriction);
1274         }
1275         if (needNotify) {
1276             notifyRestrictInfoChanged();
1277         }
1278     }
1279 
releaseRestriction(int transport, int type)1280     void releaseRestriction(int transport, int type) {
1281         releaseRestriction(transport, type, false);
1282     }
1283 
releaseRestriction(int transport, int type, boolean skipNotify)1284     void releaseRestriction(int transport, int type, boolean skipNotify) {
1285         boolean needNotify = false;
1286         HashMap<Integer, Restriction> restrictionMap =
1287                 mRestrictInfos.get(transport).getRestrictionMap();
1288         Restriction restriction = restrictionMap.get(type);
1289         Log.d(
1290                 mLogTag,
1291                 "releaseRestriction["
1292                         + QnsConstants.transportTypeToString(transport)
1293                         + "] "
1294                         + restrictTypeToString(type)
1295                         + " was restrict:"
1296                         + (restriction != null));
1297         if (restriction == null) {
1298             Log.d(mLogTag, "no restriction to release " + restrictTypeToString(type) + " " + type);
1299         } else {
1300             if (restriction.mReleaseTime > 0) {
1301                 removeReleaseRestrictionMessage(restriction);
1302             }
1303             restrictionMap.remove(restriction.mRestrictType);
1304             mRestrictionTimers.remove(restriction);
1305             needNotify = true;
1306         }
1307         if (needNotify && !skipNotify) {
1308             notifyRestrictInfoChanged();
1309         }
1310     }
1311 
processReleaseEvent(int transportType, int event)1312     void processReleaseEvent(int transportType, int event) {
1313         ArrayList<Integer> releaseList = new ArrayList<>();
1314         HashMap<Integer, Restriction> restrictMap =
1315                 mRestrictInfos.get(transportType).getRestrictionMap();
1316         Log.d(
1317                 mLogTag,
1318                 "processReleaseEvent["
1319                         + QnsConstants.transportTypeToString(transportType)
1320                         + "] "
1321                         + event);
1322 
1323         for (Integer restrictType : restrictMap.keySet()) {
1324             if (restrictMap.get(restrictType).needRelease(event)) {
1325                 releaseList.add(restrictType);
1326             }
1327         }
1328         for (Integer restrictType : releaseList) {
1329             releaseRestriction(transportType, restrictType);
1330         }
1331     }
1332 
sendReleaseRestrictionMessage(int transportType, Restriction restriction)1333     private void sendReleaseRestrictionMessage(int transportType, Restriction restriction) {
1334         if (restriction == null) {
1335             Log.e(mLogTag, "sendReleaseRestrictionMessage restriction is null");
1336             return;
1337         }
1338         Message msg =
1339                 mHandler.obtainMessage(EVENT_RELEASE_RESTRICTION, transportType, 0, restriction);
1340         long delayInMillis = restriction.mReleaseTime - SystemClock.elapsedRealtime();
1341         int timerId = mQnsTimer.registerTimer(msg, delayInMillis);
1342         mRestrictionTimers.put(restriction, timerId);
1343         Log.d(
1344                 mLogTag,
1345                 restrictTypeToString(restriction.mRestrictType)
1346                         + " will be released after "
1347                         + delayInMillis
1348                         + " millisecs");
1349     }
1350 
removeReleaseRestrictionMessage(Restriction restriction)1351     private void removeReleaseRestrictionMessage(Restriction restriction) {
1352         if (restriction == null) {
1353             Log.e(mLogTag, "removeReleaseRestrictionMessage restriction is null");
1354             return;
1355         }
1356         mQnsTimer.unregisterTimer(mRestrictionTimers.getOrDefault(restriction, INVALID_ID));
1357         mRestrictionTimers.remove(restriction);
1358     }
1359 
registerRestrictInfoChanged(Handler h, int what)1360     void registerRestrictInfoChanged(Handler h, int what) {
1361         mRestrictInfoRegistrant = new QnsRegistrant(h, what, null);
1362     }
1363 
unRegisterRestrictInfoChanged(Handler h)1364     void unRegisterRestrictInfoChanged(Handler h) {
1365         mRestrictInfoRegistrant = null;
1366     }
1367 
1368     @VisibleForTesting
isRestricted(int transportType)1369     boolean isRestricted(int transportType) {
1370         if (mRestrictInfos.isEmpty()) return false;
1371 
1372         if (mRestrictInfos.get(transportType) != null) {
1373             return mRestrictInfos.get(transportType).isRestricted();
1374         }
1375 
1376         return false;
1377     }
1378 
isRestrictedExceptGuarding(int transportType)1379     boolean isRestrictedExceptGuarding(int transportType) {
1380         try {
1381             RestrictInfo info = mRestrictInfos.get(transportType);
1382             int size = info.getRestrictionMap().size();
1383             if (info.hasRestrictionType(RESTRICT_TYPE_GUARDING)) {
1384                 size--;
1385             }
1386             return size > 0;
1387         } catch (Exception e) {
1388         }
1389         return false;
1390     }
1391 
1392     @VisibleForTesting
hasRestrictionType(int transportType, int restrictType)1393     boolean hasRestrictionType(int transportType, int restrictType) {
1394         try {
1395             if (mRestrictInfos != null) {
1396                 return mRestrictInfos.get(transportType).hasRestrictionType(restrictType);
1397             }
1398         } catch (Exception e) {
1399 
1400         }
1401         return false;
1402     }
1403 
1404     /** This method is only for Testing */
1405     @VisibleForTesting
getRemainingGuardTimer(int transportType)1406     protected long getRemainingGuardTimer(int transportType) {
1407         return mRestrictInfos
1408                         .get(transportType)
1409                         .getRestrictionMap()
1410                         .get(RESTRICT_TYPE_GUARDING)
1411                         .mReleaseTime
1412                 - SystemClock.elapsedRealtime();
1413     }
1414 
1415     @VisibleForTesting
isAllowedOnSingleTransport(int transportType)1416     boolean isAllowedOnSingleTransport(int transportType) {
1417         if (mRestrictInfos.isEmpty()) return false;
1418         Log.d(
1419                 mLogTag,
1420                 "isAllowedOnSingleTransport ("
1421                         + QnsConstants.transportTypeToString(transportType)
1422                         + ")  restriction :"
1423                         + mRestrictInfos.get(transportType).toString());
1424         int countIgnorableRestriction = 0;
1425         for (int restrictType : ignorableRestrictionsOnSingleRat) {
1426             if (mRestrictInfos.get(transportType).hasRestrictionType(restrictType)) {
1427                 countIgnorableRestriction++;
1428             }
1429         }
1430         if (mRestrictInfos.get(transportType).getRestrictionMap().size()
1431                 == countIgnorableRestriction) {
1432             return true;
1433         }
1434         return false;
1435     }
1436 
increaseCounterToRestrictIwlanInCall()1437     void increaseCounterToRestrictIwlanInCall() {
1438         mCounterForIwlanRestrictionInCall += 1;
1439         int maxAllowedRoveOutByLowRtpQuality =
1440                 mQnsCarrierConfigManager.getQnsMaxIwlanHoCountDuringCall();
1441         if (maxAllowedRoveOutByLowRtpQuality > 0
1442                 && mCounterForIwlanRestrictionInCall == maxAllowedRoveOutByLowRtpQuality) {
1443             Log.d(mLogTag, "reached maxAllowedRoveOutByLowRtpQuality");
1444             addRestriction(
1445                     AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
1446                     RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL,
1447                     sReleaseEventMap.get(RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL),
1448                     0);
1449         }
1450     }
1451 
notifyRestrictInfoChanged()1452     private void notifyRestrictInfoChanged() {
1453         Log.d(mLogTag, "notifyRestrictInfoChanged");
1454         if (mRestrictInfoRegistrant != null) {
1455             mRestrictInfoRegistrant.notifyResult(mRestrictInfos);
1456 
1457             // metrics
1458             sendRestrictionsForMetrics();
1459         } else {
1460             Log.d(mLogTag, "notifyRestrictInfoChanged. no Registrant.");
1461         }
1462     }
1463 
registerLowRtpQualityEvent()1464     private void registerLowRtpQualityEvent() {
1465         if ((mImsCallType == QnsConstants.CALL_TYPE_VOICE
1466                         || mImsCallType == QnsConstants.CALL_TYPE_EMERGENCY)
1467                 && (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
1468                         || mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
1469                 && mActiveCallTracker != null) {
1470             int hoRestrictTimeOnLowRtpQuality =
1471                     mQnsCarrierConfigManager.getHoRestrictedTimeOnLowRTPQuality(mTransportType);
1472             if (hoRestrictTimeOnLowRtpQuality > 0) {
1473                 Log.d(mLogTag, "registerLowRtpQualityEvent");
1474                 mActiveCallTracker.registerLowMediaQualityListener(
1475                         mHandler, EVENT_LOW_RTP_QUALITY_REPORTED, null);
1476             }
1477         }
1478     }
1479 
unregisterLowRtpQualityEvent()1480     private void unregisterLowRtpQualityEvent() {
1481         if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS
1482                 || mNetCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
1483             if (mActiveCallTracker != null) {
1484                 mActiveCallTracker.unregisterLowMediaQualityListener(mHandler);
1485             }
1486         }
1487     }
1488 
getGuardingTimeMillis(int transportType, int callType)1489     private int getGuardingTimeMillis(int transportType, int callType) {
1490         int delayMillis;
1491         switch (mNetCapability) {
1492             case NetworkCapabilities.NET_CAPABILITY_IMS:
1493             case NetworkCapabilities.NET_CAPABILITY_EIMS:
1494                 if (!mQnsCarrierConfigManager.isHysteresisTimerEnabled(mCellularCoverage)) {
1495                     Log.d(
1496                             mLogTag,
1497                             "getGuardingTimeMillis: handover guarding timer is not enabled at "
1498                                     + QnsConstants.coverageToString(mCellularCoverage));
1499                     return 0;
1500                 }
1501                 if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
1502                     delayMillis =
1503                             mQnsCarrierConfigManager.getWwanHysteresisTimer(
1504                                     mNetCapability, callType);
1505                 } else {
1506                     delayMillis =
1507                             mQnsCarrierConfigManager.getWlanHysteresisTimer(
1508                                     mNetCapability, callType);
1509                 }
1510                 if (delayMillis > 0
1511                         && mQnsCarrierConfigManager.isGuardTimerHysteresisOnPrefSupported()) {
1512                     int preference = mWfcPreference;
1513                     if (mCellularCoverage == QnsConstants.COVERAGE_ROAM) {
1514                         preference = mWfcRoamingPreference;
1515                     }
1516                     if (preference == QnsConstants.CELL_PREF
1517                             && transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
1518                         Log.d(
1519                                 mLogTag,
1520                                 "getGuardingTimeMillis: cellular preferred case, don't guard"
1521                                         + " handover to WLAN");
1522                         delayMillis = 0;
1523                     } else if (preference == QnsConstants.WIFI_PREF
1524                             && transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
1525                         Log.d(
1526                                 mLogTag,
1527                                 "getGuardingTimeMillis: wifi preferred case, don't guard handover"
1528                                         + " to WWAN");
1529                         delayMillis = 0;
1530                     }
1531                 }
1532                 break;
1533             case NetworkCapabilities.NET_CAPABILITY_MMS:
1534             case NetworkCapabilities.NET_CAPABILITY_XCAP:
1535             case NetworkCapabilities.NET_CAPABILITY_CBS:
1536                 callType = mQnsCallStatusTracker.isCallIdle() ? QnsConstants.CALL_TYPE_IDLE
1537                                 : QnsConstants.CALL_TYPE_VOICE;
1538                 if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
1539                     delayMillis =
1540                             mQnsCarrierConfigManager.getWwanHysteresisTimer(
1541                                     mNetCapability, callType);
1542                 } else if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
1543                     delayMillis =
1544                             mQnsCarrierConfigManager.getWlanHysteresisTimer(
1545                                     mNetCapability, callType);
1546                 } else {
1547                     delayMillis = 0;
1548                 }
1549                 break;
1550             default:
1551                 delayMillis = 0;
1552                 break;
1553         }
1554         Log.d(
1555                 mLogTag,
1556                 "getGuardingTimeMillis: timer = "
1557                         + delayMillis
1558                         + " for transport type = "
1559                         + QnsConstants.transportTypeToString(transportType)
1560                         + " in "
1561                         + QnsConstants.callTypeToString(callType)
1562                         + " state.");
1563 
1564         return delayMillis;
1565     }
1566 
1567     @VisibleForTesting
startGuarding(int delay, int transportType)1568     void startGuarding(int delay, int transportType) {
1569         // It is invalid to run to RESTRICT_TYPE_GUARDING for both Transport at same time
1570         // Make sure to release source TransportType Guarding before starting guarding for New
1571         // Transport
1572         // Type
1573         if (transportType != AccessNetworkConstants.TRANSPORT_TYPE_INVALID
1574                 && hasRestrictionType(QnsUtils.getOtherTransportType(transportType),
1575                 RestrictManager.RESTRICT_TYPE_GUARDING)) {
1576             Log.d(
1577                     mLogTag,
1578                     "RESTRICT_TYPE_GUARDING cleared from Guarding for:"
1579                             + QnsConstants.transportTypeToString(mTransportType));
1580             // addRestriction() will take care to notify the ANE of Restrict Info status
1581             releaseRestriction(
1582                     QnsUtils.getOtherTransportType(transportType), RESTRICT_TYPE_GUARDING, true);
1583         }
1584 
1585         addRestriction(
1586                 transportType,
1587                 RESTRICT_TYPE_GUARDING,
1588                 sReleaseEventMap.get(RESTRICT_TYPE_GUARDING),
1589                 delay);
1590     }
1591 
cancelGuarding(int transportType)1592     private void cancelGuarding(int transportType) {
1593         releaseRestriction(transportType, RESTRICT_TYPE_GUARDING);
1594     }
1595 
notifyThrottling(boolean throttle, long throttleTime, int transportType)1596     protected void notifyThrottling(boolean throttle, long throttleTime, int transportType) {
1597         Log.d(
1598                 mLogTag,
1599                 "notifyThrottling throttle:"
1600                         + throttle
1601                         + "  throttleTime:"
1602                         + throttleTime
1603                         + "  transportType:"
1604                         + QnsConstants.transportTypeToString(transportType));
1605         if (throttle) {
1606             if (throttleTime < 0) {
1607                 //FWK send minus value of throttle expiration time, consider anomaly report at here.
1608                 return;
1609             }
1610             long delayMillis = throttleTime - SystemClock.elapsedRealtime();
1611             if (delayMillis > 0) {
1612                 if (mDataConnectionStatusTracker.isActiveState()) {
1613                     Log.d(
1614                             mLogTag,
1615                             "Defer Throttling event during active state transportType:"
1616                                     + transportType
1617                                     + " ThrottleTime:"
1618                                     + throttleTime);
1619                     mDeferredThrottlingEvent = new Pair<>(transportType, throttleTime);
1620                 } else {
1621                     if (throttleTime == Long.MAX_VALUE || throttleTime == Integer.MAX_VALUE) {
1622                         //Keep throttle status until receiving un-throttle event.
1623                         delayMillis = 0;
1624                     }
1625                     addRestriction(
1626                             transportType,
1627                             RESTRICT_TYPE_THROTTLING,
1628                             sReleaseEventMap.get(RESTRICT_TYPE_THROTTLING),
1629                             delayMillis);
1630                 }
1631             }
1632         } else {
1633             releaseRestriction(transportType, RESTRICT_TYPE_THROTTLING);
1634             if (mDeferredThrottlingEvent != null) mDeferredThrottlingEvent = null;
1635         }
1636     }
1637 
restrictTypeToString(int restrictType)1638     static String restrictTypeToString(int restrictType) {
1639         switch (restrictType) {
1640             case RESTRICT_TYPE_GUARDING:
1641                 return "RESTRICT_TYPE_GUARDING";
1642             case RESTRICT_TYPE_THROTTLING:
1643                 return "RESTRICT_TYPE_THROTTLING";
1644             case RESTRICT_TYPE_HO_NOT_ALLOWED:
1645                 return "RESTRICT_TYPE_HO_NOT_ALLOWED";
1646             case RESTRICT_TYPE_NON_PREFERRED_TRANSPORT:
1647                 return "RESTRICT_TYPE_NON_PREFERRED_TRANSPORT";
1648             case RESTRICT_TYPE_RTP_LOW_QUALITY:
1649                 return "RESTRICT_TYPE_RTP_LOW_QUALITY";
1650             case RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL:
1651                 return "RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL";
1652             case RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL:
1653                 return "RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL";
1654             case RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL:
1655                 return "RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL";
1656             case RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL:
1657                 return "RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL";
1658             case RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL:
1659                 return "RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL";
1660         }
1661         return "";
1662     }
1663 
1664     /**
1665      * Dumps the state of {@link QualityMonitor}
1666      *
1667      * @param pw {@link PrintWriter} to write the state of the object.
1668      * @param prefix String to append at start of dumped log.
1669      */
dump(PrintWriter pw, String prefix)1670     void dump(PrintWriter pw, String prefix) {
1671         pw.println(prefix + "------------------------------");
1672         pw.println(
1673                 prefix
1674                         + "RestrictManager["
1675                         + QnsUtils.getNameOfNetCapability(mNetCapability)
1676                         + "_"
1677                         + mSlotId
1678                         + "]:");
1679         pw.println(
1680                 prefix
1681                         + "mTransportType="
1682                         + QnsConstants.transportTypeToString(mTransportType)
1683                         + ", mLastEvaluatedTransportType="
1684                         + QnsConstants.transportTypeToString(mLastEvaluatedTransportType)
1685                         + ", mLastDataConnectionTransportType="
1686                         + QnsConstants.transportTypeToString(mLastDataConnectionTransportType));
1687         pw.println(
1688                 prefix
1689                         + "mCounterForIwlanRestrictionInCall="
1690                         + mCounterForIwlanRestrictionInCall
1691                         + ", mRetryCounterOnDataConnectionFail="
1692                         + mRetryCounterOnDataConnectionFail
1693                         + ", mFallbackCounterOnDataConnectionFail="
1694                         + mFallbackCounterOnDataConnectionFail);
1695         pw.println(
1696                 prefix
1697                         + "mImsCallType="
1698                         + QnsConstants.callTypeToString(mImsCallType)
1699                         + ", mCallState="
1700                         + QnsConstants.callStateToString(mCallState));
1701         pw.println(prefix + "mRestrictInfos=" + mRestrictInfos);
1702     }
1703 
sendRestrictionsForMetrics()1704     private void sendRestrictionsForMetrics() {
1705         if (mNetCapability != NetworkCapabilities.NET_CAPABILITY_IMS) {
1706             return;
1707         }
1708         ArrayList<Integer> wlanRestrictions =
1709                 new ArrayList<>(
1710                         mRestrictInfos
1711                                 .get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
1712                                 .getRestrictionMap()
1713                                 .keySet());
1714         ArrayList<Integer> wwanRestrictions =
1715                 new ArrayList<>(
1716                         mRestrictInfos
1717                                 .get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
1718                                 .getRestrictionMap()
1719                                 .keySet());
1720         mQnsMetrics.reportAtomForRestrictions(mNetCapability, mSlotId,
1721                 wlanRestrictions, wwanRestrictions, mQnsCarrierConfigManager.getCarrierId());
1722     }
1723 }
1724