1 /* 2 * Copyright (C) 2011 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.policy; 18 19 import android.app.Notification; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.graphics.Rect; 23 import android.util.AttributeSet; 24 import android.util.Log; 25 import android.view.MotionEvent; 26 import android.view.View; 27 import android.view.ViewConfiguration; 28 import android.view.ViewGroup; 29 import android.widget.FrameLayout; 30 import android.widget.LinearLayout; 31 32 import com.android.systemui.ExpandHelper; 33 import com.android.systemui.R; 34 import com.android.systemui.SwipeHelper; 35 import com.android.systemui.statusbar.BaseStatusBar; 36 import com.android.systemui.statusbar.NotificationData; 37 38 public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback { 39 private static final String TAG = "HeadsUpNotificationView"; 40 private static final boolean DEBUG = false; 41 private static final boolean SPEW = DEBUG; 42 43 Rect mTmpRect = new Rect(); 44 45 private final int mTouchSensitivityDelay; 46 private SwipeHelper mSwipeHelper; 47 48 private BaseStatusBar mBar; 49 private ExpandHelper mExpandHelper; 50 private long mStartTouchTime; 51 52 private ViewGroup mContentHolder; 53 private ViewGroup mContentSlider; 54 55 private NotificationData.Entry mHeadsUp; 56 57 public HeadsUpNotificationView(Context context, AttributeSet attrs) { 58 this(context, attrs, 0); 59 } 60 61 public HeadsUpNotificationView(Context context, AttributeSet attrs, int defStyle) { 62 super(context, attrs, defStyle); 63 mTouchSensitivityDelay = getResources().getInteger(R.integer.heads_up_sensitivity_delay); 64 if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay); 65 } 66 67 public void setBar(BaseStatusBar bar) { 68 mBar = bar; 69 } 70 71 public ViewGroup getHolder() { 72 return mContentHolder; 73 } 74 75 public boolean setNotification(NotificationData.Entry headsUp) { 76 mHeadsUp = headsUp; 77 mHeadsUp.row.setExpanded(false); 78 if (mContentHolder == null) { 79 // too soon! 80 return false; 81 } 82 mContentHolder.setX(0); 83 mContentHolder.setVisibility(View.VISIBLE); 84 mContentHolder.setAlpha(1f); 85 mContentHolder.removeAllViews(); 86 mContentHolder.addView(mHeadsUp.row); 87 mSwipeHelper.snapChild(mContentSlider, 1f); 88 mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay; 89 return true; 90 } 91 92 public boolean isClearable() { 93 return mHeadsUp == null || mHeadsUp.notification.isClearable(); 94 } 95 96 public void setMargin(int notificationPanelMarginPx) { 97 if (SPEW) Log.v(TAG, "setMargin() " + notificationPanelMarginPx); 98 if (mContentSlider != null) { 99 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentSlider.getLayoutParams(); 100 lp.setMarginStart(notificationPanelMarginPx); 101 mContentSlider.setLayoutParams(lp); 102 } 103 } 104 105 // LinearLayout methods 106 107 @Override 108 public void onDraw(android.graphics.Canvas c) { 109 super.onDraw(c); 110 if (DEBUG) { 111 //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: " 112 // + getMeasuredHeight() + "px"); 113 c.save(); 114 c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6, 115 android.graphics.Region.Op.DIFFERENCE); 116 c.drawColor(0xFFcc00cc); 117 c.restore(); 118 } 119 } 120 121 // ViewGroup methods 122 123 @Override 124 public void onAttachedToWindow() { 125 float densityScale = getResources().getDisplayMetrics().density; 126 float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); 127 mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); 128 129 int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); 130 int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height); 131 mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight); 132 133 mContentHolder = (ViewGroup) findViewById(R.id.content_holder); 134 mContentSlider = (ViewGroup) findViewById(R.id.content_slider); 135 136 if (mHeadsUp != null) { 137 // whoops, we're on already! 138 setNotification(mHeadsUp); 139 } 140 } 141 142 @Override 143 public boolean onInterceptTouchEvent(MotionEvent ev) { 144 if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()"); 145 if (System.currentTimeMillis() < mStartTouchTime) { 146 return true; 147 } 148 return mSwipeHelper.onInterceptTouchEvent(ev) 149 || mExpandHelper.onInterceptTouchEvent(ev) 150 || super.onInterceptTouchEvent(ev); 151 } 152 153 // View methods 154 155 @Override 156 public boolean onTouchEvent(MotionEvent ev) { 157 if (System.currentTimeMillis() < mStartTouchTime) { 158 return false; 159 } 160 mBar.resetHeadsUpDecayTimer(); 161 return mSwipeHelper.onTouchEvent(ev) 162 || mExpandHelper.onTouchEvent(ev) 163 || super.onTouchEvent(ev); 164 } 165 166 @Override 167 protected void onConfigurationChanged(Configuration newConfig) { 168 super.onConfigurationChanged(newConfig); 169 float densityScale = getResources().getDisplayMetrics().density; 170 mSwipeHelper.setDensityScale(densityScale); 171 float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); 172 mSwipeHelper.setPagingTouchSlop(pagingTouchSlop); 173 } 174 175 // ExpandHelper.Callback methods 176 177 @Override 178 public View getChildAtRawPosition(float x, float y) { 179 return getChildAtPosition(x, y); 180 } 181 182 @Override 183 public View getChildAtPosition(float x, float y) { 184 return mHeadsUp == null ? null : mHeadsUp.row; 185 } 186 187 @Override 188 public boolean canChildBeExpanded(View v) { 189 return mHeadsUp != null && mHeadsUp.row == v && mHeadsUp.row.isExpandable(); 190 } 191 192 @Override 193 public void setUserExpandedChild(View v, boolean userExpanded) { 194 if (mHeadsUp != null && mHeadsUp.row == v) { 195 mHeadsUp.row.setUserExpanded(userExpanded); 196 } 197 } 198 199 @Override 200 public void setUserLockedChild(View v, boolean userLocked) { 201 if (mHeadsUp != null && mHeadsUp.row == v) { 202 mHeadsUp.row.setUserLocked(userLocked); 203 } 204 } 205 206 // SwipeHelper.Callback methods 207 208 @Override 209 public boolean canChildBeDismissed(View v) { 210 return true; 211 } 212 213 @Override 214 public void onChildDismissed(View v) { 215 Log.v(TAG, "User swiped heads up to dismiss"); 216 mBar.onHeadsUpDismissed(); 217 } 218 219 @Override 220 public void onBeginDrag(View v) { 221 } 222 223 @Override 224 public void onDragCancelled(View v) { 225 mContentHolder.setAlpha(1f); // sometimes this isn't quite reset 226 } 227 228 @Override 229 public View getChildAtPosition(MotionEvent ev) { 230 return mContentSlider; 231 } 232 233 @Override 234 public View getChildContentView(View v) { 235 return mContentSlider; 236 } 237 }