1 // Copyright (c) 2013 Intel Corporation. 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 package org.xwalk.core.extension.api.contacts;
7 import android.content.ContentProviderOperation;
8 import android.content.ContentProviderResult;
9 import android.content.ContentResolver;
10 import android.content.ContentUris;
11 import android.content.OperationApplicationException;
12 import android.database.Cursor;
13 import android.net.Uri;
14 import android.os.RemoteException;
15 import android.provider.ContactsContract;
16 import android.provider.ContactsContract.Data;
17 import android.provider.ContactsContract.Groups;
18 import android.provider.ContactsContract.RawContacts;
19 import android.util.Log;
21 import java.text.ParseException;
22 import java.text.SimpleDateFormat;
23 import java.util.ArrayList;
24 import java.util.HashSet;
28 public class ContactUtils {
29 private static final String TAG = "ContactUtils";
30 public ContentResolver mResolver;
31 public ContactUtils(ContentResolver resolver) {
35 public static <K, V> K getKeyFromValue(Map<K, V> map, V value) {
37 for (Map.Entry<K, V> entry : map.entrySet()) {
38 if (value != null && value.equals(entry.getValue())) {
47 * @param strings e.g. ["apple", "orange", "banana"]
48 * @return A list of question marks to be used in SQL clause, e.g. "?,?,?"
50 public static String makeQuestionMarkList(Set<String> strings) {
52 for (int i = 0; i < strings.size(); ++i) {
55 return ret.substring(0, ret.length()-1);
58 public boolean hasID(String id) {
59 if (id == null) return false;
62 c = mResolver.query(ContactsContract.Contacts.CONTENT_URI,
63 null, ContactsContract.Contacts._ID + " = ?",
64 new String[]{id}, null);
65 return (c.getCount() != 0);
66 } catch (SecurityException e) {
67 Log.e(TAG, "hasID: " + e.toString());
70 if (c != null) c.close();
74 public String getRawId(String id) {
77 c = mResolver.query(RawContacts.CONTENT_URI, new String[]{RawContacts._ID},
78 RawContacts.CONTACT_ID + "=?", new String[]{id}, null);
79 if (c.moveToFirst()) {
80 // Actually it is possible that for one contact id there are multiple rawIds.
81 return c.getString(0);
85 } catch (SecurityException e) {
86 Log.e(TAG, "getRawId: " + e.toString());
89 if (c != null) c.close();
93 public String getId(String rawId) {
96 c = mResolver.query(RawContacts.CONTENT_URI, new String[]{RawContacts.CONTACT_ID},
97 RawContacts._ID + "=?", new String[]{rawId}, null);
98 if (c.moveToFirst()) {
99 return c.getString(0);
103 } catch (SecurityException e) {
104 Log.e(TAG, "getId: " + e.toString());
107 if (c != null) c.close();
112 * Get lastUpdatedTimestamp and return as JS date format
113 * @param long e.g. 987654321012
114 * @return string e.g. "2001-04-19T04:25:21.012Z"
116 @android.annotation.TargetApi(android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
117 public String getLastUpdated(long contactId) {
118 String[] projection = new String[]{ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP};
120 Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
121 Cursor cursor = mResolver.query(uri, projection, null, null, null);
123 if (cursor.moveToNext()) {
124 return timeConvertToJS(cursor.getLong(0));
127 if (cursor != null) {
134 public Set<String> getCurrentRawIds() {
137 c = mResolver.query(RawContacts.CONTENT_URI,
138 new String[]{RawContacts._ID}, null, null, null);
139 Set<String> rawIds = new HashSet<String>();
140 while (c.moveToNext()) {
141 rawIds.add(c.getString(0));
144 } catch (SecurityException e) {
145 Log.e(TAG, "getCurrentRawIds: " + e.toString());
148 if (c != null) c.close();
152 public String[] getDefaultAccountNameAndType() {
153 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
154 ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
155 .withValue(RawContacts.ACCOUNT_NAME, null)
156 .withValue(RawContacts.ACCOUNT_TYPE, null)
159 ContentProviderResult[] results = null;
161 results = mResolver.applyBatch(ContactsContract.AUTHORITY, ops);
162 } catch (Exception e) {
163 if (e instanceof RemoteException ||
164 e instanceof OperationApplicationException ||
165 e instanceof SecurityException) {
166 Log.e(TAG, "getDefaultAccountNameAndType - Failed to apply batch: " + e.toString());
169 throw new RuntimeException(e);
173 Uri rawContactUri = null;
174 long rawContactId = 0;
175 for (ContentProviderResult result : results) {
176 rawContactUri = result.uri;
177 rawContactId = ContentUris.parseId(rawContactUri);
181 String accountType = "";
182 String accountName = "";
184 c = mResolver.query(RawContacts.CONTENT_URI,
185 new String[] {RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_NAME},
186 RawContacts._ID + "=?",
187 new String[] {String.valueOf(rawContactId)}, null);
188 if (c.moveToFirst()) {
189 if (!c.isAfterLast()) {
190 accountType = c.getString(c.getColumnIndex(RawContacts.ACCOUNT_TYPE));
191 accountName = c.getString(c.getColumnIndex(RawContacts.ACCOUNT_NAME));
194 } catch (SecurityException e) {
195 Log.e(TAG, "getDefaultAccountNameAndType: " + e.toString());
198 if (c != null) c.close();
201 mResolver.delete(rawContactUri, null, null);
203 return new String[] { accountName, accountType };
206 public String getGroupId(String groupTitle) {
207 final String selection = Groups.DELETED + "=? and " + Groups.GROUP_VISIBLE + "=?";
210 c = mResolver.query(Groups.CONTENT_URI, null, selection, new String[]{"0", "1"}, null);
212 for (int i = 0; i < c.getCount(); i++) {
213 final String title = c.getString(c.getColumnIndex(Groups.TITLE));
214 if (title.equals(groupTitle)) {
215 return c.getString(c.getColumnIndex(Groups._ID));
220 } catch (SecurityException e) {
221 Log.e(TAG, "getGroupId: " + e.toString());
224 if (c != null) c.close();
228 public String getGroupTitle(String groupId) {
229 final String selection = Groups.DELETED + "=? and " + Groups.GROUP_VISIBLE + "=?";
232 c = mResolver.query(Groups.CONTENT_URI, null, selection, new String[]{"0", "1"}, null);
234 for (int i = 0; i < c.getCount(); i++) {
235 final String id = c.getString(c.getColumnIndex(Groups._ID));
236 if (id.equals(groupId)) {
237 return c.getString(c.getColumnIndex(Groups.TITLE));
242 } catch (SecurityException e) {
243 Log.e(TAG, "getGroupTitle: " + e.toString());
246 if (c != null) c.close();
250 public String getEnsuredGroupId(String groupTitle) {
251 String groupId = getGroupId(groupTitle);
252 if (groupId == null) {
253 newGroup(groupTitle);
254 groupId = getGroupId(groupTitle);
255 if (groupId == null) return null;
260 public void newGroup(String groupTitle) {
261 final String accountNameType[] = getDefaultAccountNameAndType();
262 ArrayList<ContentProviderOperation> o = new ArrayList<ContentProviderOperation>();
263 o.add(ContentProviderOperation.newInsert(Groups.CONTENT_URI)
264 .withValue(Groups.TITLE, groupTitle)
265 .withValue(Groups.GROUP_VISIBLE, true)
266 .withValue(Groups.ACCOUNT_NAME, accountNameType[0])
267 .withValue(Groups.ACCOUNT_TYPE, accountNameType[1])
270 mResolver.applyBatch(ContactsContract.AUTHORITY, o);
271 } catch (Exception e) {
272 if (e instanceof RemoteException ||
273 e instanceof OperationApplicationException ||
274 e instanceof SecurityException) {
275 Log.e(TAG, "newGroup - Failed to create new contact group: " + e.toString());
277 throw new RuntimeException(e);
282 public void cleanByMimeType(String id, String mimeType) {
283 mResolver.delete(Data.CONTENT_URI,
284 String.format("%s = ? AND %s = ?", Data.CONTACT_ID, Data.MIMETYPE),
285 new String[] {id, mimeType});
289 * Get date only from a JSON date string
290 * @param string e.g. "1969-12-31T16:00:20.012-0800"
291 * @return string e.g. "1969-12-31"
293 public String dateTrim(String string) {
296 final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault());
297 date = df.format(df.parse(string));
298 } catch (ParseException e) {
299 Log.e(TAG, "dateFormat - parse failed: " + e.toString());
305 * Convert epoch seconds to JS date format
306 * @param long e.g. 61
307 * @return string e.g. "1969-12-31T00:01:01Z"
309 private String timeConvertToJS(long seconds) {
310 final SimpleDateFormat df =
311 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", java.util.Locale.getDefault());
312 return df.format(new java.util.Date(seconds));