1 /* 2 * Copyright (C) 2016 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.voicemail.impl; 18 19 import android.net.Uri; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 import android.telecom.PhoneAccountHandle; 23 import android.text.TextUtils; 24 25 /** Represents a single voicemail stored in the voicemail content provider. */ 26 public class Voicemail implements Parcelable { 27 28 private final Long timestamp; 29 private final String number; 30 private final PhoneAccountHandle phoneAccount; 31 private final Long id; 32 private final Long duration; 33 private final String source; 34 private final String providerData; 35 private final Uri uri; 36 private final Boolean isRead; 37 private final Boolean hasContent; 38 private final String transcription; 39 Voicemail( Long timestamp, String number, PhoneAccountHandle phoneAccountHandle, Long id, Long duration, String source, String providerData, Uri uri, Boolean isRead, Boolean hasContent, String transcription)40 private Voicemail( 41 Long timestamp, 42 String number, 43 PhoneAccountHandle phoneAccountHandle, 44 Long id, 45 Long duration, 46 String source, 47 String providerData, 48 Uri uri, 49 Boolean isRead, 50 Boolean hasContent, 51 String transcription) { 52 this.timestamp = timestamp; 53 this.number = number; 54 phoneAccount = phoneAccountHandle; 55 this.id = id; 56 this.duration = duration; 57 this.source = source; 58 this.providerData = providerData; 59 this.uri = uri; 60 this.isRead = isRead; 61 this.hasContent = hasContent; 62 this.transcription = transcription; 63 } 64 65 /** 66 * Create a {@link Builder} for a new {@link Voicemail} to be inserted. 67 * 68 * <p>The number and the timestamp are mandatory for insertion. 69 */ createForInsertion(long timestamp, String number)70 public static Builder createForInsertion(long timestamp, String number) { 71 return new Builder().setNumber(number).setTimestamp(timestamp); 72 } 73 74 /** 75 * Create a {@link Builder} for a {@link Voicemail} to be updated (or deleted). 76 * 77 * <p>The id and source data fields are mandatory for update - id is necessary for updating the 78 * database and source data is necessary for updating the server. 79 */ createForUpdate(long id, String sourceData)80 public static Builder createForUpdate(long id, String sourceData) { 81 return new Builder().setId(id).setSourceData(sourceData); 82 } 83 84 /** 85 * Builder pattern for creating a {@link Voicemail}. The builder must be created with the {@link 86 * #createForInsertion(long, String)} method. 87 * 88 * <p>This class is <b>not thread safe</b> 89 */ 90 public static class Builder { 91 92 private Long builderTimestamp; 93 private String builderNumber; 94 private PhoneAccountHandle builderPhoneAccount; 95 private Long builderId; 96 private Long builderDuration; 97 private String builderSourcePackage; 98 private String builderSourceData; 99 private Uri builderUri; 100 private Boolean builderIsRead; 101 private boolean builderHasContent; 102 private String builderTranscription; 103 104 /** You should use the correct factory method to construct a builder. */ Builder()105 private Builder() {} 106 setNumber(String number)107 public Builder setNumber(String number) { 108 builderNumber = number; 109 return this; 110 } 111 setTimestamp(long timestamp)112 public Builder setTimestamp(long timestamp) { 113 builderTimestamp = timestamp; 114 return this; 115 } 116 setPhoneAccount(PhoneAccountHandle phoneAccount)117 public Builder setPhoneAccount(PhoneAccountHandle phoneAccount) { 118 builderPhoneAccount = phoneAccount; 119 return this; 120 } 121 setId(long id)122 public Builder setId(long id) { 123 builderId = id; 124 return this; 125 } 126 setDuration(long duration)127 public Builder setDuration(long duration) { 128 builderDuration = duration; 129 return this; 130 } 131 setSourcePackage(String sourcePackage)132 public Builder setSourcePackage(String sourcePackage) { 133 builderSourcePackage = sourcePackage; 134 return this; 135 } 136 setSourceData(String sourceData)137 public Builder setSourceData(String sourceData) { 138 builderSourceData = sourceData; 139 return this; 140 } 141 setUri(Uri uri)142 public Builder setUri(Uri uri) { 143 builderUri = uri; 144 return this; 145 } 146 setIsRead(boolean isRead)147 public Builder setIsRead(boolean isRead) { 148 builderIsRead = isRead; 149 return this; 150 } 151 setHasContent(boolean hasContent)152 public Builder setHasContent(boolean hasContent) { 153 builderHasContent = hasContent; 154 return this; 155 } 156 setTranscription(String transcription)157 public Builder setTranscription(String transcription) { 158 builderTranscription = transcription; 159 return this; 160 } 161 build()162 public Voicemail build() { 163 builderId = builderId == null ? -1 : builderId; 164 builderTimestamp = builderTimestamp == null ? 0 : builderTimestamp; 165 builderDuration = builderDuration == null ? 0 : builderDuration; 166 builderIsRead = builderIsRead == null ? false : builderIsRead; 167 return new Voicemail( 168 builderTimestamp, 169 builderNumber, 170 builderPhoneAccount, 171 builderId, 172 builderDuration, 173 builderSourcePackage, 174 builderSourceData, 175 builderUri, 176 builderIsRead, 177 builderHasContent, 178 builderTranscription); 179 } 180 } 181 182 /** 183 * The identifier of the voicemail in the content provider. 184 * 185 * <p>This may be missing in the case of a new {@link Voicemail} that we plan to insert into the 186 * content provider, since until it has been inserted we don't know what id it should have. If 187 * none is specified, we return -1. 188 */ getId()189 public long getId() { 190 return id; 191 } 192 193 /** The number of the person leaving the voicemail, empty string if unknown, null if not set. */ getNumber()194 public String getNumber() { 195 return number; 196 } 197 198 /** The phone account associated with the voicemail, null if not set. */ getPhoneAccount()199 public PhoneAccountHandle getPhoneAccount() { 200 return phoneAccount; 201 } 202 203 /** The timestamp the voicemail was received, in millis since the epoch, zero if not set. */ getTimestampMillis()204 public long getTimestampMillis() { 205 return timestamp; 206 } 207 208 /** Gets the duration of the voicemail in millis, or zero if the field is not set. */ getDuration()209 public long getDuration() { 210 return duration; 211 } 212 213 /** 214 * Returns the package name of the source that added this voicemail, or null if this field is not 215 * set. 216 */ getSourcePackage()217 public String getSourcePackage() { 218 return source; 219 } 220 221 /** 222 * Returns the application-specific data type stored with the voicemail, or null if this field is 223 * not set. 224 * 225 * <p>Source data is typically used as an identifier to uniquely identify the voicemail against 226 * the voicemail server. This is likely to be something like the IMAP UID, or some other 227 * server-generated identifying string. 228 */ getSourceData()229 public String getSourceData() { 230 return providerData; 231 } 232 233 /** 234 * Gets the Uri that can be used to refer to this voicemail, and to make it play. 235 * 236 * <p>Returns null if we don't know the Uri. 237 */ getUri()238 public Uri getUri() { 239 return uri; 240 } 241 242 /** 243 * Tells us if the voicemail message has been marked as read. 244 * 245 * <p>Always returns false if this field has not been set, i.e. if hasRead() returns false. 246 */ isRead()247 public boolean isRead() { 248 return isRead; 249 } 250 251 /** Tells us if there is content stored at the Uri. */ hasContent()252 public boolean hasContent() { 253 return hasContent; 254 } 255 256 /** Returns the text transcription of this voicemail, or null if this field is not set. */ getTranscription()257 public String getTranscription() { 258 return transcription; 259 } 260 261 @Override describeContents()262 public int describeContents() { 263 return 0; 264 } 265 266 @Override writeToParcel(Parcel dest, int flags)267 public void writeToParcel(Parcel dest, int flags) { 268 dest.writeLong(timestamp); 269 writeCharSequence(dest, number); 270 if (phoneAccount == null) { 271 dest.writeInt(0); 272 } else { 273 dest.writeInt(1); 274 phoneAccount.writeToParcel(dest, flags); 275 } 276 dest.writeLong(id); 277 dest.writeLong(duration); 278 writeCharSequence(dest, source); 279 writeCharSequence(dest, providerData); 280 if (uri == null) { 281 dest.writeInt(0); 282 } else { 283 dest.writeInt(1); 284 uri.writeToParcel(dest, flags); 285 } 286 if (isRead) { 287 dest.writeInt(1); 288 } else { 289 dest.writeInt(0); 290 } 291 if (hasContent) { 292 dest.writeInt(1); 293 } else { 294 dest.writeInt(0); 295 } 296 writeCharSequence(dest, transcription); 297 } 298 299 public static final Creator<Voicemail> CREATOR = 300 new Creator<Voicemail>() { 301 @Override 302 public Voicemail createFromParcel(Parcel in) { 303 return new Voicemail(in); 304 } 305 306 @Override 307 public Voicemail[] newArray(int size) { 308 return new Voicemail[size]; 309 } 310 }; 311 Voicemail(Parcel in)312 private Voicemail(Parcel in) { 313 timestamp = in.readLong(); 314 number = (String) readCharSequence(in); 315 if (in.readInt() > 0) { 316 phoneAccount = PhoneAccountHandle.CREATOR.createFromParcel(in); 317 } else { 318 phoneAccount = null; 319 } 320 id = in.readLong(); 321 duration = in.readLong(); 322 source = (String) readCharSequence(in); 323 providerData = (String) readCharSequence(in); 324 if (in.readInt() > 0) { 325 uri = Uri.CREATOR.createFromParcel(in); 326 } else { 327 uri = null; 328 } 329 isRead = in.readInt() > 0 ? true : false; 330 hasContent = in.readInt() > 0 ? true : false; 331 transcription = (String) readCharSequence(in); 332 } 333 readCharSequence(Parcel in)334 private static CharSequence readCharSequence(Parcel in) { 335 return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 336 } 337 writeCharSequence(Parcel dest, CharSequence val)338 public static void writeCharSequence(Parcel dest, CharSequence val) { 339 TextUtils.writeToParcel(val, dest, 0); 340 } 341 } 342