summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Lee <anwlee@google.com>2015-05-15 10:18:45 -0700
committerAndrew Lee <anwlee@google.com>2015-05-19 18:27:01 -0700
commit7c461dc3809ce0d4d969a7c9b6406a1c6e4a1495 (patch)
treee11bc555526959b27caf34d003a9a5ad5f015813
parent49efd91e50a11dc7bdef8382a0ceac01bc060f77 (diff)
downloadandroid_packages_apps_Dialer-7c461dc3809ce0d4d969a7c9b6406a1c6e4a1495.tar.gz
android_packages_apps_Dialer-7c461dc3809ce0d4d969a7c9b6406a1c6e4a1495.tar.bz2
android_packages_apps_Dialer-7c461dc3809ce0d4d969a7c9b6406a1c6e4a1495.zip
Add AsyncTaskUtil for call log actions.
+ Factors out async tasks from Call Detail activity, so that in the near future it can be invoked from the call log directly. + Create listener interfaces for actions to execute after tasks have been completed. + Should have no logical/behavioral changes. Hopefully, this creates a more opaque interface for activities or other classes to perform these actions as well. Bug: 21170557 Change-Id: I43aea7e37600d3978e285f047cba7ce75ebb5787
-rw-r--r--src/com/android/dialer/CallDetailActivity.java425
-rw-r--r--src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java300
-rw-r--r--tests/src/com/android/dialer/CallDetailActivityTest.java4
3 files changed, 428 insertions, 301 deletions
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index 18cf753ec..db247ba11 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -19,17 +19,12 @@ package com.android.dialer;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.PowerManager;
-import android.provider.CallLog;
-import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.VoicemailContract.Voicemails;
import android.telecom.PhoneAccount;
@@ -55,15 +50,14 @@ import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.GeoUtil;
import com.android.contacts.common.CallUtil;
import com.android.dialer.calllog.CallDetailHistoryAdapter;
-import com.android.dialer.calllog.CallLogNotificationsService;
+import com.android.dialer.calllog.CallLogAsyncTaskUtil.CallLogAsyncTaskListener;
+import com.android.dialer.calllog.CallLogAsyncTaskUtil;
import com.android.dialer.calllog.CallTypeHelper;
import com.android.dialer.calllog.ContactInfo;
import com.android.dialer.calllog.ContactInfoHelper;
import com.android.dialer.calllog.PhoneAccountUtils;
import com.android.dialer.calllog.PhoneNumberDisplayUtil;
import com.android.dialer.calllog.PhoneNumberUtilsWrapper;
-import com.android.dialer.util.AsyncTaskExecutor;
-import com.android.dialer.util.AsyncTaskExecutors;
import com.android.dialer.util.IntentUtil;
import com.android.dialer.util.DialerUtils;
import com.android.dialer.util.TelecomUtil;
@@ -83,18 +77,7 @@ import java.util.List;
public class CallDetailActivity extends Activity {
private static final String TAG = "CallDetail";
- private static final char LEFT_TO_RIGHT_EMBEDDING = '\u202A';
- private static final char POP_DIRECTIONAL_FORMATTING = '\u202C';
-
- /** The enumeration of {@link AsyncTask} objects used in this class. */
- public enum Tasks {
- MARK_VOICEMAIL_READ,
- DELETE_VOICEMAIL_AND_FINISH,
- REMOVE_FROM_CALL_LOG_AND_FINISH,
- UPDATE_PHONE_CALL_DETAILS,
- }
-
- /** A long array extra containing ids of call log entries to display. */
+ /** A long array extra containing ids of call log entries to display. */
public static final String EXTRA_CALL_LOG_IDS = "EXTRA_CALL_LOG_IDS";
/** If we are started with a voicemail, we'll find the uri to play with this extra. */
public static final String EXTRA_VOICEMAIL_URI = "EXTRA_VOICEMAIL_URI";
@@ -105,12 +88,128 @@ public class CallDetailActivity extends Activity {
public static final String VOICEMAIL_FRAGMENT_TAG = "voicemail_fragment";
+ private CallLogAsyncTaskListener mCallLogAsyncTaskListener = new CallLogAsyncTaskListener() {
+ @Override
+ public void onDeleteCall() {
+ finish();
+ }
+
+ @Override
+ public void onDeleteVoicemail() {
+ finish();
+ }
+
+ @Override
+ public void onGetCallDetails(PhoneCallDetails[] details) {
+ Context context = CallDetailActivity.this;
+
+ if (details == null) {
+ // Somewhere went wrong: we're going to bail out and show error to users.
+ Toast.makeText(context, R.string.toast_call_detail_error,
+ Toast.LENGTH_SHORT).show();
+ finish();
+ return;
+ }
+
+ // We know that all calls are from the same number and the same contact, so pick the
+ // first.
+ PhoneCallDetails firstDetails = details[0];
+ mNumber = TextUtils.isEmpty(firstDetails.number) ?
+ null : firstDetails.number.toString();
+ final int numberPresentation = firstDetails.numberPresentation;
+ final Uri contactUri = firstDetails.contactUri;
+ final Uri photoUri = firstDetails.photoUri;
+ final PhoneAccountHandle accountHandle = firstDetails.accountHandle;
+
+ // Cache the details about the phone number.
+ final boolean canPlaceCallsTo =
+ PhoneNumberUtilsWrapper.canPlaceCallsTo(mNumber, numberPresentation);
+ final PhoneNumberUtilsWrapper phoneUtils = new PhoneNumberUtilsWrapper(context);
+ final boolean isVoicemailNumber =
+ phoneUtils.isVoicemailNumber(accountHandle, mNumber);
+ final boolean isSipNumber = PhoneNumberUtilsWrapper.isSipNumber(mNumber);
+
+ final CharSequence callLocationOrType = getNumberTypeOrLocation(firstDetails);
+
+ final CharSequence displayNumber = firstDetails.displayNumber;
+ final String displayNumberStr = mBidiFormatter.unicodeWrap(
+ displayNumber.toString(), TextDirectionHeuristics.LTR);
+
+ if (!TextUtils.isEmpty(firstDetails.name)) {
+ mCallerName.setText(firstDetails.name);
+ mCallerNumber.setText(callLocationOrType + " " + displayNumberStr);
+ } else {
+ mCallerName.setText(displayNumberStr);
+ if (!TextUtils.isEmpty(callLocationOrType)) {
+ mCallerNumber.setText(callLocationOrType);
+ mCallerNumber.setVisibility(View.VISIBLE);
+ } else {
+ mCallerNumber.setVisibility(View.GONE);
+ }
+ }
+
+ String accountLabel = PhoneAccountUtils.getAccountLabel(context, accountHandle);
+ if (!TextUtils.isEmpty(accountLabel)) {
+ mAccountLabel.setText(accountLabel);
+ mAccountLabel.setVisibility(View.VISIBLE);
+ } else {
+ mAccountLabel.setVisibility(View.GONE);
+ }
+
+ mHasEditNumberBeforeCallOption =
+ canPlaceCallsTo && !isSipNumber && !isVoicemailNumber;
+ mHasTrashOption = hasVoicemail();
+ mHasRemoveFromCallLogOption = !hasVoicemail();
+ invalidateOptionsMenu();
+
+ ListView historyList = (ListView) findViewById(R.id.history);
+ historyList.setAdapter(
+ new CallDetailHistoryAdapter(context, mInflater, mCallTypeHelper, details));
+
+ String lookupKey = contactUri == null ? null
+ : ContactInfoHelper.getLookupKeyFromUri(contactUri);
+
+ final boolean isBusiness = mContactInfoHelper.isBusiness(firstDetails.sourceType);
+
+ final int contactType =
+ isVoicemailNumber ? ContactPhotoManager.TYPE_VOICEMAIL :
+ isBusiness ? ContactPhotoManager.TYPE_BUSINESS :
+ ContactPhotoManager.TYPE_DEFAULT;
+
+ String nameForDefaultImage;
+ if (TextUtils.isEmpty(firstDetails.name)) {
+ nameForDefaultImage = firstDetails.displayNumber;
+ } else {
+ nameForDefaultImage = firstDetails.name.toString();
+ }
+
+ loadContactPhotos(
+ contactUri, photoUri, nameForDefaultImage, lookupKey, contactType);
+ findViewById(R.id.call_detail).setVisibility(View.VISIBLE);
+ }
+
+ /**
+ * Determines the location geocode text for a call, or the phone number type
+ * (if available).
+ *
+ * @param details The call details.
+ * @return The phone number type or location.
+ */
+ private CharSequence getNumberTypeOrLocation(PhoneCallDetails details) {
+ if (!TextUtils.isEmpty(details.name)) {
+ return Phone.getTypeLabel(mResources, details.numberType,
+ details.numberLabel);
+ } else {
+ return details.geocode;
+ }
+ }
+ };
+
private CallTypeHelper mCallTypeHelper;
private QuickContactBadge mQuickContactBadge;
private TextView mCallerName;
private TextView mCallerNumber;
private TextView mAccountLabel;
- private AsyncTaskExecutor mAsyncTaskExecutor;
private ContactInfoHelper mContactInfoHelper;
private String mNumber = null;
@@ -133,41 +232,12 @@ public class CallDetailActivity extends Activity {
/** Whether we should show "remove from call log" in the options menu. */
private boolean mHasRemoveFromCallLogOption;
- static final String[] CALL_LOG_PROJECTION = new String[] {
- CallLog.Calls.DATE,
- CallLog.Calls.DURATION,
- CallLog.Calls.NUMBER,
- CallLog.Calls.TYPE,
- CallLog.Calls.COUNTRY_ISO,
- CallLog.Calls.GEOCODED_LOCATION,
- CallLog.Calls.NUMBER_PRESENTATION,
- CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME,
- CallLog.Calls.PHONE_ACCOUNT_ID,
- CallLog.Calls.FEATURES,
- CallLog.Calls.DATA_USAGE,
- CallLog.Calls.TRANSCRIPTION
- };
-
- static final int DATE_COLUMN_INDEX = 0;
- static final int DURATION_COLUMN_INDEX = 1;
- static final int NUMBER_COLUMN_INDEX = 2;
- static final int CALL_TYPE_COLUMN_INDEX = 3;
- static final int COUNTRY_ISO_COLUMN_INDEX = 4;
- static final int GEOCODED_LOCATION_COLUMN_INDEX = 5;
- static final int NUMBER_PRESENTATION_COLUMN_INDEX = 6;
- static final int ACCOUNT_COMPONENT_NAME = 7;
- static final int ACCOUNT_ID = 8;
- static final int FEATURES = 9;
- static final int DATA_USAGE = 10;
- static final int TRANSCRIPTION_COLUMN_INDEX = 11;
-
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.call_detail);
- mAsyncTaskExecutor = AsyncTaskExecutors.createThreadPoolExecutor();
mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
mResources = getResources();
@@ -196,7 +266,8 @@ public class CallDetailActivity extends Activity {
@Override
public void onResume() {
super.onResume();
- updateData(getCallLogEntryUris());
+
+ CallLogAsyncTaskUtil.getCallDetails(this, getCallLogEntryUris(), mCallLogAsyncTaskListener);
}
/**
@@ -237,7 +308,7 @@ public class CallDetailActivity extends Activity {
}
voicemailContainer.setVisibility(View.VISIBLE);
- markVoicemailAsRead(mVoicemailUri);
+ CallLogAsyncTaskUtil.markVoicemailAsRead(this, mVoicemailUri);
}
}
@@ -245,22 +316,6 @@ public class CallDetailActivity extends Activity {
return mVoicemailUri != null;
}
- private void markVoicemailAsRead(final Uri voicemailUri) {
- mAsyncTaskExecutor.submit(Tasks.MARK_VOICEMAIL_READ, new AsyncTask<Void, Void, Void>() {
- @Override
- public Void doInBackground(Void... params) {
- ContentValues values = new ContentValues();
- values.put(Voicemails.IS_READ, true);
- getContentResolver().update(voicemailUri, values,
- Voicemails.IS_READ + " = 0", null);
- Intent intent = new Intent(getBaseContext(), CallLogNotificationsService.class);
- intent.setAction(CallLogNotificationsService.ACTION_MARK_NEW_VOICEMAILS_AS_OLD);
- getBaseContext().startService(intent);
- return null;
- }
- });
- }
-
/**
* Returns the list of URIs to show.
* <p>
@@ -285,207 +340,6 @@ public class CallDetailActivity extends Activity {
return uris;
}
- /**
- * Update user interface with details of given call.
- *
- * @param callUris URIs into {@link android.provider.CallLog.Calls} of the calls to be displayed
- */
- private void updateData(final Uri... callUris) {
- class UpdateContactDetailsTask extends AsyncTask<Void, Void, PhoneCallDetails[]> {
- @Override
- public PhoneCallDetails[] doInBackground(Void... params) {
- // TODO: All phone calls correspond to the same person, so we can make a single
- // lookup.
- final int numCalls = callUris.length;
- PhoneCallDetails[] details = new PhoneCallDetails[numCalls];
- try {
- for (int index = 0; index < numCalls; ++index) {
- details[index] = getPhoneCallDetailsForUri(callUris[index]);
- }
- return details;
- } catch (IllegalArgumentException e) {
- // Something went wrong reading in our primary data.
- Log.w(TAG, "invalid URI starting call details", e);
- return null;
- }
- }
-
- @Override
- public void onPostExecute(PhoneCallDetails[] details) {
- Context context = CallDetailActivity.this;
-
- if (details == null) {
- // Somewhere went wrong: we're going to bail out and show error to users.
- Toast.makeText(context, R.string.toast_call_detail_error,
- Toast.LENGTH_SHORT).show();
- finish();
- return;
- }
-
- // We know that all calls are from the same number and the same contact, so pick the
- // first.
- PhoneCallDetails firstDetails = details[0];
- mNumber = TextUtils.isEmpty(firstDetails.number) ?
- null : firstDetails.number.toString();
- final int numberPresentation = firstDetails.numberPresentation;
- final Uri contactUri = firstDetails.contactUri;
- final Uri photoUri = firstDetails.photoUri;
- final PhoneAccountHandle accountHandle = firstDetails.accountHandle;
-
- // Cache the details about the phone number.
- final boolean canPlaceCallsTo =
- PhoneNumberUtilsWrapper.canPlaceCallsTo(mNumber, numberPresentation);
- final PhoneNumberUtilsWrapper phoneUtils = new PhoneNumberUtilsWrapper(context);
- final boolean isVoicemailNumber =
- phoneUtils.isVoicemailNumber(accountHandle, mNumber);
- final boolean isSipNumber = PhoneNumberUtilsWrapper.isSipNumber(mNumber);
-
- final CharSequence callLocationOrType = getNumberTypeOrLocation(firstDetails);
-
- final CharSequence displayNumber = firstDetails.displayNumber;
- final String displayNumberStr = mBidiFormatter.unicodeWrap(
- displayNumber.toString(), TextDirectionHeuristics.LTR);
-
- if (!TextUtils.isEmpty(firstDetails.name)) {
- mCallerName.setText(firstDetails.name);
- mCallerNumber.setText(callLocationOrType + " " + displayNumberStr);
- } else {
- mCallerName.setText(displayNumberStr);
- if (!TextUtils.isEmpty(callLocationOrType)) {
- mCallerNumber.setText(callLocationOrType);
- mCallerNumber.setVisibility(View.VISIBLE);
- } else {
- mCallerNumber.setVisibility(View.GONE);
- }
- }
-
- String accountLabel = PhoneAccountUtils.getAccountLabel(context, accountHandle);
- if (!TextUtils.isEmpty(accountLabel)) {
- mAccountLabel.setText(accountLabel);
- mAccountLabel.setVisibility(View.VISIBLE);
- } else {
- mAccountLabel.setVisibility(View.GONE);
- }
-
- mHasEditNumberBeforeCallOption =
- canPlaceCallsTo && !isSipNumber && !isVoicemailNumber;
- mHasTrashOption = hasVoicemail();
- mHasRemoveFromCallLogOption = !hasVoicemail();
- invalidateOptionsMenu();
-
- ListView historyList = (ListView) findViewById(R.id.history);
- historyList.setAdapter(
- new CallDetailHistoryAdapter(context, mInflater, mCallTypeHelper, details));
-
- String lookupKey = contactUri == null ? null
- : ContactInfoHelper.getLookupKeyFromUri(contactUri);
-
- final boolean isBusiness = mContactInfoHelper.isBusiness(firstDetails.sourceType);
-
- final int contactType =
- isVoicemailNumber? ContactPhotoManager.TYPE_VOICEMAIL :
- isBusiness ? ContactPhotoManager.TYPE_BUSINESS :
- ContactPhotoManager.TYPE_DEFAULT;
-
- String nameForDefaultImage;
- if (TextUtils.isEmpty(firstDetails.name)) {
- nameForDefaultImage = firstDetails.displayNumber.toString();
- } else {
- nameForDefaultImage = firstDetails.name.toString();
- }
-
- loadContactPhotos(
- contactUri, photoUri, nameForDefaultImage, lookupKey, contactType);
- findViewById(R.id.call_detail).setVisibility(View.VISIBLE);
- }
-
- /**
- * Determines the location geocode text for a call, or the phone number type
- * (if available).
- *
- * @param details The call details.
- * @return The phone number type or location.
- */
- private CharSequence getNumberTypeOrLocation(PhoneCallDetails details) {
- if (!TextUtils.isEmpty(details.name)) {
- return Phone.getTypeLabel(mResources, details.numberType,
- details.numberLabel);
- } else {
- return details.geocode;
- }
- }
- }
- mAsyncTaskExecutor.submit(Tasks.UPDATE_PHONE_CALL_DETAILS, new UpdateContactDetailsTask());
- }
-
- /** Return the phone call details for a given call log URI. */
- private PhoneCallDetails getPhoneCallDetailsForUri(Uri callUri) {
- ContentResolver resolver = getContentResolver();
- Cursor callCursor = resolver.query(callUri, CALL_LOG_PROJECTION, null, null, null);
- try {
- if (callCursor == null || !callCursor.moveToFirst()) {
- throw new IllegalArgumentException("Cannot find content: " + callUri);
- }
-
- // Read call log specifics.
- final String number = callCursor.getString(NUMBER_COLUMN_INDEX);
- final int numberPresentation = callCursor.getInt(
- NUMBER_PRESENTATION_COLUMN_INDEX);
- final long date = callCursor.getLong(DATE_COLUMN_INDEX);
- final long duration = callCursor.getLong(DURATION_COLUMN_INDEX);
- final int callType = callCursor.getInt(CALL_TYPE_COLUMN_INDEX);
- String countryIso = callCursor.getString(COUNTRY_ISO_COLUMN_INDEX);
- final String geocode = callCursor.getString(GEOCODED_LOCATION_COLUMN_INDEX);
- final String transcription = callCursor.getString(TRANSCRIPTION_COLUMN_INDEX);
-
- final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
- callCursor.getString(ACCOUNT_COMPONENT_NAME),
- callCursor.getString(ACCOUNT_ID));
-
- if (TextUtils.isEmpty(countryIso)) {
- countryIso = mDefaultCountryIso;
- }
-
- // Formatted phone number.
- final CharSequence formattedNumber;
-
- // If this is not a regular number, there is no point in looking it up in the contacts.
- ContactInfo info = ContactInfo.EMPTY;
- final boolean isVoicemail = new PhoneNumberUtilsWrapper(this)
- .isVoicemailNumber(accountHandle, number);
- if (PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)
- && !isVoicemail) {
- mContactInfoHelper.lookupNumber(number, countryIso);
- }
- if (info == null) {
- formattedNumber = PhoneNumberDisplayUtil.getDisplayNumber(
- this,
- accountHandle,
- number,
- numberPresentation,
- null /* formattedNumber */,
- isVoicemail);
- } else {
- formattedNumber = info.formattedNumber;
- }
- final int features = callCursor.getInt(FEATURES);
- Long dataUsage = null;
- if (!callCursor.isNull(DATA_USAGE)) {
- dataUsage = callCursor.getLong(DATA_USAGE);
- }
- return new PhoneCallDetails(this, number, numberPresentation,
- formattedNumber, countryIso, geocode,
- new int[]{ callType }, date, duration,
- info.name, info.type, info.label, info.lookupUri, info.photoUri,
- info.sourceType, accountHandle, features, dataUsage, transcription,
- isVoicemail);
- } finally {
- if (callCursor != null) {
- callCursor.close();
- }
- }
- }
-
/** Load the contact photos and places them in the corresponding views. */
private void loadContactPhotos(Uri contactUri, Uri photoUri, String displayName,
String lookupKey, int contactType) {
@@ -525,22 +379,8 @@ public class CallDetailActivity extends Activity {
}
callIds.append(ContentUris.parseId(callUri));
}
- mAsyncTaskExecutor.submit(Tasks.REMOVE_FROM_CALL_LOG_AND_FINISH,
- new AsyncTask<Void, Void, Void>() {
- @Override
- public Void doInBackground(Void... params) {
- getContentResolver().delete(
- TelecomUtil.getCallLogUri(CallDetailActivity.this),
- Calls._ID + " IN (" + callIds + ")", null);
- return null;
- }
-
- @Override
- public void onPostExecute(Void result) {
- finish();
- }
- }
- );
+
+ CallLogAsyncTaskUtil.deleteCalls(this, callIds.toString(), mCallLogAsyncTaskListener);
}
public void onMenuEditNumberBeforeCall(MenuItem menuItem) {
@@ -548,20 +388,7 @@ public class CallDetailActivity extends Activity {
}
public void onMenuTrashVoicemail(MenuItem menuItem) {
- mAsyncTaskExecutor.submit(Tasks.DELETE_VOICEMAIL_AND_FINISH,
- new AsyncTask<Void, Void, Void>() {
- @Override
- public Void doInBackground(Void... params) {
- getContentResolver().delete(mVoicemailUri, null, null);
- return null;
- }
-
- @Override
- public void onPostExecute(Void result) {
- finish();
- }
- }
- );
+ CallLogAsyncTaskUtil.deleteVoicemail(this, mVoicemailUri, mCallLogAsyncTaskListener);
}
private void closeSystemDialogs() {
diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
new file mode 100644
index 000000000..20e213c4f
--- /dev/null
+++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.calllog;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.CallLog;
+import android.provider.VoicemailContract.Voicemails;
+import android.telecom.PhoneAccountHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.GeoUtil;
+import com.android.dialer.PhoneCallDetails;
+import com.android.dialer.util.AsyncTaskExecutor;
+import com.android.dialer.util.AsyncTaskExecutors;
+import com.android.dialer.util.TelecomUtil;
+
+public class CallLogAsyncTaskUtil {
+ private static String TAG = CallLogAsyncTaskUtil.class.getSimpleName();
+
+ /** The enumeration of {@link AsyncTask} objects used in this class. */
+ public enum Tasks {
+ DELETE_VOICEMAIL,
+ DELETE_CALL,
+ MARK_VOICEMAIL_READ,
+ GET_CALL_DETAILS,
+ }
+
+ private static class CallDetailQuery {
+ static final String[] CALL_LOG_PROJECTION = new String[] {
+ CallLog.Calls.DATE,
+ CallLog.Calls.DURATION,
+ CallLog.Calls.NUMBER,
+ CallLog.Calls.TYPE,
+ CallLog.Calls.COUNTRY_ISO,
+ CallLog.Calls.GEOCODED_LOCATION,
+ CallLog.Calls.NUMBER_PRESENTATION,
+ CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME,
+ CallLog.Calls.PHONE_ACCOUNT_ID,
+ CallLog.Calls.FEATURES,
+ CallLog.Calls.DATA_USAGE,
+ CallLog.Calls.TRANSCRIPTION
+ };
+
+ static final int DATE_COLUMN_INDEX = 0;
+ static final int DURATION_COLUMN_INDEX = 1;
+ static final int NUMBER_COLUMN_INDEX = 2;
+ static final int CALL_TYPE_COLUMN_INDEX = 3;
+ static final int COUNTRY_ISO_COLUMN_INDEX = 4;
+ static final int GEOCODED_LOCATION_COLUMN_INDEX = 5;
+ static final int NUMBER_PRESENTATION_COLUMN_INDEX = 6;
+ static final int ACCOUNT_COMPONENT_NAME = 7;
+ static final int ACCOUNT_ID = 8;
+ static final int FEATURES = 9;
+ static final int DATA_USAGE = 10;
+ static final int TRANSCRIPTION_COLUMN_INDEX = 11;
+ }
+
+ public interface CallLogAsyncTaskListener {
+ public void onDeleteCall();
+ public void onDeleteVoicemail();
+ public void onGetCallDetails(PhoneCallDetails[] details);
+ }
+
+ private static AsyncTaskExecutor sAsyncTaskExecutor;
+
+ private static void initTaskExecutor() {
+ sAsyncTaskExecutor = AsyncTaskExecutors.createThreadPoolExecutor();
+ }
+
+ public static void getCallDetails(
+ final Context context,
+ final Uri[] callUris,
+ final CallLogAsyncTaskListener callLogAsyncTaskListener) {
+ if (sAsyncTaskExecutor == null) {
+ initTaskExecutor();
+ }
+
+ sAsyncTaskExecutor.submit(Tasks.GET_CALL_DETAILS,
+ new AsyncTask<Void, Void, PhoneCallDetails[]>() {
+ @Override
+ public PhoneCallDetails[] doInBackground(Void... params) {
+ // TODO: All calls correspond to the same person, so make a single lookup.
+ final int numCalls = callUris.length;
+ PhoneCallDetails[] details = new PhoneCallDetails[numCalls];
+ try {
+ for (int index = 0; index < numCalls; ++index) {
+ details[index] =
+ getPhoneCallDetailsForUri(context, callUris[index]);
+ }
+ return details;
+ } catch (IllegalArgumentException e) {
+ // Something went wrong reading in our primary data.
+ Log.w(TAG, "Invalid URI starting call details", e);
+ return null;
+ }
+ }
+
+ @Override
+ public void onPostExecute(PhoneCallDetails[] phoneCallDetails) {
+ if (callLogAsyncTaskListener != null) {
+ callLogAsyncTaskListener.onGetCallDetails(phoneCallDetails);
+ }
+ }
+ });
+ }
+
+ /**
+ * Return the phone call details for a given call log URI.
+ */
+ private static PhoneCallDetails getPhoneCallDetailsForUri(Context context, Uri callUri) {
+ Cursor cursor = context.getContentResolver().query(
+ callUri, CallDetailQuery.CALL_LOG_PROJECTION, null, null, null);
+
+ try {
+ if (cursor == null || !cursor.moveToFirst()) {
+ throw new IllegalArgumentException("Cannot find content: " + callUri);
+ }
+
+ // Read call log.
+ final String number = cursor.getString(CallDetailQuery.NUMBER_COLUMN_INDEX);
+ final int numberPresentation =
+ cursor.getInt(CallDetailQuery.NUMBER_PRESENTATION_COLUMN_INDEX);
+ final long date = cursor.getLong(CallDetailQuery.DATE_COLUMN_INDEX);
+ final long duration = cursor.getLong(CallDetailQuery.DURATION_COLUMN_INDEX);
+ final int callType = cursor.getInt(CallDetailQuery.CALL_TYPE_COLUMN_INDEX);
+ final String geocode = cursor.getString(CallDetailQuery.GEOCODED_LOCATION_COLUMN_INDEX);
+ final String transcription =
+ cursor.getString(CallDetailQuery.TRANSCRIPTION_COLUMN_INDEX);
+
+ final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
+ cursor.getString(CallDetailQuery.ACCOUNT_COMPONENT_NAME),
+ cursor.getString(CallDetailQuery.ACCOUNT_ID));
+
+ String countryIso = cursor.getString(CallDetailQuery.COUNTRY_ISO_COLUMN_INDEX);
+ if (TextUtils.isEmpty(countryIso)) {
+ countryIso = GeoUtil.getCurrentCountryIso(context);
+ }
+
+ // Formatted phone number.
+ final CharSequence formattedNumber;
+ // Read contact specifics.
+ final CharSequence nameText;
+ final int numberType;
+ final CharSequence numberLabel;
+ final Uri photoUri;
+ final Uri lookupUri;
+ int sourceType;
+
+ // If this is not a regular number, there is no point in looking it up in the contacts.
+ ContactInfoHelper contactInfoHelper =
+ new ContactInfoHelper(context, GeoUtil.getCurrentCountryIso(context));
+ PhoneNumberUtilsWrapper phoneNumberUtilsWrapper =
+ new PhoneNumberUtilsWrapper(context);
+ boolean isVoicemail = phoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number);
+ boolean shouldLookupNumber =
+ PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)
+ && !isVoicemail;
+ ContactInfo info = shouldLookupNumber
+ ? contactInfoHelper.lookupNumber(number, countryIso) : null;
+
+ if (info == null) {
+ formattedNumber = PhoneNumberDisplayUtil.getDisplayNumber(
+ context, accountHandle, number, numberPresentation, null, isVoicemail);
+ nameText = "";
+ numberType = 0;
+ numberLabel = "";
+ photoUri = null;
+ lookupUri = null;
+ sourceType = 0;
+ } else {
+ formattedNumber = info.formattedNumber;
+ nameText = info.name;
+ numberType = info.type;
+ numberLabel = info.label;
+ photoUri = info.photoUri;
+ lookupUri = info.lookupUri;
+ sourceType = info.sourceType;
+ }
+
+
+ final int features = cursor.getInt(CallDetailQuery.FEATURES);
+
+ Long dataUsage = null;
+ if (!cursor.isNull(CallDetailQuery.DATA_USAGE)) {
+ dataUsage = cursor.getLong(CallDetailQuery.DATA_USAGE);
+ }
+
+ return new PhoneCallDetails(context, number, numberPresentation, formattedNumber,
+ countryIso, geocode, new int[]{ callType }, date, duration, nameText,
+ numberType, numberLabel, lookupUri, photoUri, sourceType, accountHandle,
+ features, dataUsage, transcription, isVoicemail);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+
+ /**
+ * Delete specified calls from the call log.
+ *
+ * @param context The context.
+ * @param callIds String of the callIds to delete from the call log, delimited by commas (",").
+ * @param callLogAsyncTaskListenerg The listener to invoke after the entries have been deleted.
+ */
+ public static void deleteCalls(
+ final Context context,
+ final String callIds,
+ final CallLogAsyncTaskListener callLogAsyncTaskListener) {
+ if (sAsyncTaskExecutor == null) {
+ initTaskExecutor();
+ }
+
+ sAsyncTaskExecutor.submit(Tasks.DELETE_CALL,
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(Void... params) {
+ context.getContentResolver().delete(
+ TelecomUtil.getCallLogUri(context),
+ CallLog.Calls._ID + " IN (" + callIds + ")", null);
+ return null;
+ }
+
+ @Override
+ public void onPostExecute(Void result) {
+ if (callLogAsyncTaskListener != null) {
+ callLogAsyncTaskListener.onDeleteCall();
+ }
+ }
+ });
+
+ }
+
+ public static void markVoicemailAsRead(final Context context, final Uri voicemailUri) {
+ if (sAsyncTaskExecutor == null) {
+ initTaskExecutor();
+ }
+
+ sAsyncTaskExecutor.submit(Tasks.MARK_VOICEMAIL_READ, new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(Void... params) {
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.IS_READ, true);
+ context.getContentResolver().update(
+ voicemailUri, values, Voicemails.IS_READ + " = 0", null);
+
+ Intent intent = new Intent(context, CallLogNotificationsService.class);
+ intent.setAction(CallLogNotificationsService.ACTION_MARK_NEW_VOICEMAILS_AS_OLD);
+ context.startService(intent);
+ return null;
+ }
+ });
+ }
+
+ public static void deleteVoicemail(
+ final Context context,
+ final Uri voicemailUri,
+ final CallLogAsyncTaskListener callLogAsyncTaskListener) {
+ if (sAsyncTaskExecutor == null) {
+ initTaskExecutor();
+ }
+
+ sAsyncTaskExecutor.submit(Tasks.DELETE_VOICEMAIL,
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(Void... params) {
+ context.getContentResolver().delete(voicemailUri, null, null);
+ return null;
+ }
+
+ @Override
+ public void onPostExecute(Void result) {
+ if (callLogAsyncTaskListener != null) {
+ callLogAsyncTaskListener.onDeleteVoicemail();
+ }
+ }
+ });
+ }
+}
diff --git a/tests/src/com/android/dialer/CallDetailActivityTest.java b/tests/src/com/android/dialer/CallDetailActivityTest.java
index 15e90fcf6..aca8f2985 100644
--- a/tests/src/com/android/dialer/CallDetailActivityTest.java
+++ b/tests/src/com/android/dialer/CallDetailActivityTest.java
@@ -16,7 +16,7 @@
package com.android.dialer;
-import static com.android.dialer.CallDetailActivity.Tasks.UPDATE_PHONE_CALL_DETAILS;
+import static com.android.dialer.calllog.CallLogAsyncTaskUtil.Tasks.GET_CALL_DETAILS;
import static com.android.dialer.voicemail.VoicemailPlaybackPresenter.Tasks.CHECK_FOR_CONTENT;
import static com.android.dialer.voicemail.VoicemailPlaybackPresenter.Tasks.PREPARE_MEDIA_PLAYER;
@@ -303,7 +303,7 @@ public class CallDetailActivityTest extends ActivityInstrumentationTestCase2<Cal
// We have to run all tasks, not just one.
// This is because it seems that we can have onResume, onPause, onResume during the course
// of a single unit test.
- mFakeAsyncTaskExecutor.runAllTasks(UPDATE_PHONE_CALL_DETAILS);
+ mFakeAsyncTaskExecutor.runAllTasks(GET_CALL_DETAILS);
}
private AssetManager getAssets() {