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 
17 package com.android.systemui.statusbar.phone;
18 
19 import android.app.Fragment;
20 import android.content.Context;
21 import android.content.res.Configuration;
22 import android.graphics.Canvas;
23 import android.support.annotation.DimenRes;
24 import android.util.AttributeSet;
25 import android.view.View;
26 import android.view.ViewStub;
27 import android.view.ViewStub.OnInflateListener;
28 import android.view.WindowInsets;
29 import android.widget.FrameLayout;
30 
31 import com.android.systemui.R;
32 import com.android.systemui.SysUiServiceProvider;
33 import com.android.systemui.fragments.FragmentHostManager;
34 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
35 import com.android.systemui.plugins.qs.QS;
36 import com.android.systemui.statusbar.NotificationData.Entry;
37 import com.android.systemui.statusbar.notification.AboveShelfObserver;
38 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
39 
40 /**
41  * The container with notification stack scroller and quick settings inside.
42  */
43 public 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 
NotificationsQuickSettingsContainer(Context context, AttributeSet attrs)59     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
60         super(context, attrs);
61     }
62 
63     @Override
onFinishInflate()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
onAttachedToWindow()76     protected void onAttachedToWindow() {
77         super.onAttachedToWindow();
78         FragmentHostManager.get(this).addTagListener(QS.TAG, this);
79     }
80 
81     @Override
onDetachedFromWindow()82     protected void onDetachedFromWindow() {
83         super.onDetachedFromWindow();
84         FragmentHostManager.get(this).removeTagListener(QS.TAG, this);
85     }
86 
87     @Override
onConfigurationChanged(Configuration newConfig)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      */
reloadWidth(View view, @DimenRes int width)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
onApplyWindowInsets(WindowInsets insets)104     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
105         mBottomPadding = insets.getStableInsetBottom();
106         setPadding(0, 0, 0, mBottomPadding);
107         return insets;
108     }
109 
110     @Override
drawChild(Canvas canvas, View child, long drawingTime)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
onInflate(ViewStub stub, View inflated)146     public void onInflate(ViewStub stub, View inflated) {
147         if (stub == mUserSwitcher) {
148             mUserSwitcher = inflated;
149             mInflated = true;
150         }
151     }
152 
153     @Override
onFragmentViewCreated(String tag, Fragment fragment)154     public void onFragmentViewCreated(String tag, Fragment fragment) {
155         QS container = (QS) fragment;
156         container.setContainer(this);
157     }
158 
setQsExpanded(boolean expanded)159     public void setQsExpanded(boolean expanded) {
160         if (mQsExpanded != expanded) {
161             mQsExpanded = expanded;
162             invalidate();
163         }
164     }
165 
setCustomizerAnimating(boolean isAnimating)166     public void setCustomizerAnimating(boolean isAnimating) {
167         if (mCustomizerAnimating != isAnimating) {
168             mCustomizerAnimating = isAnimating;
169             invalidate();
170         }
171     }
172 
setCustomizerShowing(boolean isShowing)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 
setBottomMargin(View v, int bottomMargin)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
onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf)192     public void onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf) {
193         mHasViewsAboveShelf = hasViewsAboveShelf;
194         invalidate();
195     }
196 }
197