1/*
2 * Copyright (C) 2014 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
17package com.android.systemui.statusbar.phone;
18
19import android.app.Fragment;
20import android.content.Context;
21import android.content.res.Configuration;
22import android.graphics.Canvas;
23import android.support.annotation.DimenRes;
24import android.util.AttributeSet;
25import android.view.View;
26import android.view.ViewStub;
27import android.view.ViewStub.OnInflateListener;
28import android.view.WindowInsets;
29import android.widget.FrameLayout;
30
31import com.android.systemui.R;
32import com.android.systemui.SysUiServiceProvider;
33import com.android.systemui.fragments.FragmentHostManager;
34import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
35import com.android.systemui.plugins.qs.QS;
36import com.android.systemui.statusbar.NotificationData.Entry;
37import com.android.systemui.statusbar.notification.AboveShelfObserver;
38import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
39
40/**
41 * The container with notification stack scroller and quick settings inside.
42 */
43public class NotificationsQuickSettingsContainer extends FrameLayout
44        implements OnInflateListener, FragmentListener,
45        AboveShelfObserver.HasViewAboveShelfChangedListener {
46
47    private FrameLayout mQsFrame;
48    private View mUserSwitcher;
49    private NotificationStackScrollLayout mStackScroller;
50    private View mKeyguardStatusBar;
51    private boolean mInflated;
52    private boolean mQsExpanded;
53    private boolean mCustomizerAnimating;
54
55    private int mBottomPadding;
56    private int mStackScrollerMargin;
57    private boolean mHasViewsAboveShelf;
58
59    public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
60        super(context, attrs);
61    }
62
63    @Override
64    protected void onFinishInflate() {
65        super.onFinishInflate();
66        mQsFrame = (FrameLayout) findViewById(R.id.qs_frame);
67        mStackScroller = findViewById(R.id.notification_stack_scroller);
68        mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
69        mKeyguardStatusBar = findViewById(R.id.keyguard_header);
70        ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
71        userSwitcher.setOnInflateListener(this);
72        mUserSwitcher = userSwitcher;
73    }
74
75    @Override
76    protected void onAttachedToWindow() {
77        super.onAttachedToWindow();
78        FragmentHostManager.get(this).addTagListener(QS.TAG, this);
79    }
80
81    @Override
82    protected void onDetachedFromWindow() {
83        super.onDetachedFromWindow();
84        FragmentHostManager.get(this).removeTagListener(QS.TAG, this);
85    }
86
87    @Override
88    protected void onConfigurationChanged(Configuration newConfig) {
89        super.onConfigurationChanged(newConfig);
90        reloadWidth(mQsFrame, R.dimen.qs_panel_width);
91        reloadWidth(mStackScroller, R.dimen.notification_panel_width);
92    }
93
94    /**
95     * Loads the given width resource and sets it on the given View.
96     */
97    private void reloadWidth(View view, @DimenRes int width) {
98        LayoutParams params = (LayoutParams) view.getLayoutParams();
99        params.width = getResources().getDimensionPixelSize(width);
100        view.setLayoutParams(params);
101    }
102
103    @Override
104    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
105        mBottomPadding = insets.getStableInsetBottom();
106        setPadding(0, 0, 0, mBottomPadding);
107        return insets;
108    }
109
110    @Override
111    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
112        boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
113        boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
114
115        final boolean qsBottom = mHasViewsAboveShelf;
116        View stackQsTop = qsBottom ? mStackScroller : mQsFrame;
117        View stackQsBottom = !qsBottom ? mStackScroller : mQsFrame;
118        // Invert the order of the scroll view and user switcher such that the notifications receive
119        // touches first but the panel gets drawn above.
120        if (child == mQsFrame) {
121            return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
122                    : statusBarVisible ? mKeyguardStatusBar
123                    : userSwitcherVisible ? mUserSwitcher
124                    : stackQsBottom, drawingTime);
125        } else if (child == mStackScroller) {
126            return super.drawChild(canvas,
127                    userSwitcherVisible && statusBarVisible ? mKeyguardStatusBar
128                    : statusBarVisible || userSwitcherVisible ? stackQsBottom
129                    : stackQsTop,
130                    drawingTime);
131        } else if (child == mUserSwitcher) {
132            return super.drawChild(canvas,
133                    userSwitcherVisible && statusBarVisible ? stackQsBottom
134                    : stackQsTop,
135                    drawingTime);
136        } else if (child == mKeyguardStatusBar) {
137            return super.drawChild(canvas,
138                    stackQsTop,
139                    drawingTime);
140        } else {
141            return super.drawChild(canvas, child, drawingTime);
142        }
143    }
144
145    @Override
146    public void onInflate(ViewStub stub, View inflated) {
147        if (stub == mUserSwitcher) {
148            mUserSwitcher = inflated;
149            mInflated = true;
150        }
151    }
152
153    @Override
154    public void onFragmentViewCreated(String tag, Fragment fragment) {
155        QS container = (QS) fragment;
156        container.setContainer(this);
157    }
158
159    public void setQsExpanded(boolean expanded) {
160        if (mQsExpanded != expanded) {
161            mQsExpanded = expanded;
162            invalidate();
163        }
164    }
165
166    public void setCustomizerAnimating(boolean isAnimating) {
167        if (mCustomizerAnimating != isAnimating) {
168            mCustomizerAnimating = isAnimating;
169            invalidate();
170        }
171    }
172
173    public void setCustomizerShowing(boolean isShowing) {
174        if (isShowing) {
175            // Clear out bottom paddings/margins so the qs customization can be full height.
176            setPadding(0, 0, 0, 0);
177            setBottomMargin(mStackScroller, 0);
178        } else {
179            setPadding(0, 0, 0, mBottomPadding);
180            setBottomMargin(mStackScroller, mStackScrollerMargin);
181        }
182        mStackScroller.setQsCustomizerShowing(isShowing);
183    }
184
185    private void setBottomMargin(View v, int bottomMargin) {
186        LayoutParams params = (LayoutParams) v.getLayoutParams();
187        params.bottomMargin = bottomMargin;
188        v.setLayoutParams(params);
189    }
190
191    @Override
192    public void onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf) {
193        mHasViewsAboveShelf = hasViewsAboveShelf;
194        invalidate();
195    }
196}
197