• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.shade;
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.util.AttributeSet;
24 import android.view.View;
25 import android.view.WindowInsets;
26 
27 import androidx.annotation.Nullable;
28 import androidx.constraintlayout.widget.ConstraintLayout;
29 import androidx.constraintlayout.widget.ConstraintSet;
30 
31 import com.android.systemui.R;
32 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
33 import com.android.systemui.plugins.qs.QS;
34 import com.android.systemui.statusbar.notification.AboveShelfObserver;
35 
36 import java.util.ArrayList;
37 import java.util.Comparator;
38 import java.util.function.Consumer;
39 
40 /**
41  * The container with notification stack scroller and quick settings inside.
42  */
43 public class NotificationsQuickSettingsContainer extends ConstraintLayout
44         implements FragmentListener, AboveShelfObserver.HasViewAboveShelfChangedListener {
45 
46     private View mQsFrame;
47     private View mStackScroller;
48     private View mKeyguardStatusBar;
49 
50     private final ArrayList<View> mDrawingOrderedChildren = new ArrayList<>();
51     private final ArrayList<View> mLayoutDrawingOrder = new ArrayList<>();
52     private final Comparator<View> mIndexComparator = Comparator.comparingInt(this::indexOfChild);
53     private Consumer<WindowInsets> mInsetsChangedListener = insets -> {};
54     private Consumer<QS> mQSFragmentAttachedListener = qs -> {};
55     private QS mQs;
56     private View mQSContainer;
57     private int mLastQSPaddingBottom;
58 
59     @Nullable
60     private Consumer<Configuration> mConfigurationChangedListener;
61 
NotificationsQuickSettingsContainer(Context context, AttributeSet attrs)62     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
63         super(context, attrs);
64     }
65 
66     @Override
onFinishInflate()67     protected void onFinishInflate() {
68         super.onFinishInflate();
69         mQsFrame = findViewById(R.id.qs_frame);
70         mStackScroller = findViewById(R.id.notification_stack_scroller);
71         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
72     }
73 
74     @Override
onFragmentViewCreated(String tag, Fragment fragment)75     public void onFragmentViewCreated(String tag, Fragment fragment) {
76         mQs = (QS) fragment;
77         mQSFragmentAttachedListener.accept(mQs);
78         mQSContainer = mQs.getView().findViewById(R.id.quick_settings_container);
79         // We need to restore the bottom padding as the fragment may have been recreated due to
80         // some special Configuration change, so we apply the last known padding (this will be
81         // correct even if it has changed while the fragment was destroyed and re-created).
82         setQSContainerPaddingBottom(mLastQSPaddingBottom);
83     }
84 
85     @Override
onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf)86     public void onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf) {
87         invalidate();
88     }
89 
90     @Override
onConfigurationChanged(Configuration newConfig)91     protected void onConfigurationChanged(Configuration newConfig) {
92         super.onConfigurationChanged(newConfig);
93         if (mConfigurationChangedListener != null) {
94             mConfigurationChangedListener.accept(newConfig);
95         }
96     }
97 
setConfigurationChangedListener(Consumer<Configuration> listener)98     public void setConfigurationChangedListener(Consumer<Configuration> listener) {
99         mConfigurationChangedListener = listener;
100     }
101 
setNotificationsMarginBottom(int margin)102     public void setNotificationsMarginBottom(int margin) {
103         LayoutParams params = (LayoutParams) mStackScroller.getLayoutParams();
104         params.bottomMargin = margin;
105         mStackScroller.setLayoutParams(params);
106     }
107 
setQSContainerPaddingBottom(int paddingBottom)108     public void setQSContainerPaddingBottom(int paddingBottom) {
109         mLastQSPaddingBottom = paddingBottom;
110         if (mQSContainer != null) {
111             mQSContainer.setPadding(
112                     mQSContainer.getPaddingLeft(),
113                     mQSContainer.getPaddingTop(),
114                     mQSContainer.getPaddingRight(),
115                     paddingBottom
116             );
117         }
118     }
119 
setInsetsChangedListener(Consumer<WindowInsets> onInsetsChangedListener)120     public void setInsetsChangedListener(Consumer<WindowInsets> onInsetsChangedListener) {
121         mInsetsChangedListener = onInsetsChangedListener;
122     }
123 
removeOnInsetsChangedListener()124     public void removeOnInsetsChangedListener() {
125         mInsetsChangedListener = insets -> {};
126     }
127 
setQSFragmentAttachedListener(Consumer<QS> qsFragmentAttachedListener)128     public void setQSFragmentAttachedListener(Consumer<QS> qsFragmentAttachedListener) {
129         mQSFragmentAttachedListener = qsFragmentAttachedListener;
130         // listener might be attached after fragment is attached
131         if (mQs != null) {
132             mQSFragmentAttachedListener.accept(mQs);
133         }
134     }
135 
removeQSFragmentAttachedListener()136     public void removeQSFragmentAttachedListener() {
137         mQSFragmentAttachedListener = qs -> {};
138     }
139 
140     @Override
onApplyWindowInsets(WindowInsets insets)141     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
142         mInsetsChangedListener.accept(insets);
143         return insets;
144     }
145 
146     @Override
dispatchDraw(Canvas canvas)147     protected void dispatchDraw(Canvas canvas) {
148         mDrawingOrderedChildren.clear();
149         mLayoutDrawingOrder.clear();
150         if (mKeyguardStatusBar.getVisibility() == View.VISIBLE) {
151             mDrawingOrderedChildren.add(mKeyguardStatusBar);
152             mLayoutDrawingOrder.add(mKeyguardStatusBar);
153         }
154         if (mQsFrame.getVisibility() == View.VISIBLE) {
155             mDrawingOrderedChildren.add(mQsFrame);
156             mLayoutDrawingOrder.add(mQsFrame);
157         }
158         if (mStackScroller.getVisibility() == View.VISIBLE) {
159             mDrawingOrderedChildren.add(mStackScroller);
160             mLayoutDrawingOrder.add(mStackScroller);
161         }
162 
163         // Let's now find the order that the view has when drawing regularly by sorting
164         mLayoutDrawingOrder.sort(mIndexComparator);
165         super.dispatchDraw(canvas);
166     }
167 
168     @Override
drawChild(Canvas canvas, View child, long drawingTime)169     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
170         int layoutIndex = mLayoutDrawingOrder.indexOf(child);
171         if (layoutIndex >= 0) {
172             return super.drawChild(canvas, mDrawingOrderedChildren.get(layoutIndex), drawingTime);
173         } else {
174             return super.drawChild(canvas, child, drawingTime);
175         }
176     }
177 
applyConstraints(ConstraintSet constraintSet)178     public void applyConstraints(ConstraintSet constraintSet) {
179         constraintSet.applyTo(this);
180     }
181 }
182