Merge "Query geo description in worker thread to prevent ANR"

This commit is contained in:
Hall Liu
2017-04-05 19:23:29 +00:00
committed by Gerrit Code Review
2 changed files with 67 additions and 26 deletions

View File

@@ -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)) {

View File

@@ -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.");
} }