summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/BaseContainerView.java
blob: bd4199264882b4479f6534e1e19996e05fde83d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;

import com.android.launcher3.config.ProviderConfig;

/**
 * A base container view, which supports resizing.
 */
public abstract class BaseContainerView extends FrameLayout implements Insettable {

    private final static String TAG = "BaseContainerView";

    // The window insets
    private final Rect mInsets = new Rect();
    // The bounds of the search bar.  Only the left, top, right are used to inset the
    // search bar and the height is determined by the measurement of the layout
    private final Rect mFixedSearchBarBounds = new Rect();
    // The computed padding to apply to the container to achieve the container bounds
    protected final Rect mContentPadding = new Rect();
    // The inset to apply to the edges and between the search bar and the container
    private final int mContainerBoundsInset;

    private final Drawable mRevealDrawable;

    private View mRevealView;
    private View mContent;

    public BaseContainerView(Context context) {
        this(context, null);
    }

    public BaseContainerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContainerBoundsInset = getResources().getDimensionPixelSize(R.dimen.container_bounds_inset);

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.BaseContainerView, defStyleAttr, 0);
        mRevealDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
        a.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mContent = findViewById(R.id.main_content);
        mRevealView = findViewById(R.id.reveal_view);
    }

    @Override
    final public void setInsets(Rect insets) {
        mInsets.set(insets);
        updateBackgroundAndPaddings();
    }

    /**
     * Sets the search bar bounds for this container view to match.
     */
    final public void setSearchBarBounds(Rect bounds) {
        if (ProviderConfig.IS_DOGFOOD_BUILD && !isValidSearchBarBounds(bounds)) {
            Log.e(TAG, "Invalid search bar bounds: " + bounds);
        }

        mFixedSearchBarBounds.set(bounds);

        // Post the updates since they can trigger a relayout, and this call can be triggered from
        // a layout pass itself.
        post(new Runnable() {
            @Override
            public void run() {
                updateBackgroundAndPaddings();
            }
        });
    }

    /**
     * Update the backgrounds and padding in response to a change in the bounds or insets.
     */
    protected void updateBackgroundAndPaddings() {
        Rect padding;
        if (isValidSearchBarBounds(mFixedSearchBarBounds)) {
            padding = new Rect(
                    mFixedSearchBarBounds.left,
                    mInsets.top + mContainerBoundsInset,
                    getMeasuredWidth() - mFixedSearchBarBounds.right,
                    mInsets.bottom + mContainerBoundsInset
            );
        } else {
            padding = new Rect(
                    mInsets.left + mContainerBoundsInset,
                    mInsets.top + mContainerBoundsInset,
                    mInsets.right + mContainerBoundsInset,
                    mInsets.bottom + mContainerBoundsInset
            );
        }

        // The container padding changed, notify the container.
        if (!padding.equals(mContentPadding)) {
            mContentPadding.set(padding);
            onUpdateBackgroundAndPaddings(padding);
        }
    }

    private void onUpdateBackgroundAndPaddings(Rect padding) {
        // Apply the top-bottom padding to itself so that the launcher transition is
        // clipped correctly
        setPadding(0, padding.top, 0, padding.bottom);

        InsetDrawable background = new InsetDrawable(mRevealDrawable,
                padding.left, 0, padding.right, 0);
        mRevealView.setBackground(background.getConstantState().newDrawable());
        mContent.setBackground(background);

        // We let the content have a intent background, but still have full width.
        // This allows the scroll bar to be used responsive outside the background bounds as well.
        mContent.setPadding(0, 0, 0, 0);

        Rect bgPadding = new Rect();
        background.getPadding(bgPadding);
        onUpdateBgPadding(padding, bgPadding);
    }

    protected abstract void onUpdateBgPadding(Rect padding, Rect bgPadding);

    /**
     * Returns whether the search bar bounds we got are considered valid.
     */
    private boolean isValidSearchBarBounds(Rect searchBarBounds) {
        return !searchBarBounds.isEmpty() &&
                searchBarBounds.right <= getMeasuredWidth() &&
                searchBarBounds.bottom <= getMeasuredHeight();
    }

    public final View getContentView() {
        return mContent;
    }

    public final View getRevealView() {
        return mRevealView;
    }
}