Home | History | Annotate | Download | only in launcher3
      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.launcher3;
     18 
     19 import android.content.Context;
     20 import android.graphics.Rect;
     21 import android.util.AttributeSet;
     22 import android.util.Log;
     23 import android.widget.LinearLayout;
     24 
     25 /**
     26  * A base container view, which supports resizing.
     27  */
     28 public abstract class BaseContainerView extends LinearLayout implements Insettable {
     29 
     30     private final static String TAG = "BaseContainerView";
     31 
     32     // The window insets
     33     private Rect mInsets = new Rect();
     34     // The bounds of the search bar.  Only the left, top, right are used to inset the
     35     // search bar and the height is determined by the measurement of the layout
     36     private Rect mFixedSearchBarBounds = new Rect();
     37     // The bounds of the container
     38     protected Rect mContentBounds = new Rect();
     39     // The padding to apply to the container to achieve the bounds
     40     protected Rect mContentPadding = new Rect();
     41     // The inset to apply to the edges and between the search bar and the container
     42     private int mContainerBoundsInset;
     43     private boolean mHasSearchBar;
     44 
     45     public BaseContainerView(Context context) {
     46         this(context, null);
     47     }
     48 
     49     public BaseContainerView(Context context, AttributeSet attrs) {
     50         this(context, attrs, 0);
     51     }
     52 
     53     public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
     54         super(context, attrs, defStyleAttr);
     55         mContainerBoundsInset = getResources().getDimensionPixelSize(R.dimen.container_bounds_inset);
     56     }
     57 
     58     @Override
     59     final public void setInsets(Rect insets) {
     60         mInsets.set(insets);
     61         updateBackgroundAndPaddings();
     62     }
     63 
     64     protected void setHasSearchBar() {
     65         mHasSearchBar = true;
     66     }
     67 
     68     /**
     69      * Sets the search bar bounds for this container view to match.
     70      */
     71     final public void setSearchBarBounds(Rect bounds) {
     72         if (LauncherAppState.isDogfoodBuild() && !isValidSearchBarBounds(bounds)) {
     73             Log.e(TAG, "Invalid search bar bounds: " + bounds);
     74         }
     75 
     76         mFixedSearchBarBounds.set(bounds);
     77 
     78         // Post the updates since they can trigger a relayout, and this call can be triggered from
     79         // a layout pass itself.
     80         post(new Runnable() {
     81             @Override
     82             public void run() {
     83                 updateBackgroundAndPaddings();
     84             }
     85         });
     86     }
     87 
     88     /**
     89      * Update the backgrounds and padding in response to a change in the bounds or insets.
     90      */
     91     protected void updateBackgroundAndPaddings() {
     92         Rect padding;
     93         Rect searchBarBounds = new Rect(mFixedSearchBarBounds);
     94         if (!isValidSearchBarBounds(mFixedSearchBarBounds)) {
     95             // Use the default bounds
     96             padding = new Rect(mInsets.left + mContainerBoundsInset,
     97                     (mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
     98                     mInsets.right + mContainerBoundsInset,
     99                     mInsets.bottom + mContainerBoundsInset);
    100 
    101             // Special case -- we have the search bar, but no specific bounds, so just give it
    102             // the inset bounds without a height.
    103             searchBarBounds.set(mInsets.left + mContainerBoundsInset,
    104                     mInsets.top + mContainerBoundsInset,
    105                     getMeasuredWidth() - (mInsets.right + mContainerBoundsInset), 0);
    106         } else {
    107             // Use the search bounds, if there is a search bar, the bounds will contain
    108             // the offsets for the insets so we can ignore that
    109             padding = new Rect(mFixedSearchBarBounds.left,
    110                     (mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
    111                     getMeasuredWidth() - mFixedSearchBarBounds.right,
    112                     mInsets.bottom + mContainerBoundsInset);
    113         }
    114         if (!padding.equals(mContentPadding) || !searchBarBounds.equals(mFixedSearchBarBounds)) {
    115             mContentPadding.set(padding);
    116             mContentBounds.set(padding.left, padding.top,
    117                     getMeasuredWidth() - padding.right,
    118                     getMeasuredHeight() - padding.bottom);
    119             mFixedSearchBarBounds.set(searchBarBounds);
    120             onUpdateBackgroundAndPaddings(mFixedSearchBarBounds, padding);
    121         }
    122     }
    123 
    124     /**
    125      * To be implemented by container views to update themselves when the bounds changes.
    126      */
    127     protected abstract void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding);
    128 
    129     /**
    130      * Returns whether the search bar bounds we got are considered valid.
    131      */
    132     private boolean isValidSearchBarBounds(Rect searchBarBounds) {
    133         return !searchBarBounds.isEmpty() &&
    134                 searchBarBounds.right <= getMeasuredWidth() &&
    135                 searchBarBounds.bottom <= getMeasuredHeight();
    136     }
    137 }