Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2015 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.packageinstaller.permission.ui;
     18 
     19 import android.content.Context;
     20 import android.util.AttributeSet;
     21 import android.view.Gravity;
     22 import android.view.View;
     23 import android.widget.LinearLayout;
     24 import com.android.packageinstaller.R;
     25 
     26 /**
     27  * An extension of LinearLayout that automatically switches to vertical
     28  * orientation when it can't fit its child views horizontally.
     29  */
     30 public class ButtonBarLayout extends LinearLayout {
     31     /** Whether the current configuration allows stacking. */
     32     private boolean mAllowStacking;
     33 
     34     private int mLastWidthSize = -1;
     35 
     36     public ButtonBarLayout(Context context, AttributeSet attrs) {
     37         super(context, attrs);
     38         mAllowStacking = true;
     39     }
     40 
     41     public void setAllowStacking(boolean allowStacking) {
     42         if (mAllowStacking != allowStacking) {
     43             mAllowStacking = allowStacking;
     44             if (!mAllowStacking && getOrientation() == LinearLayout.VERTICAL) {
     45                 setStacked(false);
     46             }
     47             requestLayout();
     48         }
     49     }
     50 
     51     @Override
     52     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     53         final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
     54 
     55         if (mAllowStacking) {
     56             if (widthSize > mLastWidthSize && isStacked()) {
     57                 // We're being measured wider this time, try un-stacking.
     58                 setStacked(false);
     59             }
     60 
     61             mLastWidthSize = widthSize;
     62         }
     63 
     64         boolean needsRemeasure = false;
     65 
     66         // If we're not stacked, make sure the measure spec is AT_MOST rather
     67         // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we
     68         // know to stack the buttons.
     69         final int initialWidthMeasureSpec;
     70         if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
     71             initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
     72 
     73             // We'll need to remeasure again to fill excess space.
     74             needsRemeasure = true;
     75         } else {
     76             initialWidthMeasureSpec = widthMeasureSpec;
     77         }
     78 
     79         super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
     80 
     81         if (mAllowStacking && !isStacked()) {
     82             final int measuredWidth = getMeasuredWidthAndState();
     83             final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
     84             if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
     85                 setStacked(true);
     86 
     87                 // Measure again in the new orientation.
     88                 needsRemeasure = true;
     89             }
     90         }
     91 
     92         if (needsRemeasure) {
     93             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     94         }
     95     }
     96 
     97     private void setStacked(boolean stacked) {
     98         setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
     99         setGravity(stacked ? Gravity.END : Gravity.BOTTOM);
    100 
    101         final View spacer = findViewById(R.id.spacer);
    102         if (spacer != null) {
    103             spacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
    104         }
    105 
    106         // Reverse the child order. This is specific to the Material button
    107         // bar's layout XML and will probably not generalize.
    108         final int childCount = getChildCount();
    109         for (int i = childCount - 2; i >= 0; i--) {
    110             bringChildToFront(getChildAt(i));
    111         }
    112     }
    113 
    114     private boolean isStacked() {
    115         return getOrientation() == LinearLayout.VERTICAL;
    116     }
    117 }
    118