diff options
Diffstat (limited to 'src')
16 files changed, 793 insertions, 201 deletions
diff --git a/src/com/android/dialer/PhoneCallDetails.java b/src/com/android/dialer/PhoneCallDetails.java index 17f1c2b64..8a2e52090 100644 --- a/src/com/android/dialer/PhoneCallDetails.java +++ b/src/com/android/dialer/PhoneCallDetails.java @@ -116,6 +116,9 @@ public class PhoneCallDetails { */ public boolean isRead = true; + // If this call is a spam number. + public boolean isSpam = false; + /** * Constructor with required fields for the details of a call with a number associated with a * contact. diff --git a/src/com/android/dialer/calllog/BlockReportSpamListener.java b/src/com/android/dialer/calllog/BlockReportSpamListener.java new file mode 100644 index 000000000..92cbc804b --- /dev/null +++ b/src/com/android/dialer/calllog/BlockReportSpamListener.java @@ -0,0 +1,124 @@ +package com.android.dialer.calllog; + +import android.app.Activity; +import android.app.FragmentManager; +import android.content.ContentValues; +import android.content.DialogInterface; +import android.net.Uri; +import android.support.v7.widget.RecyclerView; + +import com.android.dialer.util.BlockReportSpamDialogs; +import com.android.dialer.database.FilteredNumberAsyncQueryHandler; +import com.android.dialer.service.ExtendedCallInfoService; + +/** + * Listener to show dialogs for block and report spam actions. + */ +public class BlockReportSpamListener implements CallLogListItemViewHolder.OnClickListener { + + private final FragmentManager mFragmentManager; + private final RecyclerView.Adapter mAdapter; + private final ExtendedCallInfoService mExtendedCallInfoService; + private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler; + + public BlockReportSpamListener(FragmentManager fragmentManager, RecyclerView.Adapter adapter, + ExtendedCallInfoService extendedCallInfoService, + FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler) { + mFragmentManager = fragmentManager; + mAdapter = adapter; + mExtendedCallInfoService = extendedCallInfoService; + mFilteredNumberAsyncQueryHandler = filteredNumberAsyncQueryHandler; + } + + @Override + public void onBlockReportSpam(String displayNumber, final String number, + final String countryIso, final int callType) { + BlockReportSpamDialogs.BlockReportSpamDialogFragment.newInstance( + displayNumber, + false, + new BlockReportSpamDialogs.OnSpamDialogClickListener() { + @Override + public void onClick(boolean isSpamChecked) { + if (isSpamChecked) { + mExtendedCallInfoService.reportSpam( + number, countryIso, callType, + ExtendedCallInfoService.REPORTING_LOCATION_CALL_LOG_HISTORY); + } + mFilteredNumberAsyncQueryHandler.blockNumber( + new FilteredNumberAsyncQueryHandler.OnBlockNumberListener() { + @Override + public void onBlockComplete(Uri uri) { + mAdapter.notifyDataSetChanged(); + } + }, + number, + countryIso); + } + }, null) + .show(mFragmentManager, BlockReportSpamDialogs.BLOCK_REPORT_SPAM_DIALOG_TAG); + } + + @Override + public void onBlock(String displayNumber, final String number, final String countryIso, + final int callType) { + BlockReportSpamDialogs.BlockDialogFragment.newInstance(displayNumber, + new BlockReportSpamDialogs.OnConfirmListener() { + @Override + public void onClick() { + mExtendedCallInfoService.reportSpam(number, countryIso, callType, + ExtendedCallInfoService.REPORTING_LOCATION_CALL_LOG_HISTORY); + mFilteredNumberAsyncQueryHandler.blockNumber( + new FilteredNumberAsyncQueryHandler.OnBlockNumberListener() { + @Override + public void onBlockComplete(Uri uri) { + mAdapter.notifyDataSetChanged(); + } + }, + number, + countryIso); + } + }, null) + .show(mFragmentManager, BlockReportSpamDialogs.BLOCK_DIALOG_TAG); + } + + @Override + public void onUnblock(String displayNumber, final String number, final String countryIso, + final Integer blockId, final boolean isSpam, final int callType) { + BlockReportSpamDialogs.UnblockDialogFragment.newInstance(displayNumber, isSpam, + new BlockReportSpamDialogs.OnConfirmListener() { + @Override + public void onClick() { + if (isSpam) { + mExtendedCallInfoService.reportNotSpam( + number, countryIso, callType, + ExtendedCallInfoService.REPORTING_LOCATION_CALL_LOG_HISTORY); + } + mFilteredNumberAsyncQueryHandler.unblock( + new FilteredNumberAsyncQueryHandler.OnUnblockNumberListener() { + @Override + public void onUnblockComplete(int rows, ContentValues values) { + mAdapter.notifyDataSetChanged(); + } + }, + blockId); + } + }, null) + .show(mFragmentManager, BlockReportSpamDialogs.UNBLOCK_DIALOG_TAG); + } + + @Override + public void onReportNotSpam(String displayNumber, final String number, final String countryIso, + final int callType) { + BlockReportSpamDialogs.ReportNotSpamDialogFragment.newInstance(displayNumber, + new BlockReportSpamDialogs.OnConfirmListener() { + @Override + public void onClick() { + mExtendedCallInfoService.reportNotSpam( + number, countryIso, callType, + ExtendedCallInfoService.REPORTING_LOCATION_CALL_LOG_HISTORY); + mAdapter.notifyDataSetChanged(); + } + }, null) + .show(mFragmentManager, BlockReportSpamDialogs.NOT_SPAM_DIALOG_TAG); + } +} diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java index 3958611b9..9cde0b65d 100644 --- a/src/com/android/dialer/calllog/CallLogAdapter.java +++ b/src/com/android/dialer/calllog/CallLogAdapter.java @@ -16,8 +16,12 @@ package com.android.dialer.calllog; +import com.android.dialer.filterednumber.BlockNumberDialogFragment; +import com.android.dialer.service.ExtendedCallInfoService; +import com.android.dialerbind.ObjectFactory; import com.google.common.annotations.VisibleForTesting; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -32,10 +36,8 @@ import android.provider.ContactsContract.CommonDataKinds.Phone; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.ViewHolder; import android.telecom.PhoneAccountHandle; -import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.util.ArrayMap; import android.view.LayoutInflater; import android.view.View; import android.view.View.AccessibilityDelegate; @@ -55,23 +57,19 @@ import com.android.dialer.contactinfo.ContactInfoCache; import com.android.dialer.contactinfo.ContactInfoCache.OnContactInfoChangedListener; import com.android.dialer.database.FilteredNumberAsyncQueryHandler; import com.android.dialer.database.VoicemailArchiveContract; -import com.android.dialer.filterednumber.BlockNumberDialogFragment.Callback; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; -import com.android.dialer.service.ExtendedBlockingButtonRenderer; import com.android.dialer.util.PhoneNumberUtil; import com.android.dialer.voicemail.VoicemailPlaybackPresenter; import java.util.HashMap; -import java.util.Map; /** * Adapter class to fill in data for the Call Log. */ public class CallLogAdapter extends GroupingListAdapter implements CallLogGroupBuilder.GroupCreator, - VoicemailPlaybackPresenter.OnVoicemailDeletedListener, - ExtendedBlockingButtonRenderer.Listener { + VoicemailPlaybackPresenter.OnVoicemailDeletedListener { // Types of activities the call log adapter is used for public static final int ACTIVITY_TYPE_CALL_LOG = 1; @@ -104,7 +102,6 @@ public class CallLogAdapter extends GroupingListAdapter protected final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter; private final CallFetcher mCallFetcher; private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler; - private final Map<String, Boolean> mBlockedNumberCache = new ArrayMap<>(); protected ContactInfoCache mContactInfoCache; @@ -121,6 +118,27 @@ public class CallLogAdapter extends GroupingListAdapter private int mHiddenPosition = RecyclerView.NO_POSITION; private Uri mHiddenItemUri = null; private boolean mPendingHide = false; + private BlockNumberDialogFragment.Callback mBlockedNumberDialogCallback = + new BlockNumberDialogFragment.Callback() { + @Override + public void onFilterNumberSuccess() { + Logger.logInteraction( + InteractionEvent.BLOCK_NUMBER_CALL_LOG); + notifyDataSetChanged(); + } + + @Override + public void onUnfilterNumberSuccess() { + Logger.logInteraction( + InteractionEvent.UNBLOCK_NUMBER_CALL_LOG); + notifyDataSetChanged(); + } + + @Override + public void onChangeFilteredNumberUndo() { + } + }; + private CallLogListItemViewHolder.OnClickListener mBlockReportSpamListener; /** * Hashmap, keyed by call Id, used to track the day group for a call. As call log entries are @@ -153,6 +171,8 @@ public class CallLogAdapter extends GroupingListAdapter /** Helper to group call log entries. */ private final CallLogGroupBuilder mCallLogGroupBuilder; + private ExtendedCallInfoService mExtendedCallInfoService; + /** * The OnClickListener used to expand or collapse the action buttons of a call log entry. */ @@ -296,6 +316,12 @@ public class CallLogAdapter extends GroupingListAdapter mPrefs = PreferenceManager.getDefaultSharedPreferences(context); mContactsPreferences = new ContactsPreferences(mContext); maybeShowVoicemailPromoCard(); + + mExtendedCallInfoService = ObjectFactory.newExtendedCallInfoService(context); + mBlockReportSpamListener = new BlockReportSpamListener( + ((Activity) mContext).getFragmentManager(), this, + mExtendedCallInfoService, mFilteredNumberAsyncQueryHandler); + setHasStableIds(true); } public void onSaveInstanceState(Bundle outState) { @@ -312,24 +338,6 @@ public class CallLogAdapter extends GroupingListAdapter } } - @Override - public void onBlockedNumber(String number,String countryIso) { - String cacheKey = PhoneNumberUtils.formatNumberToE164(number, countryIso); - if (!TextUtils.isEmpty(cacheKey)) { - mBlockedNumberCache.put(cacheKey, true); - notifyDataSetChanged(); - } - } - - @Override - public void onUnblockedNumber( String number, String countryIso) { - String cacheKey = PhoneNumberUtils.formatNumberToE164(number, countryIso); - if (!TextUtils.isEmpty(cacheKey)) { - mBlockedNumberCache.put(cacheKey, false); - notifyDataSetChanged(); - } - } - /** * Requery on background thread when {@link Cursor} changes. */ @@ -406,28 +414,14 @@ public class CallLogAdapter extends GroupingListAdapter CallLogListItemViewHolder viewHolder = CallLogListItemViewHolder.create( view, mContext, - this, + mBlockReportSpamListener, mExpandCollapseListener, mCallLogCache, mCallLogListItemHelper, mVoicemailPlaybackPresenter, mFilteredNumberAsyncQueryHandler, - new Callback() { - @Override - public void onFilterNumberSuccess() { - Logger.logInteraction( - InteractionEvent.BLOCK_NUMBER_CALL_LOG); - } - - @Override - public void onUnfilterNumberSuccess() { - Logger.logInteraction( - InteractionEvent.UNBLOCK_NUMBER_CALL_LOG); - } - - @Override - public void onChangeFilteredNumberUndo() {} - }, mActivityType == ACTIVITY_TYPE_ARCHIVE); + mBlockedNumberDialogCallback, + mActivityType == ACTIVITY_TYPE_ARCHIVE); viewHolder.callLogEntryView.setTag(viewHolder); viewHolder.callLogEntryView.setAccessibilityDelegate(mAccessibilityDelegate); @@ -481,7 +475,42 @@ public class CallLogAdapter extends GroupingListAdapter * @param position The position of the list item. */ - private void bindCallLogListViewHolder(ViewHolder viewHolder, int position) { + private void bindCallLogListViewHolder(final ViewHolder viewHolder, final int position) { + Cursor c = (Cursor) getItem(position); + if (c == null) { + return; + } + + final String number = c.getString(CallLogQuery.NUMBER); + final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO); + final CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder; + boolean success = mFilteredNumberAsyncQueryHandler.isBlockedNumber( + new FilteredNumberAsyncQueryHandler.OnCheckBlockedListener() { + @Override + public void onCheckComplete(Integer id) { + views.blockId = id; + if (mExtendedCallInfoService == null) { + loadDataAndRender(views); + } else { + views.isSpamFeatureEnabled = true; + mExtendedCallInfoService.getExtendedCallInfo(number, countryIso, + new ExtendedCallInfoService.Listener() { + @Override + public void onComplete(boolean isSpam) { + views.isSpam = isSpam; + loadDataAndRender(views); + } + }); + } + } + }, number, countryIso); + if (!success) { + loadDataAndRender(views); + } + } + + private void loadDataAndRender(CallLogListItemViewHolder views) { + int position = views.getAdapterPosition(); Cursor c = (Cursor) getItem(position); if (c == null) { return; @@ -547,7 +576,6 @@ public class CallLogAdapter extends GroupingListAdapter details.contactUserType = info.userType; } - final CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder; views.info = info; views.rowId = c.getLong(CallLogQuery.ID); // Store values used when the actions ViewStub is inflated on expansion. @@ -592,19 +620,22 @@ public class CallLogAdapter extends GroupingListAdapter views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI); } - mCallLogListItemHelper.setPhoneCallDetails(views, details); + // Reversely pass spam information from views since details is not constructed when spam + // information comes back. This is used to render phone call details. + details.isSpam = views.isSpam; + render(views, details); + } + private void render(CallLogListItemViewHolder views, PhoneCallDetails details) { + mCallLogListItemHelper.setPhoneCallDetails(views, details); if (mCurrentlyExpandedRowId == views.rowId) { // In case ViewHolders were added/removed, update the expanded position if the rowIds // match so that we can restore the correct expanded state on rebind. - mCurrentlyExpandedPosition = position; + mCurrentlyExpandedPosition = views.getAdapterPosition(); views.showActions(true); } else { views.showActions(false); } - views.updatePhoto(); - - mCallLogListItemHelper.setPhoneCallDetails(views, details); } private String getPreferredDisplayName(ContactInfo contactInfo) { @@ -644,6 +675,16 @@ public class CallLogAdapter extends GroupingListAdapter } @Override + public long getItemId(int position) { + Cursor cursor = (Cursor) getItem(position); + if (cursor != null) { + return cursor.getLong(CallLogQuery.ID); + } else { + return 0; + } + } + + @Override public int getGroupSize(int position) { return super.getGroupSize(position - (mShowVoicemailPromoCard ? 1 : 0)); } diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java index 34b2f0ea9..b95d58e26 100644 --- a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java +++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java @@ -17,6 +17,7 @@ package com.android.dialer.calllog; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import android.content.ContentResolver; import android.content.ContentValues; @@ -58,7 +59,8 @@ public class CallLogAsyncTaskUtil { MARK_VOICEMAIL_READ, MARK_CALL_READ, GET_CALL_DETAILS, - UPDATE_DURATION + UPDATE_DURATION, + GET_NUMBER_IN_CALL_HISTORY } private static final class CallDetailQuery { @@ -122,6 +124,10 @@ public class CallLogAsyncTaskUtil { void onGetCallDetails(PhoneCallDetails[] details); } + public interface OnGetNumberInCallHistoryListener { + void onComplete(boolean inCallHistory); + } + public interface OnCallLogQueryFinishedListener { void onQueryFinished(boolean hasEntry); } @@ -456,6 +462,42 @@ public class CallLogAsyncTaskUtil { }); } + /** + * Checks if the number is in the call history. + */ + public static void getNumberInCallHistory( + final Context context, + final String number, + final OnGetNumberInCallHistoryListener listener) { + Preconditions.checkNotNull(listener); + if (!PermissionsUtil.hasPhonePermissions(context)) { + return; + } + if (sAsyncTaskExecutor == null) { + initTaskExecutor(); + } + + sAsyncTaskExecutor.submit(Tasks.GET_NUMBER_IN_CALL_HISTORY, + new AsyncTask<Void, Void, Boolean>() { + @Override + public Boolean doInBackground(Void... params) { + try (Cursor cursor = context.getContentResolver().query( + TelecomUtil.getCallLogUri(context), + new String[] {CallLog.Calls._ID}, + CallLog.Calls.NUMBER + " = ?", + new String[] {number}, + null)) { + return cursor != null && cursor.getCount() > 0; + } + } + + @Override + public void onPostExecute(Boolean inCallHistory) { + listener.onComplete(inCallHistory); + } + }); + } + @VisibleForTesting public static void resetForTest() { sAsyncTaskExecutor = null; diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java index 07e2bb425..18b6ff5d3 100644 --- a/src/com/android/dialer/calllog/CallLogListItemHelper.java +++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java @@ -82,6 +82,8 @@ import com.android.dialer.calllog.calllogcache.CallLogCache; // Cache country iso. Used for number filtering. views.countryIso = details.countryIso; + + views.updatePhoto(); } /** diff --git a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java index baf2e1ab5..858cc2102 100644 --- a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java +++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java @@ -54,18 +54,14 @@ import com.android.dialer.calllog.calllogcache.CallLogCache; import com.android.dialer.compat.FilteredNumberCompat; import com.android.dialer.database.FilteredNumberAsyncQueryHandler; import com.android.dialer.filterednumber.BlockNumberDialogFragment; +import com.android.dialer.filterednumber.BlockedNumbersMigrator; import com.android.dialer.filterednumber.FilteredNumbersUtil; import com.android.dialer.logging.Logger; import com.android.dialer.logging.ScreenEvent; -import com.android.dialer.service.ExtendedBlockingButtonRenderer; import com.android.dialer.util.DialerUtils; import com.android.dialer.util.PhoneNumberUtil; import com.android.dialer.voicemail.VoicemailPlaybackLayout; import com.android.dialer.voicemail.VoicemailPlaybackPresenter; -import com.android.dialerbind.ObjectFactory; -import com.google.common.collect.Lists; - -import java.util.List; /** * This is an object containing references to views contained by the call log list item. This @@ -77,6 +73,15 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, MenuItem.OnMenuItemClickListener, View.OnCreateContextMenuListener { + public interface OnClickListener { + void onBlockReportSpam( + String displayNumber, String number, String countryIso, int callType); + void onBlock(String displayNumber, String number, String countryIso, int callType); + void onUnblock(String displayNumber, String number, String countryIso, Integer blockId, + boolean isSpam, int callType); + void onReportNotSpam(String displayNumber, String number, String countryIso, int callType); + } + /** The root view of the call log list item */ public final View rootView; /** The quick contact badge for the contact. */ @@ -101,6 +106,10 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder public View createNewContactButtonView; public View addToExistingContactButtonView; public View sendMessageView; + public View blockReportView; + public View blockView; + public View unblockView; + public View reportNotSpamView; public View detailsButtonView; public View callWithNoteButtonView; public ImageView workIconView; @@ -198,9 +207,14 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder public ContactInfo info; /** - * Whether the current log entry is a blocked number or not. Used in updatePhoto() + * Whether spam feature is enabled, which affects UI. + */ + public boolean isSpamFeatureEnabled; + + /** + * Whether the current log entry is a spam number or not. */ - public boolean isBlocked; + public boolean isSpam; /** * Whether this is the archive tab or not. @@ -212,19 +226,18 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder private final CallLogListItemHelper mCallLogListItemHelper; private final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter; private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler; + private final OnClickListener mBlockReportListener; private final BlockNumberDialogFragment.Callback mFilteredNumberDialogCallback; private final int mPhotoSize; - private ViewStub mExtendedBlockingViewStub; - private final ExtendedBlockingButtonRenderer mExtendedBlockingButtonRenderer; private View.OnClickListener mExpandCollapseListener; private boolean mVoicemailPrimaryActionButtonClicked; private CallLogListItemViewHolder( Context context, - ExtendedBlockingButtonRenderer.Listener eventListener, + OnClickListener blockReportListener, View.OnClickListener expandCollapseListener, CallLogCache callLogCache, CallLogListItemHelper callLogListItemHelper, @@ -248,6 +261,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder mVoicemailPlaybackPresenter = voicemailPlaybackPresenter; mFilteredNumberAsyncQueryHandler = filteredNumberAsyncQueryHandler; mFilteredNumberDialogCallback = filteredNumberDialogCallback; + mBlockReportListener = blockReportListener; this.rootView = rootView; this.quickContactView = quickContactView; @@ -272,14 +286,12 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder primaryActionButtonView.setOnClickListener(this); primaryActionView.setOnClickListener(mExpandCollapseListener); primaryActionView.setOnCreateContextMenuListener(this); - mExtendedBlockingButtonRenderer = - ObjectFactory.newExtendedBlockingButtonRenderer(mContext, eventListener); } public static CallLogListItemViewHolder create( View view, Context context, - ExtendedBlockingButtonRenderer.Listener eventListener, + OnClickListener blockReportListener, View.OnClickListener expandCollapseListener, CallLogCache callLogCache, CallLogListItemHelper callLogListItemHelper, @@ -290,7 +302,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder return new CallLogListItemViewHolder( context, - eventListener, + blockReportListener, expandCollapseListener, callLogCache, callLogListItemHelper, @@ -428,14 +440,23 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder sendMessageView = actionsView.findViewById(R.id.send_message_action); sendMessageView.setOnClickListener(this); + blockReportView = actionsView.findViewById(R.id.block_report_action); + blockReportView.setOnClickListener(this); + + blockView = actionsView.findViewById(R.id.block_action); + blockView.setOnClickListener(this); + + unblockView = actionsView.findViewById(R.id.unblock_action); + unblockView.setOnClickListener(this); + + reportNotSpamView = actionsView.findViewById(R.id.report_not_spam_action); + reportNotSpamView.setOnClickListener(this); + detailsButtonView = actionsView.findViewById(R.id.details_action); detailsButtonView.setOnClickListener(this); callWithNoteButtonView = actionsView.findViewById(R.id.call_with_note_action); callWithNoteButtonView.setOnClickListener(this); - - mExtendedBlockingViewStub = - (ViewStub) actionsView.findViewById(R.id.extended_blocking_actions_container); } bindActionButtons(); @@ -568,32 +589,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder callWithNoteButtonView.setVisibility( supportsCallSubject && !isVoicemailNumber ? View.VISIBLE : View.GONE); - if(mExtendedBlockingButtonRenderer != null){ - List<View> completeLogListItems = Lists.newArrayList( - createNewContactButtonView, - addToExistingContactButtonView, - sendMessageView, - callButtonView, - callWithNoteButtonView, - detailsButtonView, - voicemailPlaybackView); - - List<View> blockedNumberVisibleViews = Lists.newArrayList(detailsButtonView); - List<View> extendedBlockingVisibleViews = Lists.newArrayList(detailsButtonView); - - ExtendedBlockingButtonRenderer.ViewHolderInfo viewHolderInfo = - new ExtendedBlockingButtonRenderer.ViewHolderInfo( - completeLogListItems, - extendedBlockingVisibleViews, - blockedNumberVisibleViews, - number, - countryIso, - nameOrNumber.toString(), - displayNumber); - mExtendedBlockingButtonRenderer.setViewHolderInfo(viewHolderInfo); - - mExtendedBlockingButtonRenderer.render(mExtendedBlockingViewStub); - } + updateBlockReportActions(); } /** @@ -635,6 +631,11 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder } public void updatePhoto() { + if (isSpamFeatureEnabled && isSpam) { + quickContactView.setImageDrawable( + mContext.getDrawable(R.drawable.blocked_contact)); + return; + } quickContactView.assignContactUri(info.lookupUri); final boolean isVoicemail = mCallLogCache.isVoicemailNumber(accountHandle, number); @@ -658,14 +659,6 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder ContactPhotoManager.getInstance(mContext).loadThumbnail(quickContactView, info.photoId, false /* darkTheme */, true /* isCircular */, request); } - - if (mExtendedBlockingButtonRenderer != null) { - mExtendedBlockingButtonRenderer.updatePhotoAndLabelIfNecessary( - number, - countryIso, - quickContactView, - phoneCallDetailsViews.callLocationAndDate); - } } @Override @@ -686,6 +679,26 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder view in dialog. */ numberType, /* phone number type (e.g. mobile) in second line of contact view */ accountHandle); + } else if (view.getId() == R.id.block_report_action) { + maybeShowBlockNumberMigrationDialog(new BlockedNumbersMigrator.Listener() { + @Override + public void onComplete() { + mBlockReportListener.onBlockReportSpam( + displayNumber, number, countryIso, callType); + } + }); + } else if (view.getId() == R.id.block_action) { + maybeShowBlockNumberMigrationDialog(new BlockedNumbersMigrator.Listener() { + @Override + public void onComplete() { + mBlockReportListener.onBlock(displayNumber, number, countryIso, callType); + } + }); + } else if (view.getId() == R.id.unblock_action) { + mBlockReportListener.onUnblock( + displayNumber, number, countryIso, blockId, isSpam, callType); + } else if (view.getId() == R.id.report_not_spam_action) { + mBlockReportListener.onReportNotSpam(displayNumber, number, countryIso, callType); } else { final IntentProvider intentProvider = (IntentProvider) view.getTag(); if (intentProvider != null) { @@ -698,6 +711,14 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder } } + private void maybeShowBlockNumberMigrationDialog(BlockedNumbersMigrator.Listener listener) { + if (!FilteredNumberCompat.maybeShowBlockNumberMigrationDialog( + mContext.getContentResolver(), + ((Activity) mContext).getFragmentManager(), listener)) { + listener.onComplete(); + } + } + @NeededForTesting public static CallLogListItemViewHolder createForTest(Context context) { Resources resources = context.getResources(); @@ -729,4 +750,27 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder viewHolder.workIconView = new ImageButton(context); return viewHolder; } + + private void updateBlockReportActions() { + if (!isSpamFeatureEnabled) { + return; + } + // Set block/spam actions. + blockReportView.setVisibility(View.GONE); + blockView.setVisibility(View.GONE); + unblockView.setVisibility(View.GONE); + reportNotSpamView.setVisibility(View.GONE); + boolean isBlocked = blockId != null; + if (isBlocked) { + unblockView.setVisibility(View.VISIBLE); + } else { + if (isSpam) { + blockView.setVisibility(View.VISIBLE); + reportNotSpamView.setVisibility(View.VISIBLE); + } else { + blockReportView.setVisibility(View.VISIBLE); + } + } + + } }
\ No newline at end of file diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java index b0ef0abf4..d9898ab94 100644 --- a/src/com/android/dialer/calllog/ContactInfoHelper.java +++ b/src/com/android/dialer/calllog/ContactInfoHelper.java @@ -14,6 +14,8 @@ package com.android.dialer.calllog; +import com.google.common.primitives.Longs; + import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -33,6 +35,7 @@ import android.util.Log; import com.android.contacts.common.ContactsUtils; import com.android.contacts.common.ContactsUtils.UserType; import com.android.contacts.common.compat.CompatUtils; +import com.android.contacts.common.compat.DirectoryCompat; import com.android.contacts.common.util.Constants; import com.android.contacts.common.util.PermissionsUtil; import com.android.contacts.common.util.PhoneNumberHelper; @@ -163,6 +166,9 @@ public class ContactInfoHelper { return ContactInfo.EMPTY; } + final String directory = uri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY); + final Long directoryId = directory == null ? null : Longs.tryParse(directory); + Cursor phoneLookupCursor = null; try { String[] projection = PhoneQuery.getPhoneLookupProjection(uri); @@ -183,7 +189,7 @@ public class ContactInfoHelper { String lookupKey = phoneLookupCursor.getString(PhoneQuery.LOOKUP_KEY); ContactInfo contactInfo = createPhoneLookupContactInfo(phoneLookupCursor, lookupKey); contactInfo.nameAlternative = lookUpDisplayNameAlternative(mContext, lookupKey, - contactInfo.userType); + contactInfo.userType, directoryId); return contactInfo; } finally { phoneLookupCursor.close(); @@ -210,11 +216,24 @@ public class ContactInfoHelper { } public static String lookUpDisplayNameAlternative(Context context, String lookupKey, - @UserType long userType) { + @UserType long userType, @Nullable Long directoryId) { // Query {@link Contacts#CONTENT_LOOKUP_URI} directly with work lookup key is not allowed. if (lookupKey == null || userType == ContactsUtils.USER_TYPE_WORK) { return null; } + + if (directoryId != null) { + // Query {@link Contacts#CONTENT_LOOKUP_URI} with work lookup key is not allowed. + if (DirectoryCompat.isEnterpriseDirectoryId(directoryId)) { + return null; + } + + // Skip this to avoid an extra remote network call for alternative name + if (DirectoryCompat.isRemoteDirectoryId(directoryId)) { + return null; + } + } + final Uri uri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey); Cursor cursor = null; try { @@ -226,6 +245,7 @@ public class ContactInfoHelper { } } catch (IllegalArgumentException e) { // Avoid dialer crash when lookup key is not valid + Log.e(TAG, "IllegalArgumentException in lookUpDisplayNameAlternative", e); } finally { if (cursor != null) { cursor.close(); diff --git a/src/com/android/dialer/calllog/MissedCallNotifier.java b/src/com/android/dialer/calllog/MissedCallNotifier.java index f6830168b..a879c6fa0 100644 --- a/src/com/android/dialer/calllog/MissedCallNotifier.java +++ b/src/com/android/dialer/calllog/MissedCallNotifier.java @@ -96,6 +96,7 @@ public class MissedCallNotifier { boolean useCallLog = newCalls != null && newCalls.size() == count; NewCall newestCall = useCallLog ? newCalls.get(0) : null; long timeMs = useCallLog ? newestCall.dateMs : System.currentTimeMillis(); + String missedNumber = useCallLog ? newestCall.number : number; Notification.Builder builder = new Notification.Builder(mContext); // Display the first line of the notification: @@ -104,7 +105,7 @@ public class MissedCallNotifier { if (count == 1) { //TODO: look up caller ID that is not in contacts. ContactInfo contactInfo = CallLogNotificationsHelper.getInstance(mContext) - .getContactInfo(useCallLog ? newestCall.number : number, + .getContactInfo(missedNumber, useCallLog ? newestCall.numberPresentation : Calls.PRESENTATION_ALLOWED, useCallLog ? newestCall.countryIso : null); @@ -156,17 +157,17 @@ public class MissedCallNotifier { // Add additional actions when there is only 1 missed call and the user isn't locked if (UserManagerCompat.isUserUnlocked(mContext) && count == 1) { - if (!TextUtils.isEmpty(number) + if (!TextUtils.isEmpty(missedNumber) && !TextUtils.equals( - number, mContext.getString(R.string.handle_restricted))) { + missedNumber, mContext.getString(R.string.handle_restricted))) { builder.addAction(R.drawable.ic_phone_24dp, mContext.getString(R.string.notification_missedCall_call_back), - createCallBackPendingIntent(number)); + createCallBackPendingIntent(missedNumber)); - if (!PhoneNumberHelper.isUriNumber(number)) { + if (!PhoneNumberHelper.isUriNumber(missedNumber)) { builder.addAction(R.drawable.ic_message_24dp, mContext.getString(R.string.notification_missedCall_message), - createSendSmsFromNotificationPendingIntent(number)); + createSendSmsFromNotificationPendingIntent(missedNumber)); } } } diff --git a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java index 4f1c45503..53121614c 100644 --- a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java +++ b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java @@ -324,6 +324,11 @@ public class PhoneCallDetailsHelper { /** Sets the call count, date, and if it is a voicemail, sets the duration. */ private void setDetailText(PhoneCallDetailsViews views, Integer callCount, PhoneCallDetails details) { + if (details.isSpam) { + views.callLocationAndDate.setText( + mContext.getString(R.string.spam_number_call_log_label)); + return; + } // Combine the count (if present) and the date. CharSequence dateText = getCallLocationAndDate(details); final CharSequence text; @@ -341,7 +346,6 @@ public class PhoneCallDetailsHelper { } else { views.callLocationAndDate.setText(text); } - } private String getVoicemailDuration(PhoneCallDetails details) { diff --git a/src/com/android/dialer/compat/FilteredNumberCompat.java b/src/com/android/dialer/compat/FilteredNumberCompat.java index 008782d86..8d8e9a2a5 100644 --- a/src/com/android/dialer/compat/FilteredNumberCompat.java +++ b/src/com/android/dialer/compat/FilteredNumberCompat.java @@ -247,6 +247,27 @@ public class FilteredNumberCompat { } /** + * Shows block number migration dialog if necessary. + * + * @param fragmentManager The {@link FragmentManager} used to show fragments. + * @param listener The {@link BlockedNumbersMigrator.Listener} to call when migration is + * complete. + * @return boolean True if migration dialog is shown. + */ + public static boolean maybeShowBlockNumberMigrationDialog( + ContentResolver contentResolver, FragmentManager fragmentManager, + BlockedNumbersMigrator.Listener listener) { + if (shouldShowMigrationDialog(true)) { + Log.i(TAG, "maybeShowBlockNumberMigrationDialog - showing migration dialog"); + MigrateBlockedNumbersDialogFragment + .newInstance(new BlockedNumbersMigrator(contentResolver), listener) + .show(fragmentManager, "MigrateBlockedNumbers"); + return true; + } + return false; + } + + /** * Shows the flow of {@link android.app.DialogFragment}s for blocking or unblocking numbers. * * @param blockId The id into the blocked numbers database. diff --git a/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java b/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java index 498b10a45..35d6f8d25 100644 --- a/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java +++ b/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java @@ -32,6 +32,7 @@ import android.text.TextUtils; import android.widget.Toast; import com.android.contacts.common.testing.NeededForTesting; +import com.android.contacts.common.util.PermissionsUtil; import com.android.dialer.R; import com.android.dialer.compat.FilteredNumberCompat; import com.android.dialer.database.FilteredNumberAsyncQueryHandler; @@ -124,7 +125,7 @@ public class FilteredNumbersUtil { final AsyncTask task = new AsyncTask<Object, Void, Boolean>() { @Override public Boolean doInBackground(Object[] params) { - if (context == null) { + if (context == null || !PermissionsUtil.hasContactsPermissions(context)) { return false; } diff --git a/src/com/android/dialer/service/ExtendedBlockingButtonRenderer.java b/src/com/android/dialer/service/ExtendedBlockingButtonRenderer.java deleted file mode 100644 index f8d5ea048..000000000 --- a/src/com/android/dialer/service/ExtendedBlockingButtonRenderer.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2016 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.service; - -import android.support.annotation.Nullable; -import android.view.View; -import android.view.ViewStub; -import android.widget.QuickContactBadge; -import android.widget.TextView; - -import java.util.List; - -/** - * Interface responsible for rendering spam buttons. - */ -public interface ExtendedBlockingButtonRenderer { - - final class ViewHolderInfo { - - public final List<View> completeListItemViews; - public final List<View> extendedBlockedViews; - public final List<View> blockedNumberViews; - public final String phoneNumber; - public final String countryIso; - public final String nameOrNumber; - public final String displayNumber; - - public ViewHolderInfo( - /* All existing views amongst the list item actions, even if invisible */ - List<View> completeListItemViews, - /* Views that should be seen if the number is in the blacklist */ - List<View> extendedBlockedViews, - /* Views that should be seen if the number is in the extended blacklist */ - List<View> blockedNumberViews, - String phoneNumber, - String countryIso, - String nameOrNumber, - String displayNumber) { - - this.completeListItemViews = completeListItemViews; - this.extendedBlockedViews = extendedBlockedViews; - this.blockedNumberViews = blockedNumberViews; - this.phoneNumber = phoneNumber; - this.countryIso = countryIso; - this.nameOrNumber = nameOrNumber; - this.displayNumber = displayNumber; - } - } - - interface Listener { - void onBlockedNumber(String number, @Nullable String countryIso); - void onUnblockedNumber(String number, @Nullable String countryIso); - } - - /** - * Renders buttons for a phone number. - */ - void render(ViewStub viewStub); - - void setViewHolderInfo(ViewHolderInfo info); - - /** - * Updates the photo and label for the given phone number and country iso. - * - * @param number Phone number for which the rendering occurs. - * @param countryIso Two-letter country code. - * @param badge {@link QuickContactBadge} in which the photo should be rendered. - * @param view Textview that will hold the new label. - */ - void updatePhotoAndLabelIfNecessary( - String number, String countryIso, QuickContactBadge badge, TextView view); -} diff --git a/src/com/android/dialer/service/ExtendedCallInfoService.java b/src/com/android/dialer/service/ExtendedCallInfoService.java new file mode 100644 index 000000000..5481cc90d --- /dev/null +++ b/src/com/android/dialer/service/ExtendedCallInfoService.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 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.service; + +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Interface of service to get extended call information. + */ +public interface ExtendedCallInfoService { + /** + * All the possible locations that a user can report a number as spam or not spam. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({REPORTING_LOCATION_UNKNOWN, REPORTING_LOCATION_CALL_LOG_HISTORY, + REPORTING_LOCATION_FEEDBACK_PROMPT}) + @interface ReportingLocation {} + int REPORTING_LOCATION_UNKNOWN = 0; + int REPORTING_LOCATION_CALL_LOG_HISTORY = 1; + int REPORTING_LOCATION_FEEDBACK_PROMPT = 2; + + /** + * Interface for a callback to be invoked when data is fetched. + */ + interface Listener { + /** + * Called when data is fetched. + * @param isSpam True if the call is spam. + */ + void onComplete(boolean isSpam); + } + + /** + * Gets extended call information. + * @param number The phone number of the call. + * @param countryIso The country ISO of the call. + * @param listener The callback to be invoked after {@code Info} is fetched. + */ + void getExtendedCallInfo(String number, String countryIso, Listener listener); + + /** + * Reports number as spam. + * @param number The number to be reported. + * @param countryIso The country ISO of the number. + * @param callType Whether the type of call is missed, voicemail, etc. Example of this is + * {@link android.provider.CallLog.Calls#VOICEMAIL_TYPE}. + * @param from Where in the dialer this was reported from. + * Must be one of {@link ReportingLocation}. + */ + void reportSpam(String number, String countryIso, int callType, @ReportingLocation int from); + + /** + * Reports number as not spam. + * @param number The number to be reported. + * @param countryIso The country ISO of the number. + * @param callType Whether the type of call is missed, voicemail, etc. Example of this is + * {@link android.provider.CallLog.Calls#VOICEMAIL_TYPE}. + * @param from Where in the dialer this was reported from. + * Must be one of {@link ReportingLocation}. + */ + void reportNotSpam(String number, String countryIso, int callType, @ReportingLocation int from); +} diff --git a/src/com/android/dialer/util/BlockReportSpamDialogs.java b/src/com/android/dialer/util/BlockReportSpamDialogs.java new file mode 100644 index 000000000..45b2f4228 --- /dev/null +++ b/src/com/android/dialer/util/BlockReportSpamDialogs.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2016 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.util; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; +import android.widget.CheckBox; +import android.widget.CompoundButton; + +import com.android.dialer.R; + +/** + * Helper class for creating block/report dialog fragments. + */ +public class BlockReportSpamDialogs { + public static final String BLOCK_REPORT_SPAM_DIALOG_TAG = "BlockReportSpamDialog"; + public static final String BLOCK_DIALOG_TAG = "BlockDialog"; + public static final String UNBLOCK_DIALOG_TAG = "UnblockDialog"; + public static final String NOT_SPAM_DIALOG_TAG = "NotSpamDialog"; + + /** + * Listener passed to block/report spam dialog for positive click in + * {@link BlockReportSpamDialogFragment}. + */ + public interface OnSpamDialogClickListener { + /** + * Called when user clicks on positive button in block/report spam dialog. + * @param isSpamChecked Whether the spam checkbox is checked. + */ + void onClick(boolean isSpamChecked); + } + + /** + * Listener passed to all dialogs except the block/report spam dialog for positive click. + */ + public interface OnConfirmListener { + /** + * Called when user clicks on positive button in the dialog. + */ + void onClick(); + } + + /** + * Contains the common attributes between all block/unblock/report dialog fragments. + */ + private static class CommonDialogsFragment extends DialogFragment { + /** + * The number to display in the dialog title. + */ + protected String mDisplayNumber; + + /** + * Called when dialog positive button is pressed. + */ + protected OnConfirmListener mPositiveListener; + + /** + * Called when dialog is dismissed. + */ + @Nullable + protected DialogInterface.OnDismissListener mDismissListener; + + @Override + public void onDismiss(DialogInterface dialog) { + if (mDismissListener != null) { + mDismissListener.onDismiss(dialog); + } + super.onDismiss(dialog); + } + + @Override + public void onPause() { + // The dialog is dismissed onPause, i.e. rotation. + dismiss(); + mDismissListener = null; + mPositiveListener = null; + mDisplayNumber = null; + super.onPause(); + } + } + + /** + * Dialog for block/report spam with the mark as spam checkbox. + */ + public static class BlockReportSpamDialogFragment extends CommonDialogsFragment { + /** + * Called when dialog positive button is pressed. + */ + private OnSpamDialogClickListener mPositiveListener; + + /** + * Whether the mark as spam checkbox is checked before displaying the dialog. + */ + private boolean mSpamChecked; + + public static DialogFragment newInstance(String displayNumber, + boolean spamChecked, + OnSpamDialogClickListener positiveListener, + @Nullable DialogInterface.OnDismissListener + dismissListener) { + BlockReportSpamDialogFragment fragment = new BlockReportSpamDialogFragment(); + fragment.mSpamChecked = spamChecked; + fragment.mDisplayNumber = displayNumber; + fragment.mPositiveListener = positiveListener; + fragment.mDismissListener = dismissListener; + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + super.onCreateDialog(savedInstanceState); + View dialogView = View.inflate(getActivity(), R.layout.block_report_spam_dialog, null); + final CheckBox isSpamCheckbox = + (CheckBox) dialogView.findViewById(R.id.report_number_as_spam_action); + // Listen for changes on the checkbox and update if orientation changes + isSpamCheckbox.setChecked(mSpamChecked); + isSpamCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mSpamChecked = isChecked; + } + }); + + AlertDialog.Builder alertDialogBuilder = createDialogBuilder(getActivity(), this); + Dialog dialog = alertDialogBuilder + .setView(dialogView) + .setTitle(getString(R.string.block_report_number_alert_title, mDisplayNumber)) + .setPositiveButton(R.string.block_number_ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismiss(); + mPositiveListener.onClick(isSpamCheckbox.isChecked()); + } + }).create(); + dialog.setCanceledOnTouchOutside(true); + return dialog; + } + } + + /** + * Dialog for blocking a number. + */ + public static class BlockDialogFragment extends CommonDialogsFragment { + public static DialogFragment newInstance(String displayNumber, + OnConfirmListener positiveListener, + @Nullable DialogInterface.OnDismissListener + dismissListener) { + BlockDialogFragment fragment = new BlockDialogFragment(); + fragment.mDisplayNumber = displayNumber; + fragment.mPositiveListener = positiveListener; + fragment.mDismissListener = dismissListener; + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + super.onCreateDialog(savedInstanceState); + // Return the newly created dialog + AlertDialog.Builder alertDialogBuilder = createDialogBuilder(getActivity(), this); + Dialog dialog = alertDialogBuilder + .setTitle(getString(R.string.block_report_number_alert_title, mDisplayNumber)) + .setPositiveButton(R.string.block_number_ok, + createGenericOnClickListener(this, mPositiveListener)) + .create(); + dialog.setCanceledOnTouchOutside(true); + return dialog; + } + } + + /** + * Dialog for unblocking a number. + */ + public static class UnblockDialogFragment extends CommonDialogsFragment { + /** + * Whether or not the number is spam. + */ + private boolean mIsSpam; + + public static DialogFragment newInstance(String displayNumber, + boolean isSpam, + OnConfirmListener positiveListener, + @Nullable DialogInterface.OnDismissListener + dismissListener) { + UnblockDialogFragment fragment = new UnblockDialogFragment(); + fragment.mDisplayNumber = displayNumber; + fragment.mIsSpam = isSpam; + fragment.mPositiveListener = positiveListener; + fragment.mDismissListener = dismissListener; + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + super.onCreateDialog(savedInstanceState); + // Return the newly created dialog + AlertDialog.Builder alertDialogBuilder = createDialogBuilder(getActivity(), this); + if (mIsSpam) { + alertDialogBuilder.setMessage(R.string.unblock_number_alert_details); + } + Dialog dialog = alertDialogBuilder + .setTitle(getString(R.string.unblock_report_number_alert_title, mDisplayNumber)) + .setPositiveButton(R.string.unblock_number_ok, + createGenericOnClickListener(this, mPositiveListener)) + .create(); + dialog.setCanceledOnTouchOutside(true); + return dialog; + } + } + + /** + * Dialog for reporting a number as not spam. + */ + public static class ReportNotSpamDialogFragment extends CommonDialogsFragment { + public static DialogFragment newInstance(String displayNumber, + OnConfirmListener positiveListener, + @Nullable DialogInterface.OnDismissListener + dismissListener) { + ReportNotSpamDialogFragment fragment = new ReportNotSpamDialogFragment(); + fragment.mDisplayNumber = displayNumber; + fragment.mPositiveListener = positiveListener; + fragment.mDismissListener = dismissListener; + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + super.onCreateDialog(savedInstanceState); + // Return the newly created dialog + AlertDialog.Builder alertDialogBuilder = createDialogBuilder(getActivity(), this); + Dialog dialog = alertDialogBuilder + .setTitle(getString(R.string.report_not_spam_alert_title, mDisplayNumber)) + .setMessage(R.string.report_not_spam_alert_details) + .setPositiveButton(R.string.report_not_spam_alert_button, + createGenericOnClickListener(this, mPositiveListener)) + .create(); + dialog.setCanceledOnTouchOutside(true); + return dialog; + } + } + + /** + * Creates a dialog with the default cancel button listener (dismisses dialog). + */ + private static AlertDialog.Builder createDialogBuilder(Activity activity, + final DialogFragment fragment) { + return new AlertDialog.Builder(activity) + .setCancelable(true) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + fragment.dismiss(); + } + }); + } + + /** + * Creates a generic click listener which dismisses the fragment and then calls the actual + * listener. + */ + private static DialogInterface.OnClickListener createGenericOnClickListener( + final DialogFragment fragment, + final OnConfirmListener listener) { + return new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + fragment.dismiss(); + listener.onClick(); + } + }; + } +} diff --git a/src/com/android/dialer/util/IntentUtil.java b/src/com/android/dialer/util/IntentUtil.java index 5a4a80bb1..581e10da4 100644 --- a/src/com/android/dialer/util/IntentUtil.java +++ b/src/com/android/dialer/util/IntentUtil.java @@ -19,6 +19,7 @@ package com.android.dialer.util; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.os.SystemClock; import android.provider.ContactsContract; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; @@ -37,6 +38,8 @@ public class IntentUtil { public static final String EXTRA_CALL_INITIATION_TYPE = "com.android.dialer.EXTRA_CALL_INITIATION_TYPE"; + public static final String EXTRA_CALL_CREATED_TIME_MILLIS = + "android.telecom.extra.CALL_CREATED_TIME_MILLIS"; public static class CallIntentBuilder { private Uri mUri; @@ -91,6 +94,7 @@ public class IntentUtil { intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); final Bundle b = new Bundle(); + b.putLong(EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime()); b.putInt(EXTRA_CALL_INITIATION_TYPE, callIntiationType); intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, b); diff --git a/src/com/android/dialerbind/ObjectFactory.java b/src/com/android/dialerbind/ObjectFactory.java index 303610f30..342f39cb9 100644 --- a/src/com/android/dialerbind/ObjectFactory.java +++ b/src/com/android/dialerbind/ObjectFactory.java @@ -26,7 +26,7 @@ import com.android.dialer.calllog.ContactInfoHelper; import com.android.dialer.list.RegularSearchFragment; import com.android.dialer.logging.Logger; import com.android.dialer.service.CachedNumberLookupService; -import com.android.dialer.service.ExtendedBlockingButtonRenderer; +import com.android.dialer.service.ExtendedCallInfoService; import com.android.dialer.voicemail.VoicemailPlaybackPresenter; /** @@ -60,8 +60,7 @@ public class ObjectFactory { } @Nullable - public static ExtendedBlockingButtonRenderer newExtendedBlockingButtonRenderer( - Context context, ExtendedBlockingButtonRenderer.Listener listener) { + public static ExtendedCallInfoService newExtendedCallInfoService(Context context) { return null; } |