12fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa/* 22fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Copyright (C) 2011 The Android Open Source Project 32fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 42fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); 52fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * you may not use this file except in compliance with the License. 62fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * You may obtain a copy of the License at 72fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 82fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 92fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 102fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 112fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, 122fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * See the License for the specific language governing permissions and 142fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * limitations under the License. 152fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa */ 162fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 172fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawapackage com.android.common.contacts; 182fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 192fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.content.ContentResolver; 202fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.content.ContentValues; 212fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.content.Context; 222fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.database.Cursor; 232fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.net.Uri; 242fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.os.Build; 252fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.provider.ContactsContract; 262fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Email; 272fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.Phone; 282fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.provider.ContactsContract.Data; 292fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.text.TextUtils; 302fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.text.util.Rfc822Token; 312fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.text.util.Rfc822Tokenizer; 322fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.util.Log; 332fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport android.widget.TextView; 342fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 352fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport java.util.ArrayList; 362fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport java.util.Arrays; 372fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport java.util.Collection; 382fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport java.util.HashSet; 392fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawaimport java.util.Set; 402fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 412fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa/** 422fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Convenient class for updating usage statistics in ContactsProvider. 432fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 442fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Applications like Email, Sms, etc. can promote recipients for better sorting with this class 452fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 462fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * @see ContactsContract.Contacts 472fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa */ 482fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawapublic class DataUsageStatUpdater { 492fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa private static final String TAG = DataUsageStatUpdater.class.getSimpleName(); 502fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 512fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa /** 522fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Copied from API in ICS (not available before it). You can use values here if you are sure 532fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * it is supported by the device. 542fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa */ 552fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public static final class DataUsageFeedback { 56f7da24b37a0c94e9bfb5e317548999d418fb12aeConley Owens static final Uri FEEDBACK_URI = 572fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Uri.withAppendedPath(Data.CONTENT_URI, "usagefeedback"); 582fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 59f7da24b37a0c94e9bfb5e317548999d418fb12aeConley Owens static final String USAGE_TYPE = "type"; 602fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public static final String USAGE_TYPE_CALL = "call"; 612fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public static final String USAGE_TYPE_LONG_TEXT = "long_text"; 622fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public static final String USAGE_TYPE_SHORT_TEXT = "short_text"; 632fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 642fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 652fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa private final ContentResolver mResolver; 662fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 672fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public DataUsageStatUpdater(Context context) { 682fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa mResolver = context.getContentResolver(); 692fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 702fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 712fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa /** 722fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Updates usage statistics using comma-separated RFC822 address like 732fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * "Joe <joe@example.com>, Due <due@example.com>". 742fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 752fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * This will cause Disk access so should be called in a background thread. 762fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 772fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * @return true when update request is correctly sent. False when the request fails, 782fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * input has no valid entities. 792fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa */ 802fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public boolean updateWithRfc822Address(Collection<CharSequence> texts){ 812fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (texts == null) { 822fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa return false; 832fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 842fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Set<String> addresses = new HashSet<String>(); 852fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa for (CharSequence text : texts) { 862fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text.toString().trim()); 872fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa for (Rfc822Token token : tokens) { 882fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa addresses.add(token.getAddress()); 892fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 902fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 912fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa return updateWithAddress(addresses); 922fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 932fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 942fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 952fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa /** 962fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Update usage statistics information using a list of email addresses. 972fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 982fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * This will cause Disk access so should be called in a background thread. 992fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 1002fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * @see #update(Collection, Collection, String) 1012fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 1022fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * @return true when update request is correctly sent. False when the request fails, 1032fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * input has no valid entities. 1042fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa */ 1052fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public boolean updateWithAddress(Collection<String> addresses) { 1062fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (Log.isLoggable(TAG, Log.DEBUG)) { 1072fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "updateWithAddress: " + Arrays.toString(addresses.toArray())); 1082fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1092fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (addresses != null && !addresses.isEmpty()) { 1102fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final ArrayList<String> whereArgs = new ArrayList<String>(); 1112fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final StringBuilder whereBuilder = new StringBuilder(); 1122fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final String[] questionMarks = new String[addresses.size()]; 1132fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 1142fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereArgs.addAll(addresses); 1152fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 1162fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa // Email.ADDRESS == Email.DATA1. Email.ADDRESS can be available from API Level 11. 1172fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereBuilder.append(Email.DATA1 + " IN (") 1182fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa .append(TextUtils.join(",", questionMarks)) 1192fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa .append(")"); 1202fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Cursor cursor = mResolver.query(Email.CONTENT_URI, 1212fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa new String[] {Email.CONTACT_ID, Email._ID}, whereBuilder.toString(), 1222fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereArgs.toArray(new String[0]), null); 1232fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 1242fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (cursor == null) { 1252fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.w(TAG, "Cursor for Email.CONTENT_URI became null."); 1262fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 1272fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Set<Long> contactIds = new HashSet<Long>(cursor.getCount()); 1282fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Set<Long> dataIds = new HashSet<Long>(cursor.getCount()); 1292fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa try { 1302fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa cursor.move(-1); 1312fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa while(cursor.moveToNext()) { 1322fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa contactIds.add(cursor.getLong(0)); 1332fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa dataIds.add(cursor.getLong(1)); 1342fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1352fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } finally { 1362fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa cursor.close(); 1372fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1382fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa return update(contactIds, dataIds, DataUsageFeedback.USAGE_TYPE_LONG_TEXT); 1392fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1402fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1412fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 1422fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa return false; 1432fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1442fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 1452fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa /** 1462fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * Update usage statistics information using a list of phone numbers. 1472fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 1482fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * This will cause Disk access so should be called in a background thread. 1492fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 1502fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * @see #update(Collection, Collection, String) 1512fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * 1522fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * @return true when update request is correctly sent. False when the request fails, 1532fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * input has no valid entities. 1542fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa */ 1552fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa public boolean updateWithPhoneNumber(Collection<String> numbers) { 1562fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (Log.isLoggable(TAG, Log.DEBUG)) { 1572fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "updateWithPhoneNumber: " + Arrays.toString(numbers.toArray())); 1582fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1592fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (numbers != null && !numbers.isEmpty()) { 1602fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final ArrayList<String> whereArgs = new ArrayList<String>(); 1612fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final StringBuilder whereBuilder = new StringBuilder(); 1622fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final String[] questionMarks = new String[numbers.size()]; 1632fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 1642fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereArgs.addAll(numbers); 1652fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 1662fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa // Phone.NUMBER == Phone.DATA1. NUMBER can be available from API Level 11. 1672fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereBuilder.append(Phone.DATA1 + " IN (") 1682fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa .append(TextUtils.join(",", questionMarks)) 1692fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa .append(")"); 1702fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Cursor cursor = mResolver.query(Phone.CONTENT_URI, 1712fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa new String[] {Phone.CONTACT_ID, Phone._ID}, whereBuilder.toString(), 1722fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereArgs.toArray(new String[0]), null); 1732fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 1742fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (cursor == null) { 1752fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.w(TAG, "Cursor for Phone.CONTENT_URI became null."); 1762fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 1772fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Set<Long> contactIds = new HashSet<Long>(cursor.getCount()); 1782fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Set<Long> dataIds = new HashSet<Long>(cursor.getCount()); 1792fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa try { 1802fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa cursor.move(-1); 1812fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa while(cursor.moveToNext()) { 1822fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa contactIds.add(cursor.getLong(0)); 1832fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa dataIds.add(cursor.getLong(1)); 1842fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1852fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } finally { 1862fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa cursor.close(); 1872fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1882fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa return update(contactIds, dataIds, DataUsageFeedback.USAGE_TYPE_SHORT_TEXT); 1892fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1902fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1912fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa return false; 1922fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 1932fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 1942fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa /** 1952fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * @return true when one or more of update requests are correctly sent. 1962fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa * False when all the requests fail. 1972fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa */ 1982fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa private boolean update(Collection<Long> contactIds, Collection<Long> dataIds, String type) { 1992fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 2002fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 2012fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa boolean successful = false; 2022fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 2034b80d252210137df98bb393b290725f93877b00cDaisuke Miyakawa // From ICS (SDK_INT 14) we can use per-contact-method structure. We'll check if the device 2044b80d252210137df98bb393b290725f93877b00cDaisuke Miyakawa // supports it and call the API. 2054b80d252210137df98bb393b290725f93877b00cDaisuke Miyakawa if (Build.VERSION.SDK_INT >= 14) { 2062fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (dataIds.isEmpty()) { 2072fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (Log.isLoggable(TAG, Log.DEBUG)) { 2082fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "Given list for data IDs is null. Ignoring."); 2092fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2102fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 2112fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final Uri uri = DataUsageFeedback.FEEDBACK_URI.buildUpon() 2122fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa .appendPath(TextUtils.join(",", dataIds)) 2132fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, type) 2142fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa .build(); 2152fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (mResolver.update(uri, new ContentValues(), null, null) > 0) { 2162fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa successful = true; 2172fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 2182fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (Log.isLoggable(TAG, Log.DEBUG)) { 2192fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "update toward data rows " + dataIds + " failed"); 2202fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2212fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2222fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2232fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 2242fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa // Use older API. 2252fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (contactIds.isEmpty()) { 2262fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (Log.isLoggable(TAG, Log.DEBUG)) { 2272fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "Given list for contact IDs is null. Ignoring."); 2282fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2292fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 2302fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final StringBuilder whereBuilder = new StringBuilder(); 2312fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final ArrayList<String> whereArgs = new ArrayList<String>(); 2322fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final String[] questionMarks = new String[contactIds.size()]; 2332fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa for (long contactId : contactIds) { 2342fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereArgs.add(String.valueOf(contactId)); 2352fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2362fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 2372fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereBuilder.append(ContactsContract.Contacts._ID + " IN ("). 2382fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa append(TextUtils.join(",", questionMarks)). 2392fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa append(")"); 2402fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 2412fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (Log.isLoggable(TAG, Log.DEBUG)) { 2422fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "contactId where: " + whereBuilder.toString()); 2432fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "contactId selection: " + whereArgs); 2442fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2452fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 2462fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa final ContentValues values = new ContentValues(); 2472fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa values.put(ContactsContract.Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 2482fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (mResolver.update(ContactsContract.Contacts.CONTENT_URI, values, 2492fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa whereBuilder.toString(), whereArgs.toArray(new String[0])) > 0) { 2502fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa successful = true; 2512fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } else { 2522fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa if (Log.isLoggable(TAG, Log.DEBUG)) { 2532fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa Log.d(TAG, "update toward raw contacts " + contactIds + " failed"); 2542fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2552fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2562fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2572fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2582fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa 2592fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa return successful; 2602fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa } 2612fd97117b7a325f256279a9c7ea02b48b1e57632Daisuke Miyakawa} 262