blob: 74b39268fc2ddfff3b3db9fcb26686595ace5f92 [file] [log] [blame]
Petr Cermaked7429c2017-12-18 19:38:04 +00001package com.android.systemui.statusbar.policy;
2
3import android.app.PendingIntent;
4import android.app.RemoteInput;
5import android.content.Context;
6import android.content.Intent;
Petr Cermak102431d2018-01-29 10:36:07 +00007import android.content.res.TypedArray;
8import android.graphics.Canvas;
9import android.graphics.drawable.GradientDrawable;
10import android.graphics.drawable.RippleDrawable;
Petr Cermaked7429c2017-12-18 19:38:04 +000011import android.os.Bundle;
Petr Cermak102431d2018-01-29 10:36:07 +000012import android.text.Layout;
13import android.text.TextPaint;
14import android.text.method.TransformationMethod;
Petr Cermaked7429c2017-12-18 19:38:04 +000015import android.util.AttributeSet;
16import android.util.Log;
17import android.view.LayoutInflater;
Petr Cermak102431d2018-01-29 10:36:07 +000018import android.view.View;
Petr Cermaked7429c2017-12-18 19:38:04 +000019import android.view.ViewGroup;
20import android.widget.Button;
Petr Cermaked7429c2017-12-18 19:38:04 +000021
Petr Cermak102431d2018-01-29 10:36:07 +000022import com.android.internal.annotations.VisibleForTesting;
Milo Sredkovb0f55e92018-04-04 16:13:28 +010023import com.android.keyguard.KeyguardHostView.OnDismissAction;
Petr Cermak10011fa2018-02-05 19:00:54 +000024import com.android.systemui.Dependency;
Petr Cermaked7429c2017-12-18 19:38:04 +000025import com.android.systemui.R;
Milo Sredkovb0f55e92018-04-04 16:13:28 +010026import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
Petr Cermaked7429c2017-12-18 19:38:04 +000027
Petr Cermak102431d2018-01-29 10:36:07 +000028import java.text.BreakIterator;
29import java.util.Comparator;
30import java.util.PriorityQueue;
31
Petr Cermaked7429c2017-12-18 19:38:04 +000032/** View which displays smart reply buttons in notifications. */
Petr Cermak102431d2018-01-29 10:36:07 +000033public class SmartReplyView extends ViewGroup {
Petr Cermaked7429c2017-12-18 19:38:04 +000034
35 private static final String TAG = "SmartReplyView";
36
Petr Cermak102431d2018-01-29 10:36:07 +000037 private static final int MEASURE_SPEC_ANY_WIDTH =
38 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
39
40 private static final Comparator<View> DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR =
41 (v1, v2) -> ((v2.getMeasuredWidth() - v2.getPaddingLeft() - v2.getPaddingRight())
42 - (v1.getMeasuredWidth() - v1.getPaddingLeft() - v1.getPaddingRight()));
43
44 private static final int SQUEEZE_FAILED = -1;
45
Petr Cermak10011fa2018-02-05 19:00:54 +000046 private final SmartReplyConstants mConstants;
Milo Sredkovb0f55e92018-04-04 16:13:28 +010047 private final KeyguardDismissUtil mKeyguardDismissUtil;
Petr Cermak10011fa2018-02-05 19:00:54 +000048
Petr Cermak102431d2018-01-29 10:36:07 +000049 /** Spacing to be applied between views. */
50 private final int mSpacing;
51
52 /** Horizontal padding of smart reply buttons if all of them use only one line of text. */
53 private final int mSingleLineButtonPaddingHorizontal;
54
55 /** Horizontal padding of smart reply buttons if at least one of them uses two lines of text. */
56 private final int mDoubleLineButtonPaddingHorizontal;
57
58 /** Increase in width of a smart reply button as a result of using two lines instead of one. */
59 private final int mSingleToDoubleLineButtonWidthIncrease;
60
61 private final BreakIterator mBreakIterator;
62
63 private PriorityQueue<Button> mCandidateButtonQueueForSqueezing;
64
Petr Cermaked7429c2017-12-18 19:38:04 +000065 public SmartReplyView(Context context, AttributeSet attrs) {
66 super(context, attrs);
Petr Cermak10011fa2018-02-05 19:00:54 +000067 mConstants = Dependency.get(SmartReplyConstants.class);
Milo Sredkovb0f55e92018-04-04 16:13:28 +010068 mKeyguardDismissUtil = Dependency.get(KeyguardDismissUtil.class);
Petr Cermak102431d2018-01-29 10:36:07 +000069
70 int spacing = 0;
71 int singleLineButtonPaddingHorizontal = 0;
72 int doubleLineButtonPaddingHorizontal = 0;
73
74 final TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SmartReplyView,
75 0, 0);
76 final int length = arr.getIndexCount();
77 for (int i = 0; i < length; i++) {
78 int attr = arr.getIndex(i);
79 switch (attr) {
80 case R.styleable.SmartReplyView_spacing:
81 spacing = arr.getDimensionPixelSize(i, 0);
82 break;
83 case R.styleable.SmartReplyView_singleLineButtonPaddingHorizontal:
84 singleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
85 break;
86 case R.styleable.SmartReplyView_doubleLineButtonPaddingHorizontal:
87 doubleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
88 break;
89 }
90 }
91 arr.recycle();
92
93 mSpacing = spacing;
94 mSingleLineButtonPaddingHorizontal = singleLineButtonPaddingHorizontal;
95 mDoubleLineButtonPaddingHorizontal = doubleLineButtonPaddingHorizontal;
96 mSingleToDoubleLineButtonWidthIncrease =
97 2 * (doubleLineButtonPaddingHorizontal - singleLineButtonPaddingHorizontal);
98
99 mBreakIterator = BreakIterator.getLineInstance();
100 reallocateCandidateButtonQueueForSqueezing();
101 }
102
103 private void reallocateCandidateButtonQueueForSqueezing() {
104 // Instead of clearing the priority queue, we re-allocate so that it would fit all buttons
105 // exactly. This avoids (1) wasting memory because PriorityQueue never shrinks and
106 // (2) growing in onMeasure.
107 // The constructor throws an IllegalArgument exception if initial capacity is less than 1.
108 mCandidateButtonQueueForSqueezing = new PriorityQueue<>(
109 Math.max(getChildCount(), 1), DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR);
Petr Cermaked7429c2017-12-18 19:38:04 +0000110 }
111
112 public void setRepliesFromRemoteInput(RemoteInput remoteInput, PendingIntent pendingIntent) {
113 removeAllViews();
114 if (remoteInput != null && pendingIntent != null) {
115 CharSequence[] choices = remoteInput.getChoices();
116 if (choices != null) {
117 for (CharSequence choice : choices) {
118 Button replyButton = inflateReplyButton(
119 getContext(), this, choice, remoteInput, pendingIntent);
120 addView(replyButton);
121 }
122 }
123 }
Petr Cermak102431d2018-01-29 10:36:07 +0000124 reallocateCandidateButtonQueueForSqueezing();
Petr Cermaked7429c2017-12-18 19:38:04 +0000125 }
126
127 public static SmartReplyView inflate(Context context, ViewGroup root) {
128 return (SmartReplyView)
129 LayoutInflater.from(context).inflate(R.layout.smart_reply_view, root, false);
130 }
131
Petr Cermak102431d2018-01-29 10:36:07 +0000132 @VisibleForTesting
Milo Sredkovb0f55e92018-04-04 16:13:28 +0100133 Button inflateReplyButton(Context context, ViewGroup root, CharSequence choice,
Petr Cermaked7429c2017-12-18 19:38:04 +0000134 RemoteInput remoteInput, PendingIntent pendingIntent) {
135 Button b = (Button) LayoutInflater.from(context).inflate(
136 R.layout.smart_reply_button, root, false);
137 b.setText(choice);
Milo Sredkovb0f55e92018-04-04 16:13:28 +0100138
139 OnDismissAction action = () -> {
Petr Cermaked7429c2017-12-18 19:38:04 +0000140 Bundle results = new Bundle();
141 results.putString(remoteInput.getResultKey(), choice.toString());
142 Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
143 RemoteInput.addResultsToIntent(new RemoteInput[]{remoteInput}, intent, results);
Petr Cermak9a3380c2018-01-19 15:00:24 +0000144 RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE);
Petr Cermaked7429c2017-12-18 19:38:04 +0000145 try {
146 pendingIntent.send(context, 0, intent);
147 } catch (PendingIntent.CanceledException e) {
148 Log.w(TAG, "Unable to send smart reply", e);
149 }
Milo Sredkovb0f55e92018-04-04 16:13:28 +0100150 return false; // do not defer
151 };
152
153 b.setOnClickListener(view -> {
154 mKeyguardDismissUtil.dismissKeyguardThenExecute(
155 action, null /* cancelAction */, false /* afterKeyguardGone */);
Petr Cermaked7429c2017-12-18 19:38:04 +0000156 });
157 return b;
158 }
Petr Cermak102431d2018-01-29 10:36:07 +0000159
160 @Override
161 public LayoutParams generateLayoutParams(AttributeSet attrs) {
162 return new LayoutParams(mContext, attrs);
163 }
164
165 @Override
166 protected LayoutParams generateDefaultLayoutParams() {
167 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
168 }
169
170 @Override
171 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams params) {
172 return new LayoutParams(params.width, params.height);
173 }
174
175 @Override
176 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
177 final int targetWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED
178 ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec);
179
180 // Mark all buttons as hidden and un-squeezed.
181 resetButtonsLayoutParams();
182
183 if (!mCandidateButtonQueueForSqueezing.isEmpty()) {
184 Log.wtf(TAG, "Single line button queue leaked between onMeasure calls");
185 mCandidateButtonQueueForSqueezing.clear();
186 }
187
188 int measuredWidth = mPaddingLeft + mPaddingRight;
189 int maxChildHeight = 0;
190 int displayedChildCount = 0;
191 int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal;
192
193 final int childCount = getChildCount();
194 for (int i = 0; i < childCount; i++) {
195 final View child = getChildAt(i);
196 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
197 if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) {
198 continue;
199 }
200
201 child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
202 buttonPaddingHorizontal, child.getPaddingBottom());
203 child.measure(MEASURE_SPEC_ANY_WIDTH, heightMeasureSpec);
204
205 final int lineCount = ((Button) child).getLineCount();
206 if (lineCount < 1 || lineCount > 2) {
207 // If smart reply has no text, or more than two lines, then don't show it.
208 continue;
209 }
210
211 if (lineCount == 1) {
212 mCandidateButtonQueueForSqueezing.add((Button) child);
213 }
214
215 // Remember the current measurements in case the current button doesn't fit in.
216 final int originalMaxChildHeight = maxChildHeight;
217 final int originalMeasuredWidth = measuredWidth;
218 final int originalButtonPaddingHorizontal = buttonPaddingHorizontal;
219
220 final int spacing = displayedChildCount == 0 ? 0 : mSpacing;
221 final int childWidth = child.getMeasuredWidth();
222 final int childHeight = child.getMeasuredHeight();
223 measuredWidth += spacing + childWidth;
224 maxChildHeight = Math.max(maxChildHeight, childHeight);
225
226 // Do we need to increase the number of lines in smart reply buttons to two?
227 final boolean increaseToTwoLines =
228 buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal
229 && (lineCount == 2 || measuredWidth > targetWidth);
230 if (increaseToTwoLines) {
231 measuredWidth += (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
232 buttonPaddingHorizontal = mDoubleLineButtonPaddingHorizontal;
233 }
234
235 // If the last button doesn't fit into the remaining width, try squeezing preceding
236 // smart reply buttons.
237 if (measuredWidth > targetWidth) {
238 // Keep squeezing preceding and current smart reply buttons until they all fit.
239 while (measuredWidth > targetWidth
240 && !mCandidateButtonQueueForSqueezing.isEmpty()) {
241 final Button candidate = mCandidateButtonQueueForSqueezing.poll();
242 final int squeezeReduction = squeezeButton(candidate, heightMeasureSpec);
243 if (squeezeReduction != SQUEEZE_FAILED) {
244 maxChildHeight = Math.max(maxChildHeight, candidate.getMeasuredHeight());
245 measuredWidth -= squeezeReduction;
246 }
247 }
248
249 // If the current button still doesn't fit after squeezing all buttons, undo the
250 // last squeezing round.
251 if (measuredWidth > targetWidth) {
252 measuredWidth = originalMeasuredWidth;
253 maxChildHeight = originalMaxChildHeight;
254 buttonPaddingHorizontal = originalButtonPaddingHorizontal;
255
256 // Mark all buttons from the last squeezing round as "failed to squeeze", so
257 // that they're re-measured without squeezing later.
258 markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_FAILED, i);
259
260 // The current button doesn't fit, so there's no point in measuring further
261 // buttons.
262 break;
263 }
264
265 // The current button fits, so mark all squeezed buttons as "successfully squeezed"
266 // to prevent them from being un-squeezed in a subsequent squeezing round.
267 markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, i);
268 }
269
270 lp.show = true;
271 displayedChildCount++;
272 }
273
274 // We're done squeezing buttons, so we can clear the priority queue.
275 mCandidateButtonQueueForSqueezing.clear();
276
277 // Finally, we need to update corner radius and re-measure some buttons.
278 updateCornerRadiusAndRemeasureButtonsIfNecessary(buttonPaddingHorizontal, maxChildHeight);
279
280 setMeasuredDimension(
281 resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth), widthMeasureSpec),
282 resolveSize(Math.max(getSuggestedMinimumHeight(),
283 mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec));
284 }
285
286 private void resetButtonsLayoutParams() {
287 final int childCount = getChildCount();
288 for (int i = 0; i < childCount; i++) {
289 final View child = getChildAt(i);
290 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
291 lp.show = false;
292 lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_NONE;
293 }
294 }
295
296 private int squeezeButton(Button button, int heightMeasureSpec) {
297 final int estimatedOptimalTextWidth = estimateOptimalSqueezedButtonTextWidth(button);
298 if (estimatedOptimalTextWidth == SQUEEZE_FAILED) {
299 return SQUEEZE_FAILED;
300 }
301 return squeezeButtonToTextWidth(button, heightMeasureSpec, estimatedOptimalTextWidth);
302 }
303
304 private int estimateOptimalSqueezedButtonTextWidth(Button button) {
305 // Find a line-break point in the middle of the smart reply button text.
306 final String rawText = button.getText().toString();
307
308 // The button sometimes has a transformation affecting text layout (e.g. all caps).
309 final TransformationMethod transformation = button.getTransformationMethod();
310 final String text = transformation == null ?
311 rawText : transformation.getTransformation(rawText, button).toString();
312 final int length = text.length();
313 mBreakIterator.setText(text);
314
315 if (mBreakIterator.preceding(length / 2) == BreakIterator.DONE) {
316 if (mBreakIterator.next() == BreakIterator.DONE) {
317 // Can't find a single possible line break in either direction.
318 return SQUEEZE_FAILED;
319 }
320 }
321
322 final TextPaint paint = button.getPaint();
323 final int initialPosition = mBreakIterator.current();
324 final float initialLeftTextWidth = Layout.getDesiredWidth(text, 0, initialPosition, paint);
325 final float initialRightTextWidth =
326 Layout.getDesiredWidth(text, initialPosition, length, paint);
327 float optimalTextWidth = Math.max(initialLeftTextWidth, initialRightTextWidth);
328
329 if (initialLeftTextWidth != initialRightTextWidth) {
330 // See if there's a better line-break point (leading to a more narrow button) in
331 // either left or right direction.
332 final boolean moveLeft = initialLeftTextWidth > initialRightTextWidth;
333 final int maxSqueezeRemeasureAttempts = mConstants.getMaxSqueezeRemeasureAttempts();
334 for (int i = 0; i < maxSqueezeRemeasureAttempts; i++) {
335 final int newPosition =
336 moveLeft ? mBreakIterator.previous() : mBreakIterator.next();
337 if (newPosition == BreakIterator.DONE) {
338 break;
339 }
340
341 final float newLeftTextWidth = Layout.getDesiredWidth(text, 0, newPosition, paint);
342 final float newRightTextWidth =
343 Layout.getDesiredWidth(text, newPosition, length, paint);
344 final float newOptimalTextWidth = Math.max(newLeftTextWidth, newRightTextWidth);
345 if (newOptimalTextWidth < optimalTextWidth) {
346 optimalTextWidth = newOptimalTextWidth;
347 } else {
348 break;
349 }
350
351 boolean tooFar = moveLeft
352 ? newLeftTextWidth <= newRightTextWidth
353 : newLeftTextWidth >= newRightTextWidth;
354 if (tooFar) {
355 break;
356 }
357 }
358 }
359
360 return (int) Math.ceil(optimalTextWidth);
361 }
362
363 private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
364 int oldWidth = button.getMeasuredWidth();
365 if (button.getPaddingLeft() != mDoubleLineButtonPaddingHorizontal) {
366 // Correct for the fact that the button was laid out with single-line horizontal
367 // padding.
368 oldWidth += mSingleToDoubleLineButtonWidthIncrease;
369 }
370
371 // Re-measure the squeezed smart reply button.
372 button.setPadding(mDoubleLineButtonPaddingHorizontal, button.getPaddingTop(),
373 mDoubleLineButtonPaddingHorizontal, button.getPaddingBottom());
374 final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
375 2 * mDoubleLineButtonPaddingHorizontal + textWidth, MeasureSpec.AT_MOST);
376 button.measure(widthMeasureSpec, heightMeasureSpec);
377
378 final int newWidth = button.getMeasuredWidth();
379
380 final LayoutParams lp = (LayoutParams) button.getLayoutParams();
381 if (button.getLineCount() > 2 || newWidth >= oldWidth) {
382 lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_FAILED;
383 return SQUEEZE_FAILED;
384 } else {
385 lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_PENDING;
386 return oldWidth - newWidth;
387 }
388 }
389
390 private void updateCornerRadiusAndRemeasureButtonsIfNecessary(
391 int buttonPaddingHorizontal, int maxChildHeight) {
392 final float cornerRadius = ((float) maxChildHeight) / 2;
393 final int maxChildHeightMeasure =
394 MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY);
395
396 final int childCount = getChildCount();
397 for (int i = 0; i < childCount; i++) {
398 final View child = getChildAt(i);
399 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
400 if (!lp.show) {
401 continue;
402 }
403
404 // Update corner radius.
405 GradientDrawable backgroundDrawable =
406 (GradientDrawable) ((RippleDrawable) child.getBackground()).getDrawable(0);
407 backgroundDrawable.setCornerRadius(cornerRadius);
408
409 boolean requiresNewMeasure = false;
410 int newWidth = child.getMeasuredWidth();
411
412 // Re-measure reason 1: The button needs to be un-squeezed (either because it resulted
413 // in more than two lines or because it was unnecessary).
414 if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_FAILED) {
415 requiresNewMeasure = true;
416 newWidth = Integer.MAX_VALUE;
417 }
418
419 // Re-measure reason 2: The button's horizontal padding is incorrect (because it was
420 // measured with the wrong number of lines).
421 if (child.getPaddingLeft() != buttonPaddingHorizontal) {
422 requiresNewMeasure = true;
423 if (buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal) {
424 // Decrease padding (2->1 line).
425 newWidth -= mSingleToDoubleLineButtonWidthIncrease;
426 } else {
427 // Increase padding (1->2 lines).
428 newWidth += mSingleToDoubleLineButtonWidthIncrease;
429 }
430 child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
431 buttonPaddingHorizontal, child.getPaddingBottom());
432 }
433
434 // Re-measure reason 3: The button's height is less than the max height of all buttons
435 // (all should have the same height).
436 if (child.getMeasuredHeight() != maxChildHeight) {
437 requiresNewMeasure = true;
438 }
439
440 if (requiresNewMeasure) {
441 child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.AT_MOST),
442 maxChildHeightMeasure);
443 }
444 }
445 }
446
447 private void markButtonsWithPendingSqueezeStatusAs(int squeezeStatus, int maxChildIndex) {
448 for (int i = 0; i <= maxChildIndex; i++) {
449 final View child = getChildAt(i);
450 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
451 if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_PENDING) {
452 lp.squeezeStatus = squeezeStatus;
453 }
454 }
455 }
456
457 @Override
458 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
459 final boolean isRtl = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
460
461 final int width = right - left;
462 int position = isRtl ? width - mPaddingRight : mPaddingLeft;
463
464 final int childCount = getChildCount();
465 for (int i = 0; i < childCount; i++) {
466 final View child = getChildAt(i);
467 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
468 if (!lp.show) {
469 continue;
470 }
471
472 final int childWidth = child.getMeasuredWidth();
473 final int childHeight = child.getMeasuredHeight();
474 final int childLeft = isRtl ? position - childWidth : position;
475 child.layout(childLeft, 0, childLeft + childWidth, childHeight);
476
477 final int childWidthWithSpacing = childWidth + mSpacing;
478 if (isRtl) {
479 position -= childWidthWithSpacing;
480 } else {
481 position += childWidthWithSpacing;
482 }
483 }
484 }
485
486 @Override
487 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
488 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
489 return lp.show && super.drawChild(canvas, child, drawingTime);
490 }
491
492 @VisibleForTesting
493 static class LayoutParams extends ViewGroup.LayoutParams {
494
495 /** Button is not squeezed. */
496 private static final int SQUEEZE_STATUS_NONE = 0;
497
498 /**
499 * Button was successfully squeezed, but it might be un-squeezed later if the squeezing
500 * turns out to have been unnecessary (because there's still not enough space to add another
501 * button).
502 */
503 private static final int SQUEEZE_STATUS_PENDING = 1;
504
505 /** Button was successfully squeezed and it won't be un-squeezed. */
506 private static final int SQUEEZE_STATUS_SUCCESSFUL = 2;
507
508 /**
509 * Button wasn't successfully squeezed. The squeezing resulted in more than two lines of
510 * text or it didn't reduce the button's width at all. The button will have to be
511 * re-measured to use only one line of text.
512 */
513 private static final int SQUEEZE_STATUS_FAILED = 3;
514
515 private boolean show = false;
516 private int squeezeStatus = SQUEEZE_STATUS_NONE;
517
518 private LayoutParams(Context c, AttributeSet attrs) {
519 super(c, attrs);
520 }
521
522 private LayoutParams(int width, int height) {
523 super(width, height);
524 }
525
526 @VisibleForTesting
527 boolean isShown() {
528 return show;
529 }
530 }
Petr Cermaked7429c2017-12-18 19:38:04 +0000531}