1083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon/* 2083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * Copyright (C) 2012 The Android Open Source Project 3083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * 4083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 5083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * you may not use this file except in compliance with the License. 6083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * You may obtain a copy of the License at 7083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * 8083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * http://www.apache.org/licenses/LICENSE-2.0 9083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * 10083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * Unless required by applicable law or agreed to in writing, software 11083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 12083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * See the License for the specific language governing permissions and 14083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * limitations under the License. 15083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon */ 16083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 17083c494c07681cdb826a1f2958d2143cf694de82Santos Cordonpackage com.android.incallui; 18083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 19083c494c07681cdb826a1f2958d2143cf694de82Santos Cordonimport android.view.MotionEvent; 20083c494c07681cdb826a1f2958d2143cf694de82Santos Cordonimport android.view.View; 21083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 22083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon/** 23083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * OnTouchListener used to shrink the "hit target" of some onscreen buttons. 24083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * 25083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * We do this for a few specific buttons which are vulnerable to 26083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * "false touches" because either (1) they're near the edge of the 27083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * screen and might be unintentionally touched while holding the 28083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * device in your hand, (2) they're in the upper corners and might 29083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * be touched by the user's ear before the prox sensor has a chance to 30083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * kick in, or (3) they are close to other buttons. 31083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon */ 32083c494c07681cdb826a1f2958d2143cf694de82Santos Cordonpublic class SmallerHitTargetTouchListener implements View.OnTouchListener { 33083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon private static final String TAG = "SmallerHitTargetTouchListener"; 34083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 35083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon /** 36083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * Edge dimensions where a touch does not register an action (in DIP). 37083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon */ 38083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon private static final int HIT_TARGET_EDGE_IGNORE_DP_X = 30; 39083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon private static final int HIT_TARGET_EDGE_IGNORE_DP_Y = 10; 40083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon private static final int HIT_TARGET_MIN_SIZE_DP_X = HIT_TARGET_EDGE_IGNORE_DP_X * 3; 41083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon private static final int HIT_TARGET_MIN_SIZE_DP_Y = HIT_TARGET_EDGE_IGNORE_DP_Y * 3; 42083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 43083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // True if the most recent DOWN event was a "hit". 44083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon boolean mDownEventHit; 45083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 46083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon /** 47083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * Called when a touch event is dispatched to a view. This allows listeners to 48083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * get a chance to respond before the target view. 49083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * 50083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * @return True if the listener has consumed the event, false otherwise. 51083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * (In other words, we return true when the touch is *outside* 52083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * the "smaller hit target", which will prevent the actual 53083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon * button from handling these events.) 54083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon */ 55083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon @Override 56083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon public boolean onTouch(View v, MotionEvent event) { 57083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // if (DBG) log("SmallerHitTargetTouchListener: " + v + ", event " + event); 58083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 59083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon if (event.getAction() == MotionEvent.ACTION_DOWN) { 60083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // Note that event.getX() and event.getY() are already 61083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // translated into the View's coordinates. (In other words, 62083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // "0,0" is a touch on the upper-left-most corner of the view.) 63083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int touchX = (int) event.getX(); 64083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int touchY = (int) event.getY(); 65083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 66083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int viewWidth = v.getWidth(); 67083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int viewHeight = v.getHeight(); 68083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 69083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final float pixelDensity = v.getResources().getDisplayMetrics().density; 70083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int targetMinSizeX = (int) (HIT_TARGET_MIN_SIZE_DP_X * pixelDensity); 71083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int targetMinSizeY = (int) (HIT_TARGET_MIN_SIZE_DP_Y * pixelDensity); 72083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 73083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon int edgeIgnoreX = (int) (HIT_TARGET_EDGE_IGNORE_DP_X * pixelDensity); 74083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon int edgeIgnoreY = (int) (HIT_TARGET_EDGE_IGNORE_DP_Y * pixelDensity); 75083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 76083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // If we are dealing with smaller buttons where the dead zone defined by 77083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // HIT_TARGET_EDGE_IGNORE_DP_[X|Y] is too large. 78083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon if (viewWidth < targetMinSizeX || viewHeight < targetMinSizeY) { 79083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // This really should not happen given our two use cases (as of this writing) 80083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // in the call edge button and secondary calling card. However, we leave 81083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // this is as a precautionary measure. 82083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon Log.w(TAG, "onTouch: view is too small for SmallerHitTargetTouchListener"); 83083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon edgeIgnoreX = 0; 84083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon edgeIgnoreY = 0; 85083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon } 86083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 87083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int minTouchX = edgeIgnoreX; 88083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int maxTouchX = viewWidth - edgeIgnoreX; 89083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int minTouchY = edgeIgnoreY; 90083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon final int maxTouchY = viewHeight - edgeIgnoreY; 91083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon 92083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon if (touchX < minTouchX || touchX > maxTouchX || 93083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon touchY < minTouchY || touchY > maxTouchY) { 94083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // Missed! 95083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // if (DBG) log(" -> MISSED!"); 96083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon mDownEventHit = false; 97083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon return true; // Consume this event; don't let the button see it 98083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon } else { 99083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // Hit! 100083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // if (DBG) log(" -> HIT!"); 101083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon mDownEventHit = true; 102083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon return false; // Let this event through to the actual button 103083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon } 104083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon } else { 105083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // This is a MOVE, UP or CANCEL event. 106083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // 107083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // We only do the "smaller hit target" check on DOWN events. 108083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // For the subsequent MOVE/UP/CANCEL events, we let them 109083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // through to the actual button IFF the previous DOWN event 110083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon // got through to the actual button (i.e. it was a "hit".) 111083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon return !mDownEventHit; 112083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon } 113083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon } 114083c494c07681cdb826a1f2958d2143cf694de82Santos Cordon} 115