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 17package com.android.systemui.statusbar.phone; 18 19import android.app.Fragment; 20import android.content.Context; 21import android.content.res.Configuration; 22import android.graphics.Canvas; 23import android.util.AttributeSet; 24import android.view.View; 25import android.view.ViewStub; 26import android.view.ViewStub.OnInflateListener; 27import android.view.WindowInsets; 28import android.widget.FrameLayout; 29 30import com.android.systemui.R; 31import com.android.systemui.SysUiServiceProvider; 32import com.android.systemui.fragments.FragmentHostManager; 33import com.android.systemui.fragments.FragmentHostManager.FragmentListener; 34import com.android.systemui.plugins.qs.QS; 35import com.android.systemui.recents.misc.SystemServicesProxy; 36import com.android.systemui.statusbar.NotificationData.Entry; 37import com.android.systemui.statusbar.policy.HeadsUpManager; 38import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; 39 40/** 41 * The container with notification stack scroller and quick settings inside. 42 */ 43public 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 59 public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) { 60 super(context, attrs); 61 } 62 63 @Override 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 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 85 protected void onDetachedFromWindow() { 86 super.onDetachedFromWindow(); 87 FragmentHostManager.get(this).removeTagListener(QS.TAG, this); 88 mHeadsUpManager.removeListener(this); 89 } 90 91 @Override 92 protected void onConfigurationChanged(Configuration newConfig) { 93 super.onConfigurationChanged(newConfig); 94 reloadWidth(mQsFrame); 95 reloadWidth(mStackScroller); 96 } 97 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 106 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 107 mBottomPadding = insets.getStableInsetBottom(); 108 setPadding(0, 0, 0, mBottomPadding); 109 return insets; 110 } 111 112 @Override 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 148 public void onInflate(ViewStub stub, View inflated) { 149 if (stub == mUserSwitcher) { 150 mUserSwitcher = inflated; 151 mInflated = true; 152 } 153 } 154 155 @Override 156 public void onFragmentViewCreated(String tag, Fragment fragment) { 157 QS container = (QS) fragment; 158 container.setContainer(this); 159 } 160 161 public void setQsExpanded(boolean expanded) { 162 if (mQsExpanded != expanded) { 163 mQsExpanded = expanded; 164 invalidate(); 165 } 166 } 167 168 public void setCustomizerAnimating(boolean isAnimating) { 169 if (mCustomizerAnimating != isAnimating) { 170 mCustomizerAnimating = isAnimating; 171 invalidate(); 172 } 173 } 174 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 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 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