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