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 android.telephony.AccessNetworkConstants.AccessNetworkType;
20 import android.telephony.SignalThresholdInfo;
21 import android.util.Log;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.concurrent.atomic.AtomicInteger;
26 
27 class ThresholdGroup {
28     private static final AtomicInteger sGid = new AtomicInteger();
29 
30     private final List<Threshold> mThresholds;
31     private final String mTag;
32 
ThresholdGroup(List<Threshold> ths)33     ThresholdGroup(List<Threshold> ths) {
34         int groupId = sGid.getAndIncrement();
35         mThresholds = alignGroupId(groupId, ths);
36         mTag = ThresholdGroup.class.getSimpleName() + groupId;
37     }
38 
alignGroupId(int groupId, List<Threshold> ths)39     private List<Threshold> alignGroupId(int groupId, List<Threshold> ths) {
40         if (ths == null) {
41             return new ArrayList<>();
42         }
43         ArrayList<Threshold> newList = new ArrayList<>(ths);
44         for (Threshold th : newList) {
45             th.setGroupId(groupId);
46         }
47         return newList;
48     }
49 
satisfiedByThreshold( QualityMonitor wifiMonitor, QualityMonitor cellMonitor, boolean iwlanAvailable, boolean cellAvailable, int cellularAccessNetworkType)50     boolean satisfiedByThreshold(
51             QualityMonitor wifiMonitor,
52             QualityMonitor cellMonitor,
53             boolean iwlanAvailable,
54             boolean cellAvailable,
55             int cellularAccessNetworkType) {
56         if (mThresholds == null || mThresholds.isEmpty()) {
57             return false;
58         }
59         boolean omittedCellularAvailable = true;
60         for (Threshold th : mThresholds) {
61             if (th.getAccessNetwork() == AccessNetworkType.IWLAN) {
62                 if (!satisfy(th, wifiMonitor, iwlanAvailable, AccessNetworkType.IWLAN)) {
63                     return false;
64                 }
65             }
66             if (th.getAccessNetwork() != AccessNetworkType.IWLAN) {
67                 omittedCellularAvailable = false;
68                 if (!satisfy(th, cellMonitor, cellAvailable, cellularAccessNetworkType)) {
69                     return false;
70                 }
71             }
72         }
73         if (omittedCellularAvailable && !cellAvailable) {
74             return false;
75         }
76         return true;
77     }
78 
satisfy(Threshold th, QualityMonitor monitor, boolean available, int an)79     private boolean satisfy(Threshold th, QualityMonitor monitor, boolean available, int an) {
80         // availability
81         if (th.getMeasurementType() == QnsConstants.SIGNAL_MEASUREMENT_AVAILABILITY) {
82             if (th.getThreshold() == QnsConstants.SIGNAL_AVAILABLE
83                     && available
84                     && an == th.getAccessNetwork()) {
85                 Log.d(mTag, "satisfy " + th.toShortString() + " currentQuality:Available");
86                 return true;
87             }
88             if (th.getThreshold() == QnsConstants.SIGNAL_UNAVAILABLE
89                     && (!available || an != th.getAccessNetwork())) {
90                 Log.d(mTag, "satisfy " + th.toShortString() + " currentQuality:Unavailable");
91                 return true;
92             }
93             Log.d(mTag, "not satisfy " + th.toShortString() + " available:" + available);
94             return false;
95         }
96 
97         // measurement matching
98         if (th.getAccessNetwork() != an) {
99             return false;
100         }
101         int cq = monitor.getCurrentQuality(th.getAccessNetwork(), th.getMeasurementType());
102         if (th.isMatching(cq)) {
103             Log.d(mTag, "satisfy " + th.toShortString() + " currentQuality:" + cq);
104             return true;
105         } else {
106             Log.d(mTag, "not satisfy " + th.toShortString() + " currentQuality:" + cq);
107             return false;
108         }
109     }
110 
findUnmatchedThresholds( QualityMonitor wifiMonitor, QualityMonitor cellMonitor)111     List<Threshold> findUnmatchedThresholds(
112             QualityMonitor wifiMonitor, QualityMonitor cellMonitor) {
113         List<Threshold> tl = new ArrayList<>();
114         if (mThresholds == null || mThresholds.isEmpty()) {
115             return tl;
116         }
117 
118         for (Threshold th : mThresholds) {
119             if (th.getMeasurementType() == QnsConstants.SIGNAL_MEASUREMENT_AVAILABILITY) {
120                 continue;
121             }
122 
123             boolean isIwlan = th.getAccessNetwork() == AccessNetworkType.IWLAN;
124             QualityMonitor monitor = isIwlan ? wifiMonitor : cellMonitor;
125             int cq = monitor.getCurrentQuality(th.getAccessNetwork(), th.getMeasurementType());
126 
127             if (th.isMatching(cq)) {
128                 Log.d(mTag, "Threshold " + th.toShortString() + " is matched. current:" + cq);
129             } else {
130                 Log.d(mTag, "Threshold " + th.toShortString() + " is not matched. current:" + cq);
131                 tl.add(th);
132             }
133         }
134         return tl;
135     }
136 
hasWifiThresholdWithoutCellularCondition()137     boolean hasWifiThresholdWithoutCellularCondition() {
138         if (mThresholds == null || mThresholds.isEmpty()) {
139             return false;
140         }
141         boolean foundIwlanRssiThreshold = false;
142         boolean foundCellularUnavailable = false;
143         for (Threshold th : mThresholds) {
144             if (th.getMeasurementType() == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI
145                     && th.getAccessNetwork() == AccessNetworkType.IWLAN) {
146                 foundIwlanRssiThreshold = true;
147             }
148             if (th.getMeasurementType() == QnsConstants.SIGNAL_MEASUREMENT_AVAILABILITY
149                     && th.getThreshold() == QnsConstants.SIGNAL_UNAVAILABLE
150                     && th.getAccessNetwork() != AccessNetworkType.IWLAN) {
151                 foundCellularUnavailable = true;
152             }
153         }
154         return foundIwlanRssiThreshold && foundCellularUnavailable;
155     }
156 
getThresholds(int accessNetworkType)157     List<Threshold> getThresholds(int accessNetworkType) {
158         List<Threshold> accessNetworkTypeThresholdList = new ArrayList<>();
159         for (Threshold t : mThresholds) {
160             if (t.getAccessNetwork() == accessNetworkType) {
161                 accessNetworkTypeThresholdList.add(t);
162             }
163         }
164         return accessNetworkTypeThresholdList;
165     }
166 
toShortString()167     String toShortString() {
168         StringBuilder sb = new StringBuilder();
169         sb.append("(");
170         if (mThresholds != null && mThresholds.size() > 0) {
171             for (Threshold th : mThresholds) {
172                 sb.append(th.toShortString()).append(",");
173             }
174             sb.deleteCharAt(sb.lastIndexOf(","));
175         }
176         sb.append(")");
177         return sb.toString();
178     }
179 
identicalThreshold(List<Threshold> o)180     boolean identicalThreshold(List<Threshold> o) {
181         if (mThresholds == o) return true;
182         if (mThresholds == null || o == null) return false;
183         if (mThresholds.size() != o.size()) return false;
184         for (Threshold th : mThresholds) {
185             boolean found = false;
186             for (Threshold tho : o) {
187                 if (th.identicalThreshold(tho)) {
188                     found = true;
189                     break;
190                 }
191             }
192             if (!found) {
193                 return false;
194             }
195         }
196         return true;
197     }
198 }
199