Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d0847ca authored by Andrew Lee's avatar Andrew Lee
Browse files

Polish call blocking rotation/undo behaviors.

+ Correctly dismiss filtered number dialog on rotate.
+ Polish listener interface, and extend across all block/unblock
and undo scenarios.
+ Update UI across all blocking scenarios (call log, call detail,
settings, blocked number list, blocked number search);
+ Conslidate creation of FilterNumberDialogFragment in a single
static method.

The listener interface is not ideal, because it does not maintain
state well across rotation and multiple instances. This option was
selected, however, because of the number of scenarios in which
the dialog is invoked and various circumstances (in a RecyclerView
list item, in a fragment, in an activity). This range of scenarios
makes it convoluted to implement a uniform mechanism in any other
way, so the approach opted for is to set a listener, and dismiss
the dialog on rotation..

Bug: 24638328
Bug: 24109819
Bug: 24871853
Change-Id: I2332edda2cae0341af3e80b13aa96af6068f75ac
parent 6988a32f
Loading
Loading
Loading
Loading
+20 −23
Original line number Diff line number Diff line
@@ -71,8 +71,7 @@ import com.android.incallui.Call.LogState;
 */
public class CallDetailActivity extends AppCompatActivity
        implements MenuItem.OnMenuItemClickListener, View.OnClickListener,
                FilterNumberDialogFragment.OnBlockListener,
                FilterNumberDialogFragment.OnUndoBlockListener {
                FilterNumberDialogFragment.Callback {
    private static final String TAG = CallDetailActivity.class.getSimpleName();

     /** A long array extra containing ids of call log entries to display. */
@@ -304,16 +303,6 @@ public class CallDetailActivity extends AppCompatActivity
        getCallDetails();
    }

    @Override
    public void onBlockComplete(Uri uri) {
        updateBlockActionItem();
    }

    @Override
    public void onUndoBlockComplete() {
        updateBlockActionItem();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -406,17 +395,15 @@ public class CallDetailActivity extends AppCompatActivity
    public void onClick(View view) {
        switch(view.getId()) {
            case R.id.call_detail_action_block:
                // TODO: Use helper, this code is repeated in several places.
                FilterNumberDialogFragment newFragment =
                        FilterNumberDialogFragment.newInstance(
                                mBlockedNumberId, null, mNumber, null, mDisplayNumber);
                // TODO: Cleanup this listener pattern. This only works correctly for undoing
                // blocking, not undoing unblocking.
                newFragment.setOnBlockListener(this);
                newFragment.setOnUndoBlockListener(this);
                newFragment.setParentView(findViewById(R.id.call_detail));
                newFragment.show(
                        getFragmentManager(), FilterNumberDialogFragment.BLOCK_DIALOG_FRAGMENT);
                FilterNumberDialogFragment.show(
                        mBlockedNumberId,
                        null /* normalizedNumber */,
                        mNumber,
                        null /* countryIso */,
                        mDisplayNumber,
                        R.id.call_detail,
                        getFragmentManager(),
                        this);
                break;
            case R.id.call_detail_action_copy:
                ClipboardUtils.copyText(mContext, null, mNumber, true);
@@ -431,6 +418,16 @@ public class CallDetailActivity extends AppCompatActivity
        }
    }

    @Override
    public void onChangeFilteredNumberSuccess() {
        updateBlockActionItem();
    }

    @Override
    public void onChangeFilteredNumberUndo() {
        updateBlockActionItem();
    }

    private void updateBlockActionItem() {
        if (mDetails == null) {
            return;
+17 −2
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.dialer.contactinfo.ContactInfoCache.OnContactInfoChangedListe
import com.android.dialer.contactinfo.NumberWithCountryIso;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener;
import com.android.dialer.filterednumber.FilterNumberDialogFragment;
import com.android.dialer.util.PhoneNumberUtil;
import com.android.dialer.voicemail.VoicemailPlaybackPresenter;

@@ -60,7 +61,8 @@ import java.util.Map;
 */
public class CallLogAdapter extends GroupingListAdapter
        implements CallLogGroupBuilder.GroupCreator,
                VoicemailPlaybackPresenter.OnVoicemailDeletedListener {
                VoicemailPlaybackPresenter.OnVoicemailDeletedListener,
                FilterNumberDialogFragment.Callback {

    /** Interface used to initiate a refresh of the content. */
    public interface CallFetcher {
@@ -352,7 +354,8 @@ public class CallLogAdapter extends GroupingListAdapter
                mTelecomCallLogCache,
                mCallLogListItemHelper,
                mVoicemailPlaybackPresenter,
                mFilteredNumberAsyncQueryHandler);
                mFilteredNumberAsyncQueryHandler,
                this);

        viewHolder.callLogEntryView.setTag(viewHolder);
        viewHolder.callLogEntryView.setAccessibilityDelegate(mAccessibilityDelegate);
@@ -627,6 +630,18 @@ public class CallLogAdapter extends GroupingListAdapter
        }
    }

    @Override
    public void onChangeFilteredNumberSuccess() {
        mBlockedIdCache.clear();
        notifyDataSetChanged();
    }

    @Override
    public void onChangeFilteredNumberUndo() {
        mBlockedIdCache.clear();
        notifyDataSetChanged();
    }

    /**
     * Retrieves the day group of the previous call in the call log.  Used to determine if the day
     * group has changed and to trigger display of the day group text.
+18 −10
Original line number Diff line number Diff line
@@ -182,6 +182,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
    private final CallLogListItemHelper mCallLogListItemHelper;
    private final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter;
    private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
    private final FilterNumberDialogFragment.Callback mFilteredNumberDialogCallback;

    private final int mPhotoSize;

@@ -195,6 +196,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
            CallLogListItemHelper callLogListItemHelper,
            VoicemailPlaybackPresenter voicemailPlaybackPresenter,
            FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
            FilterNumberDialogFragment.Callback filteredNumberDialogCallback,
            View rootView,
            QuickContactBadge quickContactView,
            View primaryActionView,
@@ -210,6 +212,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
        mCallLogListItemHelper = callLogListItemHelper;
        mVoicemailPlaybackPresenter = voicemailPlaybackPresenter;
        mFilteredNumberAsyncQueryHandler = filteredNumberAsyncQueryHandler;
        mFilteredNumberDialogCallback = filteredNumberDialogCallback;

        this.rootView = rootView;
        this.quickContactView = quickContactView;
@@ -226,6 +229,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
        phoneCallDetailsViews.nameView.setElegantTextHeight(false);
        phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false);

        quickContactView.setOverlay(null);
        quickContactView.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);

        primaryActionButtonView.setOnClickListener(this);
@@ -240,7 +244,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
            TelecomCallLogCache telecomCallLogCache,
            CallLogListItemHelper callLogListItemHelper,
            VoicemailPlaybackPresenter voicemailPlaybackPresenter,
            FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler) {
            FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
            FilterNumberDialogFragment.Callback filteredNumberDialogCallback) {

        return new CallLogListItemViewHolder(
                context,
@@ -249,6 +254,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
                callLogListItemHelper,
                voicemailPlaybackPresenter,
                filteredNumberAsyncQueryHandler,
                filteredNumberDialogCallback,
                view,
                (QuickContactBadge) view.findViewById(R.id.quick_contact_photo),
                view.findViewById(R.id.primary_action_view),
@@ -317,13 +323,15 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.context_menu_block_number:
                FilterNumberDialogFragment newFragment =
                        FilterNumberDialogFragment.newInstance(blockId, info.normalizedNumber,
                                number, countryIso, displayNumber);
                newFragment.setParentView(
                        ((Activity) mContext).findViewById(R.id.floating_action_button_container));
                newFragment.show(((Activity) mContext).getFragmentManager(),
                        FilterNumberDialogFragment.BLOCK_DIALOG_FRAGMENT);
                FilterNumberDialogFragment.show(
                        blockId,
                        info.normalizedNumber,
                        number,
                        countryIso,
                        displayNumber,
                        R.id.floating_action_button_container,
                        ((Activity) mContext).getFragmentManager(),
                        mFilteredNumberDialogCallback);
                return true;
            case R.id.context_menu_copy_to_clipboard:
                ClipboardUtils.copyText(mContext, null, number, true);
@@ -542,7 +550,6 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
    }

    public void updatePhoto() {
        quickContactView.setOverlay(null);
        quickContactView.assignContactUri(info.lookupUri);

        if (blockId != null) {
@@ -617,6 +624,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
                new CallLogListItemHelper(phoneCallDetailsHelper, resources, telecomCallLogCache),
                null /* voicemailPlaybackPresenter */,
                null /* filteredNumberAsyncQueryHandler */,
                null /* filteredNumberDialogCallback */,
                new View(context),
                new QuickContactBadge(context),
                new View(context),
+9 −7
Original line number Diff line number Diff line
@@ -81,13 +81,15 @@ public class BlockedNumberAdapter extends SimpleCursorAdapter {
        deleteNumber.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FilterNumberDialogFragment newFragment =
                        FilterNumberDialogFragment.newInstance(id, normalizedNumber, number,
                                countryIso, displayNumber);
                newFragment.setParentView(
                        ((Activity) mContext).findViewById(R.id.blocked_number_fragment));
                newFragment.show(((Activity) mContext).getFragmentManager(),
                        FilterNumberDialogFragment.BLOCK_DIALOG_FRAGMENT);
                FilterNumberDialogFragment.show(
                        id,
                        normalizedNumber,
                        number,
                        countryIso,
                        displayNumber,
                        R.id.blocked_number_fragment,
                        ((Activity) mContext).getFragmentManager(),
                        null /* callback */);
            }
        });

+116 −81
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.dialer.filterednumber;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.res.Resources;
@@ -33,53 +34,65 @@ import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnBlockNumber
import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnUnblockNumberListener;

public class FilterNumberDialogFragment extends DialogFragment {
    public static final String BLOCK_DIALOG_FRAGMENT = "blockUnblockNumberDialog";

    /**
     * Use a callback interface to update UI after success/undo. Favor this approach over other
     * more standard paradigms because of the variety of scenarios in which the DialogFragment
     * can be invoked (by an Activity, by a fragment, by an adapter, by an adapter list item).
     * Because of this, we do NOT support retaining state on rotation, and will dismiss the dialog
     * upon rotation instead.
     */
    public interface Callback {
        public void onChangeFilteredNumberSuccess();
        public void onChangeFilteredNumberUndo();
    }

    private static final String BLOCK_DIALOG_FRAGMENT = "blockUnblockNumberDialog";

    private static final String ARG_BLOCK_ID = "argBlockId";
    private static final String ARG_NORMALIZED_NUMBER = "argNormalizedNumber";
    private static final String ARG_NUMBER = "argNumber";
    private static final String ARG_COUNTRY_ISO = "argCountryIso";
    private static final String ARG_DISPLAY_NUMBER = "argDisplayNumber";
    private static final String ARG_PARENT_VIEW_ID = "parentViewId";

    private String mDisplayNumber;

    private FilteredNumberAsyncQueryHandler mHandler;
    private View mParentView;
    private OnBlockListener mOnBlockListener;
    private OnUndoBlockListener mOnUndoBlockListener;

    public interface OnBlockListener {
        /**
         * Invoked after inserting a blocked number.
         * @param uri The uri of the newly created row.
         */
        public void onBlockComplete(Uri uri);
    }

    public interface OnUndoBlockListener {
        /**
         * Invoked on undoing the blocking of a number.
         */
        public void onUndoBlockComplete();
    }

    public void setParentView(View view) {
        mParentView = view;
    }

    public void setOnBlockListener(OnBlockListener listener) {
        mOnBlockListener = listener;
    }

    public void setOnUndoBlockListener(OnUndoBlockListener listener) {
        mOnUndoBlockListener = listener;
    }

    public static FilterNumberDialogFragment newInstance(Integer blockId, String normalizedNumber,
        String number, String countryIso, String displayNumber) {
    private Callback mCallback;

    public static void show(
            Integer blockId,
            String normalizedNumber,
            String number,
            String countryIso,
            String displayNumber,
            Integer parentViewId,
            FragmentManager fragmentManager,
            Callback callback) {
        final FilterNumberDialogFragment newFragment = FilterNumberDialogFragment.newInstance(
                blockId, normalizedNumber, number, countryIso, displayNumber, parentViewId);

        newFragment.setCallback(callback);
        newFragment.show(fragmentManager, FilterNumberDialogFragment.BLOCK_DIALOG_FRAGMENT);
    }

    private static FilterNumberDialogFragment newInstance(
            Integer blockId,
            String normalizedNumber,
            String number,
            String countryIso,
            String displayNumber,
            Integer parentViewId) {
        final FilterNumberDialogFragment fragment = new FilterNumberDialogFragment();
        final Bundle args = new Bundle();
        if (blockId != null) {
            args.putInt(ARG_BLOCK_ID, blockId.intValue());
        }
        if (parentViewId != null) {
            args.putInt(ARG_PARENT_VIEW_ID, parentViewId.intValue());
        }
        args.putString(ARG_NORMALIZED_NUMBER, normalizedNumber);
        args.putString(ARG_NUMBER, number);
        args.putString(ARG_COUNTRY_ISO, countryIso);
@@ -92,17 +105,18 @@ public class FilterNumberDialogFragment extends DialogFragment {
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        super.onCreateDialog(savedInstanceState);
        final boolean isBlocked = getArguments().containsKey(ARG_BLOCK_ID);
        final String displayNumber = getArguments().getString(ARG_DISPLAY_NUMBER);
        mDisplayNumber = getArguments().getString(ARG_DISPLAY_NUMBER);

        mHandler = new FilteredNumberAsyncQueryHandler(getContext().getContentResolver());
        mParentView = getActivity().findViewById(getArguments().getInt(ARG_PARENT_VIEW_ID));

        String message;
        String okText;
        if (isBlocked) {
            message = getString(R.string.unblockNumberConfirmation, displayNumber);
            message = getString(R.string.unblockNumberConfirmation, mDisplayNumber);
            okText = getString(R.string.unblockNumberOk);
        } else {
            message = getString(R.string.blockNumberConfirmation, displayNumber);
            message = getString(R.string.blockNumberConfirmation, mDisplayNumber);
            okText = getString(R.string.blockNumberOk);
        }

@@ -122,79 +136,100 @@ public class FilterNumberDialogFragment extends DialogFragment {
    }

    @Override
    public void onDestroy() {
        this.dismissAllowingStateLoss();
        super.onDestroy();
    public void onPause() {
        // Dismiss on rotation.
        dismiss();
        mCallback = null;

        super.onPause();
    }

    public void setCallback(Callback callback) {
        mCallback = callback;
    }

    private String getBlockedMessage(String displayNumber) {
        return getString(R.string.snackbar_number_blocked, displayNumber);
    private String getBlockedMessage() {
        return getString(R.string.snackbar_number_blocked, mDisplayNumber);
    }

    private String getUnblockedMessage(String displayNumber) {
        return getString(R.string.snackbar_number_unblocked, displayNumber);
    private String getUnblockedMessage() {
        return getString(R.string.snackbar_number_unblocked, mDisplayNumber);
    }

    private void blockNumber() {
        final String displayNumber = getArguments().getString(ARG_DISPLAY_NUMBER);
        final String message = getBlockedMessage(displayNumber);
        final String undoMessage = getUnblockedMessage(displayNumber);
        final String message = getBlockedMessage();
        final String undoMessage = getUnblockedMessage();

        final OnUnblockNumberListener onUndoListener = new OnUnblockNumberListener() {
            @Override
            public void onUnblockComplete(int rows, ContentValues values) {
                Snackbar.make(mParentView, undoMessage, Snackbar.LENGTH_LONG).show();
                if (mOnUndoBlockListener != null) {
                    mOnUndoBlockListener.onUndoBlockComplete();
                if (mCallback != null) {
                    mCallback.onChangeFilteredNumberUndo();
                }
            }
        };

        final OnBlockNumberListener onBlockNumberListener = new OnBlockNumberListener() {
            @Override
            public void onBlockComplete(final Uri uri) {
                Snackbar.make(mParentView, message, Snackbar.LENGTH_LONG)
                        .setAction(R.string.block_number_undo,
                                // Delete the newly created row on 'undo'.
                                new View.OnClickListener() {
                final View.OnClickListener undoListener = new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        // Delete the newly created row on 'undo'.
                        mHandler.unblock(onUndoListener, uri);
                    }
                                })
                };

                Snackbar.make(mParentView, message, Snackbar.LENGTH_LONG)
                        .setAction(R.string.block_number_undo, undoListener)
                        .show();
                if (mOnBlockListener != null) {
                    mOnBlockListener.onBlockComplete(uri);

                if (mCallback != null) {
                    mCallback.onChangeFilteredNumberSuccess();
                }
            }
        };
        mHandler.blockNumber(onBlockNumberListener, getArguments().getString(ARG_NORMALIZED_NUMBER),
                getArguments().getString(ARG_NUMBER), getArguments().getString(ARG_COUNTRY_ISO));

        mHandler.blockNumber(
                onBlockNumberListener,
                getArguments().getString(ARG_NORMALIZED_NUMBER),
                getArguments().getString(ARG_NUMBER),
                getArguments().getString(ARG_COUNTRY_ISO));
    }

    private void unblockNumber() {
        final String displayNumber = getArguments().getString(ARG_DISPLAY_NUMBER);
        final String message = getUnblockedMessage(displayNumber);
        final String undoMessage = getBlockedMessage(displayNumber);
        final OnBlockNumberListener undoListener =
                new OnBlockNumberListener() {
        final String message = getUnblockedMessage();
        final String undoMessage = getBlockedMessage();

        final OnBlockNumberListener onUndoListener = new OnBlockNumberListener() {
            @Override
            public void onBlockComplete(final Uri uri) {
                Snackbar.make(mParentView, undoMessage, Snackbar.LENGTH_LONG).show();
                if (mCallback != null) {
                    mCallback.onChangeFilteredNumberUndo();
                }
            }
        };
        mHandler.unblock(
                new OnUnblockNumberListener() {

        mHandler.unblock(new OnUnblockNumberListener() {
            @Override
            public void onUnblockComplete(int rows, final ContentValues values) {
                        Snackbar.make(mParentView, message, Snackbar.LENGTH_LONG)
                                .setAction(R.string.block_number_undo,
                                        new View.OnClickListener() {
                                            // Re-insert the row on 'undo', with a new ID.
                final View.OnClickListener undoListener = new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                                                mHandler.blockNumber(undoListener, values);
                        // Re-insert the row on 'undo', with a new ID.
                        mHandler.blockNumber(onUndoListener, values);
                    }
                                        })
                };

                Snackbar.make(mParentView, message, Snackbar.LENGTH_LONG)
                        .setAction(R.string.block_number_undo, undoListener)
                        .show();

                if (mCallback != null) {
                    mCallback.onChangeFilteredNumberSuccess();
                }
            }
        }, getArguments().getInt(ARG_BLOCK_ID));
    }
Loading