1e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler/* 2e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * Copyright (C) 2012 The Android Open Source Project 3e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * 4e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * Licensed under the Apache License, Version 2.0 (the "License"); 5e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * you may not use this file except in compliance with the License. 6e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * You may obtain a copy of the License at 7e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * 8e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * http://www.apache.org/licenses/LICENSE-2.0 9e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * 10e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * Unless required by applicable law or agreed to in writing, software 11e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * distributed under the License is distributed on an "AS IS" BASIS, 12e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * See the License for the specific language governing permissions and 14e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler * limitations under the License. 15e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler */ 16e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler 17e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandlerpackage com.android.systemui.statusbar.policy; 18e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler 19c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandlerimport android.animation.ObjectAnimator; 20e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandlerimport android.content.Context; 21c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandlerimport android.content.res.TypedArray; 22c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandlerimport android.graphics.Canvas; 23c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandlerimport android.os.SystemClock; 24e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandlerimport android.util.AttributeSet; 25c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandlerimport android.util.Slog; 26e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandlerimport android.view.MotionEvent; 27e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandlerimport android.view.View; 28e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler 29e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandlerimport com.android.systemui.R; 30e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler 31e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandlerpublic class DeadZone extends View { 32c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public static final String TAG = "DeadZone"; 33c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 34c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public static final boolean DEBUG = false; 35c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public static final int HORIZONTAL = 0; 36c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public static final int VERTICAL = 1; 37c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 3825bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler private static final boolean CHATTY = true; // print to logcat when we eat a click 3925bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler 40c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private boolean mShouldFlash; 41c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private float mFlashFrac = 0f; 42c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 43c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private int mSizeMax; 44c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private int mSizeMin; 45c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler // Upon activity elsewhere in the UI, the dead zone will hold steady for 46c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler // mHold ms, then move back over the course of mDecay ms 47c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private int mHold, mDecay; 48c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private boolean mVertical; 49c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private long mLastPokeTime; 50c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 51c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private final Runnable mDebugFlash = new Runnable() { 52c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler @Override 53c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public void run() { 54c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler ObjectAnimator.ofFloat(DeadZone.this, "flash", 1f, 0f).setDuration(150).start(); 55c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 56c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler }; 57c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 58e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler public DeadZone(Context context, AttributeSet attrs) { 59e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler this(context, attrs, 0); 60e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler } 61e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler 62e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler public DeadZone(Context context, AttributeSet attrs, int defStyle) { 63e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler super(context, attrs); 64c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 65c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeadZone, 66c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler defStyle, 0); 67c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 68c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mHold = a.getInteger(R.styleable.DeadZone_holdTime, 0); 69c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mDecay = a.getInteger(R.styleable.DeadZone_decayTime, 0); 70c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 71c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mSizeMin = a.getDimensionPixelSize(R.styleable.DeadZone_minSize, 0); 72c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mSizeMax = a.getDimensionPixelSize(R.styleable.DeadZone_maxSize, 0); 73c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 74c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler int index = a.getInt(R.styleable.DeadZone_orientation, -1); 75c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mVertical = (index == VERTICAL); 76c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 77c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (DEBUG) 78c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold 79c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler + (mVertical ? " vertical" : " horizontal")); 80c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 8125bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash)); 82c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 83c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 84c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler static float lerp(float a, float b, float f) { 85c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return (b - a) * f + a; 86c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 87c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 88c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler private float getSize(long now) { 89c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (mSizeMax == 0) 90c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return 0; 91c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler long dt = (now - mLastPokeTime); 92c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (dt > mHold + mDecay) 93c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return mSizeMin; 94c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (dt < mHold) 95c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return mSizeMax; 96c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return (int) lerp(mSizeMax, mSizeMin, (float) (dt - mHold) / mDecay); 97c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 98c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 99c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public void setFlashOnTouchCapture(boolean dbg) { 100c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mShouldFlash = dbg; 101c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mFlashFrac = 0f; 102c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler postInvalidate(); 103e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler } 104e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler 10525bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler // I made you a touch event... 106e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler @Override 107c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public boolean onTouchEvent(MotionEvent event) { 10825bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler if (DEBUG) { 109c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction())); 11025bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler } 111c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 112c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler final int action = event.getAction(); 113c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (action == MotionEvent.ACTION_OUTSIDE) { 114c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler poke(event); 115c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } else if (action == MotionEvent.ACTION_DOWN) { 11625bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler if (DEBUG) { 117c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY()); 11825bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler } 119c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler int size = (int) getSize(event.getEventTime()); 120c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if ((mVertical && event.getX() < size) || event.getY() < size) { 12125bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler if (CHATTY) { 12225bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")"); 12325bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler } 124c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (mShouldFlash) { 125c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler post(mDebugFlash); 126c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler postInvalidate(); 127c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 12825bb8eec2d63add7d43d357c26f9792ae6156a92Daniel Sandler return true; // ...but I eated it 129c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 130c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 131c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return false; 132c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 133c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 134c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public void poke(MotionEvent event) { 135c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mLastPokeTime = event.getEventTime(); 136c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (DEBUG) 137c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime)); 138c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler postInvalidate(); 139c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 140c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 141c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public void setFlash(float f) { 142c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler mFlashFrac = f; 143c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler postInvalidate(); 144e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler } 145e97a776e9cbb2a7a8d698c49c5c70f2b7cd9eb1bDaniel Sandler 146c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public float getFlash() { 147c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return mFlashFrac; 148c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 149c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 150c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler @Override 151c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler public void onDraw(Canvas can) { 152c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (!mShouldFlash || mFlashFrac <= 0f) { 153c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler return; 154c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 155c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 156c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler final int size = (int) getSize(SystemClock.uptimeMillis()); 157c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler can.clipRect(0, 0, mVertical ? size : can.getWidth(), mVertical ? can.getHeight() : size); 158c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler final float frac = DEBUG ? (mFlashFrac - 0.5f) + 0.5f : mFlashFrac; 159c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler can.drawARGB((int) (frac * 0xFF), 0xDD, 0xEE, 0xAA); 160c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler 161c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler if (DEBUG && size > mSizeMin) 162c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler // crazy aggressive redrawing here, for debugging only 163c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler postInvalidateDelayed(100); 164c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler } 165c26185bb7b30508a1940eb452af64b6d8661915fDaniel Sandler} 166