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 17package com.android.setupwizardlib.view; 18 19import android.content.Context; 20import android.util.AttributeSet; 21import android.view.View; 22import android.widget.LinearLayout; 23 24import com.android.setupwizardlib.R; 25 26/** 27 * An extension of LinearLayout that automatically switches to vertical orientation when it can't 28 * fit its child views horizontally. 29 * 30 * Modified from {@code com.android.internal.widget.ButtonBarLayout} 31 */ 32public class ButtonBarLayout extends LinearLayout { 33 34 private boolean mStacked = false; 35 private int mOriginalPaddingLeft; 36 private int mOriginalPaddingRight; 37 38 public ButtonBarLayout(Context context) { 39 super(context); 40 } 41 42 public ButtonBarLayout(Context context, AttributeSet attrs) { 43 super(context, attrs); 44 } 45 46 @Override 47 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 48 final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 49 50 setStacked(false); 51 52 boolean needsRemeasure = false; 53 54 int initialWidthMeasureSpec = widthMeasureSpec; 55 if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { 56 // Measure with WRAP_CONTENT, so that we can compare the measured size with the 57 // available size to see if we need to stack. 58 initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 59 60 // We'll need to remeasure again to fill excess space. 61 needsRemeasure = true; 62 } 63 64 super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec); 65 66 if (getMeasuredWidth() > widthSize) { 67 setStacked(true); 68 69 // Measure again in the new orientation. 70 needsRemeasure = true; 71 } 72 73 if (needsRemeasure) { 74 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 75 } 76 } 77 78 private void setStacked(boolean stacked) { 79 if (mStacked == stacked) { 80 return; 81 } 82 mStacked = stacked; 83 int childCount = getChildCount(); 84 for (int i = 0; i < childCount; i++) { 85 View child = getChildAt(i); 86 LayoutParams childParams = (LayoutParams) child.getLayoutParams(); 87 if (stacked) { 88 child.setTag(R.id.suw_original_weight, childParams.weight); 89 childParams.weight = 0; 90 } else { 91 Float weight = (Float) child.getTag(R.id.suw_original_weight); 92 if (weight != null) { 93 childParams.weight = weight; 94 } 95 } 96 child.setLayoutParams(childParams); 97 } 98 99 setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL); 100 101 // Reverse the child order, so that the primary button is towards the top when vertical 102 for (int i = childCount - 1; i >= 0; i--) { 103 bringChildToFront(getChildAt(i)); 104 } 105 106 if (stacked) { 107 // HACK: In the default button bar style, the left and right paddings are not 108 // balanced to compensate for different alignment for borderless (left) button and 109 // the raised (right) button. When it's stacked, we want the buttons to be centered, 110 // so we balance out the paddings here. 111 mOriginalPaddingLeft = getPaddingLeft(); 112 mOriginalPaddingRight = getPaddingRight(); 113 int paddingHorizontal = Math.max(mOriginalPaddingLeft, mOriginalPaddingRight); 114 setPadding( 115 paddingHorizontal, getPaddingTop(), paddingHorizontal, getPaddingBottom()); 116 } else { 117 setPadding( 118 mOriginalPaddingLeft, 119 getPaddingTop(), 120 mOriginalPaddingRight, 121 getPaddingBottom()); 122 } 123 } 124} 125