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.content.res.TypedArray; 21 import android.graphics.Rect; 22 import android.graphics.drawable.Drawable; 23 import android.graphics.drawable.InsetDrawable; 24 import android.util.AttributeSet; 25 import android.view.View; 26 import android.widget.FrameLayout; 27 28 /** 29 * A base container view, which supports resizing. 30 */ 31 public abstract class BaseContainerView extends FrameLayout implements Insettable { 32 33 private final static String TAG = "BaseContainerView"; 34 35 // The window insets 36 private final Rect mInsets = new Rect(); 37 // The computed padding to apply to the container to achieve the container bounds 38 protected final Rect mContentPadding = new Rect(); 39 // The inset to apply to the edges and between the search bar and the container 40 private final int mContainerBoundsInset; 41 42 private final Drawable mRevealDrawable; 43 44 private View mRevealView; 45 private View mContent; 46 47 protected final int mHorizontalPadding; 48 BaseContainerView(Context context)49 public BaseContainerView(Context context) { 50 this(context, null); 51 } 52 BaseContainerView(Context context, AttributeSet attrs)53 public BaseContainerView(Context context, AttributeSet attrs) { 54 this(context, attrs, 0); 55 } 56 BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr)57 public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) { 58 super(context, attrs, defStyleAttr); 59 mContainerBoundsInset = getResources().getDimensionPixelSize(R.dimen.container_bounds_inset); 60 61 TypedArray a = context.obtainStyledAttributes(attrs, 62 R.styleable.BaseContainerView, defStyleAttr, 0); 63 mRevealDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground); 64 a.recycle(); 65 66 int maxSize = getResources().getDimensionPixelSize(R.dimen.container_max_width); 67 int minMargin = getResources().getDimensionPixelSize(R.dimen.container_min_margin); 68 int width = ((Launcher) context).getDeviceProfile().availableWidthPx; 69 70 if (maxSize > 0) { 71 mHorizontalPadding = Math.max(minMargin, (width - maxSize) / 2); 72 } else { 73 mHorizontalPadding = Math.max(minMargin, 74 (int) getResources().getFraction(R.fraction.container_margin, width, 1)); 75 } 76 } 77 78 @Override onFinishInflate()79 protected void onFinishInflate() { 80 super.onFinishInflate(); 81 82 mContent = findViewById(R.id.main_content); 83 mRevealView = findViewById(R.id.reveal_view); 84 } 85 86 @Override setInsets(Rect insets)87 final public void setInsets(Rect insets) { 88 mInsets.set(insets); 89 updateBackgroundAndPaddings(); 90 } 91 92 /** 93 * Sets the search bar bounds for this container view to match. 94 */ setSearchBarBounds(Rect bounds)95 final public void setSearchBarBounds(Rect bounds) { 96 // Post the updates since they can trigger a relayout, and this call can be triggered from 97 // a layout pass itself. 98 post(new Runnable() { 99 @Override 100 public void run() { 101 updateBackgroundAndPaddings(); 102 } 103 }); 104 } 105 106 /** 107 * Update the backgrounds and padding in response to a change in the bounds or insets. 108 */ updateBackgroundAndPaddings()109 protected void updateBackgroundAndPaddings() { 110 Rect padding; 111 padding = new Rect( 112 mHorizontalPadding, 113 mInsets.top + mContainerBoundsInset, 114 mHorizontalPadding, 115 mInsets.bottom + mContainerBoundsInset 116 ); 117 118 // The container padding changed, notify the container. 119 if (!padding.equals(mContentPadding)) { 120 mContentPadding.set(padding); 121 onUpdateBackgroundAndPaddings(padding); 122 } 123 } 124 onUpdateBackgroundAndPaddings(Rect padding)125 private void onUpdateBackgroundAndPaddings(Rect padding) { 126 // Apply the top-bottom padding to itself so that the launcher transition is 127 // clipped correctly 128 setPadding(0, padding.top, 0, padding.bottom); 129 130 InsetDrawable background = new InsetDrawable(mRevealDrawable, 131 padding.left, 0, padding.right, 0); 132 mRevealView.setBackground(background.getConstantState().newDrawable()); 133 mContent.setBackground(background); 134 135 // We let the content have a intent background, but still have full width. 136 // This allows the scroll bar to be used responsive outside the background bounds as well. 137 mContent.setPadding(0, 0, 0, 0); 138 139 Rect bgPadding = new Rect(); 140 background.getPadding(bgPadding); 141 onUpdateBgPadding(padding, bgPadding); 142 } 143 onUpdateBgPadding(Rect padding, Rect bgPadding)144 protected abstract void onUpdateBgPadding(Rect padding, Rect bgPadding); 145 getContentView()146 public final View getContentView() { 147 return mContent; 148 } 149 getRevealView()150 public final View getRevealView() { 151 return mRevealView; 152 } 153 }