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 
5 package org.chromium.android_webview;
6 
7 import android.os.Handler;
8 import android.os.Message;
9 import android.view.View;
10 import 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  */
19 class 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 
HandlerCallback(View eventSender)28         public HandlerCallback(View eventSender) {
29             mEventSender = eventSender;
30         }
31 
32         @Override
handleMessage(Message msg)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 
ScrollAccessibilityHelper(View eventSender)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      */
postViewScrolledAccessibilityEventCallback()59     public void postViewScrolledAccessibilityEventCallback() {
60         if (mMsgViewScrolledQueued) return;
61         mMsgViewScrolledQueued = true;
62 
63         Message msg = mHandler.obtainMessage(HandlerCallback.MSG_VIEW_SCROLLED);
64         mHandler.sendMessageDelayed(msg, SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS);
65     }
66 
removePostedViewScrolledAccessibilityEventCallback()67     public void removePostedViewScrolledAccessibilityEventCallback() {
68         if (!mMsgViewScrolledQueued) return;
69         mMsgViewScrolledQueued = false;
70 
71         mHandler.removeMessages(HandlerCallback.MSG_VIEW_SCROLLED);
72     }
73 
removePostedCallbacks()74     public void removePostedCallbacks() {
75         removePostedViewScrolledAccessibilityEventCallback();
76     }
77 }
78