Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf322ee0 authored by Selim Cinek's avatar Selim Cinek
Browse files

Add back the conversation icon in the expanded view

The conversation icon now shrinks instead of disappearing
as does the face-pile. This also requirements some adjustments
for when the conversation is inside a group since the app
name disappears there.

Bug: 150905003
Test: add group conversations observe layout
Change-Id: I4c9af08cc6adbb1deea1b750a4fd20eaa06f087d
parent 962946c9
Loading
Loading
Loading
Loading
+147 −47
Original line number Diff line number Diff line
@@ -93,7 +93,6 @@ public class ConversationLayout extends FrameLayout
    private MessagingLinearLayout mMessagingLinearLayout;
    private boolean mShowHistoricMessages;
    private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
    private TextView mTitleView;
    private int mLayoutColor;
    private int mSenderTextColor;
    private int mMessageTextColor;
@@ -108,6 +107,11 @@ public class ConversationLayout extends FrameLayout
    private boolean mIsCollapsed;
    private ImageResolver mImageResolver;
    private ImageView mConversationIcon;
    private View mConversationIconContainer;
    private int mConversationIconTopPadding;
    private int mConversationIconTopPaddingExpandedGroup;
    private int mConversationIconTopPaddingNoAppName;
    private int mExpandedGroupMessagePaddingNoAppName;
    private TextView mConversationText;
    private View mConversationIconBadge;
    private Icon mLargeIcon;
@@ -117,11 +121,12 @@ public class ConversationLayout extends FrameLayout
    private MessagingLinearLayout mImageMessageContainer;
    private int mExpandButtonExpandedTopMargin;
    private int mBadgedSideMargins;
    private int mIconSizeBadged;
    private int mIconSizeCentered;
    private int mConversationAvatarSize;
    private int mConversationAvatarSizeExpanded;
    private CachingIconView mIcon;
    private View mImportanceRingView;
    private int mExpandedGroupTopMargin;
    private int mExpandedGroupSideMargin;
    private int mExpandedGroupSideMarginFacePile;
    private View mConversationFacePile;
    private int mNotificationBackgroundColor;
    private CharSequence mFallbackChatName;
@@ -133,7 +138,12 @@ public class ConversationLayout extends FrameLayout
    private boolean mExpandable = true;
    private int mContentMarginEnd;
    private Rect mMessagingClipRect;
    private TextView mAppName;
    private ObservableTextView mAppName;
    private boolean mAppNameGone;
    private int mFacePileAvatarSize;
    private int mFacePileAvatarSizeExpandedGroup;
    private int mFacePileProtectionWidth;
    private int mFacePileProtectionWidthExpanded;

    public ConversationLayout(@NonNull Context context) {
        super(context);
@@ -165,11 +175,11 @@ public class ConversationLayout extends FrameLayout
        int size = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
        mMessagingClipRect = new Rect(0, 0, size, size);
        setMessagingClippingDisabled(false);
        mTitleView = findViewById(R.id.title);
        mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setAntiAlias(true);
        mConversationIcon = findViewById(R.id.conversation_icon);
        mConversationIconContainer = findViewById(R.id.conversation_icon_container);
        mIcon = findViewById(R.id.icon);
        mImportanceRingView = findViewById(R.id.conversation_icon_badge_ring);
        mConversationIconBadge = findViewById(R.id.conversation_icon_badge);
@@ -192,18 +202,40 @@ public class ConversationLayout extends FrameLayout
                R.dimen.notification_content_margin_end);
        mBadgedSideMargins = getResources().getDimensionPixelSize(
                R.dimen.conversation_badge_side_margin);
        mIconSizeBadged = getResources().getDimensionPixelSize(
                R.dimen.conversation_icon_size_badged);
        mIconSizeCentered = getResources().getDimensionPixelSize(
                R.dimen.conversation_icon_size_centered);
        mExpandedGroupTopMargin = getResources().getDimensionPixelSize(
                R.dimen.conversation_icon_margin_top_centered);
        mConversationAvatarSize = getResources().getDimensionPixelSize(
                R.dimen.conversation_avatar_size);
        mConversationAvatarSizeExpanded = getResources().getDimensionPixelSize(
                R.dimen.conversation_avatar_size_group_expanded);
        mConversationIconTopPadding = getResources().getDimensionPixelSize(
                R.dimen.conversation_icon_container_top_padding);
        mConversationIconTopPaddingExpandedGroup = getResources().getDimensionPixelSize(
                R.dimen.conversation_icon_container_top_padding_small_avatar);
        mConversationIconTopPaddingNoAppName = getResources().getDimensionPixelSize(
                R.dimen.conversation_icon_container_top_padding_no_app_name);
        mExpandedGroupMessagePaddingNoAppName = getResources().getDimensionPixelSize(
                R.dimen.expanded_group_conversation_message_padding_without_app_name);
        mExpandedGroupSideMargin = getResources().getDimensionPixelSize(
                R.dimen.conversation_badge_side_margin_group_expanded);
        mExpandedGroupSideMarginFacePile = getResources().getDimensionPixelSize(
                R.dimen.conversation_badge_side_margin_group_expanded_face_pile);
        mConversationFacePile = findViewById(R.id.conversation_face_pile);
        mFacePileAvatarSize = getResources().getDimensionPixelSize(
                R.dimen.conversation_face_pile_avatar_size);
        mFacePileAvatarSizeExpandedGroup = getResources().getDimensionPixelSize(
                R.dimen.conversation_face_pile_avatar_size_group_expanded);
        mFacePileProtectionWidth = getResources().getDimensionPixelSize(
                R.dimen.conversation_face_pile_protection_width);
        mFacePileProtectionWidthExpanded = getResources().getDimensionPixelSize(
                R.dimen.conversation_face_pile_protection_width_expanded);
        mFallbackChatName = getResources().getString(
                R.string.conversation_title_fallback_one_to_one);
        mFallbackGroupChatName = getResources().getString(
                R.string.conversation_title_fallback_group_chat);
        mAppName = findViewById(R.id.app_name_text);
        mAppNameGone = mAppName.getVisibility() == GONE;
        mAppName.setOnVisibilityChangedListener((visibility) -> {
            onAppNameVisibilityChanged();
        });
    }

    @RemotableViewMethod
