• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.app;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.graphics.drawable.Icon;
22 import android.net.Uri;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.util.Objects;
27 import java.util.function.Consumer;
28 
29 /**
30  * Provides an immutable reference to an entity that appears repeatedly on different surfaces of the
31  * platform. For example, this could represent the sender of a message.
32  */
33 public final class Person implements Parcelable {
34 
35     @Nullable private CharSequence mName;
36     @Nullable private Icon mIcon;
37     @Nullable private String mUri;
38     @Nullable private String mKey;
39     private boolean mIsBot;
40     private boolean mIsImportant;
41 
Person(Parcel in)42     private Person(Parcel in) {
43         mName = in.readCharSequence();
44         if (in.readInt() != 0) {
45             mIcon = Icon.CREATOR.createFromParcel(in);
46         }
47         mUri = in.readString();
48         mKey = in.readString();
49         mIsImportant = in.readBoolean();
50         mIsBot = in.readBoolean();
51     }
52 
Person(Builder builder)53     private Person(Builder builder) {
54         mName = builder.mName;
55         mIcon = builder.mIcon;
56         mUri = builder.mUri;
57         mKey = builder.mKey;
58         mIsBot = builder.mIsBot;
59         mIsImportant = builder.mIsImportant;
60     }
61 
62     /** Creates and returns a new {@link Builder} initialized with this Person's data. */
toBuilder()63     public Builder toBuilder() {
64         return new Builder(this);
65     }
66 
67     /**
68      * @return the uri provided for this person or {@code null} if no Uri was provided.
69      */
70     @Nullable
getUri()71     public String getUri() {
72         return mUri;
73     }
74 
75     /**
76      * @return the name provided for this person or {@code null} if no name was provided.
77      */
78     @Nullable
getName()79     public CharSequence getName() {
80         return mName;
81     }
82 
83     /**
84      * @return the icon provided for this person or {@code null} if no icon was provided.
85      */
86     @Nullable
getIcon()87     public Icon getIcon() {
88         return mIcon;
89     }
90 
91     /**
92      * @return the key provided for this person or {@code null} if no key was provided.
93      */
94     @Nullable
getKey()95     public String getKey() {
96         return mKey;
97     }
98 
99     /**
100      * @return whether this Person is a machine.
101      */
isBot()102     public boolean isBot() {
103         return mIsBot;
104     }
105 
106     /**
107      * @return whether this Person is important.
108      */
isImportant()109     public boolean isImportant() {
110         return mIsImportant;
111     }
112 
113     /**
114      * @return the URI associated with this person, or "name:mName" otherwise
115      *  @hide
116      */
resolveToLegacyUri()117     public String resolveToLegacyUri() {
118         if (mUri != null) {
119             return mUri;
120         }
121         if (mName != null) {
122             return "name:" + mName;
123         }
124         return "";
125     }
126 
127     /**
128      * @return the URI associated with the {@link #getIcon()} for this person, iff the icon exists
129      * and is URI based.
130      * @hide
131      */
132     @Nullable
getIconUri()133     public Uri getIconUri() {
134         if (mIcon != null && (mIcon.getType() == Icon.TYPE_URI
135                 || mIcon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
136             return mIcon.getUri();
137         }
138         return null;
139     }
140 
141     @Override
equals(@ullable Object obj)142     public boolean equals(@Nullable Object obj) {
143         if (obj instanceof Person) {
144             final Person other = (Person) obj;
145             return Objects.equals(mName, other.mName)
146                     && (mIcon == null ? other.mIcon == null :
147                     (other.mIcon != null && mIcon.sameAs(other.mIcon)))
148                     && Objects.equals(mUri, other.mUri)
149                     && Objects.equals(mKey, other.mKey)
150                     && mIsBot == other.mIsBot
151                     && mIsImportant == other.mIsImportant;
152         }
153         return false;
154     }
155 
156     @Override
hashCode()157     public int hashCode() {
158         return Objects.hash(mName, mIcon, mUri, mKey, mIsBot, mIsImportant);
159     }
160 
161     @Override
describeContents()162     public int describeContents() {
163         return 0;
164     }
165 
166     @Override
writeToParcel(Parcel dest, @WriteFlags int flags)167     public void writeToParcel(Parcel dest, @WriteFlags int flags) {
168         dest.writeCharSequence(mName);
169         if (mIcon != null) {
170             dest.writeInt(1);
171             mIcon.writeToParcel(dest, 0);
172         } else {
173             dest.writeInt(0);
174         }
175         dest.writeString(mUri);
176         dest.writeString(mKey);
177         dest.writeBoolean(mIsImportant);
178         dest.writeBoolean(mIsBot);
179     }
180 
181     /**
182      * Note all {@link Uri} that are referenced internally, with the expectation that Uri permission
183      * grants will need to be issued to ensure the recipient of this object is able to render its
184      * contents.
185      * See b/281044385 for more context and examples about what happens when this isn't done
186      * correctly.
187      *
188      * @hide
189      */
visitUris(@onNull Consumer<Uri> visitor)190     public void visitUris(@NonNull Consumer<Uri> visitor) {
191         visitor.accept(getIconUri());
192         if (Flags.visitPersonUri()) {
193             if (mUri != null && !mUri.isEmpty()) {
194                 visitor.accept(Uri.parse(mUri));
195             }
196         }
197     }
198 
199     /** Builder for the immutable {@link Person} class. */
200     public static class Builder {
201         @Nullable private CharSequence mName;
202         @Nullable private Icon mIcon;
203         @Nullable private String mUri;
204         @Nullable private String mKey;
205         private boolean mIsBot;
206         private boolean mIsImportant;
207 
208         /** Creates a new, empty {@link Builder}. */
Builder()209         public Builder() {
210         }
211 
Builder(Person person)212         private Builder(Person person) {
213             mName = person.mName;
214             mIcon = person.mIcon;
215             mUri = person.mUri;
216             mKey = person.mKey;
217             mIsBot = person.mIsBot;
218             mIsImportant = person.mIsImportant;
219         }
220 
221         /**
222          * Give this person a name.
223          *
224          * @param name the name of this person.
225          */
226         @NonNull
setName(@ullable CharSequence name)227         public Person.Builder setName(@Nullable CharSequence name) {
228             this.mName = name;
229             return this;
230         }
231 
232         /**
233          * Add an icon for this person.
234          * <br />
235          * The system will prefer this icon over any images that are resolved from the URI.
236          *
237          * @param icon the icon of the person.
238          */
239         @NonNull
setIcon(@ullable Icon icon)240         public Person.Builder setIcon(@Nullable Icon icon) {
241             this.mIcon = icon;
242             return this;
243         }
244 
245         /**
246          * Set a URI associated with this person.
247          *
248          * <P>
249          * The person should be specified by the {@code String} representation of a
250          * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
251          * </P>
252          *
253          * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema
254          * URIs. The path part of these URIs must exist in the contacts database, in the
255          * appropriate column, or the reference will be discarded as invalid. Telephone schema
256          * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
257          * </P>
258          *
259          * @param uri a URI for the person.
260          */
261         @NonNull
setUri(@ullable String uri)262         public Person.Builder setUri(@Nullable String uri) {
263             mUri = uri;
264             return this;
265         }
266 
267         /**
268          * Add a key to this person in order to uniquely identify it.
269          * This is especially useful if the name doesn't uniquely identify this person or if the
270          * display name is a short handle of the actual name.
271          *
272          * <P>If no key is provided, the name serves as the key for the purpose of
273          * identification.</P>
274          *
275          * @param key the key that uniquely identifies this person.
276          */
277         @NonNull
setKey(@ullable String key)278         public Person.Builder setKey(@Nullable String key) {
279             mKey = key;
280             return this;
281         }
282 
283         /**
284          * Sets whether this is an important person. Use this method to denote users who frequently
285          * interact with the user of this device when {@link #setUri(String)} isn't provided with
286          * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, and instead with
287          * the {@code mailto:} or {@code tel:} schemas.
288          *
289          * @param isImportant {@code true} if this is an important person, {@code false} otherwise.
290          */
291         @NonNull
setImportant(boolean isImportant)292         public Person.Builder setImportant(boolean isImportant) {
293             mIsImportant = isImportant;
294             return this;
295         }
296 
297         /**
298          * Sets whether this person is a machine rather than a human.
299          *
300          * @param isBot {@code true} if this person is a machine, {@code false} otherwise.
301          */
302         @NonNull
setBot(boolean isBot)303         public Person.Builder setBot(boolean isBot) {
304             mIsBot = isBot;
305             return this;
306         }
307 
308         /** Creates and returns the {@link Person} this builder represents. */
309         @NonNull
build()310         public Person build() {
311             return new Person(this);
312         }
313     }
314 
315     public static final @android.annotation.NonNull Creator<Person> CREATOR = new Creator<Person>() {
316         @Override
317         public Person createFromParcel(Parcel in) {
318             return new Person(in);
319         }
320 
321         @Override
322         public Person[] newArray(int size) {
323             return new Person[size];
324         }
325     };
326 }
327