Merge "Query geo description in worker thread to prevent ANR"
This commit is contained in:
@@ -576,7 +576,7 @@ public class CallerInfo {
|
|||||||
* @return a geographical description string for the specified number.
|
* @return a geographical description string for the specified number.
|
||||||
* @see com.android.i18n.phonenumbers.PhoneNumberOfflineGeocoder
|
* @see com.android.i18n.phonenumbers.PhoneNumberOfflineGeocoder
|
||||||
*/
|
*/
|
||||||
private static String getGeoDescription(Context context, String number) {
|
public static String getGeoDescription(Context context, String number) {
|
||||||
if (VDBG) Rlog.v(TAG, "getGeoDescription('" + number + "')...");
|
if (VDBG) Rlog.v(TAG, "getGeoDescription('" + number + "')...");
|
||||||
|
|
||||||
if (TextUtils.isEmpty(number)) {
|
if (TextUtils.isEmpty(number)) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import android.net.Uri;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.provider.ContactsContract.PhoneLookup;
|
import android.provider.ContactsContract.PhoneLookup;
|
||||||
@@ -35,6 +36,9 @@ import android.text.TextUtils;
|
|||||||
import android.telephony.Rlog;
|
import android.telephony.Rlog;
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to make it easier to run asynchronous caller-id lookup queries.
|
* Helper class to make it easier to run asynchronous caller-id lookup queries.
|
||||||
* @see CallerInfo
|
* @see CallerInfo
|
||||||
@@ -50,6 +54,7 @@ public class CallerInfoAsyncQuery {
|
|||||||
private static final int EVENT_END_OF_QUEUE = 3;
|
private static final int EVENT_END_OF_QUEUE = 3;
|
||||||
private static final int EVENT_EMERGENCY_NUMBER = 4;
|
private static final int EVENT_EMERGENCY_NUMBER = 4;
|
||||||
private static final int EVENT_VOICEMAIL_NUMBER = 5;
|
private static final int EVENT_VOICEMAIL_NUMBER = 5;
|
||||||
|
private static final int EVENT_GET_GEO_DESCRIPTION = 6;
|
||||||
|
|
||||||
private CallerInfoAsyncQueryHandler mHandler;
|
private CallerInfoAsyncQueryHandler mHandler;
|
||||||
|
|
||||||
@@ -79,6 +84,7 @@ public class CallerInfoAsyncQuery {
|
|||||||
public Object cookie;
|
public Object cookie;
|
||||||
public int event;
|
public int event;
|
||||||
public String number;
|
public String number;
|
||||||
|
public String geoDescription;
|
||||||
|
|
||||||
public int subId;
|
public int subId;
|
||||||
}
|
}
|
||||||
@@ -142,6 +148,7 @@ public class CallerInfoAsyncQuery {
|
|||||||
private Context mContext;
|
private Context mContext;
|
||||||
private Uri mQueryUri;
|
private Uri mQueryUri;
|
||||||
private CallerInfo mCallerInfo;
|
private CallerInfo mCallerInfo;
|
||||||
|
private List<Runnable> mPendingListenerCallbacks = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our own query worker thread.
|
* Our own query worker thread.
|
||||||
@@ -206,11 +213,32 @@ public class CallerInfoAsyncQuery {
|
|||||||
|
|
||||||
reply.sendToTarget();
|
reply.sendToTarget();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case EVENT_GET_GEO_DESCRIPTION:
|
||||||
|
handleGeoDescription(msg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleGeoDescription(Message msg) {
|
||||||
|
WorkerArgs args = (WorkerArgs) msg.obj;
|
||||||
|
CookieWrapper cw = (CookieWrapper) args.cookie;
|
||||||
|
if (!TextUtils.isEmpty(cw.number) && cw.cookie != null && mContext != null) {
|
||||||
|
final long startTimeMillis = SystemClock.elapsedRealtime();
|
||||||
|
cw.geoDescription = CallerInfo.getGeoDescription(mContext, cw.number);
|
||||||
|
final long duration = SystemClock.elapsedRealtime() - startTimeMillis;
|
||||||
|
if (duration > 500) {
|
||||||
|
if (DBG) Rlog.d(LOG_TAG, "[handleGeoDescription]" +
|
||||||
|
"Spends long time to retrieve Geo description: " + duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message reply = args.handler.obtainMessage(msg.what);
|
||||||
|
reply.obj = args;
|
||||||
|
reply.arg1 = msg.arg1;
|
||||||
|
reply.sendToTarget();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -256,6 +284,11 @@ public class CallerInfoAsyncQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cw.event == EVENT_END_OF_QUEUE) {
|
if (cw.event == EVENT_END_OF_QUEUE) {
|
||||||
|
for (Runnable r : mPendingListenerCallbacks) {
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
mPendingListenerCallbacks.clear();
|
||||||
|
|
||||||
release();
|
release();
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
@@ -263,6 +296,18 @@ public class CallerInfoAsyncQuery {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the cw.event == EVENT_GET_GEO_DESCRIPTION, means it would not be the 1st
|
||||||
|
// time entering the onQueryComplete(), mCallerInfo should not be null.
|
||||||
|
if (cw.event == EVENT_GET_GEO_DESCRIPTION) {
|
||||||
|
if (mCallerInfo != null) {
|
||||||
|
mCallerInfo.geoDescription = cw.geoDescription;
|
||||||
|
}
|
||||||
|
// notify that we can clean up the queue after this.
|
||||||
|
CookieWrapper endMarker = new CookieWrapper();
|
||||||
|
endMarker.event = EVENT_END_OF_QUEUE;
|
||||||
|
startQuery(token, endMarker, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
// check the token and if needed, create the callerinfo object.
|
// check the token and if needed, create the callerinfo object.
|
||||||
if (mCallerInfo == null) {
|
if (mCallerInfo == null) {
|
||||||
if ((mContext == null) || (mQueryUri == null)) {
|
if ((mContext == null) || (mQueryUri == null)) {
|
||||||
@@ -293,34 +338,24 @@ public class CallerInfoAsyncQuery {
|
|||||||
+ mCallerInfo);
|
+ mCallerInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final step: look up the geocoded description.
|
|
||||||
if (ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION) {
|
|
||||||
// Note we do this only if we *don't* have a valid name (i.e. if
|
|
||||||
// no contacts matched the phone number of the incoming call),
|
|
||||||
// since that's the only case where the incoming-call UI cares
|
|
||||||
// about this field.
|
|
||||||
//
|
|
||||||
// (TODO: But if we ever want the UI to show the geoDescription
|
|
||||||
// even when we *do* match a contact, we'll need to either call
|
|
||||||
// updateGeoDescription() unconditionally here, or possibly add a
|
|
||||||
// new parameter to CallerInfoAsyncQuery.startQuery() to force
|
|
||||||
// the geoDescription field to be populated.)
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(mCallerInfo.name)) {
|
|
||||||
// Actually when no contacts match the incoming phone number,
|
|
||||||
// the CallerInfo object is totally blank here (i.e. no name
|
|
||||||
// *or* phoneNumber). So we need to pass in cw.number as
|
|
||||||
// a fallback number.
|
|
||||||
mCallerInfo.updateGeoDescription(mContext, cw.number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the number entered by the user for display.
|
// Use the number entered by the user for display.
|
||||||
if (!TextUtils.isEmpty(cw.number)) {
|
if (!TextUtils.isEmpty(cw.number)) {
|
||||||
mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number,
|
mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number,
|
||||||
mCallerInfo.normalizedNumber,
|
mCallerInfo.normalizedNumber,
|
||||||
CallerInfo.getCurrentCountryIso(mContext));
|
CallerInfo.getCurrentCountryIso(mContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This condition refer to the google default code for geo.
|
||||||
|
// If the number exists in Contacts, the CallCard would never show
|
||||||
|
// the geo description, so it would be unnecessary to query it.
|
||||||
|
if (ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION) {
|
||||||
|
if (TextUtils.isEmpty(mCallerInfo.name)) {
|
||||||
|
if (DBG) Rlog.d(LOG_TAG, "start querying geo description");
|
||||||
|
cw.event = EVENT_GET_GEO_DESCRIPTION;
|
||||||
|
startQuery(token, cw, null, null, null, null, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DBG) Rlog.d(LOG_TAG, "constructing CallerInfo object for token: " + token);
|
if (DBG) Rlog.d(LOG_TAG, "constructing CallerInfo object for token: " + token);
|
||||||
@@ -333,9 +368,15 @@ public class CallerInfoAsyncQuery {
|
|||||||
|
|
||||||
//notify the listener that the query is complete.
|
//notify the listener that the query is complete.
|
||||||
if (cw.listener != null) {
|
if (cw.listener != null) {
|
||||||
Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
|
mPendingListenerCallbacks.add(new Runnable() {
|
||||||
" for token: " + token + mCallerInfo);
|
@Override
|
||||||
cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
|
public void run() {
|
||||||
|
if (DBG) Rlog.d(LOG_TAG, "notifying listener: "
|
||||||
|
+ cw.listener.getClass().toString() + " for token: " + token
|
||||||
|
+ mCallerInfo);
|
||||||
|
cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
Rlog.w(LOG_TAG, "There is no listener to notify for this query.");
|
Rlog.w(LOG_TAG, "There is no listener to notify for this query.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user