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