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 }