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

Commit 001d9740 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Use carrier presence when showing the video call icon.

- Removed some unused video assets.
- Added carrier_presence to the ContactLoader queries (this supports
load in the quick contacts view, as well as in the dialer search results).
- In search results (ContactListItemView), moved label before phone
number (per UX).

Bug: 20257833
Change-Id: I838dbf6c58939faab6d36f4afa70587b07f85f63
parent 0d53352b
Loading
Loading
Loading
Loading
+52 −10
Original line number Diff line number Diff line
@@ -40,6 +40,22 @@ import java.util.List;
 */
public class CallUtil {

    /**
     * Indicates that the video calling is not available.
     */
    public static final int VIDEO_CALLING_DISABLED = 0;

    /**
     * Indicates that video calling is enabled, regardless of presence status.
     */
    public static final int VIDEO_CALLING_ENABLED = 1;

    /**
     * Indicates that video calling is enabled, but the availability of video call affordances is
     * determined by the presence status associated with contacts.
     */
    public static final int VIDEO_CALLING_PRESENCE = 2;

    /**
     * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined
     * automatically.
@@ -103,31 +119,57 @@ public class CallUtil {
    }

    /**
     * Determines if one of the call capable phone accounts defined supports video calling.
     * Determines if video calling is available, and if so whether presence checking is available
     * as well.
     *
     * @param context The context.
     * @return {@code true} if one of the call capable phone accounts supports video calling,
     *      {@code false} otherwise.
     * Returns a bitmask with {@link #VIDEO_CALLING_ENABLED} to indicate that video calling is
     * available, and {@link #VIDEO_CALLING_PRESENCE} if presence indication is also available.
     *
     * @param context The context
     * @return A bit-mask describing the current video capabilities.
     */
    public static boolean isVideoEnabled(Context context) {
    public static int getVideoCallingAvailability(Context context) {
        if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)
                || !CompatUtils.isVideoCompatible()) {
            return false;
            return VIDEO_CALLING_DISABLED;
        }
        TelecomManager telecommMgr = (TelecomManager)
                context.getSystemService(Context.TELECOM_SERVICE);
        if (telecommMgr == null) {
            return false;
            return VIDEO_CALLING_DISABLED;
        }

        List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts();
        for (PhoneAccountHandle accountHandle : accountHandles) {
            PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);
            if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
                return true;
            if (account != null) {
                if (account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
                    // Builds prior to N do not have presence support.
                    if (!CompatUtils.isVideoPresenceCompatible()) {
                        return VIDEO_CALLING_ENABLED;
                    }

                    int videoCapabilities = VIDEO_CALLING_ENABLED;
                    if (account.hasCapabilities(
                            PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {
                        videoCapabilities |= VIDEO_CALLING_PRESENCE;
                    }
                    return videoCapabilities;
                }
        return false;
            }
        }
        return VIDEO_CALLING_DISABLED;
    }

    /**
     * Determines if one of the call capable phone accounts defined supports video calling.
     *
     * @param context The context.
     * @return {@code true} if one of the call capable phone accounts supports video calling,
     *      {@code false} otherwise.
     */
    public static boolean isVideoEnabled(Context context) {
        return (getVideoCallingAvailability(context) & VIDEO_CALLING_ENABLED) != 0;
    }

    /**
+11 −0
Original line number Diff line number Diff line
@@ -73,6 +73,17 @@ public final class CompatUtils {
                >= Build.VERSION_CODES.M;
    }

    /**
     * Determines if this version is capable of using presence checking for video calling.
     * Support for video call presence indication is added in SDK 24.
     *
     * @return {@code true} if video presence checking is allowed, {@code false} otherwise.
     */
    public static boolean isVideoPresenceCompatible() {
        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
                > Build.VERSION_CODES.M;
    }

    /**
     * Determines if this version is compatible with call subject. Can also force the version to
     * be lower through SdkVersionOverride.
+149 −20
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.text.SpannableString;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
@@ -82,6 +83,8 @@ import java.util.regex.Pattern;
public class ContactListItemView extends ViewGroup
        implements SelectionBoundsAdjuster {

    private static final String TAG = "ContactListItemView";

    // Style values for layout and appearance
    // The initialized values are defaults if none is provided through xml.
    private int mPreferredHeight = 0;
@@ -94,6 +97,8 @@ public class ContactListItemView extends ViewGroup
    private int mNameTextViewTextSize;
    private int mHeaderWidth;
    private Drawable mActivatedBackgroundDrawable;
    private int mVideoCallIconSize = 32;
    private int mVideoCallIconMargin = 16;

    // Set in onLayout. Represent left and right position of the View on the screen.
    private int mLeftOffset;
@@ -124,6 +129,21 @@ public class ContactListItemView extends ViewGroup
    // Highlighting prefix for names.
    private String mHighlightedPrefix;

    /**
     * Used to notify listeners when a video call icon is clicked.
     */
    private PhoneNumberListAdapter.Listener mPhoneNumberListAdapterListener;