@@ -234,7 +266,7 @@ public class ConversationLayout extends FrameLayout
        mIsCollapsed = isCollapsed;
        mMessagingLinearLayout.setMaxDisplayedLines(isCollapsed ? 1 : Integer.MAX_VALUE);
        updateExpandButton();
        updateContentPaddings();
        updateContentEndPaddings();
    }

    @RemotableViewMethod
@@ -354,7 +386,6 @@ public class ConversationLayout extends FrameLayout
                }
            }
        } else {
            if (mIsCollapsed) {
            if (mLargeIcon != null) {
                mConversationIcon.setVisibility(VISIBLE);
                mConversationFacePile.setVisibility(GONE);
@@ -363,13 +394,10 @@ public class ConversationLayout extends FrameLayout
                mConversationIcon.setVisibility(GONE);
                // This will also inflate it!
                mConversationFacePile.setVisibility(VISIBLE);
                // rebind the value to the inflated view instead of the stub
                mConversationFacePile = findViewById(R.id.conversation_face_pile);
                bindFacePile();
            }
            } else {
                mConversationFacePile.setVisibility(GONE);
                mConversationIcon.setVisibility(GONE);
            }
        }
        if (TextUtils.isEmpty(conversationText)) {
            conversationText = mIsOneToOne ? mFallbackChatName : mFallbackGroupChatName;
@@ -384,9 +412,10 @@ public class ConversationLayout extends FrameLayout
                    && TextUtils.equals(conversationText, messageSender);
            messagingGroup.setCanHideSenderIfFirst(canHide);
        }
        updateAppName();
        updateIconPositionAndSize();
        updateImageMessages();
        updateAppName();
        updatePaddingsBasedOnContentAvailability();
    }

    private void updateImageMessages() {
@@ -463,6 +492,38 @@ public class ConversationLayout extends FrameLayout
            secondLastIcon = createAvatarSymbol("", "", mLayoutColor);
        }
        topView.setImageIcon(secondLastIcon);

        int conversationAvatarSize;
        int facepileAvatarSize;
        int facePileBackgroundSize;
        if (mIsCollapsed) {
            conversationAvatarSize = mConversationAvatarSize;
            facepileAvatarSize = mFacePileAvatarSize;
            facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidth;
        } else {
            conversationAvatarSize = mConversationAvatarSizeExpanded;
            facepileAvatarSize = mFacePileAvatarSizeExpandedGroup;
            facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded;
        }
        LayoutParams layoutParams = (LayoutParams) mConversationIcon.getLayoutParams();
        layoutParams.width = conversationAvatarSize;
        layoutParams.height = conversationAvatarSize;
        mConversationFacePile.setLayoutParams(layoutParams);

        layoutParams = (LayoutParams) bottomView.getLayoutParams();
        layoutParams.width = facepileAvatarSize;
        layoutParams.height = facepileAvatarSize;
        bottomView.setLayoutParams(layoutParams);

        layoutParams = (LayoutParams) topView.getLayoutParams();
        layoutParams.width = facepileAvatarSize;
        layoutParams.height = facepileAvatarSize;
        topView.setLayoutParams(layoutParams);

        layoutParams = (LayoutParams) bottomBackground.getLayoutParams();
        layoutParams.width = facePileBackgroundSize;
        layoutParams.height = facePileBackgroundSize;
        bottomBackground.setLayoutParams(layoutParams);
    }

    private void updateAppName() {
@@ -477,30 +538,61 @@ public class ConversationLayout extends FrameLayout
     * update the icon position and sizing
     */
    private void updateIconPositionAndSize() {
        int gravity;
        int marginStart;
        int marginTop;
        int iconSize;
        int sidemargin;
        int conversationAvatarSize;
        if (mIsOneToOne || mIsCollapsed) {
            // Badged format
            gravity = Gravity.LEFT;
            marginStart = mBadgedSideMargins;
            marginTop = mBadgedSideMargins;
            iconSize = mIconSizeBadged;
            sidemargin = mBadgedSideMargins;
            conversationAvatarSize = mConversationAvatarSize;
        } else {
            gravity = Gravity.CENTER_HORIZONTAL;
            marginStart = 0;
            marginTop = mExpandedGroupTopMargin;
            iconSize = mIconSizeCentered;
            sidemargin = mConversationFacePile.getVisibility() == VISIBLE
                    ? mExpandedGroupSideMarginFacePile
                    : mExpandedGroupSideMargin;
            conversationAvatarSize = mConversationAvatarSizeExpanded;
        }
        LayoutParams layoutParams =
                (LayoutParams) mConversationIconBadge.getLayoutParams();
        layoutParams.gravity = gravity;
        layoutParams.topMargin = marginTop;
        layoutParams.setMarginStart(marginStart);
        layoutParams.width = iconSize;
        layoutParams.height = iconSize;
        layoutParams.topMargin = sidemargin;
        layoutParams.setMarginStart(sidemargin);
        mConversationIconBadge.setLayoutParams(layoutParams);

        if (mConversationIcon.getVisibility() == VISIBLE) {
            layoutParams = (LayoutParams) mConversationIcon.getLayoutParams();
            layoutParams.width = conversationAvatarSize;
            layoutParams.height = conversationAvatarSize;
            mConversationIcon.setLayoutParams(layoutParams);
        }
    }

    private void updatePaddingsBasedOnContentAvailability() {
        int containerTopPadding;
        int messagingPadding = 0;
        if (mIsOneToOne || mIsCollapsed) {
            containerTopPadding = mConversationIconTopPadding;
        } else {
            if (mAppName.getVisibility() != GONE) {
                // The app name is visible, let's center outselves in the two lines
                containerTopPadding = mConversationIconTopPaddingExpandedGroup;
            } else {
                // App name is gone, let's center ourselves int he one remaining line
                containerTopPadding = mConversationIconTopPaddingNoAppName;

                // The app name is gone and we're a group, we'll need to add some extra padding
                // to the messages, since otherwise it will overlap with the group
                messagingPadding = mExpandedGroupMessagePaddingNoAppName;
            }
        }

        mConversationIconContainer.setPaddingRelative(
                mConversationIconContainer.getPaddingStart(),
                containerTopPadding,
                mConversationIconContainer.getPaddingEnd(),
                mConversationIconContainer.getPaddingBottom());

        mMessagingLinearLayout.setPaddingRelative(
                mMessagingLinearLayout.getPaddingStart(),
                messagingPadding,
                mMessagingLinearLayout.getPaddingEnd(),
                mMessagingLinearLayout.getPaddingBottom());
    }

    @RemotableViewMethod
@@ -922,7 +1014,7 @@ public class ConversationLayout extends FrameLayout
        mExpandButtonContainer.setContentDescription(mContext.getText(contentDescriptionId));
    }

    private void updateContentPaddings() {
    private void updateContentEndPaddings() {

        // Let's make sure the conversation header can't run into the expand button when we're
        // collapsed and update the paddings of the content
@@ -951,6 +1043,14 @@ public class ConversationLayout extends FrameLayout
                mContentContainer.getPaddingBottom());
    }

    private void onAppNameVisibilityChanged() {
        boolean appNameGone = mAppName.getVisibility() == GONE;
        if (appNameGone != mAppNameGone) {
            mAppNameGone = appNameGone;
            updatePaddingsBasedOnContentAvailability();
        }
    }

    public void updateExpandability(boolean expandable, @Nullable OnClickListener onClickListener) {
        mExpandable = expandable;
        if (expandable) {
@@ -960,7 +1060,7 @@ public class ConversationLayout extends FrameLayout
            // TODO: handle content paddings to end of layout
            mExpandButtonContainer.setVisibility(GONE);
        }
        updateContentPaddings();
        updateContentEndPaddings();
    }

    @Override
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.internal.widget;

