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.contacts.dialpad; 18 19 import android.content.Context; 20 import android.graphics.Rect; 21 import android.util.AttributeSet; 22 import android.view.MotionEvent; 23 import android.view.View; 24 import android.view.accessibility.AccessibilityManager; 25 import android.widget.ImageButton; 26 27 /** 28 * Custom {@link ImageButton} for dialpad buttons. 29 * <p> 30 * This class implements lift-to-type interaction when touch exploration is 31 * enabled. 32 */ 33 public class DialpadImageButton extends ImageButton { 34 /** Accessibility manager instance used to check touch exploration state. */ 35 private AccessibilityManager mAccessibilityManager; 36 37 /** Bounds used to filter HOVER_EXIT events. */ 38 private Rect mHoverBounds = new Rect(); 39 40 public interface OnPressedListener { onPressed(View view, boolean pressed)41 public void onPressed(View view, boolean pressed); 42 } 43 44 private OnPressedListener mOnPressedListener; 45 setOnPressedListener(OnPressedListener onPressedListener)46 public void setOnPressedListener(OnPressedListener onPressedListener) { 47 mOnPressedListener = onPressedListener; 48 } 49 DialpadImageButton(Context context, AttributeSet attrs)50 public DialpadImageButton(Context context, AttributeSet attrs) { 51 super(context, attrs); 52 initForAccessibility(context); 53 } 54 DialpadImageButton(Context context, AttributeSet attrs, int defStyle)55 public DialpadImageButton(Context context, AttributeSet attrs, int defStyle) { 56 super(context, attrs, defStyle); 57 initForAccessibility(context); 58 } 59 initForAccessibility(Context context)60 private void initForAccessibility(Context context) { 61 mAccessibilityManager = (AccessibilityManager) context.getSystemService( 62 Context.ACCESSIBILITY_SERVICE); 63 } 64 65 @Override setPressed(boolean pressed)66 public void setPressed(boolean pressed) { 67 super.setPressed(pressed); 68 if (mOnPressedListener != null) { 69 mOnPressedListener.onPressed(this, pressed); 70 } 71 } 72 73 @Override onSizeChanged(int w, int h, int oldw, int oldh)74 public void onSizeChanged(int w, int h, int oldw, int oldh) { 75 super.onSizeChanged(w, h, oldw, oldh); 76 77 mHoverBounds.left = getPaddingLeft(); 78 mHoverBounds.right = w - getPaddingRight(); 79 mHoverBounds.top = getPaddingTop(); 80 mHoverBounds.bottom = h - getPaddingBottom(); 81 } 82 83 @Override performClick()84 public boolean performClick() { 85 // When accessibility is on, simulate press and release to preserve the 86 // semantic meaning of performClick(). Required for Braille support. 87 if (mAccessibilityManager.isEnabled()) { 88 // Checking the press state prevents double activation. 89 if (!isPressed()) { 90 setPressed(true); 91 setPressed(false); 92 } 93 94 return true; 95 } 96 97 return super.performClick(); 98 } 99 100 @Override onHoverEvent(MotionEvent event)101 public boolean onHoverEvent(MotionEvent event) { 102 // When touch exploration is turned on, lifting a finger while inside 103 // the button's hover target bounds should perform a click action. 104 if (mAccessibilityManager.isEnabled() 105 && mAccessibilityManager.isTouchExplorationEnabled()) { 106 switch (event.getActionMasked()) { 107 case MotionEvent.ACTION_HOVER_ENTER: 108 // Lift-to-type temporarily disables double-tap activation. 109 setClickable(false); 110 break; 111 case MotionEvent.ACTION_HOVER_EXIT: 112 if (mHoverBounds.contains((int) event.getX(), (int) event.getY())) { 113 performClick(); 114 } 115 setClickable(true); 116 break; 117 } 118 } 119 120 return super.onHoverEvent(event); 121 } 122 } 123