1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Populates data fields from Android contacts profile API (i.e. "me" contact).
7 package org.chromium.components.browser.autofill;
9 import android.content.ContentResolver;
10 import android.content.Context;
11 import android.content.pm.PackageManager;
12 import android.database.Cursor;
13 import android.net.Uri;
14 import android.provider.ContactsContract;
16 import org.chromium.base.CalledByNative;
17 import org.chromium.base.JNINamespace;
20 * Loads user profile information stored under the "Me" contact.
21 * Requires permissions: READ_CONTACTS and READ_PROFILE.
23 @JNINamespace("autofill")
24 public class PersonalAutofillPopulator {
26 * SQL query definitions for obtaining specific profile information.
28 private abstract static class ProfileQuery {
29 Uri profileDataUri = Uri.withAppendedPath(
30 ContactsContract.Profile.CONTENT_URI,
31 ContactsContract.Contacts.Data.CONTENT_DIRECTORY
33 public abstract String[] projection();
34 public abstract String mimeType();
37 private static class EmailProfileQuery extends ProfileQuery {
38 private static final int EMAIL_ADDRESS = 0;
41 public String[] projection() {
43 ContactsContract.CommonDataKinds.Email.ADDRESS,
48 public String mimeType() {
49 return ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE;
53 private static class PhoneProfileQuery extends ProfileQuery {
54 private static final int NUMBER = 0;
57 public String[] projection() {
59 ContactsContract.CommonDataKinds.Phone.NUMBER,
64 public String mimeType() {
65 return ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
69 private static class AddressProfileQuery extends ProfileQuery {
70 private static final int STREET = 0;
71 private static final int POBOX = 1;
72 private static final int NEIGHBORHOOD = 2;
73 private static final int CITY = 3;
74 private static final int REGION = 4;
75 private static final int POSTALCODE = 5;
76 private static final int COUNTRY = 6;
79 public String[] projection() {
81 ContactsContract.CommonDataKinds.StructuredPostal.STREET,
82 ContactsContract.CommonDataKinds.StructuredPostal.POBOX,
83 ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD,
84 ContactsContract.CommonDataKinds.StructuredPostal.CITY,
85 ContactsContract.CommonDataKinds.StructuredPostal.REGION,
86 ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE,
87 ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY,
92 public String mimeType() {
93 return ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
97 private static class NameProfileQuery extends ProfileQuery {
98 private static final int GIVEN_NAME = 0;
99 private static final int MIDDLE_NAME = 1;
100 private static final int FAMILY_NAME = 2;
101 private static final int SUFFIX = 3;
104 public String[] projection() {
105 return new String[] {
106 ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
107 ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME,
108 ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
109 ContactsContract.CommonDataKinds.StructuredName.SUFFIX
114 public String mimeType() {
115 return ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE;
120 * Takes a query object, transforms into actual query and returns cursor.
121 * Primary contact values will be first.
123 private Cursor cursorFromProfileQuery(ProfileQuery query, ContentResolver contentResolver) {
124 String sortDescriptor = ContactsContract.Contacts.Data.IS_PRIMARY + " DESC";
125 return contentResolver.query(
126 query.profileDataUri,
128 ContactsContract.Contacts.Data.MIMETYPE + " = ?",
129 new String[]{query.mimeType()},
133 // Extracted data variables.
134 private String[] mEmailAddresses;
135 private String mGivenName;
136 private String mMiddleName;
137 private String mFamilyName;
138 private String mSuffix;
139 private String mPobox;
140 private String mStreet;
141 private String mNeighborhood;
142 private String mCity;
143 private String mRegion;
144 private String mCountry;
145 private String mPostalCode;
146 private String[] mPhoneNumbers;
147 private boolean mHasPermissions;
151 * @param context a valid android context reference
153 PersonalAutofillPopulator(Context context) {
154 mHasPermissions = hasPermissions(context);
155 if (mHasPermissions) {
156 ContentResolver contentResolver = context.getContentResolver();
157 populateName(contentResolver);
158 populateEmail(contentResolver);
159 populateAddress(contentResolver);
160 populatePhone(contentResolver);
164 // Check if the user has granted permissions.
165 private boolean hasPermissions(Context context) {
166 String [] permissions = {
167 "android.permission.READ_CONTACTS",
168 "android.permission.READ_PROFILE"
170 for (String permission : permissions) {
171 int res = context.checkCallingOrSelfPermission(permission);
172 if (res != PackageManager.PERMISSION_GRANTED) return false;
177 // Populating data fields.
178 private void populateName(ContentResolver contentResolver) {
179 NameProfileQuery nameProfileQuery = new NameProfileQuery();
180 Cursor nameCursor = cursorFromProfileQuery(nameProfileQuery, contentResolver);
181 if (nameCursor.moveToNext()) {
182 mGivenName = nameCursor.getString(nameProfileQuery.GIVEN_NAME);
183 mMiddleName = nameCursor.getString(nameProfileQuery.MIDDLE_NAME);
184 mFamilyName = nameCursor.getString(nameProfileQuery.FAMILY_NAME);
185 mSuffix = nameCursor.getString(nameProfileQuery.SUFFIX);
190 private void populateEmail(ContentResolver contentResolver) {
191 EmailProfileQuery emailProfileQuery = new EmailProfileQuery();
192 Cursor emailCursor = cursorFromProfileQuery(emailProfileQuery, contentResolver);
193 mEmailAddresses = new String[emailCursor.getCount()];
194 for (int i = 0; emailCursor.moveToNext(); i++) {
195 mEmailAddresses[i] = emailCursor.getString(emailProfileQuery.EMAIL_ADDRESS);
200 private void populateAddress(ContentResolver contentResolver) {
201 AddressProfileQuery addressProfileQuery = new AddressProfileQuery();
202 Cursor addressCursor = cursorFromProfileQuery(addressProfileQuery, contentResolver);
203 if(addressCursor.moveToNext()) {
204 mPobox = addressCursor.getString(addressProfileQuery.POBOX);
205 mStreet = addressCursor.getString(addressProfileQuery.STREET);
206 mNeighborhood = addressCursor.getString(addressProfileQuery.NEIGHBORHOOD);
207 mCity = addressCursor.getString(addressProfileQuery.CITY);
208 mRegion = addressCursor.getString(addressProfileQuery.REGION);
209 mPostalCode = addressCursor.getString(addressProfileQuery.POSTALCODE);
210 mCountry = addressCursor.getString(addressProfileQuery.COUNTRY);
212 addressCursor.close();
215 private void populatePhone(ContentResolver contentResolver) {
216 PhoneProfileQuery phoneProfileQuery = new PhoneProfileQuery();
217 Cursor phoneCursor = cursorFromProfileQuery(phoneProfileQuery, contentResolver);
218 mPhoneNumbers = new String[phoneCursor.getCount()];
219 for (int i = 0; phoneCursor.moveToNext(); i++) {
220 mPhoneNumbers[i] = phoneCursor.getString(phoneProfileQuery.NUMBER);
226 * Static factory method for instance creation.
227 * @param context valid Android context.
228 * @return PersonalAutofillPopulator new instance of PersonalAutofillPopulator.
231 static PersonalAutofillPopulator create(Context context) {
232 return new PersonalAutofillPopulator(context);
236 private String getFirstName() {
241 private String getLastName() {
246 private String getMiddleName() {
251 private String getSuffix() {
256 private String[] getEmailAddresses() {
257 return mEmailAddresses;
261 private String getStreet() {
266 private String getPobox() {
271 private String getNeighborhood() {
272 return mNeighborhood;
276 private String getCity() {
281 private String getRegion() {
286 private String getPostalCode() {
291 private String getCountry() {
296 private String[] getPhoneNumbers() {
297 return mPhoneNumbers;
301 private boolean getHasPermissions() {
302 return mHasPermissions;