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