• 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.util.Log;
20 import android.view.MotionEvent;
21 import android.view.View;
22 
23 /**
24  * OnTouchListener used to shrink the "hit target" of some onscreen buttons.
25  *
26  * We do this for a few specific buttons which are vulnerable to
27  * "false touches" because either (1) they're near the edge of the
28  * screen and might be unintentionally touched while holding the
29  * device in your hand, (2) they're in the upper corners and might
30  * be touched by the user's ear before the prox sensor has a chance to
31  * kick in, or (3) they are close to other buttons.
32  */
33 public class SmallerHitTargetTouchListener implements View.OnTouchListener {
34     private static final String TAG = "SmallerHitTargetTouchListener";
35 
36     /**
37      * Edge dimensions where a touch does not register an action (in DIP).
38      */
39     private static final int HIT_TARGET_EDGE_IGNORE_DP_X = 30;
40     private static final int HIT_TARGET_EDGE_IGNORE_DP_Y = 10;
41     private static final int HIT_TARGET_MIN_SIZE_DP_X = HIT_TARGET_EDGE_IGNORE_DP_X * 3;
42     private static final int HIT_TARGET_MIN_SIZE_DP_Y = HIT_TARGET_EDGE_IGNORE_DP_Y * 3;
43 
44     // True if the most recent DOWN event was a "hit".
45     boolean mDownEventHit;
46 
47     /**
48      * Called when a touch event is dispatched to a view. This allows listeners to
49      * get a chance to respond before the target view.
50      *
51      * @return True if the listener has consumed the event, false otherwise.
52      *         (In other words, we return true when the touch is *outside*
53      *         the "smaller hit target", which will prevent the actual
54      *         button from handling these events.)
55      */
56     @Override
onTouch(View v, MotionEvent event)57     public boolean onTouch(View v, MotionEvent event) {
58         // if (DBG) log("SmallerHitTargetTouchListener: " + v + ", event " + event);
59 
60         if (event.getAction() == MotionEvent.ACTION_DOWN) {
61             // Note that event.getX() and event.getY() are already
62             // translated into the View's coordinates.  (In other words,
63             // "0,0" is a touch on the upper-left-most corner of the view.)
64             final int touchX = (int) event.getX();
65             final int touchY = (int) event.getY();
66 
67             final int viewWidth = v.getWidth();
68             final int viewHeight = v.getHeight();
69 
70             final float pixelDensity = v.getResources().getDisplayMetrics().density;
71             final int targetMinSizeX = (int) (HIT_TARGET_MIN_SIZE_DP_X * pixelDensity);
72             final int targetMinSizeY = (int) (HIT_TARGET_MIN_SIZE_DP_Y * pixelDensity);
73 
74             int edgeIgnoreX = (int) (HIT_TARGET_EDGE_IGNORE_DP_X * pixelDensity);
75             int edgeIgnoreY = (int) (HIT_TARGET_EDGE_IGNORE_DP_Y * pixelDensity);
76 
77             // If we are dealing with smaller buttons where the dead zone defined by
78             // HIT_TARGET_EDGE_IGNORE_DP_[X|Y] is too large.
79             if (viewWidth < targetMinSizeX || viewHeight < targetMinSizeY) {
80                 // This really should not happen given our two use cases (as of this writing)
81                 // in the call edge button and secondary calling card. However, we leave
82                 // this is as a precautionary measure.
83                 Log.w(TAG, "onTouch: view is too small for SmallerHitTargetTouchListener");
84                 edgeIgnoreX = 0;
85                 edgeIgnoreY = 0;
86             }
87 
88             final int minTouchX = edgeIgnoreX;
89             final int maxTouchX = viewWidth - edgeIgnoreX;
90             final int minTouchY = edgeIgnoreY;
91             final int maxTouchY = viewHeight - edgeIgnoreY;
92 
93             if (touchX < minTouchX || touchX > maxTouchX ||
94                     touchY < minTouchY || touchY > maxTouchY) {
95                 // Missed!
96                 // if (DBG) log("  -> MISSED!");
97                 mDownEventHit = false;
98                 return true;  // Consume this event; don't let the button see it
99             } else {
100                 // Hit!
101                 // if (DBG) log("  -> HIT!");
102                 mDownEventHit = true;
103                 return false;  // Let this event through to the actual button
104             }
105         } else {
106             // This is a MOVE, UP or CANCEL event.
107             //
108             // We only do the "smaller hit target" check on DOWN events.
109             // For the subsequent MOVE/UP/CANCEL events, we let them
110             // through to the actual button IFF the previous DOWN event
111             // got through to the actual button (i.e. it was a "hit".)
112             return !mDownEventHit;
113         }
114     }
115 }
116