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.HashSet; 30 import java.util.List; 31 import java.util.Objects; 32 import java.util.Set; 33 34 /** 35 * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength 36 * breach the specified thresholds. 37 */ 38 public final class SignalStrengthUpdateRequest implements Parcelable { 39 /** 40 * List of SignalThresholdInfo for the request. 41 */ 42 private final List<SignalThresholdInfo> mSignalThresholdInfos; 43 44 /** 45 * Whether the reporting is required for thresholds in the request while device is idle. 46 */ 47 private final boolean mIsReportingRequestedWhileIdle; 48 49 /** 50 * Whether the reporting requested for system thresholds while device is idle. 51 * 52 * System signal thresholds are loaded from carrier config items and mainly used for UI 53 * displaying. By default, they are ignored when device is idle. When setting the value to true, 54 * modem will continue reporting signal strength changes over the system signal thresholds even 55 * device is idle. 56 * 57 * This should only set to true by the system caller. 58 */ 59 private final boolean mIsSystemThresholdReportingRequestedWhileIdle; 60 61 /** 62 * A IBinder object as a token for server side to check if the request client is still living. 63 */ 64 private final IBinder mLiveToken; 65 SignalStrengthUpdateRequest( @onNull List<SignalThresholdInfo> signalThresholdInfos, boolean isReportingRequestedWhileIdle, boolean isSystemThresholdReportingRequestedWhileIdle)66 private SignalStrengthUpdateRequest( 67 @NonNull List<SignalThresholdInfo> signalThresholdInfos, 68 boolean isReportingRequestedWhileIdle, 69 boolean isSystemThresholdReportingRequestedWhileIdle) { 70 validate(signalThresholdInfos); 71 72 mSignalThresholdInfos = signalThresholdInfos; 73 mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; 74 mIsSystemThresholdReportingRequestedWhileIdle = 75 isSystemThresholdReportingRequestedWhileIdle; 76 mLiveToken = new Binder(); 77 } 78 79 /** 80 * Builder class to create {@link SignalStrengthUpdateRequest} object. 81 */ 82 public static final class Builder { 83 private List<SignalThresholdInfo> mSignalThresholdInfos = null; 84 private boolean mIsReportingRequestedWhileIdle = false; 85 private boolean mIsSystemThresholdReportingRequestedWhileIdle = false; 86 87 /** 88 * Set the collection of SignalThresholdInfo for the builder object 89 * 90 * @param signalThresholdInfos the collection of SignalThresholdInfo 91 * 92 * @return the builder to facilitate the chaining 93 */ setSignalThresholdInfos( @onNull Collection<SignalThresholdInfo> signalThresholdInfos)94 public @NonNull Builder setSignalThresholdInfos( 95 @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) { 96 Objects.requireNonNull(signalThresholdInfos, 97 "SignalThresholdInfo collection must not be null"); 98 for (SignalThresholdInfo info : signalThresholdInfos) { 99 Objects.requireNonNull(info, 100 "SignalThresholdInfo in the collection must not be null"); 101 } 102 103 mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos); 104 // Sort the collection with RAN ascending order, make the ordering not matter for equals 105 mSignalThresholdInfos.sort( 106 Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType)); 107 return this; 108 } 109 110 /** 111 * Set the builder object if require reporting on thresholds in this request when device is 112 * idle. 113 * 114 * @param isReportingRequestedWhileIdle true if request reporting when device is idle 115 * 116 * @return the builder to facilitate the chaining 117 */ setReportingRequestedWhileIdle( boolean isReportingRequestedWhileIdle)118 public @NonNull Builder setReportingRequestedWhileIdle( 119 boolean isReportingRequestedWhileIdle) { 120 mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; 121 return this; 122 } 123 124 /** 125 * Set the builder object if require reporting on the system thresholds when device is idle. 126 * 127 * This can only used by the system caller. 128 * 129 * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the 130 * system thresholds when device is idle 131 * @return the builder to facilitate the chaining 132 * @hide 133 */ setSystemThresholdReportingRequestedWhileIdle( boolean isSystemThresholdReportingRequestedWhileIdle)134 public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle( 135 boolean isSystemThresholdReportingRequestedWhileIdle) { 136 mIsSystemThresholdReportingRequestedWhileIdle = 137 isSystemThresholdReportingRequestedWhileIdle; 138 return this; 139 } 140 141 /** 142 * Build a {@link SignalStrengthUpdateRequest} object. 143 * 144 * @return the SignalStrengthUpdateRequest object 145 * 146 * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the 147 * radio access network type in the collection is not unique 148 */ build()149 public @NonNull SignalStrengthUpdateRequest build() { 150 return new SignalStrengthUpdateRequest(mSignalThresholdInfos, 151 mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle); 152 } 153 } 154 SignalStrengthUpdateRequest(Parcel in)155 private SignalStrengthUpdateRequest(Parcel in) { 156 mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR); 157 mIsReportingRequestedWhileIdle = in.readBoolean(); 158 mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean(); 159 mLiveToken = in.readStrongBinder(); 160 } 161 162 /** 163 * Get the collection of SignalThresholdInfo in the request. 164 * 165 * @return the collection of SignalThresholdInfo 166 */ 167 @NonNull getSignalThresholdInfos()168 public Collection<SignalThresholdInfo> getSignalThresholdInfos() { 169 return Collections.unmodifiableList(mSignalThresholdInfos); 170 } 171 172 /** 173 * Get whether reporting is requested for the threshold in the request while device is idle. 174 * 175 * @return true if reporting requested while device is idle 176 */ isReportingRequestedWhileIdle()177 public boolean isReportingRequestedWhileIdle() { 178 return mIsReportingRequestedWhileIdle; 179 } 180 181 /** 182 * @return true if reporting requested for system thresholds while device is idle 183 * 184 * @hide 185 */ isSystemThresholdReportingRequestedWhileIdle()186 public boolean isSystemThresholdReportingRequestedWhileIdle() { 187 return mIsSystemThresholdReportingRequestedWhileIdle; 188 } 189 190 /** 191 * @return the live token of the request 192 * 193 * @hide 194 */ getLiveToken()195 public @NonNull IBinder getLiveToken() { 196 return mLiveToken; 197 } 198 199 @Override describeContents()200 public int describeContents() { 201 return 0; 202 } 203 204 @Override writeToParcel(@onNull Parcel dest, int flags)205 public void writeToParcel(@NonNull Parcel dest, int flags) { 206 dest.writeTypedList(mSignalThresholdInfos); 207 dest.writeBoolean(mIsReportingRequestedWhileIdle); 208 dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle); 209 dest.writeStrongBinder(mLiveToken); 210 } 211 212 @Override equals(Object other)213 public boolean equals(Object other) { 214 if (this == other) return true; 215 216 if (!(other instanceof SignalStrengthUpdateRequest)) { 217 return false; 218 } 219 220 SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other; 221 return mSignalThresholdInfos.equals(request.mSignalThresholdInfos) 222 && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle 223 && mIsSystemThresholdReportingRequestedWhileIdle 224 == request.mIsSystemThresholdReportingRequestedWhileIdle; 225 } 226 227 @Override hashCode()228 public int hashCode() { 229 return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle, 230 mIsSystemThresholdReportingRequestedWhileIdle); 231 } 232 233 public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR = 234 new Parcelable.Creator<SignalStrengthUpdateRequest>() { 235 @Override 236 public SignalStrengthUpdateRequest createFromParcel(Parcel source) { 237 return new SignalStrengthUpdateRequest(source); 238 } 239 240 @Override 241 public SignalStrengthUpdateRequest[] newArray(int size) { 242 return new SignalStrengthUpdateRequest[size]; 243 } 244 }; 245 246 @Override toString()247 public String toString() { 248 return new StringBuilder("SignalStrengthUpdateRequest{") 249 .append("mSignalThresholdInfos=") 250 .append(mSignalThresholdInfos) 251 .append(" mIsReportingRequestedWhileIdle=") 252 .append(mIsReportingRequestedWhileIdle) 253 .append(" mIsSystemThresholdReportingRequestedWhileIdle=") 254 .append(mIsSystemThresholdReportingRequestedWhileIdle) 255 .append(" mLiveToken") 256 .append(mLiveToken) 257 .append("}").toString(); 258 } 259 260 /** 261 * Throw IAE when the RAN in the collection is not unique. 262 */ validate(Collection<SignalThresholdInfo> infos)263 private static void validate(Collection<SignalThresholdInfo> infos) { 264 Set<Integer> uniqueRan = new HashSet<>(infos.size()); 265 for (SignalThresholdInfo info : infos) { 266 final int ran = info.getRadioAccessNetworkType(); 267 if (!uniqueRan.add(ran)) { 268 throw new IllegalArgumentException("RAN: " + ran + " is not unique"); 269 } 270 } 271 } 272 } 273