Merge "Make Verification text shrink to zero size for long names or large fonts." into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4820907a6b
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.LinearLayout;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is a subclass of LinearLayout meant to be used in the Conversation header, to fix a bug
|
||||
* when multiple user-provided strings are shown in the same conversation header. b/189723284
|
||||
*
|
||||
* This works around a deficiency in LinearLayout when shrinking views that it can't fully reduce
|
||||
* all contents if any of the oversized views reaches zero.
|
||||
*/
|
||||
@RemoteViews.RemoteView
|
||||
public class ConversationHeaderLinearLayout extends LinearLayout {
|
||||
|
||||
public ConversationHeaderLinearLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ConversationHeaderLinearLayout(Context context,
|
||||
@Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ConversationHeaderLinearLayout(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
private int calculateTotalChildLength() {
|
||||
final int count = getChildCount();
|
||||
int totalLength = 0;
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final View child = getChildAt(i);
|
||||
if (child == null || child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
|
||||
child.getLayoutParams();
|
||||
totalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
|
||||
}
|
||||
return totalLength + getPaddingLeft() + getPaddingRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
final int containerWidth = getMeasuredWidth();
|
||||
final int contentsWidth = calculateTotalChildLength();
|
||||
|
||||
int excessContents = contentsWidth - containerWidth;
|
||||
if (excessContents <= 0) {
|
||||
return;
|
||||
}
|
||||
final int count = getChildCount();
|
||||
|
||||
float remainingWeight = 0;
|
||||
List<ViewInfo> visibleChildrenToShorten = null;
|
||||
|
||||
// Find children which need to be shortened in order to ensure the contents fit.
|
||||
for (int i = 0; i < count; ++i) {
|
||||
final View child = getChildAt(i);
|
||||
if (child == null || child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
final float weight = ((LayoutParams) child.getLayoutParams()).weight;
|
||||
if (weight == 0) {
|
||||
continue;
|
||||
}
|
||||
if (child.getMeasuredWidth() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (visibleChildrenToShorten == null) {
|
||||
visibleChildrenToShorten = new LinkedList<>();
|
||||
}
|
||||
visibleChildrenToShorten.add(new ViewInfo(child));
|
||||
remainingWeight += Math.max(0, weight);
|
||||
}
|
||||
if (visibleChildrenToShorten == null || visibleChildrenToShorten.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
balanceViewWidths(visibleChildrenToShorten, remainingWeight, excessContents);
|
||||
remeasureChangedChildren(visibleChildrenToShorten);
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure any child with a width that has changed.
|
||||
*/
|
||||
private void remeasureChangedChildren(List<ViewInfo> childrenInfo) {
|
||||
for (ViewInfo info : childrenInfo) {
|
||||
if (info.mWidth != info.mStartWidth) {
|
||||
final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
|
||||
Math.max(0, info.mWidth), MeasureSpec.EXACTLY);
|
||||
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
|
||||
info.mView.getMeasuredHeight(), MeasureSpec.EXACTLY);
|
||||
info.mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of view, use the weights to remove width from each view proportionally to the
|
||||
* weight (and ignoring the view's actual width), but do this iteratively whenever a view is
|
||||
* reduced to zero width, because in that case other views need reduction.
|
||||
*/
|
||||
void balanceViewWidths(List<ViewInfo> viewInfos, float weightSum, int excessContents) {
|
||||
boolean performAnotherPass = true;
|
||||
// Loops only when all of the following are true:
|
||||
// * `performAnotherPass` -- a view clamped to 0 width (or the first iteration)
|
||||
// * `excessContents > 0` -- there is still horizontal space to allocate
|
||||
// * `weightSum > 0` -- at least 1 view with nonzero width AND nonzero weight left
|
||||
while (performAnotherPass && excessContents > 0 && weightSum > 0) {
|
||||
int excessRemovedDuringThisPass = 0;
|
||||
float weightSumForNextPass = 0;
|
||||
performAnotherPass = false;
|
||||
for (ViewInfo info : viewInfos) {
|
||||
if (info.mWeight <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (info.mWidth <= 0) {
|
||||
continue;
|
||||
}
|
||||
int newWidth = (int) (info.mWidth - (excessContents * (info.mWeight / weightSum)));
|
||||
if (newWidth < 0) {
|
||||
newWidth = 0;
|
||||
performAnotherPass = true;
|
||||
}
|
||||
excessRemovedDuringThisPass += info.mWidth - newWidth;
|
||||
info.mWidth = newWidth;
|
||||
if (info.mWidth > 0) {
|
||||
weightSumForNextPass += info.mWeight;
|
||||
}
|
||||
}
|
||||
excessContents -= excessRemovedDuringThisPass;
|
||||
weightSum = weightSumForNextPass;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class for measuring children.
|
||||
*/
|
||||
static class ViewInfo {
|
||||
final View mView;
|
||||
final float mWeight;
|
||||
final int mStartWidth;
|
||||
int mWidth;
|
||||
|
||||
ViewInfo(View view) {
|
||||
this.mView = view;
|
||||
this.mWeight = ((LayoutParams) view.getLayoutParams()).weight;
|
||||
this.mStartWidth = this.mWidth = view.getMeasuredWidth();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<LinearLayout
|
||||
<com.android.internal.widget.ConversationHeaderLinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/conversation_header"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -119,6 +119,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
|
||||
android:layout_weight="100"
|
||||
android:showRelative="true"
|
||||
android:singleLine="true"
|
||||
android:visibility="gone"
|
||||
@@ -171,4 +172,4 @@
|
||||
android:src="@drawable/ic_notifications_alerted"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</com.android.internal.widget.ConversationHeaderLinearLayout>
|
||||
|
||||
Reference in New Issue
Block a user