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