import android.annotation.Nullable;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.TextView;

import java.util.function.Consumer;

/**
 * A text view whose visibility can be observed.
 */
@RemoteViews.RemoteView
public class ObservableTextView extends TextView {

    private Consumer<Integer> mOnVisibilityChangedListener;

    public ObservableTextView(Context context) {
        super(context);
    }

    public ObservableTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ObservableTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public ObservableTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (changedView == this) {
            if (mOnVisibilityChangedListener != null) {
                mOnVisibilityChangedListener.accept(visibility);
            }
        }
    }

    public void setOnVisibilityChangedListener(Consumer<Integer> listener) {
        mOnVisibilityChangedListener = listener;
    }
}
+13 −9
Original line number Diff line number Diff line
@@ -23,21 +23,25 @@
    >
    <ImageView
        android:id="@+id/conversation_face_pile_top"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_width="@dimen/messaging_avatar_size"
        android:layout_height="@dimen/messaging_avatar_size"
        android:scaleType="centerCrop"
        android:layout_gravity="end|top"
        />
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="start|bottom">
        <ImageView
            android:id="@+id/conversation_face_pile_bottom_background"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="start|bottom"
        android:background="@drawable/conversation_badge_background">
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/conversation_badge_background"
            />
        <ImageView
            android:id="@+id/conversation_face_pile_bottom"
            android:layout_width="36dp"
            android:layout_height="36dp"
            android:layout_width="@dimen/messaging_avatar_size"
            android:layout_height="@dimen/messaging_avatar_size"
            android:scaleType="centerCrop"
            android:layout_gravity="center"
            />
