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.isQsExpanded() 172 && !mService.isBouncerShowing()) { 173 intercept = mDragDownHelper.onInterceptTouchEvent(ev); 174 // wake up on a touch down event, if dozing 175 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 176 mService.wakeUpIfDozing(ev.getEventTime(), ev); 177 } 178 } 179 if (!intercept) { 180 super.onInterceptTouchEvent(ev); 181 } 182 if (intercept) { 183 MotionEvent cancellation = MotionEvent.obtain(ev); 184 cancellation.setAction(MotionEvent.ACTION_CANCEL); 185 mStackScrollLayout.onInterceptTouchEvent(cancellation); 186 mNotificationPanel.onInterceptTouchEvent(cancellation); 187 cancellation.recycle(); 188 } 189 return intercept; 190 } 191 192 @Override 193 public boolean onTouchEvent(MotionEvent ev) { 194 boolean handled = false; 195 if (mService.getBarState() == StatusBarState.KEYGUARD && !mService.isQsExpanded()) { 196 handled = mDragDownHelper.onTouchEvent(ev); 197 } 198 if (!handled) { 199 handled = super.onTouchEvent(ev); 200 } 201 final int action = ev.getAction(); 202 if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) { 203 mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 204 } 205 return handled; 206 } 207 208 @Override 209 public void onDraw(Canvas canvas) { 210 super.onDraw(canvas); 211 if (mService.isScrimSrcModeEnabled()) { 212 // We need to ensure that our window is always drawn fully even when we have paddings, 213 // since we simulate it to be opaque. 214 int paddedBottom = getHeight() - getPaddingBottom(); 215 int paddedRight = getWidth() - getPaddingRight(); 216 if (getPaddingTop() != 0) { 217 canvas.drawRect(0, 0, getWidth(), getPaddingTop(), mTransparentSrcPaint); 218 } 219 if (getPaddingBottom() != 0) { 220 canvas.drawRect(0, paddedBottom, getWidth(), getHeight(), mTransparentSrcPaint); 221 } 222 if (getPaddingLeft() != 0) { 223 canvas.drawRect(0, getPaddingTop(), getPaddingLeft(), paddedBottom, 224 mTransparentSrcPaint); 225 } 226 if (getPaddingRight() != 0) { 227 canvas.drawRect(paddedRight, getPaddingTop(), getWidth(), paddedBottom, 228 mTransparentSrcPaint); 229 } 230 } 231 if (DEBUG) { 232 Paint pt = new Paint(); 233 pt.setColor(0x80FFFF00); 234 pt.setStrokeWidth(12.0f); 235 pt.setStyle(Paint.Style.STROKE); 236 canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), pt); 237 } 238 } 239 240 public void cancelExpandHelper() { 241 if (mStackScrollLayout != null) { 242 mStackScrollLayout.cancelExpandHelper(); 243 } 244 } 245 } 246 247