• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.phone;
18 
19 import android.view.MotionEvent;
20 import android.view.View;
21 
22 /**
23  * OnTouchListener used to shrink the "hit target" of some onscreen buttons.
24  *
25  * We do this for a few specific buttons which are vulnerable to
26  * "false touches" because either (1) they're near the edge of the
27  * screen and might be unintentionally touched while holding the
28  * device in your hand, or (2) they're in the upper corners and might
29  * be touched by the user's ear before the prox sensor has a chance to
30  * kick in.
31  *
32  * TODO (new ICS layout): not sure which buttons need this yet.
33  * For now, use it only with the "End call" button (which extends all
34  * the way to the edges of the screen).  But we can consider doing
35  * this for "Dialpad" and/or "Add call" if those turn out to be a
36  * problem too.
37  */
38 public class SmallerHitTargetTouchListener implements View.OnTouchListener {
39     /**
40      * Width of the allowable "hit target" as a percentage of
41      * the total width of this button.
42      */
43     private static final int HIT_TARGET_PERCENT_X = 50;
44 
45     /**
46      * Height of the allowable "hit target" as a percentage of
47      * the total height of this button.
48      *
49      * This is larger than HIT_TARGET_PERCENT_X because some of
50      * the onscreen buttons are wide but not very tall and we don't
51      * want to make the vertical hit target *too* small.
52      */
53     private static final int HIT_TARGET_PERCENT_Y = 80;
54 
55     // Size (percentage-wise) of the "edge" area that's *not* touch-sensitive.
56     private static final int X_EDGE = (100 - HIT_TARGET_PERCENT_X) / 2;
57     private static final int Y_EDGE = (100 - HIT_TARGET_PERCENT_Y) / 2;
58     // Min/max values (percentage-wise) of the touch-sensitive hit target.
59     private static final int X_HIT_MIN = X_EDGE;
60     private static final int X_HIT_MAX = 100 - X_EDGE;
61     private static final int Y_HIT_MIN = Y_EDGE;
62     private static final int Y_HIT_MAX = 100 - Y_EDGE;
63 
64     // True if the most recent DOWN event was a "hit".
65     boolean mDownEventHit;
66 
67     /**
68      * Called when a touch event is dispatched to a view. This allows listeners to
69      * get a chance to respond before the target view.
70      *
71      * @return True if the listener has consumed the event, false otherwise.
72      *         (In other words, we return true when the touch is *outside*
73      *         the "smaller hit target", which will prevent the actual
74      *         button from handling these events.)
75      */
76     @Override
onTouch(View v, MotionEvent event)77     public boolean onTouch(View v, MotionEvent event) {
78         // if (DBG) log("SmallerHitTargetTouchListener: " + v + ", event " + event);
79 
80         if (event.getAction() == MotionEvent.ACTION_DOWN) {
81             // Note that event.getX() and event.getY() are already
82             // translated into the View's coordinates.  (In other words,
83             // "0,0" is a touch on the upper-left-most corner of the view.)
84             int touchX = (int) event.getX();
85             int touchY = (int) event.getY();
86 
87             int viewWidth = v.getWidth();
88             int viewHeight = v.getHeight();
89 
90             // Touch location as a percentage of the total button width or height.
91             int touchXPercent = (int) ((float) (touchX * 100) / (float) viewWidth);
92             int touchYPercent = (int) ((float) (touchY * 100) / (float) viewHeight);
93             // if (DBG) log("- percentage:  x = " + touchXPercent + ",  y = " + touchYPercent);
94 
95             // TODO: user research: add event logging here of the actual
96             // hit location (and button ID), and enable it for dogfooders
97             // for a few days.  That'll give us a good idea of how close
98             // to the center of the button(s) most touch events are, to
99             // help us fine-tune the HIT_TARGET_PERCENT_* constants.
100 
101             if (touchXPercent < X_HIT_MIN || touchXPercent > X_HIT_MAX
102                     || touchYPercent < Y_HIT_MIN || touchYPercent > Y_HIT_MAX) {
103                 // Missed!
104                 // if (DBG) log("  -> MISSED!");
105                 mDownEventHit = false;
106                 return true;  // Consume this event; don't let the button see it
107             } else {
108                 // Hit!
109                 // if (DBG) log("  -> HIT!");
110                 mDownEventHit = true;
111                 return false;  // Let this event through to the actual button
112             }
113         } else {
114             // This is a MOVE, UP or CANCEL event.
115             //
116             // We only do the "smaller hit target" check on DOWN events.
117             // For the subsequent MOVE/UP/CANCEL events, we let them
118             // through to the actual button IFF the previous DOWN event
119             // got through to the actual button (i.e. it was a "hit".)
120             return !mDownEventHit;
121         }
122     }
123 }