1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.android_webview;
6
7import android.os.Handler;
8import android.os.Message;
9import android.view.View;
10import android.view.accessibility.AccessibilityEvent;
11
12/**
13 * Helper used to post the VIEW_SCROLLED accessibility event.
14 *
15 * TODO(mkosiba): Investigate whether this is behavior we want to share with the chrome/ layer.
16 * TODO(mkosiba): We currently don't handle JS-initiated scrolling for layers other than the root
17 * layer.
18 */
19class ScrollAccessibilityHelper {
20    // This is copied straight out of android.view.ViewConfiguration.
21    private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100;
22
23    private class HandlerCallback implements Handler.Callback {
24        public static final int MSG_VIEW_SCROLLED = 1;
25
26        private View mEventSender;
27
28        public HandlerCallback(View eventSender) {
29            mEventSender = eventSender;
30        }
31
32        @Override
33        public boolean handleMessage(Message msg) {
34            switch(msg.what) {
35                case MSG_VIEW_SCROLLED:
36                    mMsgViewScrolledQueued = false;
37                    mEventSender.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
38                    break;
39                default:
40                    throw new IllegalStateException(
41                            "AccessibilityInjector: unhandled message: " + msg.what);
42            }
43            return true;
44        }
45    }
46
47    private Handler mHandler;
48    private boolean mMsgViewScrolledQueued;
49
50    public ScrollAccessibilityHelper(View eventSender) {
51        mHandler = new Handler(new HandlerCallback(eventSender));
52    }
53
54    /**
55     * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
56     * This event is sent at most once every
57     * {@link android.view.ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
58     */
59    public void postViewScrolledAccessibilityEventCallback() {
60        if (mMsgViewScrolledQueued)
61            return;
62        mMsgViewScrolledQueued = true;
63
64        Message msg = mHandler.obtainMessage(HandlerCallback.MSG_VIEW_SCROLLED);
65        mHandler.sendMessageDelayed(msg, SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS);
66    }
67
68    public void removePostedViewScrolledAccessibilityEventCallback() {
69        if (!mMsgViewScrolledQueued)
70            return;
71        mMsgViewScrolledQueued = false;
72
73        mHandler.removeMessages(HandlerCallback.MSG_VIEW_SCROLLED);
74    }
75
76    public void removePostedCallbacks() {
77        removePostedViewScrolledAccessibilityEventCallback();
78    }
79}
80