19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.telephony;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.AsyncQueryHandler;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.SQLException;
236a3d188f18b5ae278c802c8bbd1e0a44da555cdfBai Taoimport android.location.CountryDetector;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
28d34d30ac2e5d7fc0ee0592187492acd3d52a2545David Brownimport android.os.SystemProperties;
29158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brownimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
30158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brownimport android.provider.ContactsContract.Data;
313c513ed95cee2e0bcd7208cb7e46307f09c907c9Dmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
3794202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown * Helper class to make it easier to run asynchronous caller-id lookup queries.
3894202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown * @see CallerInfo
3994202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown *
4094202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown * {@hide}
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class CallerInfoAsyncQuery {
43431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato    private static final boolean DBG = false;
44e22415817febc8d3229d1774f3b0dfda0fda8f46Nicolas Catania    private static final String LOG_TAG = "CallerInfoAsyncQuery";
452563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_NEW_QUERY = 1;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_ADD_LISTENER = 2;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_END_OF_QUEUE = 3;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_EMERGENCY_NUMBER = 4;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_VOICEMAIL_NUMBER = 5;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private CallerInfoAsyncQueryHandler mHandler;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
542ef46c65877a7188868cec440fbe93086e011f5bDavid Brown    // If the CallerInfo query finds no contacts, should we use the
552ef46c65877a7188868cec440fbe93086e011f5bDavid Brown    // PhoneNumberOfflineGeocoder to look up a "geo description"?
562ef46c65877a7188868cec440fbe93086e011f5bDavid Brown    // (TODO: This could become a flag in config.xml if it ever needs to be
572ef46c65877a7188868cec440fbe93086e011f5bDavid Brown    // configured on a per-product basis.)
58cec25c4e8afdc56451f7405f8605c1d67433e2ffDavid Brown    private static final boolean ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION = true;
592ef46c65877a7188868cec440fbe93086e011f5bDavid Brown
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Interface for a CallerInfoAsyncQueryHandler result return.
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface OnQueryCompleteListener {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
652563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         * Called when the query is complete.
662563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         */
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onQueryComplete(int token, Object cookie, CallerInfo ci);
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
692563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
702563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Wrap the cookie from the WorkerArgs with additional information needed by our
732563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville     * classes.
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final class CookieWrapper {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public OnQueryCompleteListener listener;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Object cookie;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int event;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String number;
802563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville    }
812563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
822563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Simple exception used to communicate problems with the query pool.
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class QueryPoolException extends SQLException {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public QueryPoolException(String error) {
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(error);
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
912563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Our own implementation of the AsyncQueryHandler.
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class CallerInfoAsyncQueryHandler extends AsyncQueryHandler {
962563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The information relevant to each CallerInfo query.  Each query may have multiple
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * listeners, so each AsyncCursorInfo is associated with 2 or more CookieWrapper
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * objects in the queue (one with a new query event, and one with a end event, with
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * 0 or more additional listeners in between).
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Context mQueryContext;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Uri mQueryUri;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private CallerInfo mCallerInfo;
1062563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Our own query worker thread.
1092563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         *
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This thread handles the messages enqueued in the looper.  The normal sequence
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * of events is that a new query shows up in the looper queue, followed by 0 or
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * more add listener requests, and then an end request.  Of course, these requests
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * can be interlaced with requests from other tokens, but is irrelevant to this
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * handler since the handler has no state.
1152563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         *
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Note that we depend on the queue to keep things in order; in other words, the
1172563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         * looper queue must be FIFO with respect to input from the synchronous startQuery
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * calls and output to this handleMessage call.
1192563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         *
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This use of the queue is required because CallerInfo objects may be accessed
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * multiple times before the query is complete.  All accesses (listeners) must be
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * queued up and informed in order when the query is complete.
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        protected class CallerInfoWorkerHandler extends WorkerHandler {
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public CallerInfoWorkerHandler(Looper looper) {
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                super(looper);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void handleMessage(Message msg) {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                WorkerArgs args = (WorkerArgs) msg.obj;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                CookieWrapper cw = (CookieWrapper) args.cookie;
1332563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cw == null) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Normally, this should never be the case for calls originating
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // from within this code.
1372563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville                    // However, if there is any code that this Handler calls (such as in
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // super.handleMessage) that DOES place unexpected messages on the
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // queue, then we need pass these messages on.
140431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato                    if (DBG) Log.d(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            " ignored by CallerInfoWorkerHandler, passing onto parent.");
1422563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    super.handleMessage(msg);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1452563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
146431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato                    if (DBG) Log.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
147a42880749b368e60caee77dd682d434e48ca96bdWink Saville                        " command: " + msg.what + " query URI: " + sanitizeUriToString(args.uri));
1482563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    switch (cw.event) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case EVENT_NEW_QUERY:
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            //start the sql command.
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            super.handleMessage(msg);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // shortcuts to avoid query for recognized numbers.
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case EVENT_EMERGENCY_NUMBER:
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case EVENT_VOICEMAIL_NUMBER:
1582563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case EVENT_ADD_LISTENER:
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case EVENT_END_OF_QUEUE:
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // query was already completed, so just send the reply.
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // passing the original token value back to the caller
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // on top of the event values in arg1.
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Message reply = args.handler.obtainMessage(msg.what);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            reply.obj = args;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            reply.arg1 = msg.arg1;
1672563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            reply.sendToTarget();
1692563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        default:
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1762563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1772563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Asynchronous query handler class for the contact / callerinfo object.
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private CallerInfoAsyncQueryHandler(Context context) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(context.getContentResolver());
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        protected Handler createHandler(Looper looper) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new CallerInfoWorkerHandler(looper);
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Overrides onQueryComplete from AsyncQueryHandler.
1922563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         *
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This method takes into account the state of this class; we construct the CallerInfo
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * object only once for each set of listeners. When the query thread has done its work
1952563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         * and calls this method, we inform the remaining listeners in the queue, until we're
1962563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         * out of listeners.  Once we get the message indicating that we should expect no new
1972563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville         * listeners for this CallerInfo object, we release the AsyncCursorInfo back into the
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * pool.
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
202431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            if (DBG) Log.d(LOG_TAG, "##### onQueryComplete() #####   query complete for token: " + token);
2032563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //get the cookie and notify the listener.
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            CookieWrapper cw = (CookieWrapper) cookie;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cw == null) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Normally, this should never be the case for calls originating
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // from within this code.
2092563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville                // However, if there is any code that calls this method, we should
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // check the parameters to make sure they're viable.
211431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato                if (DBG) Log.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2142563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cw.event == EVENT_END_OF_QUEUE) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                release();
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // check the token and if needed, create the callerinfo object.
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCallerInfo == null) {
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((mQueryContext == null) || (mQueryUri == null)) {
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new QueryPoolException
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ("Bad context or query uri, or CallerInfoAsyncQuery already released.");
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2262563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // adjust the callerInfo data as needed, and only if it was set from the
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // initial query request.
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Change the callerInfo number ONLY if it is an emergency number or the
2302563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville                // voicemail number, and adjust other data (including photoResource)
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // accordingly.
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cw.event == EVENT_EMERGENCY_NUMBER) {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Note we're setting the phone number here (refer to javadoc
2342563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville                    // comments at the top of CallerInfo class).
235e22415817febc8d3229d1774f3b0dfda0fda8f46Nicolas Catania                    mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
23760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania                    mCallerInfo = new CallerInfo().markAsVoiceMail();
2382563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville                } else {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
240431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato                    if (DBG) Log.d(LOG_TAG, "==> Got mCallerInfo: " + mCallerInfo);
241158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
2426fe795ecd35c4d49822d349424fc71b660577dfcHung-ying Tyan                    CallerInfo newCallerInfo = CallerInfo.doSecondaryLookupIfNecessary(
2436fe795ecd35c4d49822d349424fc71b660577dfcHung-ying Tyan                            mQueryContext, cw.number, mCallerInfo);
2446fe795ecd35c4d49822d349424fc71b660577dfcHung-ying Tyan                    if (newCallerInfo != mCallerInfo) {
2456fe795ecd35c4d49822d349424fc71b660577dfcHung-ying Tyan                        mCallerInfo = newCallerInfo;
24623392a84bcb961d3fd50142ec40ce6ac6db89018Jeff Hamilton                        if (DBG) Log.d(LOG_TAG, "#####async contact look up with numeric username"
2476fe795ecd35c4d49822d349424fc71b660577dfcHung-ying Tyan                                + mCallerInfo);
2486fe795ecd35c4d49822d349424fc71b660577dfcHung-ying Tyan                    }
2496fe795ecd35c4d49822d349424fc71b660577dfcHung-ying Tyan
25094202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown                    // Final step: look up the geocoded description.
2512ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                    if (ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION) {
2522ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // Note we do this only if we *don't* have a valid name (i.e. if
2532ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // no contacts matched the phone number of the incoming call),
2542ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // since that's the only case where the incoming-call UI cares
2552ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // about this field.
2562ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        //
2572ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // (TODO: But if we ever want the UI to show the geoDescription
2582ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // even when we *do* match a contact, we'll need to either call
2592ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // updateGeoDescription() unconditionally here, or possibly add a
2602ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // new parameter to CallerInfoAsyncQuery.startQuery() to force
2612ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        // the geoDescription field to be populated.)
2622ef46c65877a7188868cec440fbe93086e011f5bDavid Brown
2632ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        if (TextUtils.isEmpty(mCallerInfo.name)) {
2642ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                            // Actually when no contacts match the incoming phone number,
2652ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                            // the CallerInfo object is totally blank here (i.e. no name
2662ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                            // *or* phoneNumber).  So we need to pass in cw.number as
2672ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                            // a fallback number.
2682ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                            mCallerInfo.updateGeoDescription(mQueryContext, cw.number);
2692ef46c65877a7188868cec440fbe93086e011f5bDavid Brown                        }
27094202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown                    }
27194202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Use the number entered by the user for display.
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!TextUtils.isEmpty(cw.number)) {
2746a3d188f18b5ae278c802c8bbd1e0a44da555cdfBai Tao                        CountryDetector detector = (CountryDetector) mQueryContext.getSystemService(
2756a3d188f18b5ae278c802c8bbd1e0a44da555cdfBai Tao                                Context.COUNTRY_DETECTOR);
2766a3d188f18b5ae278c802c8bbd1e0a44da555cdfBai Tao                        mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number,
27794202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown                                mCallerInfo.normalizedNumber,
2786a3d188f18b5ae278c802c8bbd1e0a44da555cdfBai Tao                                detector.detectCountry().getCountryIso());
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2812563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
282431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato                if (DBG) Log.d(LOG_TAG, "constructing CallerInfo object for token: " + token);
2832563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //notify that we can clean up the queue after this.
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                CookieWrapper endMarker = new CookieWrapper();
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                endMarker.event = EVENT_END_OF_QUEUE;
287158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                startQuery(token, endMarker, null, null, null, null, null);
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2892563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //notify the listener that the query is complete.
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cw.listener != null) {
292431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato                if (DBG) Log.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
29360d45f0f0320801a16db2ad038453c098e98966cNicolas Catania                             " for token: " + token + mCallerInfo);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2982563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Private constructor for factory methods.
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private CallerInfoAsyncQuery() {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3052563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Factory method to start query with a Uri query spec
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3092563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville    public static CallerInfoAsyncQuery startQuery(int token, Context context, Uri contactRef,
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OnQueryCompleteListener listener, Object cookie) {
3112563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        c.allocate(context, contactRef);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
315431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato        if (DBG) Log.d(LOG_TAG, "starting query for URI: " + contactRef + " handler: " + c.toString());
3162563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //create cookieWrapper, start query
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CookieWrapper cw = new CookieWrapper();
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.listener = listener;
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.cookie = cookie;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.event = EVENT_NEW_QUERY;
3222563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
323158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        c.mHandler.startQuery(token, cw, contactRef, null, null, null, null);
3242563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return c;
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3272563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
329158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * Factory method to start the query based on a number.
330158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     *
331158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * Note: if the number contains an "@" character we treat it
332158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * as a SIP address, and look it up directly in the Data table
333158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * rather than using the PhoneLookup table.
334158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * TODO: But eventually we should expose two separate methods, one for
335158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * numbers and one for SIP addresses, and then have
336158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * PhoneUtils.startGetCallerInfo() decide which one to call based on
337158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown     * the phone type of the incoming connection.
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3392563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville    public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            OnQueryCompleteListener listener, Object cookie) {
341158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        if (DBG) {
342431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            Log.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####");
343431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            Log.d(LOG_TAG, "- number: " + /*number*/ "xxxxxxx");
344431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            Log.d(LOG_TAG, "- cookie: " + cookie);
345158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        }
346158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
347158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        // Construct the URI object and query params, and start the query.
348158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
349158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        Uri contactRef;
350158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        String selection;
351158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        String[] selectionArgs;
352158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
353158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        if (PhoneNumberUtils.isUriNumber(number)) {
354158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // "number" is really a SIP address.
355431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            if (DBG) Log.d(LOG_TAG, "  - Treating number as a SIP address: " + /*number*/ "xxxxxxx");
356158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
357158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // We look up SIP addresses directly in the Data table:
358158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            contactRef = Data.CONTENT_URI;
359158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
360158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
361158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            //
362158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // Also note we use "upper(data1)" in the WHERE clause, and
363158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // uppercase the incoming SIP address, in order to do a
364158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // case-insensitive match.
365158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            //
366158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // TODO: need to confirm that the use of upper() doesn't
367158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // prevent us from using the index!  (Linear scan of the whole
368158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // contacts DB can be very slow.)
369158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            //
370158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // TODO: May also need to normalize by adding "sip:" as a
371158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // prefix, if we start storing SIP addresses that way in the
372158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // database.
373158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
374158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            selection = "upper(" + Data.DATA1 + ")=?"
375158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                    + " AND "
376158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                    + Data.MIMETYPE + "='" + SipAddress.CONTENT_ITEM_TYPE + "'";
377158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            selectionArgs = new String[] { number.toUpperCase() };
378158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
379158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        } else {
380158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            // "number" is a regular phone number.  Use the PhoneLookup table:
381158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
382158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            selection = null;
383158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            selectionArgs = null;
384158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        }
385158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown
386158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        if (DBG) {
387431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            Log.d(LOG_TAG, "==> contactRef: " + sanitizeUriToString(contactRef));
388431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            Log.d(LOG_TAG, "==> selection: " + selection);
389158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            if (selectionArgs != null) {
390158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                for (int i = 0; i < selectionArgs.length; i++) {
391431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato                    Log.d(LOG_TAG, "==> selectionArgs[" + i + "]: " + selectionArgs[i]);
392158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                }
393158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown            }
394158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        }
3952563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        c.allocate(context, contactRef);
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //create cookieWrapper, start query
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CookieWrapper cw = new CookieWrapper();
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.listener = listener;
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.cookie = cookie;
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.number = number;
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4052563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville        // check to see if these are recognized numbers, and use shortcuts if we can.
4066b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia        if (PhoneNumberUtils.isLocalEmergencyNumber(number, context)) {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cw.event = EVENT_EMERGENCY_NUMBER;
40860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
40960d45f0f0320801a16db2ad038453c098e98966cNicolas Catania            cw.event = EVENT_VOICEMAIL_NUMBER;
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
41160d45f0f0320801a16db2ad038453c098e98966cNicolas Catania            cw.event = EVENT_NEW_QUERY;
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
414158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        c.mHandler.startQuery(token,
415158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                              cw,  // cookie
416158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                              contactRef,  // uri
417158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                              null,  // projection
418158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                              selection,  // selection
419158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                              selectionArgs,  // selectionArgs
420158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown                              null);  // orderBy
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return c;
422158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown    }
4232563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Method to add listeners to a currently running query
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addQueryListener(int token, OnQueryCompleteListener listener, Object cookie) {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
429431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato        if (DBG) Log.d(LOG_TAG, "adding listener to query: " + sanitizeUriToString(mHandler.mQueryUri) +
430a42880749b368e60caee77dd682d434e48ca96bdWink Saville                " handler: " + mHandler.toString());
4312563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //create cookieWrapper, add query request to end of queue.
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CookieWrapper cw = new CookieWrapper();
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.listener = listener;
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.cookie = cookie;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cw.event = EVENT_ADD_LISTENER;
4372563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
438158d390f533f927175c5a5a3e5a1a8bc07ca1facDavid Brown        mHandler.startQuery(token, cw, null, null, null, null, null);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Method to create a new CallerInfoAsyncQueryHandler object, ensuring correct
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * state of context and uri.
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
44594202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown    private void allocate(Context context, Uri contactRef) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((context == null) || (contactRef == null)){
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new QueryPoolException("Bad context or query uri.");
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler = new CallerInfoAsyncQueryHandler(context);
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.mQueryContext = context;
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.mQueryUri = contactRef;
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Releases the relevant data.
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
45794202fe1217b9f63e1f5c314379a9f0021e96ea8David Brown    private void release() {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.mQueryContext = null;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.mQueryUri = null;
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.mCallerInfo = null;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler = null;
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4632563a3ac05dd3cf8a07203ae682c243f2e793137Wink Saville
464a42880749b368e60caee77dd682d434e48ca96bdWink Saville    private static String sanitizeUriToString(Uri uri) {
465a42880749b368e60caee77dd682d434e48ca96bdWink Saville        if (uri != null) {
466a42880749b368e60caee77dd682d434e48ca96bdWink Saville            String uriString = uri.toString();
467a42880749b368e60caee77dd682d434e48ca96bdWink Saville            int indexOfLastSlash = uriString.lastIndexOf('/');
468a42880749b368e60caee77dd682d434e48ca96bdWink Saville            if (indexOfLastSlash > 0) {
469a42880749b368e60caee77dd682d434e48ca96bdWink Saville                return uriString.substring(0, indexOfLastSlash) + "/xxxxxxx";
470a42880749b368e60caee77dd682d434e48ca96bdWink Saville            } else {
471a42880749b368e60caee77dd682d434e48ca96bdWink Saville                return uriString;
472a42880749b368e60caee77dd682d434e48ca96bdWink Saville            }
473a42880749b368e60caee77dd682d434e48ca96bdWink Saville        } else {
474a42880749b368e60caee77dd682d434e48ca96bdWink Saville            return "";
475a42880749b368e60caee77dd682d434e48ca96bdWink Saville        }
476a42880749b368e60caee77dd682d434e48ca96bdWink Saville    }
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
478