| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.messaging.ui; |
| |
| import android.content.Context; |
| import android.content.Intent; |
| import androidx.core.text.BidiFormatter; |
| import androidx.core.text.TextDirectionHeuristicsCompat; |
| import android.text.TextUtils; |
| import android.util.AttributeSet; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.View.OnLayoutChangeListener; |
| import android.widget.LinearLayout; |
| import android.widget.TextView; |
| |
| import com.android.messaging.R; |
| import com.android.messaging.datamodel.binding.BindingBase; |
| import com.android.messaging.datamodel.binding.DetachableBinding; |
| import com.android.messaging.datamodel.data.PersonItemData; |
| import com.android.messaging.datamodel.data.PersonItemData.PersonItemDataListener; |
| import com.android.messaging.util.AccessibilityUtil; |
| import com.android.messaging.util.UiUtils; |
| |
| /** |
| * Shows a view for a "person" - could be a contact or a participant. This always shows a |
| * contact icon on the left, and the person's display name on the right. |
| * |
| * This view is always bound to an abstract PersonItemData class, so to use it for a specific |
| * scenario, all you need to do is to create a concrete PersonItemData subclass that bridges |
| * between the underlying data (e.g. ParticipantData) and what the UI wants (e.g. display name). |
| */ |
| public class PersonItemView extends LinearLayout implements PersonItemDataListener, |
| OnLayoutChangeListener { |
| public interface PersonItemViewListener { |
| void onPersonClicked(PersonItemData data); |
| boolean onPersonLongClicked(PersonItemData data); |
| } |
| |
| protected final DetachableBinding<PersonItemData> mBinding; |
| private TextView mNameTextView; |
| private TextView mDetailsTextView; |
| private ContactIconView mContactIconView; |
| private View mDetailsContainer; |
| private PersonItemViewListener mListener; |
| private boolean mAvatarOnly; |
| |
| public PersonItemView(final Context context, final AttributeSet attrs) { |
| super(context, attrs); |
| mBinding = BindingBase.createDetachableBinding(this); |
| LayoutInflater.from(getContext()).inflate(R.layout.person_item_view, this, true); |
| } |
| |
| @Override |
| protected void onFinishInflate() { |
| mNameTextView = (TextView) findViewById(R.id.name); |
| mDetailsTextView = (TextView) findViewById(R.id.details); |
| mContactIconView = (ContactIconView) findViewById(R.id.contact_icon); |
| mDetailsContainer = findViewById(R.id.details_container); |
| mNameTextView.addOnLayoutChangeListener(this); |
| } |
| |
| @Override |
| protected void onDetachedFromWindow() { |
| super.onDetachedFromWindow(); |
| if (mBinding.isBound()) { |
| mBinding.detach(); |
| } |
| } |
| |
| @Override |
| protected void onAttachedToWindow() { |
| super.onAttachedToWindow(); |
| mBinding.reAttachIfPossible(); |
| } |
| |
| /** |
| * Binds to a person item data which will provide us info to be displayed. |
| * @param personData the PersonItemData to be bound to. |
| */ |
| public void bind(final PersonItemData personData) { |
| if (mBinding.isBound()) { |
| if (mBinding.getData().equals(personData)) { |
| // Don't rebind if we are requesting the same data. |
| return; |
| } |
| mBinding.unbind(); |
| } |
| |
| if (personData != null) { |
| mBinding.bind(personData); |
| mBinding.getData().setListener(this); |
| |
| // Accessibility reason : in case phone numbers are mixed in the display name, |
| // we need to vocalize it for talkback. |
| final String vocalizedDisplayName = AccessibilityUtil.getVocalizedPhoneNumber( |
| getResources(), getDisplayName()); |
| mNameTextView.setContentDescription(vocalizedDisplayName); |
| } |
| updateViewAppearance(); |
| } |
| |
| /** |
| * @return Display name, possibly comma-ellipsized. |
| */ |
| private String getDisplayName() { |
| final int width = mNameTextView.getMeasuredWidth(); |
| final String displayName = mBinding.getData().getDisplayName(); |
| if (width == 0 || TextUtils.isEmpty(displayName) || !displayName.contains(",")) { |
| return displayName; |
| } |
| final String plusOneString = getContext().getString(R.string.plus_one); |
| final String plusNString = getContext().getString(R.string.plus_n); |
| return BidiFormatter.getInstance().unicodeWrap( |
| UiUtils.commaEllipsize( |
| displayName, |
| mNameTextView.getPaint(), |
| width, |
| plusOneString, |
| plusNString).toString(), |
| TextDirectionHeuristicsCompat.LTR); |
| } |
| |
| @Override |
| public void onLayoutChange(final View v, final int left, final int top, final int right, |
| final int bottom, final int oldLeft, final int oldTop, final int oldRight, |
| final int oldBottom) { |
| if (mBinding.isBound() && v == mNameTextView) { |
| setNameTextView(); |
| } |
| } |
| |
| /** |
| * When set to true, we display only the avatar of the person and hide everything else. |
| */ |
| public void setAvatarOnly(final boolean avatarOnly) { |
| mAvatarOnly = avatarOnly; |
| mDetailsContainer.setVisibility(avatarOnly ? GONE : VISIBLE); |
| } |
| |
| public boolean isAvatarOnly() { |
| return mAvatarOnly; |
| } |
| |
| public void setNameTextColor(final int color) { |
| mNameTextView.setTextColor(color); |
| } |
| |
| public void setDetailsTextColor(final int color) { |
| mDetailsTextView.setTextColor(color); |
| } |
| |
| public void setListener(final PersonItemViewListener listener) { |
| mListener = listener; |
| if (mListener == null) { |
| return; |
| } |
| setOnClickListener(new OnClickListener() { |
| @Override |
| public void onClick(final View v) { |
| if (mListener != null && mBinding.isBound()) { |
| mListener.onPersonClicked(mBinding.getData()); |
| } |
| } |
| }); |
| final OnLongClickListener onLongClickListener = new OnLongClickListener() { |
| @Override |
| public boolean onLongClick(View v) { |
| if (mListener != null && mBinding.isBound()) { |
| return mListener.onPersonLongClicked(mBinding.getData()); |
| } |
| return false; |
| } |
| }; |
| setOnLongClickListener(onLongClickListener); |
| mContactIconView.setOnLongClickListener(onLongClickListener); |
| } |
| |
| public void performClickOnAvatar() { |
| mContactIconView.performClick(); |
| } |
| |
| protected void updateViewAppearance() { |
| if (mBinding.isBound()) { |
| setNameTextView(); |
| |
| final String details = mBinding.getData().getDetails(); |
| if (TextUtils.isEmpty(details)) { |
| mDetailsTextView.setVisibility(GONE); |
| } else { |
| mDetailsTextView.setVisibility(VISIBLE); |
| mDetailsTextView.setText(details); |
| } |
| |
| mContactIconView.setImageResourceUri(mBinding.getData().getAvatarUri(), |
| mBinding.getData().getContactId(), mBinding.getData().getLookupKey(), |
| mBinding.getData().getNormalizedDestination()); |
| } else { |
| mNameTextView.setText(""); |
| mContactIconView.setImageResourceUri(null); |
| } |
| } |
| |
| private void setNameTextView() { |
| final String displayName = getDisplayName(); |
| if (TextUtils.isEmpty(displayName)) { |
| mNameTextView.setVisibility(GONE); |
| } else { |
| mNameTextView.setVisibility(VISIBLE); |
| mNameTextView.setText(displayName); |
| } |
| } |
| |
| @Override |
| public void onPersonDataUpdated(final PersonItemData data) { |
| mBinding.ensureBound(data); |
| updateViewAppearance(); |
| } |
| |
| @Override |
| public void onPersonDataFailed(final PersonItemData data, final Exception exception) { |
| mBinding.ensureBound(data); |
| updateViewAppearance(); |
| } |
| |
| public Intent getClickIntent() { |
| return mBinding.getData().getClickIntent(); |
| } |
| } |