Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2014 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 androidx.appcompat.widget;
     18 
     19 import static android.view.View.MeasureSpec.AT_MOST;
     20 import static android.view.View.MeasureSpec.EXACTLY;
     21 import static android.view.View.MeasureSpec.getMode;
     22 
     23 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
     24 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     25 
     26 import android.content.Context;
     27 import android.graphics.Rect;
     28 import android.util.AttributeSet;
     29 import android.util.DisplayMetrics;
     30 import android.util.TypedValue;
     31 import android.widget.FrameLayout;
     32 
     33 import androidx.annotation.RestrictTo;
     34 import androidx.core.view.ViewCompat;
     35 
     36 /**
     37  * @hide
     38  */
     39 @RestrictTo(LIBRARY)
     40 public class ContentFrameLayout extends FrameLayout {
     41 
     42     public interface OnAttachListener {
     43         void onDetachedFromWindow();
     44         void onAttachedFromWindow();
     45     }
     46 
     47     private TypedValue mMinWidthMajor;
     48     private TypedValue mMinWidthMinor;
     49     private TypedValue mFixedWidthMajor;
     50     private TypedValue mFixedWidthMinor;
     51     private TypedValue mFixedHeightMajor;
     52     private TypedValue mFixedHeightMinor;
     53 
     54     private final Rect mDecorPadding;
     55 
     56     private OnAttachListener mAttachListener;
     57 
     58     public ContentFrameLayout(Context context) {
     59         this(context, null);
     60     }
     61 
     62     public ContentFrameLayout(Context context, AttributeSet attrs) {
     63         this(context, attrs, 0);
     64     }
     65 
     66     public ContentFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
     67         super(context, attrs, defStyleAttr);
     68         mDecorPadding = new Rect();
     69     }
     70 
     71     /**
     72      * @hide
     73      */
     74     @RestrictTo(LIBRARY_GROUP)
     75     public void dispatchFitSystemWindows(Rect insets) {
     76         fitSystemWindows(insets);
     77     }
     78 
     79     public void setAttachListener(OnAttachListener attachListener) {
     80         mAttachListener = attachListener;
     81     }
     82 
     83     /**
     84      * Notify this view of the window decor view's padding. We use these values when working out
     85      * our size for the window size attributes.
     86      *
     87      * @hide
     88      */
     89     @RestrictTo(LIBRARY_GROUP)
     90     public void setDecorPadding(int left, int top, int right, int bottom) {
     91         mDecorPadding.set(left, top, right, bottom);
     92         if (ViewCompat.isLaidOut(this)) {
     93             requestLayout();
     94         }
     95     }
     96 
     97     @Override
     98     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     99         final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
    100         final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
    101 
    102         final int widthMode = getMode(widthMeasureSpec);
    103         final int heightMode = getMode(heightMeasureSpec);
    104 
    105         boolean fixedWidth = false;
    106         if (widthMode == AT_MOST) {
    107             final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor;
    108             if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
    109                 int w = 0;
    110                 if (tvw.type == TypedValue.TYPE_DIMENSION) {
    111                     w = (int) tvw.getDimension(metrics);
    112                 } else if (tvw.type == TypedValue.TYPE_FRACTION) {
    113                     w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels);
    114                 }
    115                 if (w > 0) {
    116                     w -= (mDecorPadding.left + mDecorPadding.right);
    117                     final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    118                     widthMeasureSpec = MeasureSpec.makeMeasureSpec(
    119                             Math.min(w, widthSize), EXACTLY);
    120                     fixedWidth = true;
    121                 }
    122             }
    123         }
    124 
    125         if (heightMode == AT_MOST) {
    126             final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor;
    127             if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
    128                 int h = 0;
    129                 if (tvh.type == TypedValue.TYPE_DIMENSION) {
    130                     h = (int) tvh.getDimension(metrics);
    131                 } else if (tvh.type == TypedValue.TYPE_FRACTION) {
    132                     h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels);
    133                 }
    134                 if (h > 0) {
    135                     h -= (mDecorPadding.top + mDecorPadding.bottom);
    136                     final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    137                     heightMeasureSpec = MeasureSpec.makeMeasureSpec(
    138                             Math.min(h, heightSize), EXACTLY);
    139                 }
    140             }
    141         }
    142 
    143         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    144 
    145         int width = getMeasuredWidth();
    146         boolean measure = false;
    147 
    148         widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
    149 
    150         if (!fixedWidth && widthMode == AT_MOST) {
    151             final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
    152             if (tv != null && tv.type != TypedValue.TYPE_NULL) {
    153                 int min = 0;
    154                 if (tv.type == TypedValue.TYPE_DIMENSION) {
    155                     min = (int) tv.getDimension(metrics);
    156                 } else if (tv.type == TypedValue.TYPE_FRACTION) {
    157                     min = (int) tv.getFraction(metrics.widthPixels, metrics.widthPixels);
    158                 }
    159                 if (min > 0) {
    160                     min -= (mDecorPadding.left + mDecorPadding.right);
    161                 }
    162                 if (width < min) {
    163                     widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
    164                     measure = true;
    165                 }
    166             }
    167         }
    168 
    169         if (measure) {
    170             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    171         }
    172     }
    173 
    174     public TypedValue getMinWidthMajor() {
    175         if (mMinWidthMajor == null) mMinWidthMajor = new TypedValue();
    176         return mMinWidthMajor;
    177     }
    178 
    179     public TypedValue getMinWidthMinor() {
    180         if (mMinWidthMinor == null) mMinWidthMinor = new TypedValue();
    181         return mMinWidthMinor;
    182     }
    183 
    184     public TypedValue getFixedWidthMajor() {
    185         if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
    186         return mFixedWidthMajor;
    187     }
    188 
    189     public TypedValue getFixedWidthMinor() {
    190         if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
    191         return mFixedWidthMinor;
    192     }
    193 
    194     public TypedValue getFixedHeightMajor() {
    195         if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
    196         return mFixedHeightMajor;
    197     }
    198 
    199     public TypedValue getFixedHeightMinor() {
    200         if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
    201         return mFixedHeightMinor;
    202     }
    203 
    204     @Override
    205     protected void onAttachedToWindow() {
    206         super.onAttachedToWindow();
    207         if (mAttachListener != null) {
    208             mAttachListener.onAttachedFromWindow();
    209         }
    210     }
    211 
    212     @Override
    213     protected void onDetachedFromWindow() {
    214         super.onDetachedFromWindow();
    215         if (mAttachListener != null) {
    216             mAttachListener.onDetachedFromWindow();
    217         }
    218     }
    219 }
    220