+2 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
    >

    <FrameLayout
        android:id="@+id/conversation_icon_container"
        android:layout_width="@dimen/conversation_content_start"
        android:layout_height="wrap_content"
        android:gravity="start|top"
@@ -175,7 +176,7 @@
                </LinearLayout>

                <!-- App Name -->
                <TextView
                <com.android.internal.widget.ObservableTextView
                    android:id="@+id/app_name_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
+25 −4
Original line number Diff line number Diff line
@@ -694,10 +694,31 @@
    <dimen name="conversation_badge_side_margin">36dp</dimen>
    <!-- size of the notification badge when applied to the conversation icon -->
    <dimen name="conversation_icon_size_badged">20dp</dimen>
    <!-- size of the notification badge when centered in a conversation -->
    <dimen name="conversation_icon_size_centered">26dp</dimen>
    <!-- margin on the top when the icon is centered for group conversations -->
    <dimen name="conversation_icon_margin_top_centered">12dp</dimen>
    <!-- size of the conversation avatar in an expanded group -->
    <dimen name="conversation_avatar_size_group_expanded">@dimen/messaging_avatar_size</dimen>
    <!-- size of the face pile icons -->
    <dimen name="conversation_face_pile_avatar_size">@dimen/messaging_avatar_size</dimen>
    <!-- size of the face pile icons when the group is expanded -->
    <dimen name="conversation_face_pile_avatar_size_group_expanded">25dp</dimen>
    <!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded-->
    <dimen name="conversation_badge_side_margin_group_expanded">22dp</dimen>
    <!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded-->
    <dimen name="conversation_badge_side_margin_group_expanded_face_pile">18dp</dimen>
    <!-- The width of the protection of the face pile layout-->
    <dimen name="conversation_face_pile_protection_width">2dp</dimen>
    <!-- The width of the protection of the face pile layout when expanded-->
    <dimen name="conversation_face_pile_protection_width_expanded">1dp</dimen>
    <!-- The padding of the expanded message container when the app name is gone-->
    <dimen name="expanded_group_conversation_message_padding_without_app_name">14dp</dimen>

    <!-- The top padding of the conversation icon container in the regular state-->
    <dimen name="conversation_icon_container_top_padding">12dp</dimen>

    <!-- The top padding of the conversation icon container when there's no app name present in a group-->
    <dimen name="conversation_icon_container_top_padding_no_app_name">9dp</dimen>

    <!-- The top padding of the conversation icon container when the avatar is small-->
    <dimen name="conversation_icon_container_top_padding_small_avatar">17.5dp</dimen>

    <!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
    <dimen name="conversation_header_expanded_padding_end">38dp</dimen>
Loading