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.util.AttributeSet;
24import android.view.View;
25import android.view.ViewStub;
26import android.view.ViewStub.OnInflateListener;
27import android.view.WindowInsets;
28import android.widget.FrameLayout;
29
30import com.android.systemui.R;
31import com.android.systemui.SysUiServiceProvider;
32import com.android.systemui.fragments.FragmentHostManager;
33import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
34import com.android.systemui.plugins.qs.QS;
35import com.android.systemui.recents.misc.SystemServicesProxy;
36import com.android.systemui.statusbar.NotificationData.Entry;
37import com.android.systemui.statusbar.policy.HeadsUpManager;
38import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
39
40/**
41 * The container with notification stack scroller and quick settings inside.
42 */
43public class NotificationsQuickSettingsContainer extends FrameLayout
44        implements OnInflateListener, FragmentListener, OnHeadsUpChangedListener {
45
46    private FrameLayout mQsFrame;
47    private View mUserSwitcher;
48    private View mStackScroller;
49    private View mKeyguardStatusBar;
50    private boolean mInflated;
51    private boolean mQsExpanded;
52    private boolean mCustomizerAnimating;
53
54    private int mBottomPadding;
55    private int mStackScrollerMargin;
56    private boolean mHeadsUp;
57    private HeadsUpManager mHeadsUpManager;
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        mHeadsUpManager = SysUiServiceProvider.getComponent(getContext(), StatusBar.class)
80                .mHeadsUpManager;
81        mHeadsUpManager.addListener(this);
82    }
83
84    @Override
85    protected void onDetachedFromWindow() {
86        super.onDetachedFromWindow();
87        FragmentHostManager.get(this).removeTagListener(QS.TAG, this);
88        mHeadsUpManager.removeListener(this);
89    }
90
91    @Override
92    protected void onConfigurationChanged(Configuration newConfig) {
93        super.onConfigurationChanged(newConfig);
94        reloadWidth(mQsFrame);
95        reloadWidth(mStackScroller);
96    }
97
98    private void reloadWidth(View view) {
99        LayoutParams params = (LayoutParams) view.getLayoutParams();
100        params.width = getContext().getResources().getDimensionPixelSize(
101                R.dimen.notification_panel_width);
102        view.setLayoutParams(params);
103    }
104
105    @Override
106    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
107        mBottomPadding = insets.getStableInsetBottom();
108        setPadding(0, 0, 0, mBottomPadding);
109        return insets;
110    }
111
112    @Override
113    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
114        boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
115        boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
116
117        final boolean qsBottom = mHeadsUp;
118        View stackQsTop = qsBottom ? mStackScroller : mQsFrame;
119        View stackQsBottom = !qsBottom ? mStackScroller : mQsFrame;
120        // Invert the order of the scroll view and user switcher such that the notifications receive
121        // touches first but the panel gets drawn above.
122        if (child == mQsFrame) {
123            return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
124                    : statusBarVisible ? mKeyguardStatusBar
125                    : userSwitcherVisible ? mUserSwitcher
126                    : stackQsBottom, drawingTime);
127        } else if (child == mStackScroller) {
128            return super.drawChild(canvas,
129                    userSwitcherVisible && statusBarVisible ? mKeyguardStatusBar
130                    : statusBarVisible || userSwitcherVisible ? stackQsBottom
131                    : stackQsTop,
132                    drawingTime);
133        } else if (child == mUserSwitcher) {
134            return super.drawChild(canvas,
135                    userSwitcherVisible && statusBarVisible ? stackQsBottom
136                    : stackQsTop,
137                    drawingTime);
138        } else if (child == mKeyguardStatusBar) {
139            return super.drawChild(canvas,
140                    stackQsTop,
141                    drawingTime);
142        } else {
143            return super.drawChild(canvas, child, drawingTime);
144        }
145    }
146
147    @Override
148    public void onInflate(ViewStub stub, View inflated) {
149        if (stub == mUserSwitcher) {
150            mUserSwitcher = inflated;
151            mInflated = true;
152        }
153    }
154
155    @Override
156    public void onFragmentViewCreated(String tag, Fragment fragment) {
157        QS container = (QS) fragment;
158        container.setContainer(this);
159    }
160
161    public void setQsExpanded(boolean expanded) {
162        if (mQsExpanded != expanded) {
163            mQsExpanded = expanded;
164            invalidate();
165        }
166    }
167
168    public void setCustomizerAnimating(boolean isAnimating) {
169        if (mCustomizerAnimating != isAnimating) {
170            mCustomizerAnimating = isAnimating;
171            invalidate();
172        }
173    }
174
175    public void setCustomizerShowing(boolean isShowing) {
176        if (isShowing) {
177            // Clear out bottom paddings/margins so the qs customization can be full height.
178            setPadding(0, 0, 0, 0);
179            setBottomMargin(mStackScroller, 0);
180        } else {
181            setPadding(0, 0, 0, mBottomPadding);
182            setBottomMargin(mStackScroller, mStackScrollerMargin);
183        }
184
185    }
186
187    private void setBottomMargin(View v, int bottomMargin) {
188        LayoutParams params = (LayoutParams) v.getLayoutParams();
189        params.bottomMargin = bottomMargin;
190        v.setLayoutParams(params);
191    }
192
193    @Override
194    public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
195        boolean hasHeadsUp = mHeadsUpManager.getAllEntries().size() != 0;
196        if (mHeadsUp == hasHeadsUp) {
197            return;
198        }
199        mHeadsUp = hasHeadsUp;
200        invalidate();
201    }
202}
203