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