1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.setupwizardlib.view; 18 19 import android.content.Context; 20 import android.util.AttributeSet; 21 import android.view.View; 22 import android.widget.LinearLayout; 23 import com.android.setupwizardlib.R; 24 25 /** 26 * An extension of LinearLayout that automatically switches to vertical orientation when it can't 27 * fit its child views horizontally. 28 * 29 * <p>Modified from {@code com.android.internal.widget.ButtonBarLayout} 30 */ 31 public class ButtonBarLayout extends LinearLayout { 32 33 private boolean stacked = false; 34 private int originalPaddingLeft; 35 private int originalPaddingRight; 36 ButtonBarLayout(Context context)37 public ButtonBarLayout(Context context) { 38 super(context); 39 } 40 ButtonBarLayout(Context context, AttributeSet attrs)41 public ButtonBarLayout(Context context, AttributeSet attrs) { 42 super(context, attrs); 43 } 44 45 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)46 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 47 final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 48 49 setStacked(false); 50 51 boolean needsRemeasure = false; 52 53 int initialWidthMeasureSpec = widthMeasureSpec; 54 if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { 55 // Measure with WRAP_CONTENT, so that we can compare the measured size with the 56 // available size to see if we need to stack. 57 initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 58 59 // We'll need to remeasure again to fill excess space. 60 needsRemeasure = true; 61 } 62 63 super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec); 64 65 if (getMeasuredWidth() > widthSize) { 66 setStacked(true); 67 68 // Measure again in the new orientation. 69 needsRemeasure = true; 70 } 71 72 if (needsRemeasure) { 73 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 74 } 75 } 76 setStacked(boolean stacked)77 private void setStacked(boolean stacked) { 78 if (this.stacked == stacked) { 79 return; 80 } 81 this.stacked = stacked; 82 int childCount = getChildCount(); 83 for (int i = 0; i < childCount; i++) { 84 View child = getChildAt(i); 85 LayoutParams childParams = (LayoutParams) child.getLayoutParams(); 86 if (stacked) { 87 child.setTag(R.id.suw_original_weight, childParams.weight); 88 childParams.weight = 0; 89 } else { 90 Float weight = (Float) child.getTag(R.id.suw_original_weight); 91 if (weight != null) { 92 childParams.weight = weight; 93 } 94 } 95 child.setLayoutParams(childParams); 96 } 97 98 setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL); 99 100 // Reverse the child order, so that the primary button is towards the top when vertical 101 for (int i = childCount - 1; i >= 0; i--) { 102 bringChildToFront(getChildAt(i)); 103 } 104 105 if (stacked) { 106 // HACK: In the default button bar style, the left and right paddings are not 107 // balanced to compensate for different alignment for borderless (left) button and 108 // the raised (right) button. When it's stacked, we want the buttons to be centered, 109 // so we balance out the paddings here. 110 originalPaddingLeft = getPaddingLeft(); 111 originalPaddingRight = getPaddingRight(); 112 int paddingHorizontal = Math.max(originalPaddingLeft, originalPaddingRight); 113 setPadding(paddingHorizontal, getPaddingTop(), paddingHorizontal, getPaddingBottom()); 114 } else { 115 setPadding(originalPaddingLeft, getPaddingTop(), originalPaddingRight, getPaddingBottom()); 116 } 117 } 118 } 119