Loading java/com/android/bubble/Bubble.java +100 −44 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.widget.ViewAnimator; import com.android.bubble.BubbleInfo.Action; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -96,7 +97,7 @@ public class Bubble { private BubbleInfo currentInfo; @Visibility private int visibility; private boolean expanded; @VisibleForTesting boolean expanded; private boolean textShowing; private boolean hideAfterText; private CharSequence textAfterShow; Loading @@ -104,7 +105,7 @@ public class Bubble { @VisibleForTesting ViewHolder viewHolder; private ViewPropertyAnimator collapseAnimation; private Integer overrideGravity; @VisibleForTesting Integer overrideGravity; private ViewPropertyAnimator exitAnimator; private final Runnable collapseRunnable = Loading Loading @@ -497,13 +498,6 @@ public class Bubble { ViewGroup.LayoutParams layoutParams = primaryContainer.getLayoutParams(); ((FrameLayout.LayoutParams) layoutParams).gravity = onRight ? Gravity.RIGHT : Gravity.LEFT; primaryContainer.setLayoutParams(layoutParams); viewHolder .getExpandedView() .setBackgroundResource( onRight ? R.drawable.bubble_background_pill_rtl : R.drawable.bubble_background_pill_ltr); } LayoutParams getWindowParams() { Loading Loading @@ -570,20 +564,23 @@ public class Bubble { backgroundRipple.getDrawable(0).setTint(primaryTint); viewHolder.getPrimaryButton().setBackground(backgroundRipple); setBackgroundDrawable(viewHolder.getFirstButton(), primaryTint); setBackgroundDrawable(viewHolder.getSecondButton(), primaryTint); setBackgroundDrawable(viewHolder.getThirdButton(), primaryTint); for (CheckableImageButton button : viewHolder.getActionButtons()) { setBackgroundDrawable(button, primaryTint); } int numButtons = currentInfo.getActions().size(); viewHolder.getThirdButton().setVisibility(numButtons < 3 ? View.GONE : View.VISIBLE); viewHolder.getSecondButton().setVisibility(numButtons < 2 ? View.GONE : View.VISIBLE); for (CheckableImageButton button : viewHolder.getThirdButtons()) { button.setVisibility(numButtons < 3 ? View.GONE : View.VISIBLE); } for (CheckableImageButton button : viewHolder.getSecondButtons()) { button.setVisibility(numButtons < 2 ? View.GONE : View.VISIBLE); } viewHolder.getPrimaryIcon().setImageIcon(currentInfo.getPrimaryIcon()); updatePrimaryIconAnimation(); viewHolder .getExpandedView() .setBackgroundTintList(ColorStateList.valueOf(currentInfo.getPrimaryColor())); for (View expandedView : viewHolder.getExpandedViews()) { expandedView.setBackgroundTintList(ColorStateList.valueOf(currentInfo.getPrimaryColor())); } updateButtonStates(); } Loading Loading @@ -613,11 +610,17 @@ public class Bubble { int numButtons = currentInfo.getActions().size(); if (numButtons >= 1) { configureButton(currentInfo.getActions().get(0), viewHolder.getFirstButton()); for (CheckableImageButton button : viewHolder.getFirstButtons()) { configureButton(currentInfo.getActions().get(0), button); } if (numButtons >= 2) { configureButton(currentInfo.getActions().get(1), viewHolder.getSecondButton()); for (CheckableImageButton button : viewHolder.getSecondButtons()) { configureButton(currentInfo.getActions().get(1), button); } if (numButtons >= 3) { configureButton(currentInfo.getActions().get(2), viewHolder.getThirdButton()); for (CheckableImageButton button : viewHolder.getThirdButtons()) { configureButton(currentInfo.getActions().get(2), button); } } } } Loading Loading @@ -788,10 +791,15 @@ public class Bubble { private final TextView primaryText; private final CheckableImageButton firstButton; private final CheckableImageButton firstButtonRtl; private final CheckableImageButton secondButton; private final CheckableImageButton secondButtonRtl; private final CheckableImageButton thirdButton; private final CheckableImageButton thirdButtonRtl; private final View expandedView; private final View expandedViewRtl; private final View shadowProvider; private final View shadowProviderRtl; public ViewHolder(Context context) { // Window root is not in the layout file so that the inflater has a view to inflate into Loading @@ -799,14 +807,19 @@ public class Bubble { LayoutInflater inflater = LayoutInflater.from(root.getContext()); View contentView = inflater.inflate(R.layout.bubble_base, root, true); expandedView = contentView.findViewById(R.id.bubble_expanded_layout); expandedViewRtl = contentView.findViewById(R.id.bubble_expanded_layout_rtl); primaryButton = contentView.findViewById(R.id.bubble_button_primary); primaryIcon = contentView.findViewById(R.id.bubble_icon_primary); primaryText = contentView.findViewById(R.id.bubble_text); shadowProvider = contentView.findViewById(R.id.bubble_drawer_shadow_provider); shadowProviderRtl = contentView.findViewById(R.id.bubble_drawer_shadow_provider_rtl); firstButton = contentView.findViewById(R.id.bubble_icon_first); firstButtonRtl = contentView.findViewById(R.id.bubble_icon_first_rtl); secondButton = contentView.findViewById(R.id.bubble_icon_second); secondButtonRtl = contentView.findViewById(R.id.bubble_icon_second_rtl); thirdButton = contentView.findViewById(R.id.bubble_icon_third); thirdButtonRtl = contentView.findViewById(R.id.bubble_icon_third_rtl); root.setOnBackPressedListener( () -> { Loading Loading @@ -839,27 +852,34 @@ public class Bubble { int parentOffset = ((MarginLayoutParams) ((ViewGroup) expandedView.getParent()).getLayoutParams()) .leftMargin; if (isDrawingFromRight()) { int maxLeft = shadowProvider.getRight() - context.getResources().getDimensionPixelSize(R.dimen.bubble_size); shadowProvider.setLeft( Math.min(maxLeft, expandedView.getLeft() + translationX + parentOffset)); } else { int minRight = shadowProvider.getLeft() + context.getResources().getDimensionPixelSize(R.dimen.bubble_size); shadowProvider.setRight( Math.max(minRight, expandedView.getRight() + translationX + parentOffset)); } }); expandedViewRtl .getViewTreeObserver() .addOnDrawListener( () -> { int translationX = (int) expandedViewRtl.getTranslationX(); int parentOffset = ((MarginLayoutParams) ((ViewGroup) expandedViewRtl.getParent()).getLayoutParams()) .leftMargin; int maxLeft = shadowProviderRtl.getRight() - context.getResources().getDimensionPixelSize(R.dimen.bubble_size); shadowProviderRtl.setLeft( Math.min(maxLeft, expandedViewRtl.getLeft() + translationX + parentOffset)); }); moveHandler = new MoveHandler(primaryButton, Bubble.this); } private void setChildClickable(boolean clickable) { firstButton.setClickable(clickable); secondButton.setClickable(clickable); thirdButton.setClickable(clickable); for (CheckableImageButton button : getActionButtons()) { button.setClickable(clickable); } primaryButton.setOnTouchListener(clickable ? moveHandler : null); } Loading @@ -880,30 +900,66 @@ public class Bubble { return primaryText; } /** Get list of all the action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getActionButtons() { return Arrays.asList( firstButton, firstButtonRtl, secondButton, secondButtonRtl, thirdButton, thirdButtonRtl); } /** Get the first action button used in the current orientation drawer. */ public CheckableImageButton getFirstButton() { return firstButton; return isDrawingFromRight() ? firstButtonRtl : firstButton; } /** Get both of the first action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getFirstButtons() { return Arrays.asList(firstButton, firstButtonRtl); } /** Get the second action button used in the current orientation drawer. */ public CheckableImageButton getSecondButton() { return secondButton; return isDrawingFromRight() ? secondButtonRtl : secondButton; } /** Get both of the second action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getSecondButtons() { return Arrays.asList(secondButton, secondButtonRtl); } /** Get the third action button used in the current orientation drawer. */ public CheckableImageButton getThirdButton() { return thirdButton; return isDrawingFromRight() ? thirdButtonRtl : thirdButton; } /** Get both of the third action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getThirdButtons() { return Arrays.asList(thirdButton, thirdButtonRtl); } /** Get the correct expanded view used in current bubble orientation. */ public View getExpandedView() { return expandedView; return isDrawingFromRight() ? expandedViewRtl : expandedView; } /** Get both views of the LTR and RTL drawers. */ public List<View> getExpandedViews() { return Arrays.asList(expandedView, expandedViewRtl); } /** Get the correct shadow provider view used in current bubble orientation. */ public View getShadowProvider() { return shadowProvider; return isDrawingFromRight() ? shadowProviderRtl : shadowProvider; } public void setDrawerVisibility(int visibility) { if (isDrawingFromRight()) { expandedViewRtl.setVisibility(visibility); shadowProviderRtl.setVisibility(visibility); } else { expandedView.setVisibility(visibility); shadowProvider.setVisibility(visibility); } } public boolean isMoving() { return moveHandler.isMoving(); Loading java/com/android/bubble/res/layout/bubble_base.xml +66 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,19 @@ android:elevation="10dp" android:visibility="invisible" /> <View android:id="@+id/bubble_drawer_shadow_provider_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginTop="@dimen/bubble_shadow_padding_size" android:layout_marginBottom="@dimen/bubble_shadow_padding_size" android:layout_marginRight="@dimen/bubble_shadow_padding_size" android:layout_gravity="right" android:background="@drawable/bubble_ripple_circle" android:backgroundTint="@android:color/transparent" android:elevation="10dp" android:visibility="invisible" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" Loading @@ -49,7 +62,7 @@ android:paddingStart="32dp" android:paddingEnd="8dp" android:background="@drawable/bubble_background_pill_ltr" android:layoutDirection="inherit" android:layoutDirection="ltr" android:orientation="horizontal" android:visibility="gone" tools:backgroundTint="#FF0000FF" Loading Loading @@ -86,6 +99,58 @@ tools:src="@android:drawable/ic_menu_call"/> </LinearLayout> </FrameLayout> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="48dp" android:elevation="10dp" android:paddingTop="@dimen/bubble_shadow_padding_size" android:paddingBottom="@dimen/bubble_shadow_padding_size" android:paddingLeft="@dimen/bubble_shadow_padding_size"> <LinearLayout android:id="@+id/bubble_expanded_layout_rtl" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingRight="32dp" android:paddingLeft="8dp" android:background="@drawable/bubble_background_pill_rtl" android:layoutDirection="rtl" android:orientation="horizontal" android:visibility="gone" tools:backgroundTint="#FF0000FF" tools:visibility="invisible"> <com.android.bubble.CheckableImageButton android:id="@+id/bubble_icon_first_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginRight="4dp" android:padding="@dimen/bubble_icon_padding" android:tint="@color/bubble_icon_tint_states" android:tintMode="src_in" tools:background="@drawable/bubble_ripple_checkable_circle" tools:src="@android:drawable/ic_lock_idle_lock"/> <com.android.bubble.CheckableImageButton android:id="@+id/bubble_icon_second_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginRight="4dp" android:padding="@dimen/bubble_icon_padding" android:tint="@color/bubble_icon_tint_states" android:tintMode="src_in" tools:background="@drawable/bubble_ripple_checkable_circle" tools:src="@android:drawable/ic_input_add"/> <com.android.bubble.CheckableImageButton android:id="@+id/bubble_icon_third_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginRight="4dp" android:padding="@dimen/bubble_icon_padding" android:tint="@color/bubble_icon_tint_states" android:tintMode="src_in" tools:background="@drawable/bubble_ripple_checkable_circle" tools:src="@android:drawable/ic_menu_call"/> </LinearLayout> </FrameLayout> <FrameLayout android:id="@+id/bubble_primary_container" android:layout_width="wrap_content" Loading java/com/android/dialer/app/DialtactsActivity.java +14 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.os.Trace; import android.provider.CallLog.Calls; import android.provider.ContactsContract.QuickContact; import android.speech.RecognizerIntent; import android.support.annotation.MainThread; import android.support.annotation.NonNull; Loading Loading @@ -59,6 +60,7 @@ import android.view.animation.AnimationUtils; import android.widget.AbsListView.OnScrollListener; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; Loading Loading @@ -101,6 +103,7 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactsfragment.ContactsFragment; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.database.Database; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.dialpadview.DialpadFragment; Loading @@ -109,6 +112,7 @@ import com.android.dialer.dialpadview.DialpadFragment.LastOutgoingCallCallback; import com.android.dialer.interactions.PhoneNumberInteraction; import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; import com.android.dialer.logging.LoggingBindings; import com.android.dialer.logging.ScreenEvent; Loading Loading @@ -166,7 +170,8 @@ public class DialtactsActivity extends TransactionSafeActivity PhoneNumberInteraction.DisambigDialogDismissedListener, ActivityCompat.OnRequestPermissionsResultCallback, DialpadListener, SearchFragmentListener { SearchFragmentListener, OnContactSelectedListener { public static final boolean DEBUG = false; @VisibleForTesting public static final String TAG_DIALPAD_FRAGMENT = "dialpad"; Loading Loading @@ -1695,6 +1700,14 @@ public class DialtactsActivity extends TransactionSafeActivity return mPreviouslySelectedTabIndex; } @Override public void onContactSelected(ImageView photo, Uri contactUri, long contactId) { Logger.get(this) .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_ITEM); QuickContact.showQuickContact( this, photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */); } /** Popup menu accessible from the search bar */ protected class OptionsPopupMenu extends PopupMenu { Loading java/com/android/dialer/app/calllog/CallLogAdapter.java +24 −24 Original line number Diff line number Diff line Loading @@ -828,65 +828,65 @@ public class CallLogAdapter extends GroupingListAdapter } private void loadAndRender( final CallLogListItemViewHolder views, final CallLogListItemViewHolder viewHolder, final long rowId, final PhoneCallDetails details, final CallDetailsEntries callDetailsEntries) { LogUtil.d("CallLogAdapter.loadAndRender", "position: %d", views.getAdapterPosition()); LogUtil.d("CallLogAdapter.loadAndRender", "position: %d", viewHolder.getAdapterPosition()); // Reset block and spam information since this view could be reused which may contain // outdated data. views.isSpam = false; views.blockId = null; views.isSpamFeatureEnabled = false; viewHolder.isSpam = false; viewHolder.blockId = null; viewHolder.isSpamFeatureEnabled = false; // Attempt to set the isCallComposerCapable field. If capabilities are unknown for this number, // the value will be false while capabilities are requested. mExpandCollapseListener will // attempt to set the field properly in that case views.isCallComposerCapable = isCallComposerCapable(views.number); views.setDetailedPhoneDetails(callDetailsEntries); views.duoReady = getDuo().isReachable(mActivity, views.number); viewHolder.isCallComposerCapable = isCallComposerCapable(viewHolder.number); viewHolder.setDetailedPhoneDetails(callDetailsEntries); viewHolder.duo = getDuo(); final AsyncTask<Void, Void, Boolean> loadDataTask = new AsyncTask<Void, Void, Boolean>() { @Override protected Boolean doInBackground(Void... params) { views.blockId = viewHolder.blockId = mFilteredNumberAsyncQueryHandler.getBlockedIdSynchronous( views.number, views.countryIso); details.isBlocked = views.blockId != null; viewHolder.number, viewHolder.countryIso); details.isBlocked = viewHolder.blockId != null; if (isCancelled()) { return false; } if (mIsSpamEnabled) { views.isSpamFeatureEnabled = true; viewHolder.isSpamFeatureEnabled = true; // Only display the call as a spam call if there are incoming calls in the list. // Call log cards with only outgoing calls should never be displayed as spam. views.isSpam = viewHolder.isSpam = details.hasIncomingCalls() && Spam.get(mActivity) .checkSpamStatusSynchronous(views.number, views.countryIso); details.isSpam = views.isSpam; .checkSpamStatusSynchronous(viewHolder.number, viewHolder.countryIso); details.isSpam = viewHolder.isSpam; } return !isCancelled() && loadData(views, rowId, details); return !isCancelled() && loadData(viewHolder, rowId, details); } @Override protected void onPostExecute(Boolean success) { views.isLoaded = true; viewHolder.isLoaded = true; if (success) { views.callbackAction = getCallbackAction(views.rowId); int currentDayGroup = getDayGroup(views.rowId); viewHolder.callbackAction = getCallbackAction(viewHolder.rowId); int currentDayGroup = getDayGroup(viewHolder.rowId); if (currentDayGroup != details.previousGroup) { views.dayGroupHeaderVisibility = View.VISIBLE; views.dayGroupHeaderText = getGroupDescription(currentDayGroup); viewHolder.dayGroupHeaderVisibility = View.VISIBLE; viewHolder.dayGroupHeaderText = getGroupDescription(currentDayGroup); } else { views.dayGroupHeaderVisibility = View.GONE; viewHolder.dayGroupHeaderVisibility = View.GONE; } render(views, details, rowId); render(viewHolder, details, rowId); } } }; views.asyncTask = loadDataTask; viewHolder.asyncTask = loadDataTask; mAsyncTaskExecutor.submit(LOAD_DATA_TASK_IDENTIFIER, loadDataTask); } Loading java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +20 −3 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactphoto.ContactPhotoManager; import com.android.dialer.dialercontact.DialerContact; import com.android.dialer.dialercontact.SimDetails; import com.android.dialer.duo.Duo; import com.android.dialer.duo.DuoConstants; import com.android.dialer.lettertile.LetterTileDrawable; import com.android.dialer.lettertile.LetterTileDrawable.ContactType; Loading Loading @@ -147,6 +148,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder public View callButtonView; public View videoCallButtonView; public View setUpVideoButtonView; public View inviteVideoButtonView; public View createNewContactButtonView; public View addToExistingContactButtonView; public View sendMessageView; Loading Loading @@ -228,7 +231,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder public boolean isSpam; public boolean isCallComposerCapable; public boolean duoReady; public Duo duo; private View.OnClickListener mExpandCollapseListener; private final OnActionModeStateChangedListener onActionModeStateChangedListener; Loading Loading @@ -466,6 +469,12 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder videoCallButtonView = actionsView.findViewById(R.id.video_call_action); videoCallButtonView.setOnClickListener(this); setUpVideoButtonView = actionsView.findViewById(R.id.set_up_video_action); setUpVideoButtonView.setOnClickListener(this); inviteVideoButtonView = actionsView.findViewById(R.id.invite_video_action); inviteVideoButtonView.setOnClickListener(this); createNewContactButtonView = actionsView.findViewById(R.id.create_new_contact_action); createNewContactButtonView.setOnClickListener(this); Loading Loading @@ -593,6 +602,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder // This saves us having to remember to set it to GONE in multiple places. callButtonView.setVisibility(View.GONE); videoCallButtonView.setVisibility(View.GONE); setUpVideoButtonView.setVisibility(View.GONE); inviteVideoButtonView.setVisibility(View.GONE); if (isFullyUndialableVoicemail()) { // Sometimes the voicemail server will report the message is from some non phone number Loading Loading @@ -665,9 +676,15 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder && (hasPlacedCarrierVideoCall() || canSupportCarrierVideoCall())) { videoCallButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number)); videoCallButtonView.setVisibility(View.VISIBLE); } else if (duoReady) { } else if (duo.isReachable(mContext, number)) { videoCallButtonView.setTag(IntentProvider.getDuoVideoIntentProvider(number)); videoCallButtonView.setVisibility(View.VISIBLE); } else if (duo.isActivated(mContext)) { inviteVideoButtonView.setTag(IntentProvider.getDuoInviteIntentProvider(number)); inviteVideoButtonView.setVisibility(View.VISIBLE); } else if (duo.isEnabled(mContext)) { setUpVideoButtonView.setTag(IntentProvider.getSetUpDuoIntentProvider()); setUpVideoButtonView.setVisibility(View.VISIBLE); } break; default: Loading Loading @@ -755,7 +772,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder private boolean showDuoPrimaryButton() { return accountHandle != null && accountHandle.getComponentName().equals(DuoConstants.PHONE_ACCOUNT_COMPONENT_NAME) && duoReady; && duo.isReachable(mContext, number); } private static boolean hasDialableChar(CharSequence number) { Loading Loading
java/com/android/bubble/Bubble.java +100 −44 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.widget.ViewAnimator; import com.android.bubble.BubbleInfo.Action; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -96,7 +97,7 @@ public class Bubble { private BubbleInfo currentInfo; @Visibility private int visibility; private boolean expanded; @VisibleForTesting boolean expanded; private boolean textShowing; private boolean hideAfterText; private CharSequence textAfterShow; Loading @@ -104,7 +105,7 @@ public class Bubble { @VisibleForTesting ViewHolder viewHolder; private ViewPropertyAnimator collapseAnimation; private Integer overrideGravity; @VisibleForTesting Integer overrideGravity; private ViewPropertyAnimator exitAnimator; private final Runnable collapseRunnable = Loading Loading @@ -497,13 +498,6 @@ public class Bubble { ViewGroup.LayoutParams layoutParams = primaryContainer.getLayoutParams(); ((FrameLayout.LayoutParams) layoutParams).gravity = onRight ? Gravity.RIGHT : Gravity.LEFT; primaryContainer.setLayoutParams(layoutParams); viewHolder .getExpandedView() .setBackgroundResource( onRight ? R.drawable.bubble_background_pill_rtl : R.drawable.bubble_background_pill_ltr); } LayoutParams getWindowParams() { Loading Loading @@ -570,20 +564,23 @@ public class Bubble { backgroundRipple.getDrawable(0).setTint(primaryTint); viewHolder.getPrimaryButton().setBackground(backgroundRipple); setBackgroundDrawable(viewHolder.getFirstButton(), primaryTint); setBackgroundDrawable(viewHolder.getSecondButton(), primaryTint); setBackgroundDrawable(viewHolder.getThirdButton(), primaryTint); for (CheckableImageButton button : viewHolder.getActionButtons()) { setBackgroundDrawable(button, primaryTint); } int numButtons = currentInfo.getActions().size(); viewHolder.getThirdButton().setVisibility(numButtons < 3 ? View.GONE : View.VISIBLE); viewHolder.getSecondButton().setVisibility(numButtons < 2 ? View.GONE : View.VISIBLE); for (CheckableImageButton button : viewHolder.getThirdButtons()) { button.setVisibility(numButtons < 3 ? View.GONE : View.VISIBLE); } for (CheckableImageButton button : viewHolder.getSecondButtons()) { button.setVisibility(numButtons < 2 ? View.GONE : View.VISIBLE); } viewHolder.getPrimaryIcon().setImageIcon(currentInfo.getPrimaryIcon()); updatePrimaryIconAnimation(); viewHolder .getExpandedView() .setBackgroundTintList(ColorStateList.valueOf(currentInfo.getPrimaryColor())); for (View expandedView : viewHolder.getExpandedViews()) { expandedView.setBackgroundTintList(ColorStateList.valueOf(currentInfo.getPrimaryColor())); } updateButtonStates(); } Loading Loading @@ -613,11 +610,17 @@ public class Bubble { int numButtons = currentInfo.getActions().size(); if (numButtons >= 1) { configureButton(currentInfo.getActions().get(0), viewHolder.getFirstButton()); for (CheckableImageButton button : viewHolder.getFirstButtons()) { configureButton(currentInfo.getActions().get(0), button); } if (numButtons >= 2) { configureButton(currentInfo.getActions().get(1), viewHolder.getSecondButton()); for (CheckableImageButton button : viewHolder.getSecondButtons()) { configureButton(currentInfo.getActions().get(1), button); } if (numButtons >= 3) { configureButton(currentInfo.getActions().get(2), viewHolder.getThirdButton()); for (CheckableImageButton button : viewHolder.getThirdButtons()) { configureButton(currentInfo.getActions().get(2), button); } } } } Loading Loading @@ -788,10 +791,15 @@ public class Bubble { private final TextView primaryText; private final CheckableImageButton firstButton; private final CheckableImageButton firstButtonRtl; private final CheckableImageButton secondButton; private final CheckableImageButton secondButtonRtl; private final CheckableImageButton thirdButton; private final CheckableImageButton thirdButtonRtl; private final View expandedView; private final View expandedViewRtl; private final View shadowProvider; private final View shadowProviderRtl; public ViewHolder(Context context) { // Window root is not in the layout file so that the inflater has a view to inflate into Loading @@ -799,14 +807,19 @@ public class Bubble { LayoutInflater inflater = LayoutInflater.from(root.getContext()); View contentView = inflater.inflate(R.layout.bubble_base, root, true); expandedView = contentView.findViewById(R.id.bubble_expanded_layout); expandedViewRtl = contentView.findViewById(R.id.bubble_expanded_layout_rtl); primaryButton = contentView.findViewById(R.id.bubble_button_primary); primaryIcon = contentView.findViewById(R.id.bubble_icon_primary); primaryText = contentView.findViewById(R.id.bubble_text); shadowProvider = contentView.findViewById(R.id.bubble_drawer_shadow_provider); shadowProviderRtl = contentView.findViewById(R.id.bubble_drawer_shadow_provider_rtl); firstButton = contentView.findViewById(R.id.bubble_icon_first); firstButtonRtl = contentView.findViewById(R.id.bubble_icon_first_rtl); secondButton = contentView.findViewById(R.id.bubble_icon_second); secondButtonRtl = contentView.findViewById(R.id.bubble_icon_second_rtl); thirdButton = contentView.findViewById(R.id.bubble_icon_third); thirdButtonRtl = contentView.findViewById(R.id.bubble_icon_third_rtl); root.setOnBackPressedListener( () -> { Loading Loading @@ -839,27 +852,34 @@ public class Bubble { int parentOffset = ((MarginLayoutParams) ((ViewGroup) expandedView.getParent()).getLayoutParams()) .leftMargin; if (isDrawingFromRight()) { int maxLeft = shadowProvider.getRight() - context.getResources().getDimensionPixelSize(R.dimen.bubble_size); shadowProvider.setLeft( Math.min(maxLeft, expandedView.getLeft() + translationX + parentOffset)); } else { int minRight = shadowProvider.getLeft() + context.getResources().getDimensionPixelSize(R.dimen.bubble_size); shadowProvider.setRight( Math.max(minRight, expandedView.getRight() + translationX + parentOffset)); } }); expandedViewRtl .getViewTreeObserver() .addOnDrawListener( () -> { int translationX = (int) expandedViewRtl.getTranslationX(); int parentOffset = ((MarginLayoutParams) ((ViewGroup) expandedViewRtl.getParent()).getLayoutParams()) .leftMargin; int maxLeft = shadowProviderRtl.getRight() - context.getResources().getDimensionPixelSize(R.dimen.bubble_size); shadowProviderRtl.setLeft( Math.min(maxLeft, expandedViewRtl.getLeft() + translationX + parentOffset)); }); moveHandler = new MoveHandler(primaryButton, Bubble.this); } private void setChildClickable(boolean clickable) { firstButton.setClickable(clickable); secondButton.setClickable(clickable); thirdButton.setClickable(clickable); for (CheckableImageButton button : getActionButtons()) { button.setClickable(clickable); } primaryButton.setOnTouchListener(clickable ? moveHandler : null); } Loading @@ -880,30 +900,66 @@ public class Bubble { return primaryText; } /** Get list of all the action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getActionButtons() { return Arrays.asList( firstButton, firstButtonRtl, secondButton, secondButtonRtl, thirdButton, thirdButtonRtl); } /** Get the first action button used in the current orientation drawer. */ public CheckableImageButton getFirstButton() { return firstButton; return isDrawingFromRight() ? firstButtonRtl : firstButton; } /** Get both of the first action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getFirstButtons() { return Arrays.asList(firstButton, firstButtonRtl); } /** Get the second action button used in the current orientation drawer. */ public CheckableImageButton getSecondButton() { return secondButton; return isDrawingFromRight() ? secondButtonRtl : secondButton; } /** Get both of the second action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getSecondButtons() { return Arrays.asList(secondButton, secondButtonRtl); } /** Get the third action button used in the current orientation drawer. */ public CheckableImageButton getThirdButton() { return thirdButton; return isDrawingFromRight() ? thirdButtonRtl : thirdButton; } /** Get both of the third action buttons from both LTR/RTL drawers. */ public List<CheckableImageButton> getThirdButtons() { return Arrays.asList(thirdButton, thirdButtonRtl); } /** Get the correct expanded view used in current bubble orientation. */ public View getExpandedView() { return expandedView; return isDrawingFromRight() ? expandedViewRtl : expandedView; } /** Get both views of the LTR and RTL drawers. */ public List<View> getExpandedViews() { return Arrays.asList(expandedView, expandedViewRtl); } /** Get the correct shadow provider view used in current bubble orientation. */ public View getShadowProvider() { return shadowProvider; return isDrawingFromRight() ? shadowProviderRtl : shadowProvider; } public void setDrawerVisibility(int visibility) { if (isDrawingFromRight()) { expandedViewRtl.setVisibility(visibility); shadowProviderRtl.setVisibility(visibility); } else { expandedView.setVisibility(visibility); shadowProvider.setVisibility(visibility); } } public boolean isMoving() { return moveHandler.isMoving(); Loading
java/com/android/bubble/res/layout/bubble_base.xml +66 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,19 @@ android:elevation="10dp" android:visibility="invisible" /> <View android:id="@+id/bubble_drawer_shadow_provider_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginTop="@dimen/bubble_shadow_padding_size" android:layout_marginBottom="@dimen/bubble_shadow_padding_size" android:layout_marginRight="@dimen/bubble_shadow_padding_size" android:layout_gravity="right" android:background="@drawable/bubble_ripple_circle" android:backgroundTint="@android:color/transparent" android:elevation="10dp" android:visibility="invisible" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" Loading @@ -49,7 +62,7 @@ android:paddingStart="32dp" android:paddingEnd="8dp" android:background="@drawable/bubble_background_pill_ltr" android:layoutDirection="inherit" android:layoutDirection="ltr" android:orientation="horizontal" android:visibility="gone" tools:backgroundTint="#FF0000FF" Loading Loading @@ -86,6 +99,58 @@ tools:src="@android:drawable/ic_menu_call"/> </LinearLayout> </FrameLayout> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="48dp" android:elevation="10dp" android:paddingTop="@dimen/bubble_shadow_padding_size" android:paddingBottom="@dimen/bubble_shadow_padding_size" android:paddingLeft="@dimen/bubble_shadow_padding_size"> <LinearLayout android:id="@+id/bubble_expanded_layout_rtl" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingRight="32dp" android:paddingLeft="8dp" android:background="@drawable/bubble_background_pill_rtl" android:layoutDirection="rtl" android:orientation="horizontal" android:visibility="gone" tools:backgroundTint="#FF0000FF" tools:visibility="invisible"> <com.android.bubble.CheckableImageButton android:id="@+id/bubble_icon_first_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginRight="4dp" android:padding="@dimen/bubble_icon_padding" android:tint="@color/bubble_icon_tint_states" android:tintMode="src_in" tools:background="@drawable/bubble_ripple_checkable_circle" tools:src="@android:drawable/ic_lock_idle_lock"/> <com.android.bubble.CheckableImageButton android:id="@+id/bubble_icon_second_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginRight="4dp" android:padding="@dimen/bubble_icon_padding" android:tint="@color/bubble_icon_tint_states" android:tintMode="src_in" tools:background="@drawable/bubble_ripple_checkable_circle" tools:src="@android:drawable/ic_input_add"/> <com.android.bubble.CheckableImageButton android:id="@+id/bubble_icon_third_rtl" android:layout_width="@dimen/bubble_size" android:layout_height="@dimen/bubble_size" android:layout_marginRight="4dp" android:padding="@dimen/bubble_icon_padding" android:tint="@color/bubble_icon_tint_states" android:tintMode="src_in" tools:background="@drawable/bubble_ripple_checkable_circle" tools:src="@android:drawable/ic_menu_call"/> </LinearLayout> </FrameLayout> <FrameLayout android:id="@+id/bubble_primary_container" android:layout_width="wrap_content" Loading
java/com/android/dialer/app/DialtactsActivity.java +14 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.os.Trace; import android.provider.CallLog.Calls; import android.provider.ContactsContract.QuickContact; import android.speech.RecognizerIntent; import android.support.annotation.MainThread; import android.support.annotation.NonNull; Loading Loading @@ -59,6 +60,7 @@ import android.view.animation.AnimationUtils; import android.widget.AbsListView.OnScrollListener; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; Loading Loading @@ -101,6 +103,7 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactsfragment.ContactsFragment; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.database.Database; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.dialpadview.DialpadFragment; Loading @@ -109,6 +112,7 @@ import com.android.dialer.dialpadview.DialpadFragment.LastOutgoingCallCallback; import com.android.dialer.interactions.PhoneNumberInteraction; import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; import com.android.dialer.logging.LoggingBindings; import com.android.dialer.logging.ScreenEvent; Loading Loading @@ -166,7 +170,8 @@ public class DialtactsActivity extends TransactionSafeActivity PhoneNumberInteraction.DisambigDialogDismissedListener, ActivityCompat.OnRequestPermissionsResultCallback, DialpadListener, SearchFragmentListener { SearchFragmentListener, OnContactSelectedListener { public static final boolean DEBUG = false; @VisibleForTesting public static final String TAG_DIALPAD_FRAGMENT = "dialpad"; Loading Loading @@ -1695,6 +1700,14 @@ public class DialtactsActivity extends TransactionSafeActivity return mPreviouslySelectedTabIndex; } @Override public void onContactSelected(ImageView photo, Uri contactUri, long contactId) { Logger.get(this) .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_ITEM); QuickContact.showQuickContact( this, photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */); } /** Popup menu accessible from the search bar */ protected class OptionsPopupMenu extends PopupMenu { Loading
java/com/android/dialer/app/calllog/CallLogAdapter.java +24 −24 Original line number Diff line number Diff line Loading @@ -828,65 +828,65 @@ public class CallLogAdapter extends GroupingListAdapter } private void loadAndRender( final CallLogListItemViewHolder views, final CallLogListItemViewHolder viewHolder, final long rowId, final PhoneCallDetails details, final CallDetailsEntries callDetailsEntries) { LogUtil.d("CallLogAdapter.loadAndRender", "position: %d", views.getAdapterPosition()); LogUtil.d("CallLogAdapter.loadAndRender", "position: %d", viewHolder.getAdapterPosition()); // Reset block and spam information since this view could be reused which may contain // outdated data. views.isSpam = false; views.blockId = null; views.isSpamFeatureEnabled = false; viewHolder.isSpam = false; viewHolder.blockId = null; viewHolder.isSpamFeatureEnabled = false; // Attempt to set the isCallComposerCapable field. If capabilities are unknown for this number, // the value will be false while capabilities are requested. mExpandCollapseListener will // attempt to set the field properly in that case views.isCallComposerCapable = isCallComposerCapable(views.number); views.setDetailedPhoneDetails(callDetailsEntries); views.duoReady = getDuo().isReachable(mActivity, views.number); viewHolder.isCallComposerCapable = isCallComposerCapable(viewHolder.number); viewHolder.setDetailedPhoneDetails(callDetailsEntries); viewHolder.duo = getDuo(); final AsyncTask<Void, Void, Boolean> loadDataTask = new AsyncTask<Void, Void, Boolean>() { @Override protected Boolean doInBackground(Void... params) { views.blockId = viewHolder.blockId = mFilteredNumberAsyncQueryHandler.getBlockedIdSynchronous( views.number, views.countryIso); details.isBlocked = views.blockId != null; viewHolder.number, viewHolder.countryIso); details.isBlocked = viewHolder.blockId != null; if (isCancelled()) { return false; } if (mIsSpamEnabled) { views.isSpamFeatureEnabled = true; viewHolder.isSpamFeatureEnabled = true; // Only display the call as a spam call if there are incoming calls in the list. // Call log cards with only outgoing calls should never be displayed as spam. views.isSpam = viewHolder.isSpam = details.hasIncomingCalls() && Spam.get(mActivity) .checkSpamStatusSynchronous(views.number, views.countryIso); details.isSpam = views.isSpam; .checkSpamStatusSynchronous(viewHolder.number, viewHolder.countryIso); details.isSpam = viewHolder.isSpam; } return !isCancelled() && loadData(views, rowId, details); return !isCancelled() && loadData(viewHolder, rowId, details); } @Override protected void onPostExecute(Boolean success) { views.isLoaded = true; viewHolder.isLoaded = true; if (success) { views.callbackAction = getCallbackAction(views.rowId); int currentDayGroup = getDayGroup(views.rowId); viewHolder.callbackAction = getCallbackAction(viewHolder.rowId); int currentDayGroup = getDayGroup(viewHolder.rowId); if (currentDayGroup != details.previousGroup) { views.dayGroupHeaderVisibility = View.VISIBLE; views.dayGroupHeaderText = getGroupDescription(currentDayGroup); viewHolder.dayGroupHeaderVisibility = View.VISIBLE; viewHolder.dayGroupHeaderText = getGroupDescription(currentDayGroup); } else { views.dayGroupHeaderVisibility = View.GONE; viewHolder.dayGroupHeaderVisibility = View.GONE; } render(views, details, rowId); render(viewHolder, details, rowId); } } }; views.asyncTask = loadDataTask; viewHolder.asyncTask = loadDataTask; mAsyncTaskExecutor.submit(LOAD_DATA_TASK_IDENTIFIER, loadDataTask); } Loading
java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +20 −3 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactphoto.ContactPhotoManager; import com.android.dialer.dialercontact.DialerContact; import com.android.dialer.dialercontact.SimDetails; import com.android.dialer.duo.Duo; import com.android.dialer.duo.DuoConstants; import com.android.dialer.lettertile.LetterTileDrawable; import com.android.dialer.lettertile.LetterTileDrawable.ContactType; Loading Loading @@ -147,6 +148,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder public View callButtonView; public View videoCallButtonView; public View setUpVideoButtonView; public View inviteVideoButtonView; public View createNewContactButtonView; public View addToExistingContactButtonView; public View sendMessageView; Loading Loading @@ -228,7 +231,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder public boolean isSpam; public boolean isCallComposerCapable; public boolean duoReady; public Duo duo; private View.OnClickListener mExpandCollapseListener; private final OnActionModeStateChangedListener onActionModeStateChangedListener; Loading Loading @@ -466,6 +469,12 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder videoCallButtonView = actionsView.findViewById(R.id.video_call_action); videoCallButtonView.setOnClickListener(this); setUpVideoButtonView = actionsView.findViewById(R.id.set_up_video_action); setUpVideoButtonView.setOnClickListener(this); inviteVideoButtonView = actionsView.findViewById(R.id.invite_video_action); inviteVideoButtonView.setOnClickListener(this); createNewContactButtonView = actionsView.findViewById(R.id.create_new_contact_action); createNewContactButtonView.setOnClickListener(this); Loading Loading @@ -593,6 +602,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder // This saves us having to remember to set it to GONE in multiple places. callButtonView.setVisibility(View.GONE); videoCallButtonView.setVisibility(View.GONE); setUpVideoButtonView.setVisibility(View.GONE); inviteVideoButtonView.setVisibility(View.GONE); if (isFullyUndialableVoicemail()) { // Sometimes the voicemail server will report the message is from some non phone number Loading Loading @@ -665,9 +676,15 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder && (hasPlacedCarrierVideoCall() || canSupportCarrierVideoCall())) { videoCallButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number)); videoCallButtonView.setVisibility(View.VISIBLE); } else if (duoReady) { } else if (duo.isReachable(mContext, number)) { videoCallButtonView.setTag(IntentProvider.getDuoVideoIntentProvider(number)); videoCallButtonView.setVisibility(View.VISIBLE); } else if (duo.isActivated(mContext)) { inviteVideoButtonView.setTag(IntentProvider.getDuoInviteIntentProvider(number)); inviteVideoButtonView.setVisibility(View.VISIBLE); } else if (duo.isEnabled(mContext)) { setUpVideoButtonView.setTag(IntentProvider.getSetUpDuoIntentProvider()); setUpVideoButtonView.setVisibility(View.VISIBLE); } break; default: Loading Loading @@ -755,7 +772,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder private boolean showDuoPrimaryButton() { return accountHandle != null && accountHandle.getComponentName().equals(DuoConstants.PHONE_ACCOUNT_COMPONENT_NAME) && duoReady; && duo.isReachable(mContext, number); } private static boolean hasDialableChar(CharSequence number) { Loading