    /**
     * Indicates whether to show the "video call" icon, used to initiate a video call.
     */
    private boolean mShowVideoCallIcon = false;

    /**
     * Indicates whether the view should leave room for the "video call" icon.
     */
    private boolean mSupportVideoCallIcon = false;

    /**
     * Where to put contact photo. This affects the other Views' layout or look-and-feel.
     *
@@ -164,11 +184,10 @@ public class ContactListItemView extends ViewGroup
    private TextView mStatusView;
    private ImageView mPresenceIcon;
    private CheckBox mCheckBox;
    private ImageView mVideoCallIcon;

    private ColorStateList mSecondaryTextColor;



    private int mDefaultPhotoViewSize = 0;
    /**
     * Can be effective even when {@link #mPhotoView} is null, as we want to have horizontal padding
@@ -228,6 +247,7 @@ public class ContactListItemView extends ViewGroup
    /** A helper used to highlight a prefix in a text field. */
    private final TextHighlighter mTextHighlighter;
    private CharSequence mUnknownNameText;
    private int mPosition;

    public ContactListItemView(Context context) {
        super(context);
@@ -237,6 +257,12 @@ public class ContactListItemView extends ViewGroup
        mNumberHighlightSequence = new ArrayList<HighlightSequence>();
    }

    public ContactListItemView(Context context, AttributeSet attrs, boolean supportVideoCallIcon) {
        this(context, attrs);

        mSupportVideoCallIcon = supportVideoCallIcon;
    }

    public ContactListItemView(Context context, AttributeSet attrs) {
        super(context, attrs);

@@ -280,6 +306,13 @@ public class ContactListItemView extends ViewGroup
            mNameTextViewTextSize = (int) a.getDimension(
                    R.styleable.ContactListItemView_list_item_name_text_size,
                    (int) getResources().getDimension(R.dimen.contact_browser_list_item_text_size));
            mVideoCallIconSize = a.getDimensionPixelOffset(
                    R.styleable.ContactListItemView_list_item_video_call_icon_size,
                    mVideoCallIconSize);
            mVideoCallIconMargin = a.getDimensionPixelOffset(
                    R.styleable.ContactListItemView_list_item_video_call_icon_margin,
                    mVideoCallIconMargin);


            setPaddingRelative(
                    a.getDimensionPixelOffset(
@@ -323,6 +356,59 @@ public class ContactListItemView extends ViewGroup
        mQuickContactEnabled = flag;
    }

    /**
     * Sets whether the video calling icon is shown.  For the video calling icon to be shown,
     * {@link #mSupportVideoCallIcon} must be {@code true}.
     *
     * @param showVideoCallIcon {@code true} if the video calling icon is shown, {@code false}
     *      otherwise.
     * @param listener Listener to notify when the video calling icon is clicked.
     * @param position The position in the adapater of the video calling icon.
     */
    public void setShowVideoCallIcon(boolean showVideoCallIcon,
            PhoneNumberListAdapter.Listener listener, int position) {
        mShowVideoCallIcon = showVideoCallIcon;
        mPhoneNumberListAdapterListener = listener;
        mPosition = position;

        if (mShowVideoCallIcon) {
            if (mVideoCallIcon == null) {
                mVideoCallIcon = new ImageView(getContext());
                addView(mVideoCallIcon);
            }
            mVideoCallIcon.setContentDescription(getContext().getString(
                    R.string.description_search_video_call));
            mVideoCallIcon.setImageResource(R.drawable.ic_search_video_call);
            mVideoCallIcon.setScaleType(ScaleType.CENTER);
            mVideoCallIcon.setVisibility(View.VISIBLE);
            mVideoCallIcon.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Inform the adapter that the video calling icon was clicked.
                    if (mPhoneNumberListAdapterListener != null) {
                        mPhoneNumberListAdapterListener.onVideoCallIconClicked(mPosition);
                    }
                }
            });
        } else {
            if (mVideoCallIcon != null) {
                mVideoCallIcon.setVisibility(View.GONE);
            }
        }
    }

    /**
     * Sets whether the view supports a video calling icon.  This is independent of whether the view
     * is actually showing an icon.  Support for the video calling icon ensures that the layout
     * leaves space for the video icon, should it be shown.
     *
     * @param supportVideoCallIcon {@code true} if the video call icon is supported, {@code false}
     *      otherwise.
     */
    public void setSupportVideoCallIcon(boolean supportVideoCallIcon) {
        mSupportVideoCallIcon = supportVideoCallIcon;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // We will match parent's width and wrap content vertically, but make sure
@@ -356,6 +442,10 @@ public class ContactListItemView extends ViewGroup
            effectiveWidth -= mHeaderWidth + mGapBetweenImageAndText;
        }

        if (mSupportVideoCallIcon) {
            effectiveWidth -= (mVideoCallIconSize + mVideoCallIconMargin);
        }

        // Go over all visible text views and measure actual width of each of them.
        // Also calculate their heights to get the total height for this entire view.

