1 /* 2 * Copyright (C) 2019 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 package android.telephony.ims; 17 18 import android.annotation.IntDef; 19 import android.annotation.NonNull; 20 import android.annotation.WorkerThread; 21 22 import java.lang.annotation.Retention; 23 import java.lang.annotation.RetentionPolicy; 24 import java.util.Collections; 25 import java.util.HashSet; 26 import java.util.Set; 27 28 /** 29 * This is a single instance of a message sent or received over RCS. 30 * 31 * @hide 32 */ 33 public abstract class RcsMessage { 34 /** 35 * The value to indicate that this {@link RcsMessage} does not have any location information. 36 */ 37 public static final double LOCATION_NOT_SET = Double.MIN_VALUE; 38 39 /** 40 * The status to indicate that this {@link RcsMessage}s status is not set yet. 41 */ 42 public static final int NOT_SET = 0; 43 44 /** 45 * The status to indicate that this {@link RcsMessage} is a draft and is not in the process of 46 * sending yet. 47 */ 48 public static final int DRAFT = 1; 49 50 /** 51 * The status to indicate that this {@link RcsMessage} was successfully sent. 52 */ 53 public static final int QUEUED = 2; 54 55 /** 56 * The status to indicate that this {@link RcsMessage} is actively being sent. 57 */ 58 public static final int SENDING = 3; 59 60 /** 61 * The status to indicate that this {@link RcsMessage} was successfully sent. 62 */ 63 public static final int SENT = 4; 64 65 /** 66 * The status to indicate that this {@link RcsMessage} failed to send in an attempt before, and 67 * now being retried. 68 */ 69 public static final int RETRYING = 5; 70 71 /** 72 * The status to indicate that this {@link RcsMessage} has permanently failed to send. 73 */ 74 public static final int FAILED = 6; 75 76 /** 77 * The status to indicate that this {@link RcsMessage} was successfully received. 78 */ 79 public static final int RECEIVED = 7; 80 81 /** 82 * The status to indicate that this {@link RcsMessage} was seen. 83 */ 84 public static final int SEEN = 9; 85 86 /** 87 * @hide 88 */ 89 protected final RcsControllerCall mRcsControllerCall; 90 91 /** 92 * @hide 93 */ 94 protected final int mId; 95 96 @IntDef({ 97 DRAFT, QUEUED, SENDING, SENT, RETRYING, FAILED, RECEIVED, SEEN 98 }) 99 @Retention(RetentionPolicy.SOURCE) 100 public @interface RcsMessageStatus { 101 } 102 RcsMessage(RcsControllerCall rcsControllerCall, int id)103 RcsMessage(RcsControllerCall rcsControllerCall, int id) { 104 mRcsControllerCall = rcsControllerCall; 105 mId = id; 106 } 107 108 /** 109 * Returns the row Id from the common message. 110 * 111 * @hide 112 */ getId()113 public int getId() { 114 return mId; 115 } 116 117 /** 118 * @return Returns the subscription ID that this {@link RcsMessage} was sent from, or delivered 119 * to. 120 * @throws RcsMessageStoreException if the value could not be read from the storage 121 * @see android.telephony.SubscriptionInfo#getSubscriptionId 122 */ getSubscriptionId()123 public int getSubscriptionId() throws RcsMessageStoreException { 124 return mRcsControllerCall.call( 125 (iRcs, callingPackage) -> iRcs.getMessageSubId(mId, isIncoming(), callingPackage)); 126 } 127 128 /** 129 * Sets the subscription ID that this {@link RcsMessage} was sent from, or delivered to and 130 * persists it into storage. 131 * 132 * @param subId The subscription ID to persists into storage. 133 * @throws RcsMessageStoreException if the value could not be persisted into storage 134 * @see android.telephony.SubscriptionInfo#getSubscriptionId 135 */ 136 @WorkerThread setSubscriptionId(int subId)137 public void setSubscriptionId(int subId) throws RcsMessageStoreException { 138 mRcsControllerCall.callWithNoReturn( 139 (iRcs, callingPackage) -> iRcs.setMessageSubId(mId, isIncoming(), subId, 140 callingPackage)); 141 } 142 143 /** 144 * Sets the status of this message and persists it into storage. Please see 145 * {@link RcsFileTransferPart#setFileTransferStatus(int)} to set statuses around file transfers. 146 * 147 * @throws RcsMessageStoreException if the value could not be persisted into storage 148 */ 149 @WorkerThread setStatus(@csMessageStatus int rcsMessageStatus)150 public void setStatus(@RcsMessageStatus int rcsMessageStatus) throws RcsMessageStoreException { 151 mRcsControllerCall.callWithNoReturn( 152 (iRcs, callingPackage) -> iRcs.setMessageStatus(mId, isIncoming(), rcsMessageStatus, 153 callingPackage)); 154 } 155 156 /** 157 * @return Returns the status of this message. Please see 158 * {@link RcsFileTransferPart#setFileTransferStatus(int)} to set statuses around file transfers. 159 * @throws RcsMessageStoreException if the value could not be read from the storage 160 */ 161 @WorkerThread getStatus()162 public @RcsMessageStatus int getStatus() throws RcsMessageStoreException { 163 return mRcsControllerCall.call( 164 (iRcs, callingPackage) -> iRcs.getMessageStatus(mId, isIncoming(), callingPackage)); 165 } 166 167 /** 168 * Sets the origination timestamp of this message and persists it into storage. Origination is 169 * defined as when the sender tapped the send button. 170 * 171 * @param timestamp The origination timestamp value in milliseconds passed after midnight, 172 * January 1, 1970 UTC 173 * @throws RcsMessageStoreException if the value could not be persisted into storage 174 */ 175 @WorkerThread setOriginationTimestamp(long timestamp)176 public void setOriginationTimestamp(long timestamp) throws RcsMessageStoreException { 177 mRcsControllerCall.callWithNoReturn( 178 (iRcs, callingPackage) -> iRcs.setMessageOriginationTimestamp(mId, isIncoming(), 179 timestamp, callingPackage)); 180 } 181 182 /** 183 * @return Returns the origination timestamp of this message in milliseconds passed after 184 * midnight, January 1, 1970 UTC. Origination is defined as when the sender tapped the send 185 * button. 186 * @throws RcsMessageStoreException if the value could not be read from the storage 187 */ 188 @WorkerThread getOriginationTimestamp()189 public long getOriginationTimestamp() throws RcsMessageStoreException { 190 return mRcsControllerCall.call( 191 (iRcs, callingPackage) -> iRcs.getMessageOriginationTimestamp(mId, isIncoming(), 192 callingPackage)); 193 } 194 195 /** 196 * Sets the globally unique RCS message identifier for this message and persists it into 197 * storage. This function does not confirm that this message id is unique. Please see 4.4.5.2 198 * - GSMA RCC.53 (RCS Device API 1.6 Specification 199 * 200 * @param rcsMessageGlobalId The globally RCS message identifier 201 * @throws RcsMessageStoreException if the value could not be persisted into storage 202 */ 203 @WorkerThread setRcsMessageId(String rcsMessageGlobalId)204 public void setRcsMessageId(String rcsMessageGlobalId) throws RcsMessageStoreException { 205 mRcsControllerCall.callWithNoReturn( 206 (iRcs, callingPackage) -> iRcs.setGlobalMessageIdForMessage(mId, isIncoming(), 207 rcsMessageGlobalId, callingPackage)); 208 } 209 210 /** 211 * @return Returns the globally unique RCS message identifier for this message. Please see 212 * 4.4.5.2 - GSMA RCC.53 (RCS Device API 1.6 Specification 213 * @throws RcsMessageStoreException if the value could not be read from the storage 214 */ 215 @WorkerThread getRcsMessageId()216 public String getRcsMessageId() throws RcsMessageStoreException { 217 return mRcsControllerCall.call( 218 (iRcs, callingPackage) -> iRcs.getGlobalMessageIdForMessage(mId, isIncoming(), 219 callingPackage)); 220 } 221 222 /** 223 * @return Returns the user visible text included in this message. 224 * @throws RcsMessageStoreException if the value could not be read from the storage 225 */ 226 @WorkerThread getText()227 public String getText() throws RcsMessageStoreException { 228 return mRcsControllerCall.call( 229 (iRcs, callingPackage) -> iRcs.getTextForMessage(mId, isIncoming(), 230 callingPackage)); 231 } 232 233 /** 234 * Sets the user visible text for this message and persists in storage. 235 * 236 * @param text The text this message now has 237 * @throws RcsMessageStoreException if the value could not be persisted into storage 238 */ 239 @WorkerThread setText(String text)240 public void setText(String text) throws RcsMessageStoreException { 241 mRcsControllerCall.callWithNoReturn( 242 (iRcs, callingPackage) -> iRcs.setTextForMessage(mId, isIncoming(), text, 243 callingPackage)); 244 } 245 246 /** 247 * @return Returns the associated latitude for this message, or 248 * {@link RcsMessage#LOCATION_NOT_SET} if it does not contain a location. 249 * @throws RcsMessageStoreException if the value could not be read from the storage 250 */ 251 @WorkerThread getLatitude()252 public double getLatitude() throws RcsMessageStoreException { 253 return mRcsControllerCall.call( 254 (iRcs, callingPackage) -> iRcs.getLatitudeForMessage(mId, isIncoming(), 255 callingPackage)); 256 } 257 258 /** 259 * Sets the latitude for this message and persists in storage. 260 * 261 * @param latitude The latitude for this location message. 262 * @throws RcsMessageStoreException if the value could not be persisted into storage 263 */ 264 @WorkerThread setLatitude(double latitude)265 public void setLatitude(double latitude) throws RcsMessageStoreException { 266 mRcsControllerCall.callWithNoReturn( 267 (iRcs, callingPackage) -> iRcs.setLatitudeForMessage(mId, isIncoming(), latitude, 268 callingPackage)); 269 } 270 271 /** 272 * @return Returns the associated longitude for this message, or 273 * {@link RcsMessage#LOCATION_NOT_SET} if it does not contain a location. 274 * @throws RcsMessageStoreException if the value could not be read from the storage 275 */ 276 @WorkerThread getLongitude()277 public double getLongitude() throws RcsMessageStoreException { 278 return mRcsControllerCall.call( 279 (iRcs, callingPackage) -> iRcs.getLongitudeForMessage(mId, isIncoming(), 280 callingPackage)); 281 } 282 283 /** 284 * Sets the longitude for this message and persists in storage. 285 * 286 * @param longitude The longitude for this location message. 287 * @throws RcsMessageStoreException if the value could not be persisted into storage 288 */ 289 @WorkerThread setLongitude(double longitude)290 public void setLongitude(double longitude) throws RcsMessageStoreException { 291 mRcsControllerCall.callWithNoReturn( 292 (iRcs, callingPackage) -> iRcs.setLongitudeForMessage(mId, isIncoming(), longitude, 293 callingPackage)); 294 } 295 296 /** 297 * Attaches an {@link RcsFileTransferPart} to this message and persists into storage. 298 * 299 * @param fileTransferCreationParameters The parameters to be used to create the 300 * {@link RcsFileTransferPart} 301 * @return A new instance of {@link RcsFileTransferPart} 302 * @throws RcsMessageStoreException if the file transfer could not be persisted into storage. 303 */ 304 @NonNull 305 @WorkerThread insertFileTransfer( RcsFileTransferCreationParams fileTransferCreationParameters)306 public RcsFileTransferPart insertFileTransfer( 307 RcsFileTransferCreationParams fileTransferCreationParameters) 308 throws RcsMessageStoreException { 309 return new RcsFileTransferPart(mRcsControllerCall, mRcsControllerCall.call( 310 (iRcs, callingPackage) -> iRcs.storeFileTransfer(mId, isIncoming(), 311 fileTransferCreationParameters, callingPackage))); 312 } 313 314 /** 315 * @return Returns all the {@link RcsFileTransferPart}s associated with this message in an 316 * unmodifiable set. 317 * @throws RcsMessageStoreException if the file transfers could not be read from the storage 318 */ 319 @NonNull 320 @WorkerThread getFileTransferParts()321 public Set<RcsFileTransferPart> getFileTransferParts() throws RcsMessageStoreException { 322 Set<RcsFileTransferPart> fileTransferParts = new HashSet<>(); 323 324 int[] fileTransferIds = mRcsControllerCall.call( 325 (iRcs, callingPackage) -> iRcs.getFileTransfersAttachedToMessage(mId, isIncoming(), 326 callingPackage)); 327 328 for (int fileTransfer : fileTransferIds) { 329 fileTransferParts.add(new RcsFileTransferPart(mRcsControllerCall, fileTransfer)); 330 } 331 332 return Collections.unmodifiableSet(fileTransferParts); 333 } 334 335 /** 336 * Removes a {@link RcsFileTransferPart} from this message, and deletes it in storage. 337 * 338 * @param fileTransferPart The part to delete. 339 * @throws RcsMessageStoreException if the file transfer could not be removed from storage 340 */ 341 @WorkerThread removeFileTransferPart(@onNull RcsFileTransferPart fileTransferPart)342 public void removeFileTransferPart(@NonNull RcsFileTransferPart fileTransferPart) 343 throws RcsMessageStoreException { 344 if (fileTransferPart == null) { 345 return; 346 } 347 348 mRcsControllerCall.callWithNoReturn( 349 (iRcs, callingPackage) -> iRcs.deleteFileTransfer(fileTransferPart.getId(), 350 callingPackage)); 351 } 352 353 /** 354 * @return Returns {@code true} if this message was received on this device, {@code false} if it 355 * was sent. 356 */ isIncoming()357 public abstract boolean isIncoming(); 358 } 359