blob: 2db12196cfb710cec2b974b07e09f54c32e32b65 [file] [log] [blame]
/*
* 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();
}
}