238 lines
8.4 KiB
Java
238 lines
8.4 KiB
Java
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
* Copyright (C) 2024 The LineageOS 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(v -> {
|
|
if (mListener != null && mBinding.isBound()) {
|
|
mListener.onPersonClicked(mBinding.getData());
|
|
}
|
|
});
|
|
final OnLongClickListener onLongClickListener = 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();
|
|
}
|
|
}
|