Merge "Make sure all Notification actions are shown" into nyc-dev am: 9cb7652fb1
am: 798a860efb
* commit '798a860efb0c599448483d5a8e6a9429777c5bc5':
Make sure all Notification actions are shown
Change-Id: I094ba82280047da811da0e65e1a2e6d38f88497f
This commit is contained in:
@@ -3412,10 +3412,6 @@ public class Notification implements Parcelable
|
|||||||
validRemoteInput |= hasValidRemoteInput(action);
|
validRemoteInput |= hasValidRemoteInput(action);
|
||||||
|
|
||||||
final RemoteViews button = generateActionButton(action);
|
final RemoteViews button = generateActionButton(action);
|
||||||
if (i == N - 1) {
|
|
||||||
button.setViewLayoutWidth(com.android.internal.R.id.action0,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
|
||||||
}
|
|
||||||
big.addView(R.id.actions, button);
|
big.addView(R.id.actions, button);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.RemoteViews;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout for notification actions that ensures that no action consumes more than their share of
|
||||||
|
* the remaining available width, and the last action consumes the remaining space.
|
||||||
|
*/
|
||||||
|
@RemoteViews.RemoteView
|
||||||
|
public class NotificationActionListLayout extends ViewGroup {
|
||||||
|
|
||||||
|
private int mTotalWidth = 0;
|
||||||
|
private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
|
||||||
|
private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
|
||||||
|
|
||||||
|
public NotificationActionListLayout(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
final int N = getChildCount();
|
||||||
|
int textViews = 0;
|
||||||
|
int otherViews = 0;
|
||||||
|
int notGoneChildren = 0;
|
||||||
|
|
||||||
|
View lastNotGoneChild = null;
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
View c = getChildAt(i);
|
||||||
|
if (c instanceof TextView) {
|
||||||
|
textViews++;
|
||||||
|
} else {
|
||||||
|
otherViews++;
|
||||||
|
}
|
||||||
|
if (c.getVisibility() != GONE) {
|
||||||
|
notGoneChildren++;
|
||||||
|
lastNotGoneChild = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild the measure order if the number of children changed or the text length of
|
||||||
|
// any of the children changed.
|
||||||
|
boolean needRebuild = false;
|
||||||
|
if (textViews != mMeasureOrderTextViews.size()
|
||||||
|
|| otherViews != mMeasureOrderOther.size()) {
|
||||||
|
needRebuild = true;
|
||||||
|
}
|
||||||
|
if (!needRebuild) {
|
||||||
|
final int size = mMeasureOrderTextViews.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
Pair<Integer, TextView> pair = mMeasureOrderTextViews.get(i);
|
||||||
|
if (pair.first != pair.second.getText().length()) {
|
||||||
|
needRebuild = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notGoneChildren > 1 && needRebuild) {
|
||||||
|
rebuildMeasureOrder(textViews, otherViews);
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean constrained =
|
||||||
|
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
|
||||||
|
|
||||||
|
final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
|
||||||
|
final int otherSize = mMeasureOrderOther.size();
|
||||||
|
int usedWidth = 0;
|
||||||
|
|
||||||
|
// Optimization: Don't do this if there's only one child.
|
||||||
|
int measuredChildren = 0;
|
||||||
|
for (int i = 0; i < N && notGoneChildren > 1; i++) {
|
||||||
|
// Measure shortest children first. To avoid measuring twice, we approximate by looking
|
||||||
|
// at the text length.
|
||||||
|
View c;
|
||||||
|
if (i < otherSize) {
|
||||||
|
c = mMeasureOrderOther.get(i);
|
||||||
|
} else {
|
||||||
|
c = mMeasureOrderTextViews.get(i - otherSize).second;
|
||||||
|
}
|
||||||
|
if (c.getVisibility() == GONE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
MarginLayoutParams lp = (MarginLayoutParams) c.getLayoutParams();
|
||||||
|
|
||||||
|
int usedWidthForChild = usedWidth;
|
||||||
|
if (constrained) {
|
||||||
|
// Make sure that this child doesn't consume more than its share of the remaining
|
||||||
|
// total available space. Not used space will benefit subsequent views. Since we
|
||||||
|
// measure in the order of (approx.) size, a large view can still take more than its
|
||||||
|
// share if the others are small.
|
||||||
|
int availableWidth = innerWidth - usedWidth;
|
||||||
|
int maxWidthForChild = availableWidth / (notGoneChildren - measuredChildren);
|
||||||
|
|
||||||
|
usedWidthForChild = innerWidth - maxWidthForChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
measureChildWithMargins(c, widthMeasureSpec, usedWidthForChild,
|
||||||
|
heightMeasureSpec, 0 /* usedHeight */);
|
||||||
|
|
||||||
|
usedWidth += c.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
|
||||||
|
measuredChildren++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure to measure the last child full-width if we didn't use up the entire width,
|
||||||
|
// or we didn't measure yet because there's just one child.
|
||||||
|
if (lastNotGoneChild != null && (constrained && usedWidth < innerWidth
|
||||||
|
|| notGoneChildren == 1)) {
|
||||||
|
MarginLayoutParams lp = (MarginLayoutParams) lastNotGoneChild.getLayoutParams();
|
||||||
|
if (notGoneChildren > 1) {
|
||||||
|
// Need to make room, since we already measured this once.
|
||||||
|
usedWidth -= lastNotGoneChild.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
int originalWidth = lp.width;
|
||||||
|
lp.width = LayoutParams.MATCH_PARENT;
|
||||||
|
measureChildWithMargins(lastNotGoneChild, widthMeasureSpec, usedWidth,
|
||||||
|
heightMeasureSpec, 0 /* usedHeight */);
|
||||||
|
lp.width = originalWidth;
|
||||||
|
|
||||||
|
usedWidth += lastNotGoneChild.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft;
|
||||||
|
setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
|
||||||
|
resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rebuildMeasureOrder(int capacityText, int capacityOther) {
|
||||||
|
clearMeasureOrder();
|
||||||
|
mMeasureOrderTextViews.ensureCapacity(capacityText);
|
||||||
|
mMeasureOrderOther.ensureCapacity(capacityOther);
|
||||||
|
final int childCount = getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
View c = getChildAt(i);
|
||||||
|
if (c instanceof TextView && ((TextView) c).getText().length() > 0) {
|
||||||
|
mMeasureOrderTextViews.add(Pair.create(((TextView) c).getText().length(),
|
||||||
|
(TextView)c));
|
||||||
|
} else {
|
||||||
|
mMeasureOrderOther.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mMeasureOrderTextViews.sort(MEASURE_ORDER_COMPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearMeasureOrder() {
|
||||||
|
mMeasureOrderOther.clear();
|
||||||
|
mMeasureOrderTextViews.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewAdded(View child) {
|
||||||
|
super.onViewAdded(child);
|
||||||
|
clearMeasureOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewRemoved(View child) {
|
||||||
|
super.onViewRemoved(child);
|
||||||
|
clearMeasureOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
|
final boolean isLayoutRtl = isLayoutRtl();
|
||||||
|
final int paddingTop = mPaddingTop;
|
||||||
|
|
||||||
|
int childTop;
|
||||||
|
int childLeft;
|
||||||
|
|
||||||
|
// Where bottom of child should go
|
||||||
|
final int height = bottom - top;
|
||||||
|
|
||||||
|
// Space available for child
|
||||||
|
int innerHeight = height - paddingTop - mPaddingBottom;
|
||||||
|
|
||||||
|
final int count = getChildCount();
|
||||||
|
|
||||||
|
final int layoutDirection = getLayoutDirection();
|
||||||
|
switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) {
|
||||||
|
case Gravity.RIGHT:
|
||||||
|
// mTotalWidth contains the padding already
|
||||||
|
childLeft = mPaddingLeft + right - left - mTotalWidth;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Gravity.LEFT:
|
||||||
|
default:
|
||||||
|
childLeft = mPaddingLeft;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
int dir = 1;
|
||||||
|
//In case of RTL, start drawing from the last child.
|
||||||
|
if (isLayoutRtl) {
|
||||||
|
start = count - 1;
|
||||||
|
dir = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final int childIndex = start + dir * i;
|
||||||
|
final View child = getChildAt(childIndex);
|
||||||
|
if (child.getVisibility() != GONE) {
|
||||||
|
final int childWidth = child.getMeasuredWidth();
|
||||||
|
final int childHeight = child.getMeasuredHeight();
|
||||||
|
|
||||||
|
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
|
||||||
|
|
||||||
|
childTop = paddingTop + ((innerHeight - childHeight) / 2)
|
||||||
|
+ lp.topMargin - lp.bottomMargin;
|
||||||
|
|
||||||
|
childLeft += lp.leftMargin;
|
||||||
|
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
|
||||||
|
childLeft += childWidth + lp.rightMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LayoutParams generateLayoutParams(AttributeSet attrs) {
|
||||||
|
return new MarginLayoutParams(getContext(), attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LayoutParams generateDefaultLayoutParams() {
|
||||||
|
return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LayoutParams generateLayoutParams(LayoutParams p) {
|
||||||
|
if (p instanceof MarginLayoutParams) {
|
||||||
|
return new MarginLayoutParams((MarginLayoutParams)p);
|
||||||
|
}
|
||||||
|
return new MarginLayoutParams(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean checkLayoutParams(LayoutParams p) {
|
||||||
|
return p instanceof MarginLayoutParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Comparator<Pair<Integer, TextView>> MEASURE_ORDER_COMPARATOR
|
||||||
|
= (a, b) -> a.first.compareTo(b.first);
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
android:id="@+id/actions_container"
|
android:id="@+id/actions_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
<LinearLayout
|
<com.android.internal.widget.NotificationActionListLayout
|
||||||
android:id="@+id/actions"
|
android:id="@+id/actions"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
@@ -29,5 +29,5 @@
|
|||||||
android:background="@color/notification_action_list"
|
android:background="@color/notification_action_list"
|
||||||
>
|
>
|
||||||
<!-- actions will be added here -->
|
<!-- actions will be added here -->
|
||||||
</LinearLayout>
|
</com.android.internal.widget.NotificationActionListLayout>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user