blob: 1cad61fb6728378c15ad6a0ea77ecf1473ab38e8 [file] [log] [blame]
Daniel Sandlere97a7762012-03-19 22:56:42 -04001/*
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
17package com.android.systemui.statusbar.policy;
18
Daniel Sandlerc26185b2012-08-29 15:49:53 -040019import android.animation.ObjectAnimator;
Daniel Sandlere97a7762012-03-19 22:56:42 -040020import android.content.Context;
Daniel Sandlerc26185b2012-08-29 15:49:53 -040021import android.content.res.TypedArray;
22import android.graphics.Canvas;
23import android.os.SystemClock;
Daniel Sandlere97a7762012-03-19 22:56:42 -040024import android.util.AttributeSet;
Daniel Sandler29787f6e2013-11-12 20:33:34 -050025import android.util.Slog;
Daniel Sandlere97a7762012-03-19 22:56:42 -040026import android.view.MotionEvent;
27import android.view.View;
28
29import com.android.systemui.R;
30
James Cookf8da2082015-04-09 10:38:05 -070031/**
32 * The "dead zone" consumes unintentional taps along the top edge of the navigation bar.
33 * When users are typing quickly on an IME they may attempt to hit the space bar, overshoot, and
34 * accidentally hit the home button. The DeadZone expands temporarily after each tap in the UI
35 * outside the navigation bar (since this is when accidental taps are more likely), then contracts
36 * back over time (since a later tap might be intended for the top of the bar).
37 */
Daniel Sandlere97a7762012-03-19 22:56:42 -040038public class DeadZone extends View {
Daniel Sandlerc26185b2012-08-29 15:49:53 -040039 public static final String TAG = "DeadZone";
40
41 public static final boolean DEBUG = false;
James Cookf8da2082015-04-09 10:38:05 -070042 public static final int HORIZONTAL = 0; // Consume taps along the top edge.
43 public static final int VERTICAL = 1; // Consume taps along the left edge.
Daniel Sandlerc26185b2012-08-29 15:49:53 -040044
Daniel Sandler25bb8ee2012-08-30 17:10:50 -040045 private static final boolean CHATTY = true; // print to logcat when we eat a click
46
Daniel Sandlerc26185b2012-08-29 15:49:53 -040047 private boolean mShouldFlash;
48 private float mFlashFrac = 0f;
49
50 private int mSizeMax;
51 private int mSizeMin;
52 // Upon activity elsewhere in the UI, the dead zone will hold steady for
53 // mHold ms, then move back over the course of mDecay ms
54 private int mHold, mDecay;
55 private boolean mVertical;
56 private long mLastPokeTime;
57
58 private final Runnable mDebugFlash = new Runnable() {
59 @Override
60 public void run() {
61 ObjectAnimator.ofFloat(DeadZone.this, "flash", 1f, 0f).setDuration(150).start();
62 }
63 };
64
Daniel Sandlere97a7762012-03-19 22:56:42 -040065 public DeadZone(Context context, AttributeSet attrs) {
66 this(context, attrs, 0);
67 }
68
69 public DeadZone(Context context, AttributeSet attrs, int defStyle) {
70 super(context, attrs);
Daniel Sandlerc26185b2012-08-29 15:49:53 -040071
72 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeadZone,
73 defStyle, 0);
74
75 mHold = a.getInteger(R.styleable.DeadZone_holdTime, 0);
76 mDecay = a.getInteger(R.styleable.DeadZone_decayTime, 0);
77
78 mSizeMin = a.getDimensionPixelSize(R.styleable.DeadZone_minSize, 0);
79 mSizeMax = a.getDimensionPixelSize(R.styleable.DeadZone_maxSize, 0);
80
81 int index = a.getInt(R.styleable.DeadZone_orientation, -1);
82 mVertical = (index == VERTICAL);
83
84 if (DEBUG)
Daniel Sandler29787f6e2013-11-12 20:33:34 -050085 Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
Daniel Sandlerc26185b2012-08-29 15:49:53 -040086 + (mVertical ? " vertical" : " horizontal"));
87
Daniel Sandler25bb8ee2012-08-30 17:10:50 -040088 setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash));
Daniel Sandlerc26185b2012-08-29 15:49:53 -040089 }
90
91 static float lerp(float a, float b, float f) {
92 return (b - a) * f + a;
93 }
94
95 private float getSize(long now) {
96 if (mSizeMax == 0)
97 return 0;
98 long dt = (now - mLastPokeTime);
99 if (dt > mHold + mDecay)
100 return mSizeMin;
101 if (dt < mHold)
102 return mSizeMax;
103 return (int) lerp(mSizeMax, mSizeMin, (float) (dt - mHold) / mDecay);
104 }
105
106 public void setFlashOnTouchCapture(boolean dbg) {
107 mShouldFlash = dbg;
108 mFlashFrac = 0f;
109 postInvalidate();
Daniel Sandlere97a7762012-03-19 22:56:42 -0400110 }
111
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400112 // I made you a touch event...
Daniel Sandlere97a7762012-03-19 22:56:42 -0400113 @Override
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400114 public boolean onTouchEvent(MotionEvent event) {
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400115 if (DEBUG) {
Daniel Sandler29787f6e2013-11-12 20:33:34 -0500116 Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400117 }
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400118
James Cookf8da2082015-04-09 10:38:05 -0700119 // Don't consume events for high precision pointing devices. For this purpose a stylus is
120 // considered low precision (like a finger), so its events may be consumed.
121 if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
122 return false;
123 }
124
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400125 final int action = event.getAction();
126 if (action == MotionEvent.ACTION_OUTSIDE) {
127 poke(event);
128 } else if (action == MotionEvent.ACTION_DOWN) {
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400129 if (DEBUG) {
Daniel Sandler29787f6e2013-11-12 20:33:34 -0500130 Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400131 }
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400132 int size = (int) getSize(event.getEventTime());
James Cookf8da2082015-04-09 10:38:05 -0700133 // In the vertical orientation consume taps along the left edge.
134 // In horizontal orientation consume taps along the top edge.
135 final boolean consumeEvent = mVertical ? event.getX() < size : event.getY() < size;
136 if (consumeEvent) {
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400137 if (CHATTY) {
Daniel Sandler29787f6e2013-11-12 20:33:34 -0500138 Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400139 }
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400140 if (mShouldFlash) {
141 post(mDebugFlash);
142 postInvalidate();
143 }
Daniel Sandler25bb8ee2012-08-30 17:10:50 -0400144 return true; // ...but I eated it
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400145 }
146 }
147 return false;
148 }
149
150 public void poke(MotionEvent event) {
151 mLastPokeTime = event.getEventTime();
152 if (DEBUG)
Daniel Sandler29787f6e2013-11-12 20:33:34 -0500153 Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
Daniel Sandler4f6ec7f2013-01-17 16:02:36 -0500154 if (mShouldFlash) postInvalidate();
Daniel Sandlerc26185b2012-08-29 15:49:53 -0400155 }
156
157 public void setFlash(float f) {
158 mFlashFrac = f;
159 postInvalidate();
160 }
161
162 public float getFlash() {
163 return mFlashFrac;
164 }
165
166 @Override
167 public void onDraw(Canvas can) {
168 if (!mShouldFlash || mFlashFrac <= 0f) {
169 return;
170 }
171
172 final int size = (int) getSize(SystemClock.uptimeMillis());
173 can.clipRect(0, 0, mVertical ? size : can.getWidth(), mVertical ? can.getHeight() : size);
174 final float frac = DEBUG ? (mFlashFrac - 0.5f) + 0.5f : mFlashFrac;
175 can.drawARGB((int) (frac * 0xFF), 0xDD, 0xEE, 0xAA);
176
177 if (DEBUG && size > mSizeMin)
178 // crazy aggressive redrawing here, for debugging only
179 postInvalidateDelayed(100);
Daniel Sandlere97a7762012-03-19 22:56:42 -0400180 }
181}