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 }