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.util.AttributeSet; 24 import android.view.View; 25 import android.view.ViewStub; 26 import android.view.ViewStub.OnInflateListener; 27 import android.view.WindowInsets; 28 import android.widget.FrameLayout; 29 30 import com.android.systemui.R; 31 import com.android.systemui.SysUiServiceProvider; 32 import com.android.systemui.fragments.FragmentHostManager; 33 import com.android.systemui.fragments.FragmentHostManager.FragmentListener; 34 import com.android.systemui.plugins.qs.QS; 35 import com.android.systemui.recents.misc.SystemServicesProxy; 36 import com.android.systemui.statusbar.NotificationData.Entry; 37 import com.android.systemui.statusbar.policy.HeadsUpManager; 38 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; 39 40 /** 41 * The container with notification stack scroller and quick settings inside. 42 */ 43 public 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 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 mHeadsUpManager = SysUiServiceProvider.getComponent(getContext(), StatusBar.class) 80 .mHeadsUpManager; 81 mHeadsUpManager.addListener(this); 82 } 83 84 @Override onDetachedFromWindow()85 protected void onDetachedFromWindow() { 86 super.onDetachedFromWindow(); 87 FragmentHostManager.get(this).removeTagListener(QS.TAG, this); 88 mHeadsUpManager.removeListener(this); 89 } 90 91 @Override onConfigurationChanged(Configuration newConfig)92 protected void onConfigurationChanged(Configuration newConfig) { 93 super.onConfigurationChanged(newConfig); 94 reloadWidth(mQsFrame); 95 reloadWidth(mStackScroller); 96 } 97 reloadWidth(View view)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 onApplyWindowInsets(WindowInsets insets)106 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 107 mBottomPadding = insets.getStableInsetBottom(); 108 setPadding(0, 0, 0, mBottomPadding); 109 return insets; 110 } 111 112 @Override drawChild(Canvas canvas, View child, long drawingTime)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 onInflate(ViewStub stub, View inflated)148 public void onInflate(ViewStub stub, View inflated) { 149 if (stub == mUserSwitcher) { 150 mUserSwitcher = inflated; 151 mInflated = true; 152 } 153 } 154 155 @Override onFragmentViewCreated(String tag, Fragment fragment)156 public void onFragmentViewCreated(String tag, Fragment fragment) { 157 QS container = (QS) fragment; 158 container.setContainer(this); 159 } 160 setQsExpanded(boolean expanded)161 public void setQsExpanded(boolean expanded) { 162 if (mQsExpanded != expanded) { 163 mQsExpanded = expanded; 164 invalidate(); 165 } 166 } 167 setCustomizerAnimating(boolean isAnimating)168 public void setCustomizerAnimating(boolean isAnimating) { 169 if (mCustomizerAnimating != isAnimating) { 170 mCustomizerAnimating = isAnimating; 171 invalidate(); 172 } 173 } 174 setCustomizerShowing(boolean isShowing)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 setBottomMargin(View v, int bottomMargin)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 onHeadsUpStateChanged(Entry entry, boolean isHeadsUp)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