@@ -418,11 +508,7 @@ public class ContactListItemView extends ViewGroup
        }

        if (isVisible(mLabelView)) {
            // For performance reason we don't want AT_MOST usually, but when the picture is
            // on right, we need to use it anyway because mDataView is next to mLabelView.
            final int mode = (mPhotoPosition == PhotoPosition.LEFT
                    ? MeasureSpec.EXACTLY : MeasureSpec.AT_MOST);
            mLabelView.measure(MeasureSpec.makeMeasureSpec(labelWidth, mode),
            mLabelView.measure(MeasureSpec.makeMeasureSpec(labelWidth, MeasureSpec.AT_MOST),
                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            mLabelViewHeight = mLabelView.getMeasuredHeight();
        }
@@ -443,6 +529,12 @@ public class ContactListItemView extends ViewGroup
            mStatusTextViewHeight = mPresenceIcon.getMeasuredHeight();
        }

        if (mSupportVideoCallIcon && isVisible(mVideoCallIcon)) {
            mVideoCallIcon.measure(
                    MeasureSpec.makeMeasureSpec(mVideoCallIconSize, MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(mVideoCallIconSize, MeasureSpec.EXACTLY));
        }

        if (isVisible(mStatusView)) {
            // Presence and status are in a same row, so status will be affected by icon size.
            final int statusWidth;
@@ -577,6 +669,36 @@ public class ContactListItemView extends ViewGroup
            leftBound += mTextIndent;
        }

        if (mSupportVideoCallIcon) {
            // Place the video call button at the end of the list (e.g. take into account RTL mode).
            if (isVisible(mVideoCallIcon)) {
                // Center the video icon vertically
                final int videoIconTop = topBound +
                        (bottomBound - topBound - mVideoCallIconSize) / 2;

                if (!isLayoutRtl) {
                    // When photo is on left, video icon is placed on the right edge.
                    mVideoCallIcon.layout(rightBound - mVideoCallIconSize,
                            videoIconTop,
                            rightBound,
                            videoIconTop + mVideoCallIconSize);
                } else {
                    // When photo is on right, video icon is placed on the left edge.
                    mVideoCallIcon.layout(leftBound,
                            videoIconTop,
                            leftBound + mVideoCallIconSize,
                            videoIconTop + mVideoCallIconSize);
                }
            }

            if (mPhotoPosition == PhotoPosition.LEFT) {
                rightBound -= (mVideoCallIconSize + mVideoCallIconMargin);
            } else {
                leftBound += mVideoCallIconSize + mVideoCallIconMargin;
            }
        }


        // Center text vertically, then apply the top offset.
        final int totalTextHeight = mNameTextViewHeight + mPhoneticNameTextViewHeight +
                mLabelAndDataViewMaxHeight + mSnippetTextViewHeight + mStatusTextViewHeight;
@@ -656,29 +778,34 @@ public class ContactListItemView extends ViewGroup

        // Label and Data align bottom.
        if (isVisible(mLabelView)) {
            if (mPhotoPosition == PhotoPosition.LEFT) {
                // When photo is on left, label is placed on the right edge of the list item.
                mLabelView.layout(rightBound - mLabelView.getMeasuredWidth(),
            if (!isLayoutRtl) {
                mLabelView.layout(dataLeftBound,
                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
                        rightBound,
                        textTopBound + mLabelAndDataViewMaxHeight);
                rightBound -= mLabelView.getMeasuredWidth();
                dataLeftBound += mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData;
            } else {
                // When photo is on right, label is placed on the left of data view.
                dataLeftBound = leftBound + mLabelView.getMeasuredWidth();
                mLabelView.layout(leftBound,
                mLabelView.layout(rightBound - mLabelView.getMeasuredWidth(),
                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
                        dataLeftBound,
                        rightBound,
                        textTopBound + mLabelAndDataViewMaxHeight);
                dataLeftBound += mGapBetweenLabelAndData;
                rightBound -= (mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData);
            }
        }

        if (isVisible(mDataView)) {
            if (!isLayoutRtl) {
                mDataView.layout(dataLeftBound,
                        textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
                        rightBound,
                        textTopBound + mLabelAndDataViewMaxHeight);
            } else {
                mDataView.layout(rightBound - mDataView.getMeasuredWidth(),
                        textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
                        rightBound,
                        textTopBound + mLabelAndDataViewMaxHeight);
            }
        }
        if (isVisible(mLabelView) || isVisible(mDataView)) {
            textTopBound += mLabelAndDataViewMaxHeight;
@@ -975,12 +1102,14 @@ public class ContactListItemView extends ViewGroup
    public TextView getLabelView() {
        if (mLabelView == null) {
            mLabelView = new TextView(getContext());
            mLabelView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                    LayoutParams.WRAP_CONTENT));

            mLabelView.setSingleLine(true);
            mLabelView.setEllipsize(getTextEllipsis());
            mLabelView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
            if (mPhotoPosition == PhotoPosition.LEFT) {
                mLabelView.setAllCaps(true);
                mLabelView.setGravity(Gravity.END);
            } else {
                mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
            }
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ public interface OnPhoneNumberPickerActionListener {
    /**
     * Returns the selected phone number uri to the requester.
     */
    void onPickDataUri(Uri dataUri, int callInitiationType);
    void onPickDataUri(Uri dataUri, boolean isVideoCall, int callInitiationType);

    /**
     * Returns the specified phone number to the requester.
+36 −3
Original line number Diff line number Diff line
@@ -33,8 +33,8 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import com.android.contacts.common.CallUtil;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.GeoUtil;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.CallableCompat;
@@ -60,6 +60,10 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {

    private static final String TAG = PhoneNumberListAdapter.class.getSimpleName();

    public interface Listener {
        void onVideoCallIconClicked(int position);
    }

    // A list of extended directories to add to the directories from the database
    private final List<DirectoryPartition> mExtendedDirectories;

@@ -98,6 +102,7 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
            Phone.PHOTO_ID,                     // 6
            Phone.DISPLAY_NAME_PRIMARY,         // 7
            Phone.PHOTO_THUMBNAIL_URI,          // 8
            Phone.CARRIER_PRESENCE,             // 9
        };

        public static final String[] PROJECTION_ALTERNATIVE = new String[] {
@@ -110,6 +115,7 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
            Phone.PHOTO_ID,                     // 6
            Phone.DISPLAY_NAME_ALTERNATIVE,     // 7
            Phone.PHOTO_THUMBNAIL_URI,          // 8
            Phone.CARRIER_PRESENCE,             // 9
        };

        public static final int PHONE_ID                = 0;
@@ -121,6 +127,7 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
        public static final int PHOTO_ID                = 6;
        public static final int DISPLAY_NAME            = 7;
        public static final int PHOTO_URI               = 8;
        public static final int CARRIER_PRESENCE        = 9;
    }

    private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE =
@@ -133,6 +140,11 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {

    private boolean mUseCallableUri;

    private Listener mListener;

    private boolean mIsVideoEnabled;
    private boolean mIsPresenceEnabled;

    public PhoneNumberListAdapter(Context context) {
        super(context);
        setDefaultFilterHeaderText(R.string.list_filter_phones);
@@ -147,6 +159,10 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
            // Empty list to avoid sticky NPE's
            mExtendedDirectories = new ArrayList<DirectoryPartition>();
        }

        int videoCapabilities = CallUtil.getVideoCallingAvailability(context);
        mIsVideoEnabled = (videoCapabilities & CallUtil.VIDEO_CALLING_ENABLED) != 0;
        mIsPresenceEnabled = (videoCapabilities & CallUtil.VIDEO_CALLING_PRESENCE) != 0;
    }

    protected CharSequence getUnknownNameText() {
@@ -413,10 +429,11 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
        }

        final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
        bindPhoneNumber(view, cursor, directory.isDisplayNumber());
        bindPhoneNumber(view, cursor, directory.isDisplayNumber(), position);
    }

    protected void bindPhoneNumber(ContactListItemView view, Cursor cursor, boolean displayNumber) {
    protected void bindPhoneNumber(ContactListItemView view, Cursor cursor, boolean displayNumber,
            int position) {
        CharSequence label = null;
        if (displayNumber &&  !cursor.isNull(PhoneQuery.PHONE_TYPE)) {
            final int type = cursor.getInt(PhoneQuery.PHONE_TYPE);
@@ -440,6 +457,14 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
            }
        }
        view.setPhoneNumber(text, mCountryIso);

        // Determine if carrier presence indicates the number supports video calling.
        int carrierPresence = cursor.getInt(PhoneQuery.CARRIER_PRESENCE);
        boolean isPresent = (carrierPresence & Phone.CARRIER_PRESENCE_VT_CAPABLE) != 0;

        boolean isVideoIconShown = mIsVideoEnabled && (
                mIsPresenceEnabled && isPresent || !mIsPresenceEnabled);
        view.setShowVideoCallIcon(isVideoIconShown, mListener, position);
    }

    protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
@@ -576,4 +601,12 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
                .encodedFragment(cursor.getString(lookUpKeyColumn))
                .build();
    }

    public Listener getListener() {
        return mListener;
    }

    public void setListener(Listener listener) {
        mListener = listener;
    }
}
Loading