Java tutorial
/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.screenspeak.eventprocessor; import android.support.v4.view.accessibility.AccessibilityEventCompat; import android.util.SparseIntArray; import android.view.accessibility.AccessibilityEvent; import com.android.utils.AccessibilityEventUtils; import java.util.ArrayList; import java.util.Iterator; /** * This class is a queue that tracks events that ScreenSpeak will process. This * queue self-prunes events that exceed a maximum threshold for certain event * types. */ class EventQueue { /** * The maximum number of events for each type included in * {@code MASK_LIMITED_EVENT_TYPES} that may remain in the queue. */ private static final int MAXIMUM_QUALIFYING_EVENTS = 2; /** * The types of events that should be pruned if there are more than * {@code MAXIMUM_QUALIFYING_EVENTS} of these events in the queue. */ private static final int MASK_LIMITED_EVENT_TYPES = AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER | AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED; /** * The list responsible for maintaining events in the event queue. */ private final ArrayList<AccessibilityEvent> mEventQueue = new ArrayList<>(); /** * The current number of events in the queue for each event type that match * a type defined in {@code MASK_LIMITED_EVENT_TYPES}. */ private final SparseIntArray mQualifyingEvents = new SparseIntArray(); /** * Adds an {@link AccessibilityEvent} to the queue for processing. If this * addition causes the queue to exceed the maximum allowable events for an * event's type, earlier events of this type will be pruned from the queue. * * @param event The event to add to the queue */ public void enqueue(AccessibilityEvent event) { final AccessibilityEvent clone = AccessibilityEvent.obtain(event); final int eventType = clone.getEventType(); if (AccessibilityEventUtils.eventMatchesAnyType(clone, MASK_LIMITED_EVENT_TYPES)) { final int eventCountOfType = mQualifyingEvents.get(eventType, 0); mQualifyingEvents.put(eventType, (eventCountOfType + 1)); } mEventQueue.add(clone); enforceEventLimits(); } /** * Removes and returns an AccessibilityEvent from the front of the event queue. * * @return The event at the front of the queue. */ public AccessibilityEvent dequeue() { if (mEventQueue.isEmpty()) { return null; } final AccessibilityEvent event = mEventQueue.remove(0); if (event != null && AccessibilityEventUtils.eventMatchesAnyType(event, MASK_LIMITED_EVENT_TYPES)) { final int eventType = event.getEventType(); final int eventCountOfType = mQualifyingEvents.get(eventType, 0); mQualifyingEvents.put(eventType, (eventCountOfType - 1)); } return event; } /** * Clears the event queue and discards all events waiting for processing. */ public void clear() { mEventQueue.clear(); mQualifyingEvents.clear(); } /** * Determines if the event queue is empty. * * @return {@code true} if the queue is empty, {@code false} otherwise */ public boolean isEmpty() { return mEventQueue.isEmpty(); } /** * Enforces that the event queue has no more than * {@code MAXIMUM_QUALIFYING_EVENTS} events of each type defined by * {@code MASK_LIMITED_EVENT_TYPES}. The excessive events are pruned by * removing the oldest event first. */ private void enforceEventLimits() { int eventTypesToPrune = 0; // Locate event types which exceed the allowable limit for (int i = 0; i < mQualifyingEvents.size(); i++) { final int eventType = mQualifyingEvents.keyAt(i); final int eventsOfType = mQualifyingEvents.valueAt(i); if (eventsOfType > MAXIMUM_QUALIFYING_EVENTS) { eventTypesToPrune |= eventType; } } final Iterator<AccessibilityEvent> iterator = mEventQueue.iterator(); while (iterator.hasNext() && (eventTypesToPrune != 0)) { final AccessibilityEvent next = iterator.next(); // Prune offending events if (AccessibilityEventUtils.eventMatchesAnyType(next, eventTypesToPrune)) { final int eventType = next.getEventType(); int eventCountOfType = mQualifyingEvents.get(eventType, 0); eventCountOfType--; mQualifyingEvents.put(eventType, eventCountOfType); iterator.remove(); // Stop pruning further events of this type if the number of // events is below the limit if (eventCountOfType <= MAXIMUM_QUALIFYING_EVENTS) { eventTypesToPrune &= ~eventType; } } } } }