10cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv/*
20cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * Copyright (C) 2013 The Android Open Source Project
30cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv *
40cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * Licensed under the Apache License, Version 2.0 (the "License");
50cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * you may not use this file except in compliance with the License.
60cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * You may obtain a copy of the License at
70cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv *
80cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv *      http://www.apache.org/licenses/LICENSE-2.0
90cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv *
100cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * Unless required by applicable law or agreed to in writing, software
110cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * distributed under the License is distributed on an "AS IS" BASIS,
120cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * See the License for the specific language governing permissions and
140cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * limitations under the License.
150cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv */
160cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
175ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Millerpackage com.android.keyguard;
180cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
190cbbc5766fb7c56c49ec55eece905fa7764a8b2balanvimport android.content.Context;
200cbbc5766fb7c56c49ec55eece905fa7764a8b2balanvimport android.view.MotionEvent;
210cbbc5766fb7c56c49ec55eece905fa7764a8b2balanvimport android.view.View;
220cbbc5766fb7c56c49ec55eece905fa7764a8b2balanvimport android.view.accessibility.AccessibilityManager;
230cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
240cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv/**
250cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * Hover listener that implements lift-to-activate interaction for
260cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv * accessibility. May be added to multiple views.
270cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv */
280cbbc5766fb7c56c49ec55eece905fa7764a8b2balanvclass LiftToActivateListener implements View.OnHoverListener {
290cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    /** Manager used to query accessibility enabled state. */
300cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    private final AccessibilityManager mAccessibilityManager;
310cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
320cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    private boolean mCachedClickableState;
330cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
340cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    public LiftToActivateListener(Context context) {
350cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
360cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                Context.ACCESSIBILITY_SERVICE);
370cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    }
380cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
390cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    @Override
400cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    public boolean onHover(View v, MotionEvent event) {
410cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        // When touch exploration is turned on, lifting a finger while
420cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        // inside the view bounds should perform a click action.
430cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        if (mAccessibilityManager.isEnabled()
440cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                && mAccessibilityManager.isTouchExplorationEnabled()) {
450cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv            switch (event.getActionMasked()) {
460cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                case MotionEvent.ACTION_HOVER_ENTER:
470cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    // Lift-to-type temporarily disables double-tap
480cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    // activation by setting the view as not clickable.
490cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    mCachedClickableState = v.isClickable();
500cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    v.setClickable(false);
510cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    break;
520cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                case MotionEvent.ACTION_HOVER_EXIT:
530cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    final int x = (int) event.getX();
540cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    final int y = (int) event.getY();
550cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
560cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                            && (x < v.getWidth() - v.getPaddingRight())
570cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                            && (y < v.getHeight() - v.getPaddingBottom())) {
580cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                        v.performClick();
590cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    }
600cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    v.setClickable(mCachedClickableState);
610cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv                    break;
620cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv            }
630cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        }
640cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
650cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        // Pass the event to View.onHoverEvent() to handle accessibility.
660cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        v.onHoverEvent(event);
670cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
680cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        // Consume the event so it doesn't fall through to other views.
690cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        return true;
700cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    }
710cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv}