• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.car.telephony.common;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.database.Cursor;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.provider.ContactsContract;
25 import android.provider.ContactsContract.CommonDataKinds.Phone;
26 
27 import androidx.annotation.NonNull;
28 import androidx.annotation.Nullable;
29 
30 import java.util.Objects;
31 
32 /**
33  * Contact phone number and its meta data.
34  */
35 public class PhoneNumber implements Parcelable {
36 
37     private final I18nPhoneNumberWrapper mI18nPhoneNumber;
38     @NonNull
39     private final String mAccountName;
40     @NonNull
41     private final String mAccountType;
42 
43     private int mType;
44     @Nullable
45     private String mLabel;
46     private boolean mIsPrimary;
47     private long mId;
48     private int mDataVersion;
49 
50     /** The favorite bit is from local database, presenting a
51      *  {@link com.android.car.dialer.storage.FavoriteNumberEntity}. */
52     private boolean mIsFavorite;
53 
fromCursor(Context context, Cursor cursor)54     static PhoneNumber fromCursor(Context context, Cursor cursor) {
55         int typeColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
56         int labelColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL);
57         int numberColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
58         int rawDataIdColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
59         int dataVersionColumn = cursor.getColumnIndex(
60                 ContactsContract.CommonDataKinds.Phone.DATA_VERSION);
61         // IS_PRIMARY means primary entry of the raw contact and IS_SUPER_PRIMARY means primary
62         // entry of the aggregated contact. It is guaranteed that only one data entry is super
63         // primary.
64         int isPrimaryColumn = cursor.getColumnIndex(
65                 ContactsContract.CommonDataKinds.Phone.IS_SUPER_PRIMARY);
66         int accountNameColumn = cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_NAME);
67         int accountTypeColumn = cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE);
68         return PhoneNumber.newInstance(
69                 context,
70                 cursor.getString(numberColumn),
71                 cursor.getInt(typeColumn),
72                 cursor.getString(labelColumn),
73                 cursor.getInt(isPrimaryColumn) > 0,
74                 cursor.getLong(rawDataIdColumn),
75                 cursor.getString(accountNameColumn),
76                 cursor.getString(accountTypeColumn),
77                 cursor.getInt(dataVersionColumn));
78     }
79 
80     /**
81      * Creates a new {@link PhoneNumber}.
82      *
83      * @param rawNumber   A potential phone number.
84      * @param type        The phone number type. See more at {@link Phone#TYPE}
85      * @param label       The user defined label. See more at {@link Phone#LABEL}
86      * @param isPrimary   Whether this is the primary entry of the aggregated contact it belongs
87      *                    to. See more at {@link Phone#IS_SUPER_PRIMARY}.
88      * @param id          The unique key for raw contact entry containing the phone number entity.
89      *                    See more at {@link Phone#_ID}
90      * @param dataVersion The dataVersion of the raw contact entry record. See more at {@link
91      *                    Phone#DATA_VERSION}
92      */
newInstance(Context context, String rawNumber, int type, @Nullable String label, boolean isPrimary, long id, String accountName, String accountType, int dataVersion)93     public static PhoneNumber newInstance(Context context, String rawNumber, int type,
94             @Nullable String label, boolean isPrimary, long id, String accountName,
95             String accountType, int dataVersion) {
96         I18nPhoneNumberWrapper i18nPhoneNumber = I18nPhoneNumberWrapper.Factory.INSTANCE.get(
97                 context, rawNumber);
98         return new PhoneNumber(i18nPhoneNumber, type, label, isPrimary, id, accountName,
99                 accountType, dataVersion);
100     }
101 
PhoneNumber(I18nPhoneNumberWrapper i18nNumber, int type, @Nullable String label, boolean isPrimary, long id, String accountName, String accountType, int dataVersion)102     private PhoneNumber(I18nPhoneNumberWrapper i18nNumber, int type, @Nullable String label,
103             boolean isPrimary, long id, String accountName, String accountType, int dataVersion) {
104         mI18nPhoneNumber = i18nNumber;
105         mType = type;
106         mLabel = label;
107         mIsPrimary = isPrimary;
108         mId = id;
109         mAccountName = accountName == null ? "" : accountName;
110         mAccountType = accountType == null ? "" : accountType;
111         mDataVersion = dataVersion;
112     }
113 
114     @Override
equals(Object obj)115     public boolean equals(Object obj) {
116         return obj instanceof PhoneNumber
117                 && mI18nPhoneNumber.equals(((PhoneNumber) obj).mI18nPhoneNumber)
118                 && mAccountName.equals(((PhoneNumber) obj).mAccountName)
119                 && mAccountType.equals(((PhoneNumber) obj).mAccountType);
120     }
121 
122     @Override
hashCode()123     public int hashCode() {
124         return Objects.hash(mI18nPhoneNumber, mAccountName, mAccountType);
125     }
126 
127     /**
128      * Returns if the phone number is the primary entry for the aggregated contact it belongs to.
129      * See more at {@link Phone#IS_SUPER_PRIMARY}.
130      */
isPrimary()131     public boolean isPrimary() {
132         return mIsPrimary;
133     }
134 
135     /**
136      * Returns a human readable string label. For example, Home, Work, etc.
137      */
getReadableLabel(Resources res)138     public CharSequence getReadableLabel(Resources res) {
139         return Phone.getTypeLabel(res, mType, mLabel);
140     }
141 
142     /**
143      * Gets a phone number in the international format if valid. Otherwise, returns the raw number.
144      */
getNumber()145     public String getNumber() {
146         return mI18nPhoneNumber.getNumber();
147     }
148 
149     /**
150      * Returns the raw number, the number that is input by the user
151      */
getRawNumber()152     public String getRawNumber() {
153         return mI18nPhoneNumber.getRawNumber();
154     }
155 
156     /**
157      * Returns the format independent i18n {@link I18nPhoneNumberWrapper wrapper} class.
158      */
getI18nPhoneNumberWrapper()159     public I18nPhoneNumberWrapper getI18nPhoneNumberWrapper() {
160         return mI18nPhoneNumber;
161     }
162 
163     /**
164      * Gets the type of phone number, for example Home or Work. Possible values are defined in
165      * {@link Phone}.
166      */
getType()167     public int getType() {
168         return mType;
169     }
170 
getId()171     public long getId() {
172         return mId;
173     }
174 
175     @Nullable
getAccountName()176     public String getAccountName() {
177         return mAccountName;
178     }
179 
180     @Nullable
getAccountType()181     public String getAccountType() {
182         return mAccountType;
183     }
184 
185     /**
186      * Updates the favorite bit, which is local database. See
187      * {@link com.android.car.dialer.storage.FavoriteNumberDatabase}.
188      */
setIsFavorite(boolean isFavorite)189     public void setIsFavorite(boolean isFavorite) {
190         mIsFavorite = isFavorite;
191     }
192 
193     /** Returns if the phone number is favorite entry. */
isFavorite()194     public boolean isFavorite() {
195         return mIsFavorite;
196     }
197 
198     /**
199      * Each contact may have a few sources with the same phone number. Merge same phone numbers as
200      * one.
201      *
202      * <p>As long as one of those phone numbers is primary entry of the aggregated contact, mark
203      * the merged phone number as primary.
204      */
merge(PhoneNumber phoneNumber)205     public PhoneNumber merge(PhoneNumber phoneNumber) {
206         if (equals(phoneNumber)) {
207             if (mDataVersion < phoneNumber.mDataVersion) {
208                 mDataVersion = phoneNumber.mDataVersion;
209                 mId = phoneNumber.mId;
210                 mIsPrimary |= phoneNumber.mIsPrimary;
211                 mType = phoneNumber.mType;
212                 mLabel = phoneNumber.mLabel;
213             }
214         }
215         return this;
216     }
217 
218     /**
219      * Gets the user defined label for the the contact method.
220      */
221     @Nullable
getLabel()222     public String getLabel() {
223         return mLabel;
224     }
225 
226     @Override
toString()227     public String toString() {
228         return getNumber() + " " + mAccountName + " " + mAccountType;
229     }
230 
231     @Override
describeContents()232     public int describeContents() {
233         return 0;
234     }
235 
236     @Override
writeToParcel(Parcel dest, int flags)237     public void writeToParcel(Parcel dest, int flags) {
238         dest.writeInt(mType);
239         dest.writeString(mLabel);
240         dest.writeParcelable(mI18nPhoneNumber, flags);
241         dest.writeBoolean(mIsPrimary);
242         dest.writeLong(mId);
243         dest.writeString(mAccountName);
244         dest.writeString(mAccountType);
245         dest.writeInt(mDataVersion);
246         dest.writeBoolean(mIsFavorite);
247     }
248 
249     public static Creator<PhoneNumber> CREATOR = new Creator<PhoneNumber>() {
250         @Override
251         public PhoneNumber createFromParcel(Parcel source) {
252             int type = source.readInt();
253             String label = source.readString();
254             I18nPhoneNumberWrapper i18nPhoneNumberWrapper = source.readParcelable(
255                     I18nPhoneNumberWrapper.class.getClassLoader());
256             boolean isPrimary = source.readBoolean();
257             long id = source.readLong();
258             String accountName = source.readString();
259             String accountType = source.readString();
260             int dataVersion = source.readInt();
261             PhoneNumber phoneNumber = new PhoneNumber(i18nPhoneNumberWrapper, type, label,
262                     isPrimary, id, accountName, accountType, dataVersion);
263             phoneNumber.setIsFavorite(source.readBoolean());
264             return phoneNumber;
265         }
266 
267         @Override
268         public PhoneNumber[] newArray(int size) {
269             return new PhoneNumber[size];
270         }
271     };
272 }
273