blob: f38b34e85d89dac92377f990fabb68047828d2fd [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Hall Liud2f962a2019-10-31 15:17:58 -070017package android.telecom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Makoto Onuki5692dcc2014-07-17 14:57:04 -070019import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.AsyncQueryHandler;
Makoto Onuki5692dcc2014-07-17 14:57:04 -070021import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
Makoto Onuki5692dcc2014-07-17 14:57:04 -070023import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.database.Cursor;
25import android.database.SQLException;
26import android.net.Uri;
27import android.os.Handler;
28import android.os.Looper;
29import android.os.Message;
Ceci Wu3b90d482016-08-25 14:48:19 +080030import android.os.SystemClock;
Makoto Onuki5692dcc2014-07-17 14:57:04 -070031import android.os.UserHandle;
32import android.os.UserManager;
Dmitri Plotnikov3c513ed2009-08-19 15:56:30 -070033import android.provider.ContactsContract.PhoneLookup;
Hall Liud2f962a2019-10-31 15:17:58 -070034import android.telephony.PhoneNumberUtils;
35import android.telephony.SubscriptionManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.text.TextUtils;
Ceci Wu3b90d482016-08-25 14:48:19 +080037import java.util.ArrayList;
38import java.util.List;
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040/**
David Brown94202fe2011-06-10 16:24:05 -070041 * Helper class to make it easier to run asynchronous caller-id lookup queries.
42 * @see CallerInfo
43 *
44 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046public class CallerInfoAsyncQuery {
Joe Onorato431bb222010-10-18 19:13:23 -040047 private static final boolean DBG = false;
Nicolas Cataniae2241582009-09-14 19:01:43 -070048 private static final String LOG_TAG = "CallerInfoAsyncQuery";
Wink Saville2563a3a2009-06-09 10:30:03 -070049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 private static final int EVENT_NEW_QUERY = 1;
51 private static final int EVENT_ADD_LISTENER = 2;
52 private static final int EVENT_END_OF_QUEUE = 3;
53 private static final int EVENT_EMERGENCY_NUMBER = 4;
54 private static final int EVENT_VOICEMAIL_NUMBER = 5;
Ceci Wu3b90d482016-08-25 14:48:19 +080055 private static final int EVENT_GET_GEO_DESCRIPTION = 6;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
57 private CallerInfoAsyncQueryHandler mHandler;
58
David Brown2ef46c62011-06-20 12:53:12 -070059 // If the CallerInfo query finds no contacts, should we use the
60 // PhoneNumberOfflineGeocoder to look up a "geo description"?
61 // (TODO: This could become a flag in config.xml if it ever needs to be
62 // configured on a per-product basis.)
David Browncec25c42011-06-23 14:17:27 -070063 private static final boolean ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION = true;
David Brown2ef46c62011-06-20 12:53:12 -070064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 /**
66 * Interface for a CallerInfoAsyncQueryHandler result return.
67 */
68 public interface OnQueryCompleteListener {
69 /**
Wink Saville2563a3a2009-06-09 10:30:03 -070070 * Called when the query is complete.
71 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 public void onQueryComplete(int token, Object cookie, CallerInfo ci);
73 }
Wink Saville2563a3a2009-06-09 10:30:03 -070074
75
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 /**
77 * Wrap the cookie from the WorkerArgs with additional information needed by our
Wink Saville2563a3a2009-06-09 10:30:03 -070078 * classes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 */
80 private static final class CookieWrapper {
81 public OnQueryCompleteListener listener;
82 public Object cookie;
83 public int event;
84 public String number;
Ceci Wu3b90d482016-08-25 14:48:19 +080085 public String geoDescription;
Wink Savillefb40dd42014-06-12 17:02:31 -070086
Wink Saville63f03dd2014-10-23 10:44:45 -070087 public int subId;
Wink Saville2563a3a2009-06-09 10:30:03 -070088 }
89
90
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 /**
92 * Simple exception used to communicate problems with the query pool.
93 */
94 public static class QueryPoolException extends SQLException {
95 public QueryPoolException(String error) {
96 super(error);
97 }
98 }
Wink Saville2563a3a2009-06-09 10:30:03 -070099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 /**
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700101 * @return {@link ContentResolver} for the "current" user.
102 */
103 static ContentResolver getCurrentProfileContentResolver(Context context) {
104
Hall Liud2f962a2019-10-31 15:17:58 -0700105 if (DBG) Log.d(LOG_TAG, "Trying to get current content resolver...");
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700106
107 final int currentUser = ActivityManager.getCurrentUser();
108 final int myUser = UserManager.get(context).getUserHandle();
109
Hall Liud2f962a2019-10-31 15:17:58 -0700110 if (DBG) Log.d(LOG_TAG, "myUser=" + myUser + "currentUser=" + currentUser);
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700111
112 if (myUser != currentUser) {
113 final Context otherContext;
114 try {
115 otherContext = context.createPackageContextAsUser(context.getPackageName(),
Chen Xue5ea21a2019-08-05 11:39:13 -0700116 /* flags =*/ 0, UserHandle.of(currentUser));
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700117 return otherContext.getContentResolver();
118 } catch (NameNotFoundException e) {
Hall Liud2f962a2019-10-31 15:17:58 -0700119 Log.e(LOG_TAG, e, "Can't find self package");
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700120 // Fall back to the primary user.
121 }
122 }
123 return context.getContentResolver();
124 }
125
126 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 * Our own implementation of the AsyncQueryHandler.
128 */
129 private class CallerInfoAsyncQueryHandler extends AsyncQueryHandler {
Wink Saville2563a3a2009-06-09 10:30:03 -0700130
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700131 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 * The information relevant to each CallerInfo query. Each query may have multiple
133 * listeners, so each AsyncCursorInfo is associated with 2 or more CookieWrapper
134 * objects in the queue (one with a new query event, and one with a end event, with
135 * 0 or more additional listeners in between).
136 */
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700137
138 /**
139 * Context passed by the caller.
140 *
141 * NOTE: The actual context we use for query may *not* be this context; since we query
142 * against the "current" contacts provider. In the constructor we pass the "current"
143 * context resolver (obtained via {@link #getCurrentProfileContentResolver) and pass it
144 * to the super class.
145 */
146 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 private Uri mQueryUri;
148 private CallerInfo mCallerInfo;
Ceci Wu3b90d482016-08-25 14:48:19 +0800149 private List<Runnable> mPendingListenerCallbacks = new ArrayList<>();
Wink Saville2563a3a2009-06-09 10:30:03 -0700150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 /**
152 * Our own query worker thread.
Wink Saville2563a3a2009-06-09 10:30:03 -0700153 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 * This thread handles the messages enqueued in the looper. The normal sequence
155 * of events is that a new query shows up in the looper queue, followed by 0 or
156 * more add listener requests, and then an end request. Of course, these requests
157 * can be interlaced with requests from other tokens, but is irrelevant to this
158 * handler since the handler has no state.
Wink Saville2563a3a2009-06-09 10:30:03 -0700159 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 * Note that we depend on the queue to keep things in order; in other words, the
Wink Saville2563a3a2009-06-09 10:30:03 -0700161 * looper queue must be FIFO with respect to input from the synchronous startQuery
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 * calls and output to this handleMessage call.
Wink Saville2563a3a2009-06-09 10:30:03 -0700163 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 * This use of the queue is required because CallerInfo objects may be accessed
165 * multiple times before the query is complete. All accesses (listeners) must be
166 * queued up and informed in order when the query is complete.
167 */
168 protected class CallerInfoWorkerHandler extends WorkerHandler {
169 public CallerInfoWorkerHandler(Looper looper) {
170 super(looper);
171 }
172
173 @Override
174 public void handleMessage(Message msg) {
175 WorkerArgs args = (WorkerArgs) msg.obj;
176 CookieWrapper cw = (CookieWrapper) args.cookie;
Wink Saville2563a3a2009-06-09 10:30:03 -0700177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 if (cw == null) {
179 // Normally, this should never be the case for calls originating
180 // from within this code.
Wink Saville2563a3a2009-06-09 10:30:03 -0700181 // However, if there is any code that this Handler calls (such as in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 // super.handleMessage) that DOES place unexpected messages on the
183 // queue, then we need pass these messages on.
Hall Liud2f962a2019-10-31 15:17:58 -0700184 Log.i(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 " ignored by CallerInfoWorkerHandler, passing onto parent.");
Wink Saville2563a3a2009-06-09 10:30:03 -0700186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 super.handleMessage(msg);
188 } else {
Wink Saville2563a3a2009-06-09 10:30:03 -0700189
Hall Liud2f962a2019-10-31 15:17:58 -0700190 Log.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
Wink Savillea4288072010-10-12 12:36:38 -0700191 " command: " + msg.what + " query URI: " + sanitizeUriToString(args.uri));
Wink Saville2563a3a2009-06-09 10:30:03 -0700192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 switch (cw.event) {
194 case EVENT_NEW_QUERY:
195 //start the sql command.
196 super.handleMessage(msg);
197 break;
198
199 // shortcuts to avoid query for recognized numbers.
200 case EVENT_EMERGENCY_NUMBER:
201 case EVENT_VOICEMAIL_NUMBER:
Wink Saville2563a3a2009-06-09 10:30:03 -0700202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 case EVENT_ADD_LISTENER:
204 case EVENT_END_OF_QUEUE:
205 // query was already completed, so just send the reply.
206 // passing the original token value back to the caller
207 // on top of the event values in arg1.
208 Message reply = args.handler.obtainMessage(msg.what);
209 reply.obj = args;
210 reply.arg1 = msg.arg1;
Wink Saville2563a3a2009-06-09 10:30:03 -0700211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 reply.sendToTarget();
Wink Saville2563a3a2009-06-09 10:30:03 -0700213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 break;
Ceci Wu3b90d482016-08-25 14:48:19 +0800215 case EVENT_GET_GEO_DESCRIPTION:
216 handleGeoDescription(msg);
217 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 default:
219 }
220 }
221 }
Ceci Wu3b90d482016-08-25 14:48:19 +0800222
223 private void handleGeoDescription(Message msg) {
224 WorkerArgs args = (WorkerArgs) msg.obj;
225 CookieWrapper cw = (CookieWrapper) args.cookie;
226 if (!TextUtils.isEmpty(cw.number) && cw.cookie != null && mContext != null) {
227 final long startTimeMillis = SystemClock.elapsedRealtime();
228 cw.geoDescription = CallerInfo.getGeoDescription(mContext, cw.number);
229 final long duration = SystemClock.elapsedRealtime() - startTimeMillis;
230 if (duration > 500) {
Hall Liud2f962a2019-10-31 15:17:58 -0700231 if (DBG) Log.d(LOG_TAG, "[handleGeoDescription]" +
Ceci Wu3b90d482016-08-25 14:48:19 +0800232 "Spends long time to retrieve Geo description: " + duration);
233 }
234 }
235 Message reply = args.handler.obtainMessage(msg.what);
236 reply.obj = args;
237 reply.arg1 = msg.arg1;
238 reply.sendToTarget();
239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700241
242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 /**
244 * Asynchronous query handler class for the contact / callerinfo object.
245 */
246 private CallerInfoAsyncQueryHandler(Context context) {
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700247 super(getCurrentProfileContentResolver(context));
248 mContext = context;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 }
250
251 @Override
252 protected Handler createHandler(Looper looper) {
253 return new CallerInfoWorkerHandler(looper);
254 }
255
256 /**
257 * Overrides onQueryComplete from AsyncQueryHandler.
Wink Saville2563a3a2009-06-09 10:30:03 -0700258 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 * This method takes into account the state of this class; we construct the CallerInfo
260 * object only once for each set of listeners. When the query thread has done its work
Wink Saville2563a3a2009-06-09 10:30:03 -0700261 * and calls this method, we inform the remaining listeners in the queue, until we're
262 * out of listeners. Once we get the message indicating that we should expect no new
263 * listeners for this CallerInfo object, we release the AsyncCursorInfo back into the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 * pool.
265 */
266 @Override
267 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
Hall Liud2f962a2019-10-31 15:17:58 -0700268 Log.d(LOG_TAG, "##### onQueryComplete() ##### query complete for token: " + token);
Wink Saville2563a3a2009-06-09 10:30:03 -0700269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 //get the cookie and notify the listener.
271 CookieWrapper cw = (CookieWrapper) cookie;
272 if (cw == null) {
273 // Normally, this should never be the case for calls originating
274 // from within this code.
Wink Saville2563a3a2009-06-09 10:30:03 -0700275 // However, if there is any code that calls this method, we should
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // check the parameters to make sure they're viable.
Hall Liud2f962a2019-10-31 15:17:58 -0700277 Log.i(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
Wink Savillefb40dd42014-06-12 17:02:31 -0700278 if (cursor != null) {
279 cursor.close();
280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 return;
282 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 if (cw.event == EVENT_END_OF_QUEUE) {
Ceci Wu3b90d482016-08-25 14:48:19 +0800285 for (Runnable r : mPendingListenerCallbacks) {
286 r.run();
287 }
288 mPendingListenerCallbacks.clear();
289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 release();
Wink Savillefb40dd42014-06-12 17:02:31 -0700291 if (cursor != null) {
292 cursor.close();
293 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 return;
295 }
296
Ceci Wu3b90d482016-08-25 14:48:19 +0800297 // If the cw.event == EVENT_GET_GEO_DESCRIPTION, means it would not be the 1st
298 // time entering the onQueryComplete(), mCallerInfo should not be null.
299 if (cw.event == EVENT_GET_GEO_DESCRIPTION) {
300 if (mCallerInfo != null) {
301 mCallerInfo.geoDescription = cw.geoDescription;
302 }
303 // notify that we can clean up the queue after this.
304 CookieWrapper endMarker = new CookieWrapper();
305 endMarker.event = EVENT_END_OF_QUEUE;
306 startQuery(token, endMarker, null, null, null, null, null);
307 }
308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 // check the token and if needed, create the callerinfo object.
310 if (mCallerInfo == null) {
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700311 if ((mContext == null) || (mQueryUri == null)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 throw new QueryPoolException
313 ("Bad context or query uri, or CallerInfoAsyncQuery already released.");
314 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 // adjust the callerInfo data as needed, and only if it was set from the
317 // initial query request.
318 // Change the callerInfo number ONLY if it is an emergency number or the
Wink Saville2563a3a2009-06-09 10:30:03 -0700319 // voicemail number, and adjust other data (including photoResource)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 // accordingly.
321 if (cw.event == EVENT_EMERGENCY_NUMBER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 // Note we're setting the phone number here (refer to javadoc
Wink Saville2563a3a2009-06-09 10:30:03 -0700323 // comments at the top of CallerInfo class).
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700324 mCallerInfo = new CallerInfo().markAsEmergency(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 } else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
Hall Liud2f962a2019-10-31 15:17:58 -0700326 mCallerInfo = new CallerInfo().markAsVoiceMail(mContext, cw.subId);
Wink Saville2563a3a2009-06-09 10:30:03 -0700327 } else {
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700328 mCallerInfo = CallerInfo.getCallerInfo(mContext, mQueryUri, cursor);
Hall Liud2f962a2019-10-31 15:17:58 -0700329 if (DBG) Log.d(LOG_TAG, "==> Got mCallerInfo: " + mCallerInfo);
David Brown158d3902010-09-27 16:29:14 -0700330
Hung-ying Tyan6fe795e2010-10-20 11:12:02 +0800331 CallerInfo newCallerInfo = CallerInfo.doSecondaryLookupIfNecessary(
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700332 mContext, cw.number, mCallerInfo);
Hung-ying Tyan6fe795e2010-10-20 11:12:02 +0800333 if (newCallerInfo != mCallerInfo) {
334 mCallerInfo = newCallerInfo;
Hall Liud2f962a2019-10-31 15:17:58 -0700335 if (DBG) Log.d(LOG_TAG, "#####async contact look up with numeric username"
Hung-ying Tyan6fe795e2010-10-20 11:12:02 +0800336 + mCallerInfo);
337 }
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 // Use the number entered by the user for display.
340 if (!TextUtils.isEmpty(cw.number)) {
Chen Xufba9ca42019-09-07 18:56:17 -0700341 mCallerInfo.setPhoneNumber(PhoneNumberUtils.formatNumber(cw.number,
David Brown94202fe2011-06-10 16:24:05 -0700342 mCallerInfo.normalizedNumber,
Chen Xufba9ca42019-09-07 18:56:17 -0700343 CallerInfo.getCurrentCountryIso(mContext)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 }
Ceci Wu3b90d482016-08-25 14:48:19 +0800345
346 // This condition refer to the google default code for geo.
347 // If the number exists in Contacts, the CallCard would never show
348 // the geo description, so it would be unnecessary to query it.
349 if (ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION) {
Chen Xufba9ca42019-09-07 18:56:17 -0700350 if (TextUtils.isEmpty(mCallerInfo.getName())) {
Hall Liud2f962a2019-10-31 15:17:58 -0700351 if (DBG) Log.d(LOG_TAG, "start querying geo description");
Ceci Wu3b90d482016-08-25 14:48:19 +0800352 cw.event = EVENT_GET_GEO_DESCRIPTION;
353 startQuery(token, cw, null, null, null, null, null);
354 return;
355 }
356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700358
Hall Liud2f962a2019-10-31 15:17:58 -0700359 if (DBG) Log.d(LOG_TAG, "constructing CallerInfo object for token: " + token);
Wink Saville2563a3a2009-06-09 10:30:03 -0700360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 //notify that we can clean up the queue after this.
362 CookieWrapper endMarker = new CookieWrapper();
363 endMarker.event = EVENT_END_OF_QUEUE;
David Brown158d3902010-09-27 16:29:14 -0700364 startQuery(token, endMarker, null, null, null, null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 //notify the listener that the query is complete.
368 if (cw.listener != null) {
Ceci Wu3b90d482016-08-25 14:48:19 +0800369 mPendingListenerCallbacks.add(new Runnable() {
370 @Override
371 public void run() {
Hall Liud2f962a2019-10-31 15:17:58 -0700372 if (DBG) Log.d(LOG_TAG, "notifying listener: "
Ceci Wu3b90d482016-08-25 14:48:19 +0800373 + cw.listener.getClass().toString() + " for token: " + token
374 + mCallerInfo);
375 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
376 }
377 });
Hall Liu4c019102016-10-05 16:56:17 -0700378 } else {
Hall Liud2f962a2019-10-31 15:17:58 -0700379 Log.w(LOG_TAG, "There is no listener to notify for this query.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
Wink Savillefb40dd42014-06-12 17:02:31 -0700381
382 if (cursor != null) {
383 cursor.close();
384 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 }
386 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 /**
389 * Private constructor for factory methods.
390 */
391 private CallerInfoAsyncQuery() {
392 }
393
Wink Saville2563a3a2009-06-09 10:30:03 -0700394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 /**
396 * Factory method to start query with a Uri query spec
397 */
Wink Saville2563a3a2009-06-09 10:30:03 -0700398 public static CallerInfoAsyncQuery startQuery(int token, Context context, Uri contactRef,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 OnQueryCompleteListener listener, Object cookie) {
Wink Saville2563a3a2009-06-09 10:30:03 -0700400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
402 c.allocate(context, contactRef);
403
Hall Liud2f962a2019-10-31 15:17:58 -0700404 if (DBG) Log.d(LOG_TAG, "starting query for URI: " + contactRef + " handler: " + c.toString());
Wink Saville2563a3a2009-06-09 10:30:03 -0700405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 //create cookieWrapper, start query
407 CookieWrapper cw = new CookieWrapper();
408 cw.listener = listener;
409 cw.cookie = cookie;
410 cw.event = EVENT_NEW_QUERY;
Wink Saville2563a3a2009-06-09 10:30:03 -0700411
David Brown158d3902010-09-27 16:29:14 -0700412 c.mHandler.startQuery(token, cw, contactRef, null, null, null, null);
Wink Saville2563a3a2009-06-09 10:30:03 -0700413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 return c;
415 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 /**
David Brown158d3902010-09-27 16:29:14 -0700418 * Factory method to start the query based on a number.
419 *
420 * Note: if the number contains an "@" character we treat it
421 * as a SIP address, and look it up directly in the Data table
422 * rather than using the PhoneLookup table.
423 * TODO: But eventually we should expose two separate methods, one for
424 * numbers and one for SIP addresses, and then have
425 * PhoneUtils.startGetCallerInfo() decide which one to call based on
426 * the phone type of the incoming connection.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 */
Wink Saville2563a3a2009-06-09 10:30:03 -0700428 public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 OnQueryCompleteListener listener, Object cookie) {
Wink Savillefb40dd42014-06-12 17:02:31 -0700430
Shishir Agrawal7ea3e8b2016-01-25 13:03:07 -0800431 int subId = SubscriptionManager.getDefaultSubscriptionId();
Wink Savillefb40dd42014-06-12 17:02:31 -0700432 return startQuery(token, context, number, listener, cookie, subId);
433 }
434
435 /**
436 * Factory method to start the query based on a number with specific subscription.
437 *
438 * Note: if the number contains an "@" character we treat it
439 * as a SIP address, and look it up directly in the Data table
440 * rather than using the PhoneLookup table.
441 * TODO: But eventually we should expose two separate methods, one for
442 * numbers and one for SIP addresses, and then have
443 * PhoneUtils.startGetCallerInfo() decide which one to call based on
444 * the phone type of the incoming connection.
445 */
446 public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
Wink Saville63f03dd2014-10-23 10:44:45 -0700447 OnQueryCompleteListener listener, Object cookie, int subId) {
Wink Savillefb40dd42014-06-12 17:02:31 -0700448
David Brown158d3902010-09-27 16:29:14 -0700449 if (DBG) {
Hall Liud2f962a2019-10-31 15:17:58 -0700450 Log.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####");
451 Log.d(LOG_TAG, "- number: " + /*number*/ "xxxxxxx");
452 Log.d(LOG_TAG, "- cookie: " + cookie);
David Brown158d3902010-09-27 16:29:14 -0700453 }
454
455 // Construct the URI object and query params, and start the query.
456
Makoto Onukia2295e62014-07-10 15:32:16 -0700457 final Uri contactRef = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
458 .appendPath(number)
459 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS,
460 String.valueOf(PhoneNumberUtils.isUriNumber(number)))
461 .build();
David Brown158d3902010-09-27 16:29:14 -0700462
463 if (DBG) {
Hall Liud2f962a2019-10-31 15:17:58 -0700464 Log.d(LOG_TAG, "==> contactRef: " + sanitizeUriToString(contactRef));
David Brown158d3902010-09-27 16:29:14 -0700465 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
468 c.allocate(context, contactRef);
469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 //create cookieWrapper, start query
471 CookieWrapper cw = new CookieWrapper();
472 cw.listener = listener;
473 cw.cookie = cookie;
474 cw.number = number;
Wink Savillefb40dd42014-06-12 17:02:31 -0700475 cw.subId = subId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476
Wink Saville2563a3a2009-06-09 10:30:03 -0700477 // check to see if these are recognized numbers, and use shortcuts if we can.
Yorke Lee282129f2014-06-05 08:41:47 -0700478 if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 cw.event = EVENT_EMERGENCY_NUMBER;
Jordan Liu360d5672016-11-09 13:23:42 -0800480 } else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) {
Nicolas Catania60d45f02009-09-15 18:32:02 -0700481 cw.event = EVENT_VOICEMAIL_NUMBER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 } else {
Nicolas Catania60d45f02009-09-15 18:32:02 -0700483 cw.event = EVENT_NEW_QUERY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 }
485
David Brown158d3902010-09-27 16:29:14 -0700486 c.mHandler.startQuery(token,
487 cw, // cookie
488 contactRef, // uri
489 null, // projection
Makoto Onukia2295e62014-07-10 15:32:16 -0700490 null, // selection
491 null, // selectionArgs
David Brown158d3902010-09-27 16:29:14 -0700492 null); // orderBy
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 return c;
David Brown158d3902010-09-27 16:29:14 -0700494 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 /**
497 * Method to add listeners to a currently running query
498 */
499 public void addQueryListener(int token, OnQueryCompleteListener listener, Object cookie) {
500
Hall Liud2f962a2019-10-31 15:17:58 -0700501 if (DBG) Log.d(LOG_TAG, "adding listener to query: "
502 + sanitizeUriToString(mHandler.mQueryUri) + " handler: " + mHandler.toString());
Wink Saville2563a3a2009-06-09 10:30:03 -0700503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 //create cookieWrapper, add query request to end of queue.
505 CookieWrapper cw = new CookieWrapper();
506 cw.listener = listener;
507 cw.cookie = cookie;
508 cw.event = EVENT_ADD_LISTENER;
Wink Saville2563a3a2009-06-09 10:30:03 -0700509
David Brown158d3902010-09-27 16:29:14 -0700510 mHandler.startQuery(token, cw, null, null, null, null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 }
512
513 /**
514 * Method to create a new CallerInfoAsyncQueryHandler object, ensuring correct
515 * state of context and uri.
516 */
David Brown94202fe2011-06-10 16:24:05 -0700517 private void allocate(Context context, Uri contactRef) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 if ((context == null) || (contactRef == null)){
519 throw new QueryPoolException("Bad context or query uri.");
520 }
521 mHandler = new CallerInfoAsyncQueryHandler(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 mHandler.mQueryUri = contactRef;
523 }
524
525 /**
526 * Releases the relevant data.
527 */
David Brown94202fe2011-06-10 16:24:05 -0700528 private void release() {
Makoto Onuki5692dcc2014-07-17 14:57:04 -0700529 mHandler.mContext = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 mHandler.mQueryUri = null;
531 mHandler.mCallerInfo = null;
532 mHandler = null;
533 }
Wink Saville2563a3a2009-06-09 10:30:03 -0700534
Wink Savillea4288072010-10-12 12:36:38 -0700535 private static String sanitizeUriToString(Uri uri) {
536 if (uri != null) {
537 String uriString = uri.toString();
538 int indexOfLastSlash = uriString.lastIndexOf('/');
539 if (indexOfLastSlash > 0) {
540 return uriString.substring(0, indexOfLastSlash) + "/xxxxxxx";
541 } else {
542 return uriString;
543 }
544 } else {
545 return "";
546 }
547 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548}