1 /* 2 * Copyright (C) 2012 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.StatusBarManager; 20 import android.content.Context; 21 import android.graphics.Canvas; 22 import android.graphics.Paint; 23 import android.graphics.PorterDuff; 24 import android.graphics.PorterDuffXfermode; 25 import android.graphics.Rect; 26 import android.media.session.MediaSessionLegacyHelper; 27 import android.os.IBinder; 28 import android.util.AttributeSet; 29 import android.view.KeyEvent; 30 import android.view.MotionEvent; 31 import android.view.View; 32 import android.view.ViewRootImpl; 33 import android.view.WindowManager; 34 import android.view.WindowManagerGlobal; 35 import android.widget.FrameLayout; 36 37 import com.android.systemui.R; 38 import com.android.systemui.statusbar.BaseStatusBar; 39 import com.android.systemui.statusbar.DragDownHelper; 40 import com.android.systemui.statusbar.StatusBarState; 41 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 42 43 44 public class StatusBarWindowView extends FrameLayout { 45 public static final String TAG = "StatusBarWindowView"; 46 public static final boolean DEBUG = BaseStatusBar.DEBUG; 47 48 private DragDownHelper mDragDownHelper; 49 private NotificationStackScrollLayout mStackScrollLayout; 50 private NotificationPanelView mNotificationPanel; 51 private View mBrightnessMirror; 52 53 PhoneStatusBar mService; 54 private final Paint mTransparentSrcPaint = new Paint(); 55 56 public StatusBarWindowView(Context context, AttributeSet attrs) { 57 super(context, attrs); 58 setMotionEventSplittingEnabled(false); 59 mTransparentSrcPaint.setColor(0); 60 mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); 61 } 62 63 @Override 64 protected boolean fitSystemWindows(Rect insets) { 65 if (getFitsSystemWindows()) { 66 boolean changed = insets.left != getPaddingLeft() 67 || insets.top != getPaddingTop() 68 || insets.right != getPaddingRight() 69 || insets.bottom != getPaddingBottom(); 70 if (changed) { 71 setPadding(insets.left, insets.top, insets.right, 0); 72 } 73 insets.left = 0; 74 insets.top = 0; 75 insets.right = 0; 76 } else { 77 boolean changed = getPaddingLeft() != 0 78 || getPaddingRight() != 0 79 || getPaddingTop() != 0 80 || getPaddingBottom() != 0; 81 if (changed) { 82 setPadding(0, 0, 0, 0); 83 } 84 } 85 return false; 86 } 87 88 @Override 89 protected void onAttachedToWindow () { 90 super.onAttachedToWindow(); 91 92 mStackScrollLayout = (NotificationStackScrollLayout) findViewById( 93 R.id.notification_stack_scroller); 94 mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel); 95 mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService); 96 mBrightnessMirror = findViewById(R.id.brightness_mirror); 97 98 // We really need to be able to animate while window animations are going on 99 // so that activities may be started asynchronously from panel animations 100 final ViewRootImpl root = getViewRootImpl(); 101 if (root != null) { 102 root.setDrawDuringWindowsAnimating(true); 103 } 104 105 // We need to ensure that our window doesn't suffer from overdraw which would normally 106 // occur if our window is translucent. Since we are drawing the whole window anyway with 107 // the scrim, we don't need the window to be cleared in the beginning. 108 if (mService.isScrimSrcModeEnabled()) { 109 IBinder windowToken = getWindowToken(); 110 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); 111 lp.token = windowToken; 112 setLayoutParams(lp); 113 WindowManagerGlobal.getInstance().changeCanvasOpacity(windowToken, true); 114 setWillNotDraw(false); 115 } else { 116 setWillNotDraw(!DEBUG); 117 } 118 } 119 120 @Override 121 public boolean dispatchKeyEvent(KeyEvent event) { 122 boolean down = event.getAction() == KeyEvent.ACTION_DOWN; 123 switch (event.getKeyCode()) { 124 case KeyEvent.KEYCODE_BACK: 125 if (!down) { 126 mService.onBackPressed(); 127 } 128 return true; 129 case KeyEvent.KEYCODE_MENU: 130 if (!down) { 131 return mService.onMenuPressed(); 132 } 133 case KeyEvent.KEYCODE_SPACE: 134 if (!down) { 135 return mService.onSpacePressed(); 136 } 137 break; 138 case KeyEvent.KEYCODE_VOLUME_DOWN: 139 case KeyEvent.KEYCODE_VOLUME_UP: 140 if (mService.isDozing()) { 141 MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, true); 142 return true; 143 } 144 break; 145 } 146 if (mService.interceptMediaKey(event)) { 147 return true; 148 } 149 return super.dispatchKeyEvent(event); 150 } 151 152 @Override 153 public boolean dispatchTouchEvent(MotionEvent ev) { 154 if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) { 155 // Disallow new pointers while the brightness mirror is visible. This is so that you 156 // can't touch anything other than the brightness slider while the mirror is showing 157 // and the rest of the panel is transparent. 158 if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { 159 return false; 160 } 161 } 162 return super.dispatchTouchEvent(ev); 163 } 164 165 @Override 166 public boolean onInterceptTouchEvent(MotionEvent ev) { 167 boolean intercept = false; 168 if (mNotificationPanel.isFullyExpanded() 169 && mStackScrollLayout.getVisibility() == View.VISIBLE 170 && mService.getBarState() == StatusBarState.KEYGUARD 171 && !mService.isBouncerShowing()) { 172 intercept = mDragDownHelper.onInterceptTouchEvent(ev); 173 // wake up on a touch down event, if dozing 174 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 175 mService.wakeUpIfDozing(ev.getEventTime(), true); 176 } 177 } 178 if (!intercept) { 179 super.onInterceptTouchEvent(ev); 180 } 181 if (intercept) { 182 MotionEvent cancellation = MotionEvent.obtain(ev); 183 cancellation.setAction(MotionEvent.ACTION_CANCEL); 184 mStackScrollLayout.onInterceptTouchEvent(cancellation); 185 mNotificationPanel.onInterceptTouchEvent(cancellation); 186 cancellation.recycle(); 187 } 188 return intercept; 189 } 190 191 @Override 192 public boolean onTouchEvent(MotionEvent ev) { 193 boolean handled = false; 194 if (mService.getBarState() == StatusBarState.KEYGUARD && !mService.isQsExpanded()) { 195 handled = mDragDownHelper.onTouchEvent(ev); 196 } 197 if (!handled) { 198 handled = super.onTouchEvent(ev); 199 } 200 final int action = ev.getAction(); 201 if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) { 202 mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 203 } 204 return handled; 205 } 206 207 @Override 208 public void onDraw(Canvas canvas) { 209 super.onDraw(canvas); 210 if (mService.isScrimSrcModeEnabled()) { 211 // We need to ensure that our window is always drawn fully even when we have paddings, 212 // since we simulate it to be opaque. 213 int paddedBottom = getHeight() - getPaddingBottom(); 214 int paddedRight = getWidth() - getPaddingRight(); 215 if (getPaddingTop() != 0) { 216 canvas.drawRect(0, 0, getWidth(), getPaddingTop(), mTransparentSrcPaint); 217 } 218 if (getPaddingBottom() != 0) { 219 canvas.drawRect(0, paddedBottom, getWidth(), getHeight(), mTransparentSrcPaint); 220 } 221 if (getPaddingLeft() != 0) { 222 canvas.drawRect(0, getPaddingTop(), getPaddingLeft(), paddedBottom, 223 mTransparentSrcPaint); 224 } 225 if (getPaddingRight() != 0) { 226 canvas.drawRect(paddedRight, getPaddingTop(), getWidth(), paddedBottom, 227 mTransparentSrcPaint); 228 } 229 } 230 if (DEBUG) { 231 Paint pt = new Paint(); 232 pt.setColor(0x80FFFF00); 233 pt.setStrokeWidth(12.0f); 234 pt.setStyle(Paint.Style.STROKE); 235 canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), pt); 236 } 237 } 238 239 public void cancelExpandHelper() { 240 if (mStackScrollLayout != null) { 241 mStackScrollLayout.cancelExpandHelper(); 242 } 243 } 244 } 245 246