Loading src/com/android/contacts/common/CallUtil.java +52 −10 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; } /** Loading src/com/android/contacts/common/compat/CompatUtils.java +11 −0 Original line number Diff line number Diff line Loading @@ -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. Loading src/com/android/contacts/common/list/ContactListItemView.java +149 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. * Loading Loading @@ -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 Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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( Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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(); } Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); } Loading src/com/android/contacts/common/list/OnPhoneNumberPickerActionListener.java +1 −1 Original line number Diff line number Diff line Loading @@ -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. Loading src/com/android/contacts/common/list/PhoneNumberListAdapter.java +36 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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[] { Loading @@ -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; Loading @@ -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 = Loading @@ -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); Loading @@ -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() { Loading Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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
src/com/android/contacts/common/CallUtil.java +52 −10 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; } /** Loading
src/com/android/contacts/common/compat/CompatUtils.java +11 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
src/com/android/contacts/common/list/ContactListItemView.java +149 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. * Loading Loading @@ -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 Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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( Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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(); } Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); } Loading
src/com/android/contacts/common/list/OnPhoneNumberPickerActionListener.java +1 −1 Original line number Diff line number Diff line Loading @@ -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. Loading
src/com/android/contacts/common/list/PhoneNumberListAdapter.java +36 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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[] { Loading @@ -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; Loading @@ -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 = Loading @@ -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); Loading @@ -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() { Loading Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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; } }