1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telephony; 18 19 import android.annotation.NonNull; 20 import android.os.Binder; 21 import android.os.IBinder; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.util.ArrayList; 26 import java.util.Collection; 27 import java.util.Collections; 28 import java.util.Comparator; 29 import java.util.HashMap; 30 import java.util.HashSet; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.Objects; 34 import java.util.Set; 35 36 /** 37 * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength 38 * breach the specified thresholds. 39 */ 40 public final class SignalStrengthUpdateRequest implements Parcelable { 41 /** 42 * List of SignalThresholdInfo for the request. 43 */ 44 private final List<SignalThresholdInfo> mSignalThresholdInfos; 45 46 /** 47 * Whether the reporting is required for thresholds in the request while device is idle. 48 */ 49 private final boolean mIsReportingRequestedWhileIdle; 50 51 /** 52 * Whether the reporting requested for system thresholds while device is idle. 53 * 54 * System signal thresholds are loaded from carrier config items and mainly used for UI 55 * displaying. By default, they are ignored when device is idle. When setting the value to true, 56 * modem will continue reporting signal strength changes over the system signal thresholds even 57 * device is idle. 58 * 59 * This should only set to true by the system caller. 60 */ 61 private final boolean mIsSystemThresholdReportingRequestedWhileIdle; 62 63 /** 64 * A IBinder object as a token for server side to check if the request client is still living. 65 */ 66 private final IBinder mLiveToken; 67 SignalStrengthUpdateRequest( @onNull List<SignalThresholdInfo> signalThresholdInfos, boolean isReportingRequestedWhileIdle, boolean isSystemThresholdReportingRequestedWhileIdle)68 private SignalStrengthUpdateRequest( 69 @NonNull List<SignalThresholdInfo> signalThresholdInfos, 70 boolean isReportingRequestedWhileIdle, 71 boolean isSystemThresholdReportingRequestedWhileIdle) { 72 validate(signalThresholdInfos); 73 74 mSignalThresholdInfos = signalThresholdInfos; 75 mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; 76 mIsSystemThresholdReportingRequestedWhileIdle = 77 isSystemThresholdReportingRequestedWhileIdle; 78 mLiveToken = new Binder(); 79 } 80 81 /** 82 * Builder class to create {@link SignalStrengthUpdateRequest} object. 83 */ 84 public static final class Builder { 85 private List<SignalThresholdInfo> mSignalThresholdInfos = null; 86 private boolean mIsReportingRequestedWhileIdle = false; 87 private boolean mIsSystemThresholdReportingRequestedWhileIdle = false; 88 89 /** 90 * Set the collection of SignalThresholdInfo for the builder object 91 * 92 * @param signalThresholdInfos the collection of SignalThresholdInfo 93 * 94 * @return the builder to facilitate the chaining 95 */ setSignalThresholdInfos( @onNull Collection<SignalThresholdInfo> signalThresholdInfos)96 public @NonNull Builder setSignalThresholdInfos( 97 @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) { 98 Objects.requireNonNull(signalThresholdInfos, 99 "SignalThresholdInfo collection must not be null"); 100 for (SignalThresholdInfo info : signalThresholdInfos) { 101 Objects.requireNonNull(info, 102 "SignalThresholdInfo in the collection must not be null"); 103 } 104 105 mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos); 106 // Sort the collection with RAN and then SignalMeasurementType ascending order, make the 107 // ordering not matter for equals 108 mSignalThresholdInfos.sort( 109 Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType) 110 .thenComparing(SignalThresholdInfo::getSignalMeasurementType)); 111 return this; 112 } 113 114 /** 115 * Set the builder object if require reporting on thresholds in this request when device is 116 * idle. 117 * 118 * @param isReportingRequestedWhileIdle true if request reporting when device is idle 119 * 120 * @return the builder to facilitate the chaining 121 */ setReportingRequestedWhileIdle( boolean isReportingRequestedWhileIdle)122 public @NonNull Builder setReportingRequestedWhileIdle( 123 boolean isReportingRequestedWhileIdle) { 124 mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; 125 return this; 126 } 127 128 /** 129 * Set the builder object if require reporting on the system thresholds when device is idle. 130 * 131 * This can only used by the system caller. 132 * 133 * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the 134 * system thresholds when device is idle 135 * @return the builder to facilitate the chaining 136 * @hide 137 */ setSystemThresholdReportingRequestedWhileIdle( boolean isSystemThresholdReportingRequestedWhileIdle)138 public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle( 139 boolean isSystemThresholdReportingRequestedWhileIdle) { 140 mIsSystemThresholdReportingRequestedWhileIdle = 141 isSystemThresholdReportingRequestedWhileIdle; 142 return this; 143 } 144 145 /** 146 * Build a {@link SignalStrengthUpdateRequest} object. 147 * 148 * @return the SignalStrengthUpdateRequest object 149 * 150 * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the 151 * signal measurement type for the same RAN in the collection is not unique 152 */ build()153 public @NonNull SignalStrengthUpdateRequest build() { 154 return new SignalStrengthUpdateRequest(mSignalThresholdInfos, 155 mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle); 156 } 157 } 158 SignalStrengthUpdateRequest(Parcel in)159 private SignalStrengthUpdateRequest(Parcel in) { 160 mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR); 161 mIsReportingRequestedWhileIdle = in.readBoolean(); 162 mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean(); 163 mLiveToken = in.readStrongBinder(); 164 } 165 166 /** 167 * Get the collection of SignalThresholdInfo in the request. 168 * 169 * @return the collection of SignalThresholdInfo 170 */ 171 @NonNull getSignalThresholdInfos()172 public Collection<SignalThresholdInfo> getSignalThresholdInfos() { 173 return Collections.unmodifiableList(mSignalThresholdInfos); 174 } 175 176 /** 177 * Get whether reporting is requested for the threshold in the request while device is idle. 178 * 179 * @return true if reporting requested while device is idle 180 */ isReportingRequestedWhileIdle()181 public boolean isReportingRequestedWhileIdle() { 182 return mIsReportingRequestedWhileIdle; 183 } 184 185 /** 186 * @return true if reporting requested for system thresholds while device is idle 187 * 188 * @hide 189 */ isSystemThresholdReportingRequestedWhileIdle()190 public boolean isSystemThresholdReportingRequestedWhileIdle() { 191 return mIsSystemThresholdReportingRequestedWhileIdle; 192 } 193 194 /** 195 * @return the live token of the request 196 * 197 * @hide 198 */ getLiveToken()199 public @NonNull IBinder getLiveToken() { 200 return mLiveToken; 201 } 202 203 @Override describeContents()204 public int describeContents() { 205 return 0; 206 } 207 208 @Override writeToParcel(@onNull Parcel dest, int flags)209 public void writeToParcel(@NonNull Parcel dest, int flags) { 210 dest.writeTypedList(mSignalThresholdInfos); 211 dest.writeBoolean(mIsReportingRequestedWhileIdle); 212 dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle); 213 dest.writeStrongBinder(mLiveToken); 214 } 215 216 @Override equals(Object other)217 public boolean equals(Object other) { 218 if (this == other) return true; 219 220 if (!(other instanceof SignalStrengthUpdateRequest)) { 221 return false; 222 } 223 224 SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other; 225 return mSignalThresholdInfos.equals(request.mSignalThresholdInfos) 226 && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle 227 && mIsSystemThresholdReportingRequestedWhileIdle 228 == request.mIsSystemThresholdReportingRequestedWhileIdle; 229 } 230 231 @Override hashCode()232 public int hashCode() { 233 return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle, 234 mIsSystemThresholdReportingRequestedWhileIdle); 235 } 236 237 public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR = 238 new Parcelable.Creator<SignalStrengthUpdateRequest>() { 239 @Override 240 public SignalStrengthUpdateRequest createFromParcel(Parcel source) { 241 return new SignalStrengthUpdateRequest(source); 242 } 243 244 @Override 245 public SignalStrengthUpdateRequest[] newArray(int size) { 246 return new SignalStrengthUpdateRequest[size]; 247 } 248 }; 249 250 @Override toString()251 public String toString() { 252 return new StringBuilder("SignalStrengthUpdateRequest{") 253 .append("mSignalThresholdInfos=") 254 .append(mSignalThresholdInfos) 255 .append(" mIsReportingRequestedWhileIdle=") 256 .append(mIsReportingRequestedWhileIdle) 257 .append(" mIsSystemThresholdReportingRequestedWhileIdle=") 258 .append(mIsSystemThresholdReportingRequestedWhileIdle) 259 .append(" mLiveToken") 260 .append(mLiveToken) 261 .append("}").toString(); 262 } 263 264 /** 265 * Throw IAE if SignalThresholdInfo collection is null or empty, 266 * or the SignalMeasurementType for the same RAN in the collection is not unique. 267 */ validate(Collection<SignalThresholdInfo> infos)268 private static void validate(Collection<SignalThresholdInfo> infos) { 269 if (infos == null || infos.isEmpty()) { 270 throw new IllegalArgumentException("SignalThresholdInfo collection is null or empty"); 271 } 272 273 // Map from RAN to set of SignalMeasurementTypes 274 Map<Integer, Set<Integer>> ranToTypes = new HashMap<>(infos.size()); 275 for (SignalThresholdInfo info : infos) { 276 final int ran = info.getRadioAccessNetworkType(); 277 final int type = info.getSignalMeasurementType(); 278 ranToTypes.putIfAbsent(ran, new HashSet<>()); 279 if (!ranToTypes.get(ran).add(type)) { 280 throw new IllegalArgumentException( 281 "SignalMeasurementType " + type + " for RAN " + ran + " is not unique"); 282 } 283 } 284 } 285 } 286