14a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka/* 24a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Copyright (C) 2013 The Android Open Source Project 34a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * 44a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 54a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * you may not use this file except in compliance with the License. 64a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * You may obtain a copy of the License at 74a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * 84a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 94a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * 104a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 114a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 124a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * See the License for the specific language governing permissions and 144a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * limitations under the License. 154a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 164a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 174a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaokapackage com.android.inputmethod.keyboard.internal; 184a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 199342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants; 2036799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalardimport com.android.inputmethod.latin.common.InputPointers; 214a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 224a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka/** 234a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * This class arbitrates batch input. 244a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * An instance of this class holds a {@link GestureStrokeRecognitionPoints}. 254a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * And it arbitrates multiple strokes gestured by multiple fingers and aggregates those gesture 264a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * points into one batch input. 274a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 284a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaokapublic class BatchInputArbiter { 294a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public interface BatchInputArbiterListener { 304a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onStartBatchInput(); 314a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onUpdateBatchInput( 324a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final InputPointers aggregatedPointers, final long moveEventTime); 334a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onStartUpdateBatchInputTimer(); 344a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onEndBatchInput(final InputPointers aggregatedPointers, final long upEventTime); 354a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 364a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 374a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // The starting time of the first stroke of a gesture input. 384a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka private static long sGestureFirstDownTime; 394a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // The {@link InputPointers} that includes all events of a gesture input. 404a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka private static final InputPointers sAggregatedPointers = new InputPointers( 414a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka Constants.DEFAULT_GESTURE_POINTS_CAPACITY); 424a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka private static int sLastRecognitionPointSize = 0; // synchronized using sAggregatedPointers 434a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka private static long sLastRecognitionTime = 0; // synchronized using sAggregatedPointers 444a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 454a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka private final GestureStrokeRecognitionPoints mRecognitionPoints; 464a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 474a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public BatchInputArbiter(final int pointerId, final GestureStrokeRecognitionParams params) { 484a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mRecognitionPoints = new GestureStrokeRecognitionPoints(pointerId, params); 494a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 504a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 514a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { 524a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mRecognitionPoints.setKeyboardGeometry(keyWidth, keyboardHeight); 534a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 544a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 554a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka /** 564a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Calculate elapsed time since the first gesture down. 574a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param eventTime the time of this event. 584a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @return the elapsed time in millisecond from the first gesture down. 594a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 604a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public int getElapsedTimeSinceFirstDown(final long eventTime) { 614a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka return (int)(eventTime - sGestureFirstDownTime); 624a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 634a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 644a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka /** 654a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Add a down event point. 664a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param x the x-coordinate of this down event. 674a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param y the y-coordinate of this down event. 684a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param downEventTime the time of this down event. 694a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param lastLetterTypingTime the last typing input time. 704a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param activePointerCount the number of active pointers when this pointer down event occurs. 714a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 724a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void addDownEventPoint(final int x, final int y, final long downEventTime, 734a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final long lastLetterTypingTime, final int activePointerCount) { 744a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (activePointerCount == 1) { 754a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sGestureFirstDownTime = downEventTime; 764a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 774a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final int elapsedTimeSinceFirstDown = getElapsedTimeSinceFirstDown(downEventTime); 784a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final int elapsedTimeSinceLastTyping = (int)(downEventTime - lastLetterTypingTime); 794a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mRecognitionPoints.addDownEventPoint( 804a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka x, y, elapsedTimeSinceFirstDown, elapsedTimeSinceLastTyping); 814a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 824a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 834a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka /** 844a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Add a move event point. 854a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param x the x-coordinate of this move event. 864a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param y the y-coordinate of this move event. 874a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param moveEventTime the time of this move event. 884a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param isMajorEvent false if this is a historical move event. 894a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param listener {@link BatchInputArbiterListener#onStartUpdateBatchInputTimer()} of this 904a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * <code>listener</code> may be called if enough move points have been added. 914a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @return true if this move event occurs on the valid gesture area. 924a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 934a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public boolean addMoveEventPoint(final int x, final int y, final long moveEventTime, 944a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final boolean isMajorEvent, final BatchInputArbiterListener listener) { 954a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final int beforeLength = mRecognitionPoints.getLength(); 964a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final boolean onValidArea = mRecognitionPoints.addEventPoint( 974a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka x, y, getElapsedTimeSinceFirstDown(moveEventTime), isMajorEvent); 984a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (mRecognitionPoints.getLength() > beforeLength) { 994a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka listener.onStartUpdateBatchInputTimer(); 1004a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1014a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka return onValidArea; 1024a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1034a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 1044a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka /** 1054a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Determine whether the batch input has started or not. 1064a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param listener {@link BatchInputArbiterListener#onStartBatchInput()} of this 1074a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * <code>listener</code> will be called when the batch input has started successfully. 1084a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @return true if the batch input has started successfully. 1094a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 1104a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public boolean mayStartBatchInput(final BatchInputArbiterListener listener) { 1114a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (!mRecognitionPoints.isStartOfAGesture()) { 1124a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka return false; 1134a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1144a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka synchronized (sAggregatedPointers) { 1154a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sAggregatedPointers.reset(); 1164a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sLastRecognitionPointSize = 0; 1174a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sLastRecognitionTime = 0; 1184a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka listener.onStartBatchInput(); 1194a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1204a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka return true; 1214a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1224a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 1234a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka /** 1244a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Add synthetic move event point. After adding the point, 1254a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * {@link #updateBatchInput(long,BatchInputArbiterListener)} will be called internally. 1264a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param syntheticMoveEventTime the synthetic move event time. 1274a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param listener the listener to be passed to 1284a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * {@link #updateBatchInput(long,BatchInputArbiterListener)}. 1294a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 1304a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void updateBatchInputByTimer(final long syntheticMoveEventTime, 1314a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final BatchInputArbiterListener listener) { 1324a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mRecognitionPoints.duplicateLastPointWith( 1334a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka getElapsedTimeSinceFirstDown(syntheticMoveEventTime)); 1344a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka updateBatchInput(syntheticMoveEventTime, listener); 1354a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1364a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 1374a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka /** 1384a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Determine whether we have enough gesture points to lookup dictionary. 1394a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param moveEventTime the time of this move event. 1404a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param listener {@link BatchInputArbiterListener#onUpdateBatchInput(InputPointers,long)} of 1414a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * this <code>listener</code> will be called when enough event points we have. Also 1424a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * {@link BatchInputArbiterListener#onStartUpdateBatchInputTimer()} will be called to have 1434a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * possible future synthetic move event. 1444a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 1454a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void updateBatchInput(final long moveEventTime, 1464a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final BatchInputArbiterListener listener) { 1474a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka synchronized (sAggregatedPointers) { 1484a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mRecognitionPoints.appendIncrementalBatchPoints(sAggregatedPointers); 1494a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final int size = sAggregatedPointers.getPointerSize(); 1504a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (size > sLastRecognitionPointSize && mRecognitionPoints.hasRecognitionTimePast( 1514a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka moveEventTime, sLastRecognitionTime)) { 1524a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka listener.onUpdateBatchInput(sAggregatedPointers, moveEventTime); 1534a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka listener.onStartUpdateBatchInputTimer(); 1544a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // The listener may change the size of the pointers (when auto-committing 1554a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // for example), so we need to get the size from the pointers again. 1564a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sLastRecognitionPointSize = sAggregatedPointers.getPointerSize(); 1574a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sLastRecognitionTime = moveEventTime; 1584a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1594a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1604a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1614a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 1624a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka /** 1634a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * Determine whether the batch input has ended successfully or continues. 1644a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param upEventTime the time of this up event. 1654a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param activePointerCount the number of active pointers when this pointer up event occurs. 1664a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @param listener {@link BatchInputArbiterListener#onEndBatchInput(InputPointers,long)} of this 1674a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * <code>listener</code> will be called when the batch input has started successfully. 1684a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka * @return true if the batch input has ended successfully. 1694a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka */ 1704a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public boolean mayEndBatchInput(final long upEventTime, final int activePointerCount, 1714a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final BatchInputArbiterListener listener) { 1724a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka synchronized (sAggregatedPointers) { 1734a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mRecognitionPoints.appendAllBatchPoints(sAggregatedPointers); 1744a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (activePointerCount == 1) { 1754a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka listener.onEndBatchInput(sAggregatedPointers, upEventTime); 1764a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka return true; 1774a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1784a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1794a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka return false; 1804a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 1814a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka} 182