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

Commit ce8d25ec authored by Tyler Gunn's avatar Tyler Gunn Committed by Android (Google) Code Review
Browse files

Merge "Use carrier presence when showing the video call icon." into ub-contactsdialer-b-dev

parents 78384189 001d9740
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
@@ -81,6 +81,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
@@ -36,6 +36,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;
@@ -84,6 +85,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;
@@ -96,6 +99,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;
@@ -126,6 +131,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.
     *
@@ -166,11 +186,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
@@ -230,6 +249,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);
@@ -239,6 +259,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);

@@ -282,6 +308,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(
@@ -325,6 +358,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
@@ -358,6 +444,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.

@@ -420,11 +510,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();
        }
@@ -445,6 +531,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;
@@ -579,6 +671,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;
@@ -658,29 +780,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;
@@ -981,12 +1108,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