Merge "Move out all framework-tests classes." into gingerbread
diff --git a/common/Android.mk b/common/Android.mk
deleted file mode 100644
index 1f78840..0000000
--- a/common/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-# Note: the source code is in java/, not src/, because this code is also part of
-# the framework library, and build/core/pathmap.mk expects a java/ subdirectory.
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android-common
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, java) \
- $(call all-logtags-files-under, java)
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Include this library in the build server's output directory
-$(call dist-for-goals, droid, $(LOCAL_BUILT_MODULE):android-common.jar)
-
-# Build the test package
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/common/java/com/android/common/ArrayListCursor.java b/common/java/com/android/common/ArrayListCursor.java
deleted file mode 100644
index 9ad5c36..0000000
--- a/common/java/com/android/common/ArrayListCursor.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2006 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.common;
-
-import android.database.AbstractCursor;
-import android.database.CursorWindow;
-
-import java.lang.System;
-import java.util.ArrayList;
-
-/**
- * A convenience class that presents a two-dimensional ArrayList
- * as a Cursor.
- * @deprecated This is has been replaced by MatrixCursor.
-*/
-public class ArrayListCursor extends AbstractCursor {
- private String[] mColumnNames;
- private ArrayList<Object>[] mRows;
-
- @SuppressWarnings({"unchecked"})
- public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
- int colCount = columnNames.length;
- boolean foundID = false;
- // Add an _id column if not in columnNames
- for (int i = 0; i < colCount; ++i) {
- if (columnNames[i].compareToIgnoreCase("_id") == 0) {
- mColumnNames = columnNames;
- foundID = true;
- break;
- }
- }
-
- if (!foundID) {
- mColumnNames = new String[colCount + 1];
- System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
- mColumnNames[colCount] = "_id";
- }
-
- int rowCount = rows.size();
- mRows = new ArrayList[rowCount];
-
- for (int i = 0; i < rowCount; ++i) {
- mRows[i] = rows.get(i);
- if (!foundID) {
- mRows[i].add(i);
- }
- }
- }
-
- @Override
- public void fillWindow(int position, CursorWindow window) {
- if (position < 0 || position > getCount()) {
- return;
- }
-
- window.acquireReference();
- try {
- int oldpos = mPos;
- mPos = position - 1;
- window.clear();
- window.setStartPosition(position);
- int columnNum = getColumnCount();
- window.setNumColumns(columnNum);
- while (moveToNext() && window.allocRow()) {
- for (int i = 0; i < columnNum; i++) {
- final Object data = mRows[mPos].get(i);
- if (data != null) {
- if (data instanceof byte[]) {
- byte[] field = (byte[]) data;
- if (!window.putBlob(field, mPos, i)) {
- window.freeLastRow();
- break;
- }
- } else {
- String field = data.toString();
- if (!window.putString(field, mPos, i)) {
- window.freeLastRow();
- break;
- }
- }
- } else {
- if (!window.putNull(mPos, i)) {
- window.freeLastRow();
- break;
- }
- }
- }
- }
-
- mPos = oldpos;
- } catch (IllegalStateException e){
- // simply ignore it
- } finally {
- window.releaseReference();
- }
- }
-
- @Override
- public int getCount() {
- return mRows.length;
- }
-
- @Override
- public String[] getColumnNames() {
- return mColumnNames;
- }
-
- @Override
- public byte[] getBlob(int columnIndex) {
- return (byte[]) mRows[mPos].get(columnIndex);
- }
-
- @Override
- public String getString(int columnIndex) {
- Object cell = mRows[mPos].get(columnIndex);
- return (cell == null) ? null : cell.toString();
- }
-
- @Override
- public short getShort(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.shortValue();
- }
-
- @Override
- public int getInt(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.intValue();
- }
-
- @Override
- public long getLong(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.longValue();
- }
-
- @Override
- public float getFloat(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.floatValue();
- }
-
- @Override
- public double getDouble(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.doubleValue();
- }
-
- @Override
- public boolean isNull(int columnIndex) {
- return mRows[mPos].get(columnIndex) == null;
- }
-}
diff --git a/common/java/com/android/common/GoogleLogTags.logtags b/common/java/com/android/common/GoogleLogTags.logtags
deleted file mode 100644
index f848ddf..0000000
--- a/common/java/com/android/common/GoogleLogTags.logtags
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2010 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.
-
-option java_package com.android.common
-
-#####
-# This file contains definitions for event log (android.util.EventLog) tags
-# used by Google Mobile Services applications. These definitions are part of
-# the platform even when the Google applications are not.
-#
-# See system/core/logcat/event.logtags for a description of the file format.
-#
-# These event log tags must be assigned specific numbers (no "?") in the range
-# 200000-300000. If new tags are added, be aware that older platforms will be
-# missing the tag definitions, and may not be able to show them in their logs.
-
-#####
-# System Update (OTA)
-
-# System update status bits
-# [31- 9] Reserved for future use
-# [ 8- 7] package verified (0=not attempted, 1=succeeded, 2=failed)
-# [ 6] install approved
-# [ 5] download approved
-# [ 4- 0] status
-201001 system_update (status|1|5),(download_result|1|5),(bytes|2|2),(url|3)
-201002 system_update_user (action|3)
-
-#####
-# Android Market
-
-# @param changes Number of changes made to database in reconstruct
-202001 vending_reconstruct (changes|1)
-
-#####
-# Google Services Framework
-
-203001 sync_details (authority|3),(send|1|2),(recv|1|2),(details|3)
-
-203002 google_http_request (elapsed|2|3),(status|1),(appname|3),(reused|1)
-
-#####
-# Google Talk Service
-
-# This event is logged when GTalkService encounters important events
-204001 gtalkservice (eventType|1)
-# This event is logged for GTalk connection state changes. The status field is an int, but
-# it really contains 4 separate values, each taking up a byte
-# (eventType << 24) + (connection state << 16) + (connection error << 8) + network state
-204002 gtalk_connection (status|1)
-
-# This event is logged when GTalk connection is closed.
-# The status field is an int, but contains 2 different values, it's represented as
-#
-# (networkType << 8) + connection error
-#
-# the possible error values are
-#
-# no_error=0, no_network=1, connection_failed=2, unknown_host=3, auth_failed=4,
-# auth_expired=5, heart_beat_timeout=6, server_error=7, server_reject_rate_limiting=8, unknown=10
-#
-# duration is the connection duration.
-204003 gtalk_conn_close (status|1),(duration|1)
-
-# This event is logged for GTalk heartbeat resets
-# interval_and_nt contains both the heartbeat interval and the network type, It's represented as
-# (networkType << 16) + interval
-# interval is in seconds; network type can be 0 (mobile) or 1 (wifi); ip is the host ip addr.
-204004 gtalk_heartbeat_reset (interval_and_nt|1),(ip|3)
-
-# This event is logged when an Rmq v2 packet is sent or received.
-204005 c2dm (packet_type|1),(persistent_id|3),(stream_id|1),(last_stream_id|1)
-
-#####
-# Google Login Service and Setup Wizard
-
-# This event is for when communicating to the server times out during account setup
-205001 setup_server_timeout
-205002 setup_required_captcha (action|3)
-205003 setup_io_error (status|3)
-205004 setup_server_error
-205005 setup_retries_exhausted
-205006 setup_no_data_network
-205007 setup_completed
-
-205008 gls_account_tried (status|1)
-205009 gls_account_saved (status|1)
-205010 gls_authenticate (status|1),(service|3)
-205011 google_mail_switch (direction|1)
diff --git a/common/java/com/android/common/NetworkConnectivityListener.java b/common/java/com/android/common/NetworkConnectivityListener.java
deleted file mode 100644
index b49b80d..0000000
--- a/common/java/com/android/common/NetworkConnectivityListener.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2006 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.common;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Iterator;
-
-/**
- * A wrapper for a broadcast receiver that provides network connectivity
- * state information, independent of network type (mobile, Wi-Fi, etc.).
- * @deprecated Code tempted to use this class should simply listen for connectivity intents
- * (or poll ConnectivityManager) directly.
- * {@hide}
- */
-public class NetworkConnectivityListener {
- private static final String TAG = "NetworkConnectivityListener";
- private static final boolean DBG = false;
-
- private Context mContext;
- private HashMap<Handler, Integer> mHandlers = new HashMap<Handler, Integer>();
- private State mState;
- private boolean mListening;
- private String mReason;
- private boolean mIsFailover;
-
- /** Network connectivity information */
- private NetworkInfo mNetworkInfo;
-
- /**
- * In case of a Disconnect, the connectivity manager may have
- * already established, or may be attempting to establish, connectivity
- * with another network. If so, {@code mOtherNetworkInfo} will be non-null.
- */
- private NetworkInfo mOtherNetworkInfo;
-
- private ConnectivityBroadcastReceiver mReceiver;
-
- private class ConnectivityBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
-
- if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
- mListening == false) {
- Log.w(TAG, "onReceived() called with " + mState.toString() + " and " + intent);
- return;
- }
-
- boolean noConnectivity =
- intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-
- if (noConnectivity) {
- mState = State.NOT_CONNECTED;
- } else {
- mState = State.CONNECTED;
- }
-
- mNetworkInfo = (NetworkInfo)
- intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
- mOtherNetworkInfo = (NetworkInfo)
- intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
-
- mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
- mIsFailover =
- intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
-
- if (DBG) {
- Log.d(TAG, "onReceive(): mNetworkInfo=" + mNetworkInfo + " mOtherNetworkInfo = "
- + (mOtherNetworkInfo == null ? "[none]" : mOtherNetworkInfo +
- " noConn=" + noConnectivity) + " mState=" + mState.toString());
- }
-
- // Notifiy any handlers.
- Iterator<Handler> it = mHandlers.keySet().iterator();
- while (it.hasNext()) {
- Handler target = it.next();
- Message message = Message.obtain(target, mHandlers.get(target));
- target.sendMessage(message);
- }
- }
- };
-
- public enum State {
- UNKNOWN,
-
- /** This state is returned if there is connectivity to any network **/
- CONNECTED,
- /**
- * This state is returned if there is no connectivity to any network. This is set
- * to true under two circumstances:
- * <ul>
- * <li>When connectivity is lost to one network, and there is no other available
- * network to attempt to switch to.</li>
- * <li>When connectivity is lost to one network, and the attempt to switch to
- * another network fails.</li>
- */
- NOT_CONNECTED
- }
-
- /**
- * Create a new NetworkConnectivityListener.
- */
- public NetworkConnectivityListener() {
- mState = State.UNKNOWN;
- mReceiver = new ConnectivityBroadcastReceiver();
- }
-
- /**
- * This method starts listening for network connectivity state changes.
- * @param context
- */
- public synchronized void startListening(Context context) {
- if (!mListening) {
- mContext = context;
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- context.registerReceiver(mReceiver, filter);
- mListening = true;
- }
- }
-
- /**
- * This method stops this class from listening for network changes.
- */
- public synchronized void stopListening() {
- if (mListening) {
- mContext.unregisterReceiver(mReceiver);
- mContext = null;
- mNetworkInfo = null;
- mOtherNetworkInfo = null;
- mIsFailover = false;
- mReason = null;
- mListening = false;
- }
- }
-
- /**
- * This methods registers a Handler to be called back onto with the specified what code when
- * the network connectivity state changes.
- *
- * @param target The target handler.
- * @param what The what code to be used when posting a message to the handler.
- */
- public void registerHandler(Handler target, int what) {
- mHandlers.put(target, what);
- }
-
- /**
- * This methods unregisters the specified Handler.
- * @param target
- */
- public void unregisterHandler(Handler target) {
- mHandlers.remove(target);
- }
-
- public State getState() {
- return mState;
- }
-
- /**
- * Return the NetworkInfo associated with the most recent connectivity event.
- * @return {@code NetworkInfo} for the network that had the most recent connectivity event.
- */
- public NetworkInfo getNetworkInfo() {
- return mNetworkInfo;
- }
-
- /**
- * If the most recent connectivity event was a DISCONNECT, return
- * any information supplied in the broadcast about an alternate
- * network that might be available. If this returns a non-null
- * value, then another broadcast should follow shortly indicating
- * whether connection to the other network succeeded.
- *
- * @return NetworkInfo
- */
- public NetworkInfo getOtherNetworkInfo() {
- return mOtherNetworkInfo;
- }
-
- /**
- * Returns true if the most recent event was for an attempt to switch over to
- * a new network following loss of connectivity on another network.
- * @return {@code true} if this was a failover attempt, {@code false} otherwise.
- */
- public boolean isFailover() {
- return mIsFailover;
- }
-
- /**
- * An optional reason for the connectivity state change may have been supplied.
- * This returns it.
- * @return the reason for the state change, if available, or {@code null}
- * otherwise.
- */
- public String getReason() {
- return mReason;
- }
-}
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
deleted file mode 100644
index 1786957..0000000
--- a/common/java/com/android/common/OperationScheduler.java
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * 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.common;
-
-import android.content.SharedPreferences;
-import android.net.http.AndroidHttpClient;
-import android.text.format.Time;
-
-import java.util.Map;
-import java.util.TreeSet;
-
-/**
- * Tracks the success/failure history of a particular network operation in
- * persistent storage and computes retry strategy accordingly. Handles
- * exponential backoff, periodic rescheduling, event-driven triggering,
- * retry-after moratorium intervals, etc. based on caller-specified parameters.
- *
- * <p>This class does not directly perform or invoke any operations,
- * it only keeps track of the schedule. Somebody else needs to call
- * {@link #getNextTimeMillis()} as appropriate and do the actual work.
- */
-public class OperationScheduler {
- /** Tunable parameter options for {@link #getNextTimeMillis}. */
- public static class Options {
- /** Wait this long after every error before retrying. */
- public long backoffFixedMillis = 0;
-
- /** Wait this long times the number of consecutive errors so far before retrying. */
- public long backoffIncrementalMillis = 5000;
-
- /** Maximum duration of moratorium to honor. Mostly an issue for clock rollbacks. */
- public long maxMoratoriumMillis = 24 * 3600 * 1000;
-
- /** Minimum duration after success to wait before allowing another trigger. */
- public long minTriggerMillis = 0;
-
- /** Automatically trigger this long after the last success. */
- public long periodicIntervalMillis = 0;
-
- @Override
- public String toString() {
- return String.format(
- "OperationScheduler.Options[backoff=%.1f+%.1f max=%.1f min=%.1f period=%.1f]",
- backoffFixedMillis / 1000.0, backoffIncrementalMillis / 1000.0,
- maxMoratoriumMillis / 1000.0, minTriggerMillis / 1000.0,
- periodicIntervalMillis / 1000.0);
- }
- }
-
- private static final String PREFIX = "OperationScheduler_";
- private final SharedPreferences mStorage;
-
- /**
- * Initialize the scheduler state.
- * @param storage to use for recording the state of operations across restarts/reboots
- */
- public OperationScheduler(SharedPreferences storage) {
- mStorage = storage;
- }
-
- /**
- * Parse scheduler options supplied in this string form:
- *
- * <pre>
- * backoff=(fixed)+(incremental) max=(maxmoratorium) min=(mintrigger) [period=](interval)
- * </pre>
- *
- * All values are times in (possibly fractional) <em>seconds</em> (not milliseconds).
- * Omitted settings are left at whatever existing default value was passed in.
- *
- * <p>
- * The default options: <code>backoff=0+5 max=86400 min=0 period=0</code><br>
- * Fractions are OK: <code>backoff=+2.5 period=10.0</code><br>
- * The "period=" can be omitted: <code>3600</code><br>
- *
- * @param spec describing some or all scheduler options.
- * @param options to update with parsed values.
- * @return the options passed in (for convenience)
- * @throws IllegalArgumentException if the syntax is invalid
- */
- public static Options parseOptions(String spec, Options options)
- throws IllegalArgumentException {
- for (String param : spec.split(" +")) {
- if (param.length() == 0) continue;
- if (param.startsWith("backoff=")) {
- int plus = param.indexOf('+', 8);
- if (plus < 0) {
- options.backoffFixedMillis = parseSeconds(param.substring(8));
- } else {
- if (plus > 8) {
- options.backoffFixedMillis = parseSeconds(param.substring(8, plus));
- }
- options.backoffIncrementalMillis = parseSeconds(param.substring(plus + 1));
- }
- } else if (param.startsWith("max=")) {
- options.maxMoratoriumMillis = parseSeconds(param.substring(4));
- } else if (param.startsWith("min=")) {
- options.minTriggerMillis = parseSeconds(param.substring(4));
- } else if (param.startsWith("period=")) {
- options.periodicIntervalMillis = parseSeconds(param.substring(7));
- } else {
- options.periodicIntervalMillis = parseSeconds(param);
- }
- }
- return options;
- }
-
- private static long parseSeconds(String param) throws NumberFormatException {
- return (long) (Float.parseFloat(param) * 1000);
- }
-
- /**
- * Compute the time of the next operation. Does not modify any state
- * (unless the clock rolls backwards, in which case timers are reset).
- *
- * @param options to use for this computation.
- * @return the wall clock time ({@link System#currentTimeMillis()}) when the
- * next operation should be attempted -- immediately, if the return value is
- * before the current time.
- */
- public long getNextTimeMillis(Options options) {
- boolean enabledState = mStorage.getBoolean(PREFIX + "enabledState", true);
- if (!enabledState) return Long.MAX_VALUE;
-
- boolean permanentError = mStorage.getBoolean(PREFIX + "permanentError", false);
- if (permanentError) return Long.MAX_VALUE;
-
- // We do quite a bit of limiting to prevent a clock rollback from totally
- // hosing the scheduler. Times which are supposed to be in the past are
- // clipped to the current time so we don't languish forever.
-
- int errorCount = mStorage.getInt(PREFIX + "errorCount", 0);
- long now = currentTimeMillis();
- long lastSuccessTimeMillis = getTimeBefore(PREFIX + "lastSuccessTimeMillis", now);
- long lastErrorTimeMillis = getTimeBefore(PREFIX + "lastErrorTimeMillis", now);
- long triggerTimeMillis = mStorage.getLong(PREFIX + "triggerTimeMillis", Long.MAX_VALUE);
- long moratoriumSetMillis = getTimeBefore(PREFIX + "moratoriumSetTimeMillis", now);
- long moratoriumTimeMillis = getTimeBefore(PREFIX + "moratoriumTimeMillis",
- moratoriumSetMillis + options.maxMoratoriumMillis);
-
- long time = triggerTimeMillis;
- if (options.periodicIntervalMillis > 0) {
- time = Math.min(time, lastSuccessTimeMillis + options.periodicIntervalMillis);
- }
-
- time = Math.max(time, moratoriumTimeMillis);
- time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis);
- if (errorCount > 0) {
- time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
- options.backoffIncrementalMillis * errorCount);
- }
- return time;
- }
-
- /**
- * Return the last time the operation completed. Does not modify any state.
- *
- * @return the wall clock time when {@link #onSuccess()} was last called.
- */
- public long getLastSuccessTimeMillis() {
- return mStorage.getLong(PREFIX + "lastSuccessTimeMillis", 0);
- }
-
- /**
- * Return the last time the operation was attempted. Does not modify any state.
- *
- * @return the wall clock time when {@link #onSuccess()} or {@link
- * #onTransientError()} was last called.
- */
- public long getLastAttemptTimeMillis() {
- return Math.max(
- mStorage.getLong(PREFIX + "lastSuccessTimeMillis", 0),
- mStorage.getLong(PREFIX + "lastErrorTimeMillis", 0));
- }
-
- /**
- * Fetch a {@link SharedPreferences} property, but force it to be before
- * a certain time, updating the value if necessary. This is to recover
- * gracefully from clock rollbacks which could otherwise strand our timers.
- *
- * @param name of SharedPreferences key
- * @param max time to allow in result
- * @return current value attached to key (default 0), limited by max
- */
- private long getTimeBefore(String name, long max) {
- long time = mStorage.getLong(name, 0);
- if (time > max) mStorage.edit().putLong(name, (time = max)).commit();
- return time;
- }
-
- /**
- * Request an operation to be performed at a certain time. The actual
- * scheduled time may be affected by error backoff logic and defined
- * minimum intervals. Use {@link Long#MAX_VALUE} to disable triggering.
- *
- * @param millis wall clock time ({@link System#currentTimeMillis()}) to
- * trigger another operation; 0 to trigger immediately
- */
- public void setTriggerTimeMillis(long millis) {
- mStorage.edit().putLong(PREFIX + "triggerTimeMillis", millis).commit();
- }
-
- /**
- * Forbid any operations until after a certain (absolute) time.
- * Limited by {@link #Options.maxMoratoriumMillis}.
- *
- * @param millis wall clock time ({@link System#currentTimeMillis()})
- * when operations should be allowed again; 0 to remove moratorium
- */
- public void setMoratoriumTimeMillis(long millis) {
- mStorage.edit()
- .putLong(PREFIX + "moratoriumTimeMillis", millis)
- .putLong(PREFIX + "moratoriumSetTimeMillis", currentTimeMillis())
- .commit();
- }
-
- /**
- * Forbid any operations until after a certain time, as specified in
- * the format used by the HTTP "Retry-After" header.
- * Limited by {@link #Options.maxMoratoriumMillis}.
- *
- * @param retryAfter moratorium time in HTTP format
- * @return true if a time was successfully parsed
- */
- public boolean setMoratoriumTimeHttp(String retryAfter) {
- try {
- long ms = Long.valueOf(retryAfter) * 1000;
- setMoratoriumTimeMillis(ms + currentTimeMillis());
- return true;
- } catch (NumberFormatException nfe) {
- try {
- setMoratoriumTimeMillis(AndroidHttpClient.parseDate(retryAfter));
- return true;
- } catch (IllegalArgumentException iae) {
- return false;
- }
- }
- }
-
- /**
- * Enable or disable all operations. When disabled, all calls to
- * {@link #getNextTimeMillis()} return {@link Long#MAX_VALUE}.
- * Commonly used when data network availability goes up and down.
- *
- * @param enabled if operations can be performed
- */
- public void setEnabledState(boolean enabled) {
- mStorage.edit().putBoolean(PREFIX + "enabledState", enabled).commit();
- }
-
- /**
- * Report successful completion of an operation. Resets all error
- * counters, clears any trigger directives, and records the success.
- */
- public void onSuccess() {
- resetTransientError();
- resetPermanentError();
- mStorage.edit()
- .remove(PREFIX + "errorCount")
- .remove(PREFIX + "lastErrorTimeMillis")
- .remove(PREFIX + "permanentError")
- .remove(PREFIX + "triggerTimeMillis")
- .putLong(PREFIX + "lastSuccessTimeMillis", currentTimeMillis()).commit();
- }
-
- /**
- * Report a transient error (usually a network failure). Increments
- * the error count and records the time of the latest error for backoff
- * purposes.
- */
- public void onTransientError() {
- mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", currentTimeMillis()).commit();
- mStorage.edit().putInt(PREFIX + "errorCount",
- mStorage.getInt(PREFIX + "errorCount", 0) + 1).commit();
- }
-
- /**
- * Reset all transient error counts, allowing the next operation to proceed
- * immediately without backoff. Commonly used on network state changes, when
- * partial progress occurs (some data received), and in other circumstances
- * where there is reason to hope things might start working better.
- */
- public void resetTransientError() {
- mStorage.edit().remove(PREFIX + "errorCount").commit();
- }
-
- /**
- * Report a permanent error that will not go away until further notice.
- * No operation will be scheduled until {@link #resetPermanentError()}
- * is called. Commonly used for authentication failures (which are reset
- * when the accounts database is updated).
- */
- public void onPermanentError() {
- mStorage.edit().putBoolean(PREFIX + "permanentError", true).commit();
- }
-
- /**
- * Reset any permanent error status set by {@link #onPermanentError},
- * allowing operations to be scheduled as normal.
- */
- public void resetPermanentError() {
- mStorage.edit().remove(PREFIX + "permanentError").commit();
- }
-
- /**
- * Return a string description of the scheduler state for debugging.
- */
- public String toString() {
- StringBuilder out = new StringBuilder("[OperationScheduler:");
- for (String key : new TreeSet<String>(mStorage.getAll().keySet())) { // Sort keys
- if (key.startsWith(PREFIX)) {
- if (key.endsWith("TimeMillis")) {
- Time time = new Time();
- time.set(mStorage.getLong(key, 0));
- out.append(" ").append(key.substring(PREFIX.length(), key.length() - 10));
- out.append("=").append(time.format("%Y-%m-%d/%H:%M:%S"));
- } else {
- out.append(" ").append(key.substring(PREFIX.length()));
- out.append("=").append(mStorage.getAll().get(key).toString());
- }
- }
- }
- return out.append("]").toString();
- }
-
- /**
- * Gets the current time. Can be overridden for unit testing.
- *
- * @return {@link System#currentTimeMillis()}
- */
- protected long currentTimeMillis() {
- return System.currentTimeMillis();
- }
-}
diff --git a/common/java/com/android/common/Rfc822InputFilter.java b/common/java/com/android/common/Rfc822InputFilter.java
deleted file mode 100644
index 6dfdc7b..0000000
--- a/common/java/com/android/common/Rfc822InputFilter.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2008 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.common;
-
-import android.text.InputFilter;
-import android.text.Spanned;
-import android.text.SpannableStringBuilder;
-
-/**
- * Implements special address cleanup rules:
- * The first space key entry following an "@" symbol that is followed by any combination
- * of letters and symbols, including one+ dots and zero commas, should insert an extra
- * comma (followed by the space).
- *
- * @hide
- */
-public class Rfc822InputFilter implements InputFilter {
-
- public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
- int dstart, int dend) {
-
- // quick check - did they enter a single space?
- if (end-start != 1 || source.charAt(start) != ' ') {
- return null;
- }
-
- // determine if the characters before the new space fit the pattern
- // follow backwards and see if we find a comma, dot, or @
- int scanBack = dstart;
- boolean dotFound = false;
- while (scanBack > 0) {
- char c = dest.charAt(--scanBack);
- switch (c) {
- case '.':
- dotFound = true; // one or more dots are req'd
- break;
- case ',':
- return null;
- case '@':
- if (!dotFound) {
- return null;
- }
- // we have found a comma-insert case. now just do it
- // in the least expensive way we can.
- if (source instanceof Spanned) {
- SpannableStringBuilder sb = new SpannableStringBuilder(",");
- sb.append(source);
- return sb;
- } else {
- return ", ";
- }
- default:
- // just keep going
- }
- }
-
- // no termination cases were found, so don't edit the input
- return null;
- }
-}
diff --git a/common/java/com/android/common/Rfc822Validator.java b/common/java/com/android/common/Rfc822Validator.java
deleted file mode 100644
index 087e425..0000000
--- a/common/java/com/android/common/Rfc822Validator.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2008 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.common;
-
-import android.text.TextUtils;
-import android.text.util.Rfc822Token;
-import android.text.util.Rfc822Tokenizer;
-import android.widget.AutoCompleteTextView;
-
-import java.util.regex.Pattern;
-
-/**
- * This class works as a Validator for AutoCompleteTextView for
- * email addresses. If a token does not appear to be a valid address,
- * it is trimmed of characters that cannot legitimately appear in one
- * and has the specified domain name added. It is meant for use with
- * {@link Rfc822Token} and {@link Rfc822Tokenizer}.
- *
- * @deprecated In the future make sure we don't quietly alter the user's
- * text in ways they did not intend. Meanwhile, hide this
- * class from the public API because it does not even have
- * a full understanding of the syntax it claims to correct.
- * @hide
- */
-public class Rfc822Validator implements AutoCompleteTextView.Validator {
- /*
- * Regex.EMAIL_ADDRESS_PATTERN hardcodes the TLD that we accept, but we
- * want to make sure we will keep accepting email addresses with TLD's
- * that don't exist at the time of this writing, so this regexp relaxes
- * that constraint by accepting any kind of top level domain, not just
- * ".com", ".fr", etc...
- */
- private static final Pattern EMAIL_ADDRESS_PATTERN =
- Pattern.compile("[^\\s@]+@[^\\s@]+\\.[a-zA-z][a-zA-Z][a-zA-Z]*");
-
- private String mDomain;
-
- /**
- * Constructs a new validator that uses the specified domain name as
- * the default when none is specified.
- */
- public Rfc822Validator(String domain) {
- mDomain = domain;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isValid(CharSequence text) {
- Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text);
-
- return tokens.length == 1 &&
- EMAIL_ADDRESS_PATTERN.
- matcher(tokens[0].getAddress()).matches();
- }
-
- /**
- * @return a string in which all the characters that are illegal for the username
- * or the domain name part of the email address have been removed.
- */
- private String removeIllegalCharacters(String s) {
- StringBuilder result = new StringBuilder();
- int length = s.length();
- for (int i = 0; i < length; i++) {
- char c = s.charAt(i);
-
- /*
- * An RFC822 atom can contain any ASCII printing character
- * except for periods and any of the following punctuation.
- * A local-part can contain multiple atoms, concatenated by
- * periods, so do allow periods here.
- */
-
- if (c <= ' ' || c > '~') {
- continue;
- }
-
- if (c == '(' || c == ')' || c == '<' || c == '>' ||
- c == '@' || c == ',' || c == ';' || c == ':' ||
- c == '\\' || c == '"' || c == '[' || c == ']') {
- continue;
- }
-
- result.append(c);
- }
- return result.toString();
- }
-
- /**
- * {@inheritDoc}
- */
- public CharSequence fixText(CharSequence cs) {
- // Return an empty string if the email address only contains spaces, \n or \t
- if (TextUtils.getTrimmedLength(cs) == 0) return "";
-
- Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs);
- StringBuilder sb = new StringBuilder();
-
- for (int i = 0; i < tokens.length; i++) {
- String text = tokens[i].getAddress();
- int index = text.indexOf('@');
- if (index < 0) {
- // If there is no @, just append the domain of the account
- tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain);
- } else {
- // Otherwise, remove the illegal characters on both sides of the '@'
- String fix = removeIllegalCharacters(text.substring(0, index));
- String domain = removeIllegalCharacters(text.substring(index + 1));
- tokens[i].setAddress(fix + "@" + (domain.length() != 0 ? domain : mDomain));
- }
-
- sb.append(tokens[i].toString());
- if (i + 1 < tokens.length) {
- sb.append(", ");
- }
- }
-
- return sb;
- }
-}
diff --git a/common/java/com/android/common/Search.java b/common/java/com/android/common/Search.java
deleted file mode 100644
index 55fa6f5..0000000
--- a/common/java/com/android/common/Search.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2010 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.common;
-
-/**
- * Utilities for search implementations.
- *
- * @see android.app.SearchManager
- */
-public class Search {
-
- /**
- * Key for the source identifier set by the application that launched a search intent.
- * The identifier is search-source specific string. It can be used
- * by the search provider to keep statistics of where searches are started from.
- *
- * The source identifier is stored in the {@link android.app.SearchManager#APP_DATA}
- * Bundle in {@link android.content.Intent#ACTION_SEARCH} and
- * {@link android.content.Intent#ACTION_WEB_SEARCH} intents.
- */
- public final static String SOURCE = "source";
-
- private Search() { } // don't instantiate
-}
diff --git a/common/java/com/android/common/speech/LoggingEvents.java b/common/java/com/android/common/speech/LoggingEvents.java
deleted file mode 100644
index 1f3c6ef..0000000
--- a/common/java/com/android/common/speech/LoggingEvents.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.speech;
-
-/**
- * Logging event constants used for Voice Search and VoiceIME. These are the
- * keys and values of extras to be specified in logging broadcast intents.
- * This class is used by clients of the android.speech APIs to log how the
- * user interacts with the IME settings and speech recognition result.
- */
-public class LoggingEvents {
- // The name of the broadcast intent for logging.
- public static final String ACTION_LOG_EVENT = "com.android.common.speech.LOG_EVENT";
-
- // The extra key used for the name of the app being logged.
- public static final String EXTRA_APP_NAME = "app_name";
-
- // The extra key used for the name of the app issuing the VoiceSearch
- // or VoiceIME request
- public static final String EXTRA_CALLING_APP_NAME = "";
-
- // The extra key used for the event value. The possible event values depend
- // on the app being logged for, and are defined in the subclasses below.
- public static final String EXTRA_EVENT = "extra_event";
-
- // The extra key used to log the time in milliseconds at which the EXTRA_EVENT
- // occurred in the client.
- public static final String EXTRA_TIMESTAMP = "timestamp";
-
- // The extra key used (with a boolean value of 'true') as a way to trigger a
- // flush of the log events to the server.
- public static final String EXTRA_FLUSH = "flush";
-
- /**
- * Logging event constants for voice search. Below are the extra values for
- * {@link LoggingEvents#EXTRA_EVENT}, clustered with keys to additional
- * extras for some events that need to be included as additional fields in
- * the event. Note that this is not representative of *all* voice search
- * events - only the ones that need to be reported from outside the voice
- * search app, such as from Browser.
- */
- public class VoiceSearch {
- // The app name to be used for logging VoiceSearch events.
- public static final String APP_NAME = "googlemobile";
-
- public static final int RETRY = 0;
-
- public static final int N_BEST_REVEAL = 1;
-
- public static final int N_BEST_CHOOSE = 2;
- public static final String EXTRA_N_BEST_CHOOSE_INDEX = "index"; // value should be int
-
- public static final int QUERY_UPDATED = 3;
- public static final String EXTRA_QUERY_UPDATED_VALUE = "value"; // value should be String
- }
-
- /**
- * Logging event constants for VoiceIME. Below are the extra values for
- * {@link LoggingEvents#EXTRA_EVENT}, clustered with keys to additional
- * extras for some events that need to be included as additional fields in
- * the event.
- */
- public class VoiceIme {
- // The app name to be used for logging VoiceIME events.
- public static final String APP_NAME = "voiceime";
-
- public static final int KEYBOARD_WARNING_DIALOG_SHOWN = 0;
-
- public static final int KEYBOARD_WARNING_DIALOG_DISMISSED = 1;
-
- public static final int KEYBOARD_WARNING_DIALOG_OK = 2;
-
- public static final int KEYBOARD_WARNING_DIALOG_CANCEL = 3;
-
- public static final int SETTINGS_WARNING_DIALOG_SHOWN = 4;
-
- public static final int SETTINGS_WARNING_DIALOG_DISMISSED = 5;
-
- public static final int SETTINGS_WARNING_DIALOG_OK = 6;
-
- public static final int SETTINGS_WARNING_DIALOG_CANCEL = 7;
-
- public static final int SWIPE_HINT_DISPLAYED = 8;
-
- public static final int PUNCTUATION_HINT_DISPLAYED = 9;
-
- public static final int CANCEL_DURING_LISTENING = 10;
-
- public static final int CANCEL_DURING_WORKING = 11;
-
- public static final int CANCEL_DURING_ERROR = 12;
-
- public static final int ERROR = 13;
- public static final String EXTRA_ERROR_CODE = "code"; // value should be int
-
- public static final int START = 14;
- public static final String EXTRA_START_LOCALE = "locale"; // value should be String
- public static final String EXTRA_START_SWIPE = "swipe"; // value should be boolean
-
- public static final int VOICE_INPUT_DELIVERED = 15;
-
- public static final int N_BEST_CHOOSE = 16;
- public static final String EXTRA_N_BEST_CHOOSE_INDEX = "index"; // value should be int
-
- public static final int TEXT_MODIFIED = 17;
- public static final String EXTRA_TEXT_MODIFIED_LENGTH = "length"; // value should be int
- public static final String EXTRA_TEXT_MODIFIED_TYPE = "type"; // value should be int below
- public static final int TEXT_MODIFIED_TYPE_CHOOSE_SUGGESTION = 1;
- public static final int TEXT_MODIFIED_TYPE_TYPING_DELETION = 2;
- public static final int TEXT_MODIFIED_TYPE_TYPING_INSERTION = 3;
- public static final int TEXT_MODIFIED_TYPE_TYPING_INSERTION_PUNCTUATION = 4;
-
- public static final int INPUT_ENDED = 18;
-
- public static final int VOICE_INPUT_SETTING_ENABLED = 19;
-
- public static final int VOICE_INPUT_SETTING_DISABLED = 20;
-
- public static final int IME_TEXT_ACCEPTED = 21;
- }
-
-}
diff --git a/common/java/com/android/common/speech/Recognition.java b/common/java/com/android/common/speech/Recognition.java
deleted file mode 100644
index 1970179..0000000
--- a/common/java/com/android/common/speech/Recognition.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.speech;
-
-/**
- * Utilities for voice recognition implementations.
- *
- * @see android.speech.RecognitionService
- * @see android.speech.RecognizerIntent
- */
-public class Recognition {
-
- /**
- * The key to the extra in the Bundle returned by
- * android.speech.RecognizerIntent#ACTION_GET_LANGUAGE_DETAILS
- * which is an ArrayList of CharSequences which are hints that can be shown to
- * the user for voice actions currently supported by voice search for the user's current
- * language preference for voice search (i.e., the one defined in the extra
- * android.speech.RecognizerIntent#EXTRA_LANGUAGE_PREFERENCE).
- *
- * If this is paired with EXTRA_HINT_CONTEXT, should return a set of hints that are
- * appropriate for the provided context.
- *
- * The CharSequences are SpannedStrings and will contain segments wrapped in
- * <annotation action="true"></annotation>. This is to indicate the section of the text
- * which represents the voice action, to be highlighted in the UI if so desired.
- */
- public static final String EXTRA_HINT_STRINGS = "android.speech.extra.HINT_STRINGS";
-
- /**
- * The key to an extra to be included in the request intent for
- * android.speech.RecognizerIntent#ACTION_GET_LANGUAGE_DETAILS.
- * Should be an int of one of the values defined below. If an
- * unknown int value is provided, it should be ignored.
- */
- public static final String EXTRA_HINT_CONTEXT = "android.speech.extra.HINT_CONTEXT";
-
- /**
- * A set of values for EXTRA_HINT_CONTEXT.
- */
- public static final int HINT_CONTEXT_UNKNOWN = 0;
- public static final int HINT_CONTEXT_VOICE_SEARCH_HELP = 1;
- public static final int HINT_CONTEXT_CAR_HOME = 2;
- public static final int HINT_CONTEXT_LAUNCHER = 3;
-
- private Recognition() { } // don't instantiate
-}
diff --git a/common/java/com/android/common/userhappiness/UserHappinessSignals.java b/common/java/com/android/common/userhappiness/UserHappinessSignals.java
deleted file mode 100644
index 347bdaa..0000000
--- a/common/java/com/android/common/userhappiness/UserHappinessSignals.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.userhappiness;
-
-import android.content.Intent;
-import android.content.Context;
-import com.android.common.speech.LoggingEvents;
-
-/**
- * Metrics for User Happiness are recorded here. Each app can define when to
- * call these User Happiness metrics.
- */
-public class UserHappinessSignals {
-
- /**
- * Log when a user "accepted" IME text. Each application can define what
- * it means to "accept" text. In the case of Gmail, pressing the "Send"
- * button indicates text acceptance. We broadcast this information to
- * VoiceSearch LoggingEvents and use it to aggregate VoiceIME Happiness Metrics
- */
- public static void userAcceptedImeText(Context context) {
- // Create a Voice IME Logging intent.
- Intent i = new Intent(LoggingEvents.ACTION_LOG_EVENT);
- i.putExtra(LoggingEvents.EXTRA_APP_NAME, LoggingEvents.VoiceIme.APP_NAME);
- i.putExtra(LoggingEvents.EXTRA_EVENT, LoggingEvents.VoiceIme.IME_TEXT_ACCEPTED);
- i.putExtra(LoggingEvents.EXTRA_CALLING_APP_NAME, context.getPackageName());
- i.putExtra(LoggingEvents.EXTRA_TIMESTAMP, System.currentTimeMillis());
- context.sendBroadcast(i);
- }
-
-}
diff --git a/common/tests/Android.mk b/common/tests/Android.mk
deleted file mode 100644
index 7425552..0000000
--- a/common/tests/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := AndroidCommonTests
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := android-common
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/common/tests/AndroidManifest.xml b/common/tests/AndroidManifest.xml
deleted file mode 100644
index 151ec20..0000000
--- a/common/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.common.tests"
- android:sharedUserId="com.android.uid.test">
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <!-- Run tests with "runtest common" -->
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.common.tests"
- android:label="Android Common Library Tests" />
-
-</manifest>
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
deleted file mode 100644
index 955508f..0000000
--- a/common/tests/src/com/android/common/OperationSchedulerTest.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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.common;
-
-import android.content.SharedPreferences;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
-public class OperationSchedulerTest extends AndroidTestCase {
- /**
- * OperationScheduler subclass which uses an artificial time.
- * Set {@link #timeMillis} to whatever value you like.
- */
- private class TimeTravelScheduler extends OperationScheduler {
- static final long DEFAULT_TIME = 1250146800000L; // 13-Aug-2009, 12:00:00 am
- public long timeMillis = DEFAULT_TIME;
-
- @Override
- protected long currentTimeMillis() { return timeMillis; }
- public TimeTravelScheduler() { super(getFreshStorage()); }
- }
-
- private SharedPreferences getFreshStorage() {
- SharedPreferences sp = getContext().getSharedPreferences("OperationSchedulerTest", 0);
- sp.edit().clear().commit();
- return sp;
- }
-
- @MediumTest
- public void testScheduler() throws Exception {
- TimeTravelScheduler scheduler = new TimeTravelScheduler();
- OperationScheduler.Options options = new OperationScheduler.Options();
- assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
- assertEquals(0, scheduler.getLastSuccessTimeMillis());
- assertEquals(0, scheduler.getLastAttemptTimeMillis());
-
- long beforeTrigger = scheduler.timeMillis;
- scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
- assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
-
- // It will schedule for the later of the trigger and the moratorium...
- scheduler.setMoratoriumTimeMillis(beforeTrigger + 500000);
- assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
- scheduler.setMoratoriumTimeMillis(beforeTrigger + 1500000);
- assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
-
- // Test enable/disable toggle
- scheduler.setEnabledState(false);
- assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
- scheduler.setEnabledState(true);
- assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
-
- // Backoff interval after an error
- long beforeError = (scheduler.timeMillis += 100);
- scheduler.onTransientError();
- assertEquals(0, scheduler.getLastSuccessTimeMillis());
- assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
- assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
- options.backoffFixedMillis = 1000000;
- options.backoffIncrementalMillis = 500000;
- assertEquals(beforeError + 1500000, scheduler.getNextTimeMillis(options));
-
- // Two errors: backoff interval increases
- beforeError = (scheduler.timeMillis += 100);
- scheduler.onTransientError();
- assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
- assertEquals(beforeError + 2000000, scheduler.getNextTimeMillis(options));
-
- // Reset transient error: no backoff interval
- scheduler.resetTransientError();
- assertEquals(0, scheduler.getLastSuccessTimeMillis());
- assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
- assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
-
- // Permanent error holds true even if transient errors are reset
- // However, we remember that the transient error was reset...
- scheduler.onPermanentError();
- assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
- scheduler.resetTransientError();
- assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
- scheduler.resetPermanentError();
- assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
-
- // Success resets the trigger
- long beforeSuccess = (scheduler.timeMillis += 100);
- scheduler.onSuccess();
- assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis());
- assertEquals(beforeSuccess, scheduler.getLastSuccessTimeMillis());
- assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
-
- // The moratorium is not reset by success!
- scheduler.setTriggerTimeMillis(0);
- assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
- scheduler.setMoratoriumTimeMillis(0);
- assertEquals(beforeSuccess, scheduler.getNextTimeMillis(options));
-
- // Periodic interval after success
- options.periodicIntervalMillis = 250000;
- scheduler.setTriggerTimeMillis(Long.MAX_VALUE);
- assertEquals(beforeSuccess + 250000, scheduler.getNextTimeMillis(options));
-
- // Trigger minimum is also since the last success
- options.minTriggerMillis = 1000000;
- assertEquals(beforeSuccess + 1000000, scheduler.getNextTimeMillis(options));
- }
-
- @SmallTest
- public void testParseOptions() throws Exception {
- OperationScheduler.Options options = new OperationScheduler.Options();
- assertEquals(
- "OperationScheduler.Options[backoff=0.0+5.0 max=86400.0 min=0.0 period=3600.0]",
- OperationScheduler.parseOptions("3600", options).toString());
-
- assertEquals(
- "OperationScheduler.Options[backoff=0.0+2.5 max=86400.0 min=0.0 period=3700.0]",
- OperationScheduler.parseOptions("backoff=+2.5 3700", options).toString());
-
- assertEquals(
- "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
- OperationScheduler.parseOptions("max=12345.6 min=7 backoff=10 period=3800",
- options).toString());
-
- assertEquals(
- "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
- OperationScheduler.parseOptions("", options).toString());
- }
-
- @SmallTest
- public void testMoratoriumWithHttpDate() throws Exception {
- TimeTravelScheduler scheduler = new TimeTravelScheduler();
- OperationScheduler.Options options = new OperationScheduler.Options();
-
- long beforeTrigger = scheduler.timeMillis;
- scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
- assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
-
- scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000);
- assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options));
-
- long beforeMoratorium = scheduler.timeMillis;
- assertTrue(scheduler.setMoratoriumTimeHttp("3000"));
- long afterMoratorium = scheduler.timeMillis;
- assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options));
- assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options));
-
- options.maxMoratoriumMillis = Long.MAX_VALUE / 2;
- assertTrue(scheduler.setMoratoriumTimeHttp("Fri, 31 Dec 2030 23:59:59 GMT"));
- assertEquals(1924991999000L, scheduler.getNextTimeMillis(options));
-
- assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date"));
- }
-
- @SmallTest
- public void testClockRollbackScenario() throws Exception {
- TimeTravelScheduler scheduler = new TimeTravelScheduler();
- OperationScheduler.Options options = new OperationScheduler.Options();
- options.minTriggerMillis = 2000;
-
- // First, set up a scheduler with reasons to wait: a transient
- // error with backoff and a moratorium for a few minutes.
-
- long beforeTrigger = scheduler.timeMillis;
- long triggerTime = beforeTrigger - 10000000;
- scheduler.setTriggerTimeMillis(triggerTime);
- assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
- assertEquals(0, scheduler.getLastAttemptTimeMillis());
-
- long beforeSuccess = (scheduler.timeMillis += 100);
- scheduler.onSuccess();
- scheduler.setTriggerTimeMillis(triggerTime);
- assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis());
- assertEquals(beforeSuccess + 2000, scheduler.getNextTimeMillis(options));
-
- long beforeError = (scheduler.timeMillis += 100);
- scheduler.onTransientError();
- assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
- assertEquals(beforeError + 5000, scheduler.getNextTimeMillis(options));
-
- long beforeMoratorium = (scheduler.timeMillis += 100);
- scheduler.setMoratoriumTimeMillis(beforeTrigger + 1000000);
- assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
-
- // Now set the time back a few seconds.
- // The moratorium time should still be honored.
- long beforeRollback = (scheduler.timeMillis = beforeTrigger - 10000);
- assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
-
- // The rollback also moved the last-attempt clock back to the rollback time.
- assertEquals(scheduler.timeMillis, scheduler.getLastAttemptTimeMillis());
-
- // But if we set the time back more than a day, the moratorium
- // resets to the maximum moratorium (a day, by default), exposing
- // the original trigger time.
- beforeRollback = (scheduler.timeMillis = beforeTrigger - 100000000);
- assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
- assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
-
- // If we roll forward until after the re-set moratorium, then it expires.
- scheduler.timeMillis = triggerTime + 5000000;
- assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
- assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
- assertEquals(beforeRollback, scheduler.getLastSuccessTimeMillis());
- }
-}
diff --git a/common/tools/make-iana-tld-pattern.py b/common/tools/make-iana-tld-pattern.py
deleted file mode 100755
index de81c58..0000000
--- a/common/tools/make-iana-tld-pattern.py
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/usr/bin/env python
-
-from urllib2 import urlopen
-
-TLD_PREFIX = r"""
- /**
- * Regular expression to match all IANA top-level domains.
- * List accurate as of 2010/02/05. List taken from:
- * http://data.iana.org/TLD/tlds-alpha-by-domain.txt
- * This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
- */
- public static final String TOP_LEVEL_DOMAIN_STR =
-"""
-TLD_SUFFIX = '";'
-
-URL_PREFIX = r"""
- /**
- * Regular expression to match all IANA top-level domains for WEB_URL.
- * List accurate as of 2010/02/05. List taken from:
- * http://data.iana.org/TLD/tlds-alpha-by-domain.txt
- * This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
- */
- public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL =
- "(?:"
-"""
-
-URL_SUFFIX = ';'
-
-class Bucket:
- def __init__(self, baseLetter):
- self.base=baseLetter
- self.words=[]
- self.letters=[]
-
- def dump(self, isWebUrl=False, isFirst=False, isLast=False):
- if (len(self.words) == 0) and (len(self.letters) == 0):
- return ''
-
- self.words.sort()
- self.letters.sort()
-
- output = ' ';
-
- if isFirst:
- if isWebUrl:
- output += '+ "'
- else:
- output += '"('
- else:
- output += '+ "|'
-
- if len(self.words) != 0:
- output += '('
-
- if isWebUrl:
- output += '?:'
-
- firstWord = 1
- for word in self.words:
- if firstWord == 0:
- output += '|'
- firstWord = 0
- for letter in word:
- if letter == '-':
- output += '\\\\' # escape the '-' character.
- output += letter
-
- if len(self.words) > 0 and len(self.letters) > 0:
- output += '|'
-
- if len(self.letters) == 1:
- output += '%c%c' % (self.base, self.letters[0])
- elif len(self.letters) > 0:
- output += '%c[' % self.base
-
- for letter in self.letters:
- output += letter
-
- output += ']'
-
- if len(self.words) != 0:
- output += ')'
-
- if not isLast:
- output += '"'
- output += '\n'
-
- return output;
-
- def add(self, line):
- length = len(line)
-
- if line.startswith('#') or (length == 0):
- return;
-
- if length == 2:
- self.letters.append(line[1:2])
- else:
- self.words.append(line)
-
-def getBucket(buckets, line):
- letter = line[0]
- bucket = buckets.get(letter)
-
- if bucket is None:
- bucket = Bucket(letter)
- buckets[letter] = bucket
-
- return bucket
-
-def makePattern(prefix, suffix, buckets, isWebUrl=False):
- output = prefix
-
- output += getBucket(buckets, 'a').dump(isFirst=True, isWebUrl=isWebUrl)
-
- for letter in range(ord('b'), ord('z')):
- output += getBucket(buckets, chr(letter)).dump(isWebUrl=isWebUrl)
-
- output += getBucket(buckets, 'z').dump(isLast=True, isWebUrl=isWebUrl)
-
- if isWebUrl:
- output += '))"'
- else:
- output += ')'
-
- output += suffix
-
- print output
-
-if __name__ == "__main__":
- f = urlopen('http://data.iana.org/TLD/tlds-alpha-by-domain.txt')
- domains = f.readlines()
- f.close()
-
- buckets = {}
-
- for domain in domains:
- domain = domain.lower()
-
- if len(domain) > 0:
- getBucket(buckets, domain[0]).add(domain.strip())
-
- makePattern(TLD_PREFIX, TLD_SUFFIX, buckets, isWebUrl=False)
- makePattern(URL_PREFIX, URL_SUFFIX, buckets, isWebUrl=True)
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 6a5c8a8..d45bfcf 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -73,7 +73,7 @@
POLICY_FLAG_MENU = 0x00000040,
POLICY_FLAG_LAUNCHER = 0x00000080,
- /* These flags are set by the input dispatch policy as it intercepts each event. */
+ /* These flags are set by the input reader policy as it intercepts each event. */
// Indicates that the screen was off when the event was received and the event
// should wake the device.
@@ -85,6 +85,37 @@
};
/*
+ * Describes the basic configuration of input devices that are present.
+ */
+struct InputConfiguration {
+ enum {
+ TOUCHSCREEN_UNDEFINED = 0,
+ TOUCHSCREEN_NOTOUCH = 1,
+ TOUCHSCREEN_STYLUS = 2,
+ TOUCHSCREEN_FINGER = 3
+ };
+
+ enum {
+ KEYBOARD_UNDEFINED = 0,
+ KEYBOARD_NOKEYS = 1,
+ KEYBOARD_QWERTY = 2,
+ KEYBOARD_12KEY = 3
+ };
+
+ enum {
+ NAVIGATION_UNDEFINED = 0,
+ NAVIGATION_NONAV = 1,
+ NAVIGATION_DPAD = 2,
+ NAVIGATION_TRACKBALL = 3,
+ NAVIGATION_WHEEL = 4
+ };
+
+ int32_t touchScreen;
+ int32_t keyboard;
+ int32_t navigation;
+};
+
+/*
* Pointer coordinate data.
*/
struct PointerCoords {
diff --git a/include/ui/InputDispatchPolicy.h b/include/ui/InputDispatchPolicy.h
deleted file mode 100644
index 3546813..0000000
--- a/include/ui/InputDispatchPolicy.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef _UI_INPUT_DISPATCH_POLICY_H
-#define _UI_INPUT_DISPATCH_POLICY_H
-
-/**
- * Native input dispatch policy.
- */
-
-#include <ui/Input.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-
-namespace android {
-
-class InputChannel;
-
-/*
- * An input target specifies how an input event is to be dispatched to a particular window
- * including the window's input channel, control flags, a timeout, and an X / Y offset to
- * be added to input event coordinates to compensate for the absolute position of the
- * window area.
- */
-struct InputTarget {
- enum {
- /* This flag indicates that subsequent event delivery should be held until the
- * current event is delivered to this target or a timeout occurs. */
- FLAG_SYNC = 0x01,
-
- /* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
- * this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */
- FLAG_OUTSIDE = 0x02,
-
- /* This flag indicates that a KeyEvent or MotionEvent is being canceled.
- * In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
- * In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */
- FLAG_CANCEL = 0x04
- };
-
- // The input channel to be targeted.
- sp<InputChannel> inputChannel;
-
- // Flags for the input target.
- int32_t flags;
-
- // The timeout for event delivery to this target in nanoseconds. Or -1 if none.
- nsecs_t timeout;
-
- // The x and y offset to add to a MotionEvent as it is delivered.
- // (ignored for KeyEvents)
- float xOffset, yOffset;
-};
-
-/*
- * Input dispatch policy interface.
- *
- * The input dispatch policy is used by the input dispatcher to interact with the
- * Window Manager and other system components. This separation of concerns keeps
- * the input dispatcher relatively free of special case logic such as is required
- * to determine the target of iput events, when to wake the device, how to interact
- * with key guard, and when to transition to the home screen.
- *
- * The actual implementation is partially supported by callbacks into the DVM
- * via JNI. This class is also mocked in the input dispatcher unit tests since
- * it is an ideal test seam.
- */
-class InputDispatchPolicyInterface : public virtual RefBase {
-protected:
- InputDispatchPolicyInterface() { }
- virtual ~InputDispatchPolicyInterface() { }
-
-public:
- enum {
- ROTATION_0 = 0,
- ROTATION_90 = 1,
- ROTATION_180 = 2,
- ROTATION_270 = 3
- };
-
- enum {
- // The input dispatcher should do nothing and discard the input unless other
- // flags are set.
- ACTION_NONE = 0,
-
- // The input dispatcher should dispatch the input to the application.
- ACTION_DISPATCH = 0x00000001,
-
- // The input dispatcher should perform special filtering in preparation for
- // a pending app switch.
- ACTION_APP_SWITCH_COMING = 0x00000002,
-
- // The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
- // passes through the dispatch pipeline.
- ACTION_WOKE_HERE = 0x00000004,
-
- // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
- // passes through the dispatch pipeline.
- ACTION_BRIGHT_HERE = 0x00000008
- };
-
- enum {
- TOUCHSCREEN_UNDEFINED = 0,
- TOUCHSCREEN_NOTOUCH = 1,
- TOUCHSCREEN_STYLUS = 2,
- TOUCHSCREEN_FINGER = 3
- };
-
- enum {
- KEYBOARD_UNDEFINED = 0,
- KEYBOARD_NOKEYS = 1,
- KEYBOARD_QWERTY = 2,
- KEYBOARD_12KEY = 3
- };
-
- enum {
- NAVIGATION_UNDEFINED = 0,
- NAVIGATION_NONAV = 1,
- NAVIGATION_DPAD = 2,
- NAVIGATION_TRACKBALL = 3,
- NAVIGATION_WHEEL = 4
- };
-
- struct VirtualKeyDefinition {
- int32_t scanCode;
-
- // configured position data, specified in display coords
- int32_t centerX;
- int32_t centerY;
- int32_t width;
- int32_t height;
- };
-
- /* Gets information about the display with the specified id.
- * Returns true if the display info is available, false otherwise.
- */
- virtual bool getDisplayInfo(int32_t displayId,
- int32_t* width, int32_t* height, int32_t* orientation) = 0;
-
- virtual void notifyConfigurationChanged(nsecs_t when,
- int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) = 0;
-
- virtual void notifyLidSwitchChanged(nsecs_t when, bool lidOpen) = 0;
-
- virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t flags, int32_t keyCode,
- int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
-
- virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
-
- virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
- bool rolled) = 0;
-
- virtual int32_t interceptTouch(nsecs_t when) = 0;
-
- virtual bool allowKeyRepeat() = 0;
- virtual nsecs_t getKeyRepeatTimeout() = 0;
-
- virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
- Vector<InputTarget>& outTargets) = 0;
- virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
- Vector<InputTarget>& outTargets) = 0;
-
- /* Determine whether to turn on some hacks we have to improve the touch interaction with a
- * certain device whose screen currently is not all that good.
- */
- virtual bool filterTouchEvents() = 0;
-
- /* Determine whether to turn on some hacks to improve touch interaction with another device
- * where touch coordinate data can get corrupted.
- */
- virtual bool filterJumpyTouchEvents() = 0;
-
- virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
- virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_DISPATCH_POLICY_H
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index bde07f2..80a20c9 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -18,7 +18,6 @@
#define _UI_INPUT_DISPATCHER_H
#include <ui/Input.h>
-#include <ui/InputDispatchPolicy.h>
#include <ui/InputTransport.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
@@ -35,6 +34,82 @@
namespace android {
+/*
+ * An input target specifies how an input event is to be dispatched to a particular window
+ * including the window's input channel, control flags, a timeout, and an X / Y offset to
+ * be added to input event coordinates to compensate for the absolute position of the
+ * window area.
+ */
+struct InputTarget {
+ enum {
+ /* This flag indicates that subsequent event delivery should be held until the
+ * current event is delivered to this target or a timeout occurs. */
+ FLAG_SYNC = 0x01,
+
+ /* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
+ * this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */
+ FLAG_OUTSIDE = 0x02,
+
+ /* This flag indicates that a KeyEvent or MotionEvent is being canceled.
+ * In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
+ * In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */
+ FLAG_CANCEL = 0x04
+ };
+
+ // The input channel to be targeted.
+ sp<InputChannel> inputChannel;
+
+ // Flags for the input target.
+ int32_t flags;
+
+ // The timeout for event delivery to this target in nanoseconds. Or -1 if none.
+ nsecs_t timeout;
+
+ // The x and y offset to add to a MotionEvent as it is delivered.
+ // (ignored for KeyEvents)
+ float xOffset, yOffset;
+};
+
+/*
+ * Input dispatcher policy interface.
+ *
+ * The input reader policy is used by the input reader to interact with the Window Manager
+ * and other system components.
+ *
+ * The actual implementation is partially supported by callbacks into the DVM
+ * via JNI. This interface is also mocked in the unit tests.
+ */
+class InputDispatcherPolicyInterface : public virtual RefBase {
+protected:
+ InputDispatcherPolicyInterface() { }
+ virtual ~InputDispatcherPolicyInterface() { }
+
+public:
+ /* Notifies the system that a configuration change has occurred. */
+ virtual void notifyConfigurationChanged(nsecs_t when) = 0;
+
+ /* Notifies the system that an input channel is unrecoverably broken. */
+ virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Notifies the system that an input channel is not responding. */
+ virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Notifies the system that an input channel recovered from ANR. */
+ virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */
+ virtual nsecs_t getKeyRepeatTimeout() = 0;
+
+ /* Gets the input targets for a key event. */
+ virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
+ Vector<InputTarget>& outTargets) = 0;
+
+ /* Gets the input targets for a motion event. */
+ virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+ Vector<InputTarget>& outTargets) = 0;
+};
+
+
/* Notifies the system about input events generated by the input reader.
* The dispatcher is expected to be mostly asynchronous. */
class InputDispatcherInterface : public virtual RefBase {
@@ -51,14 +126,10 @@
virtual void dispatchOnce() = 0;
/* Notifies the dispatcher about new events.
- * The dispatcher will process most of these events asynchronously although some
- * policy processing may occur synchronously.
*
* These methods should only be called on the input reader thread.
*/
- virtual void notifyConfigurationChanged(nsecs_t eventTime,
- int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) = 0;
- virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) = 0;
+ virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0;
virtual void notifyAppSwitchComing(nsecs_t eventTime) = 0;
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
@@ -76,19 +147,33 @@
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
};
-/* Dispatches events. */
+/* Dispatches events to input targets. Some functions of the input dispatcher, such as
+ * identifying input targets, are controlled by a separate policy object.
+ *
+ * IMPORTANT INVARIANT:
+ * Because the policy can potentially block or cause re-entrance into the input dispatcher,
+ * the input dispatcher never calls into the policy while holding its internal locks.
+ * The implementation is also carefully designed to recover from scenarios such as an
+ * input channel becoming unregistered while identifying input targets or processing timeouts.
+ *
+ * Methods marked 'Locked' must be called with the lock acquired.
+ *
+ * Methods marked 'LockedInterruptible' must be called with the lock acquired but
+ * may during the course of their execution release the lock, call into the policy, and
+ * then reacquire the lock. The caller is responsible for recovering gracefully.
+ *
+ * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa.
+ */
class InputDispatcher : public InputDispatcherInterface {
protected:
virtual ~InputDispatcher();
public:
- explicit InputDispatcher(const sp<InputDispatchPolicyInterface>& policy);
+ explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
virtual void dispatchOnce();
- virtual void notifyConfigurationChanged(nsecs_t eventTime,
- int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig);
- virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen);
+ virtual void notifyConfigurationChanged(nsecs_t eventTime);
virtual void notifyAppSwitchComing(nsecs_t eventTime);
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
@@ -119,12 +204,11 @@
int32_t refCount;
int32_t type;
nsecs_t eventTime;
+
+ bool dispatchInProgress; // initially false, set to true while dispatching
};
struct ConfigurationChangedEntry : EventEntry {
- int32_t touchScreenConfig;
- int32_t keyboardConfig;
- int32_t navigationConfig;
};
struct KeyEntry : EventEntry {
@@ -165,6 +249,7 @@
MotionSample* lastSample;
};
+ // Tracks the progress of dispatching a particular event to a particular connection.
struct DispatchEntry : Link<DispatchEntry> {
EventEntry* eventEntry; // the event to dispatch
int32_t targetFlags;
@@ -189,6 +274,36 @@
MotionSample* tailMotionSample;
};
+ // A command entry captures state and behavior for an action to be performed in the
+ // dispatch loop after the initial processing has taken place. It is essentially
+ // a kind of continuation used to postpone sensitive policy interactions to a point
+ // in the dispatch loop where it is safe to release the lock (generally after finishing
+ // the critical parts of the dispatch cycle).
+ //
+ // The special thing about commands is that they can voluntarily release and reacquire
+ // the dispatcher lock at will. Initially when the command starts running, the
+ // dispatcher lock is held. However, if the command needs to call into the policy to
+ // do some work, it can release the lock, do the work, then reacquire the lock again
+ // before returning.
+ //
+ // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
+ // never calls into the policy while holding its lock.
+ //
+ // Commands are implicitly 'LockedInterruptible'.
+ struct CommandEntry;
+ typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
+
+ struct CommandEntry : Link<CommandEntry> {
+ CommandEntry();
+ ~CommandEntry();
+
+ Command command;
+
+ // parameters for the command (usage varies by command)
+ sp<InputChannel> inputChannel;
+ };
+
+ // Generic queue implementation.
template <typename T>
struct Queue {
T head;
@@ -242,17 +357,17 @@
KeyEntry* obtainKeyEntry();
MotionEntry* obtainMotionEntry();
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry);
+ CommandEntry* obtainCommandEntry(Command command);
void releaseEventEntry(EventEntry* entry);
void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
void releaseKeyEntry(KeyEntry* entry);
void releaseMotionEntry(MotionEntry* entry);
void releaseDispatchEntry(DispatchEntry* entry);
+ void releaseCommandEntry(CommandEntry* entry);
void appendMotionSample(MotionEntry* motionEntry,
nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords);
- void freeMotionSample(MotionSample* sample);
- void freeMotionSampleList(MotionSample* head);
private:
Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool;
@@ -260,6 +375,7 @@
Pool<MotionEntry> mMotionEntryPool;
Pool<MotionSample> mMotionSamplePool;
Pool<DispatchEntry> mDispatchEntryPool;
+ Pool<CommandEntry> mCommandEntryPool;
};
/* Manages the dispatch state associated with a single input channel. */
@@ -291,7 +407,9 @@
explicit Connection(const sp<InputChannel>& inputChannel);
- inline const char* getInputChannelName() { return inputChannel->getName().string(); }
+ inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
+
+ const char* getStatusLabel() const;
// Finds a DispatchEntry in the outbound queue associated with the specified event.
// Returns NULL if not found.
@@ -323,22 +441,23 @@
status_t initialize();
};
- sp<InputDispatchPolicyInterface> mPolicy;
+ sp<InputDispatcherPolicyInterface> mPolicy;
Mutex mLock;
- Queue<EventEntry> mInboundQueue;
Allocator mAllocator;
-
sp<PollLoop> mPollLoop;
+ Queue<EventEntry> mInboundQueue;
+ Queue<CommandEntry> mCommandQueue;
+
// All registered connections mapped by receive pipe file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
// Active connections are connections that have a non-empty outbound queue.
Vector<Connection*> mActiveConnections;
- // Pool of key and motion event objects used only to ask the input dispatch policy
+ // Preallocated key and motion event objects used only to ask the input dispatcher policy
// for the targets of an event that is to be dispatched.
KeyEvent mReusableKeyEvent;
MotionEvent mReusableMotionEvent;
@@ -347,6 +466,7 @@
// If there is a synchronous event dispatch in progress, the current input targets will
// remain unchanged until the dispatch has completed or been aborted.
Vector<InputTarget> mCurrentInputTargets;
+ bool mCurrentInputTargetsValid; // false while targets are being recomputed
// Key repeat tracking.
// XXX Move this up to the input reader instead.
@@ -357,17 +477,27 @@
void resetKeyRepeatLocked();
+ // Deferred command processing.
+ bool runCommandsLockedInterruptible();
+ CommandEntry* postCommandLocked(Command command);
+
// Process events that have just been dequeued from the head of the input queue.
- void processConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry);
- void processKeyLocked(nsecs_t currentTime, KeyEntry* entry);
- void processKeyRepeatLocked(nsecs_t currentTime);
- void processMotionLocked(nsecs_t currentTime, MotionEntry* entry);
+ void processConfigurationChangedLockedInterruptible(
+ nsecs_t currentTime, ConfigurationChangedEntry* entry);
+ void processKeyLockedInterruptible(
+ nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout);
+ void processKeyRepeatLockedInterruptible(
+ nsecs_t currentTime, nsecs_t keyRepeatTimeout);
+ void processMotionLockedInterruptible(
+ nsecs_t currentTime, MotionEntry* entry);
// Identify input targets for an event and dispatch to them.
- void identifyInputTargetsAndDispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry);
- void identifyInputTargetsAndDispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry);
- void dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime, EventEntry* entry,
- bool resumeWithAppendedMotionSample);
+ void identifyInputTargetsAndDispatchKeyLockedInterruptible(
+ nsecs_t currentTime, KeyEntry* entry);
+ void identifyInputTargetsAndDispatchMotionLockedInterruptible(
+ nsecs_t currentTime, MotionEntry* entry);
+ void dispatchEventToCurrentInputTargetsLocked(
+ nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
// Manage the dispatch cycle for a single connection.
void prepareDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
@@ -384,12 +514,22 @@
void activateConnectionLocked(Connection* connection);
void deactivateConnectionLocked(Connection* connection);
+ // Outbound policy interactions.
+ void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry);
+
// Interesting events that we might like to log or tell the framework about.
- void onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection);
- void onDispatchCycleFinishedLocked(nsecs_t currentTime, Connection* connection,
- bool recoveredFromANR);
- void onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection);
- void onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection);
+ void onDispatchCycleStartedLocked(
+ nsecs_t currentTime, Connection* connection);
+ void onDispatchCycleFinishedLocked(
+ nsecs_t currentTime, Connection* connection, bool recoveredFromANR);
+ void onDispatchCycleANRLocked(
+ nsecs_t currentTime, Connection* connection);
+ void onDispatchCycleBrokenLocked(
+ nsecs_t currentTime, Connection* connection);
+
+ void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
+ void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
+ void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
};
/* Enqueues and dispatches input events, endlessly. */
diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h
index eb27513..3872c26 100644
--- a/include/ui/InputManager.h
+++ b/include/ui/InputManager.h
@@ -23,7 +23,6 @@
#include <ui/EventHub.h>
#include <ui/Input.h>
-#include <ui/InputDispatchPolicy.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
@@ -32,9 +31,14 @@
namespace android {
-class InputReader;
-class InputDispatcher;
+class InputChannel;
+
+class InputReaderInterface;
+class InputReaderPolicyInterface;
class InputReaderThread;
+
+class InputDispatcherInterface;
+class InputDispatcherPolicyInterface;
class InputDispatcherThread;
/*
@@ -74,8 +78,11 @@
/* Unregisters an input channel. */
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
+ /* Gets input device configuration. */
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;
+
/*
- * Query current input state.
+ * Queries current input state.
* deviceId may be -1 to search for the device automatically, filtered by class.
* deviceClasses may be -1 to ignore device class while searching.
*/
@@ -86,7 +93,7 @@
virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses,
int32_t sw) const = 0;
- /* Determine whether physical keys exist for the given framework-domain key codes. */
+ /* Determines whether physical keys exist for the given framework-domain key codes. */
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
};
@@ -95,12 +102,15 @@
virtual ~InputManager();
public:
- /*
- * Creates an input manager that reads events from the given
- * event hub and applies the given input dispatch policy.
- */
- InputManager(const sp<EventHubInterface>& eventHub,
- const sp<InputDispatchPolicyInterface>& policy);
+ InputManager(
+ const sp<EventHubInterface>& eventHub,
+ const sp<InputReaderPolicyInterface>& readerPolicy,
+ const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
+
+ // (used for testing purposes)
+ InputManager(
+ const sp<InputReaderInterface>& reader,
+ const sp<InputDispatcherInterface>& dispatcher);
virtual status_t start();
virtual status_t stop();
@@ -108,6 +118,7 @@
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
int32_t scanCode) const;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
@@ -117,16 +128,13 @@
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
private:
- sp<EventHubInterface> mEventHub;
- sp<InputDispatchPolicyInterface> mPolicy;
-
- sp<InputDispatcher> mDispatcher;
- sp<InputDispatcherThread> mDispatcherThread;
-
- sp<InputReader> mReader;
+ sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
- void configureExcludedDevices();
+ sp<InputDispatcherInterface> mDispatcher;
+ sp<InputDispatcherThread> mDispatcherThread;
+
+ void initialize();
};
} // namespace android
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 7e7a64c..d76b8fe 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -19,7 +19,6 @@
#include <ui/EventHub.h>
#include <ui/Input.h>
-#include <ui/InputDispatchPolicy.h>
#include <ui/InputDispatcher.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
@@ -35,21 +34,6 @@
* (This is limited by our use of BitSet32 to track pointer assignments.) */
#define MAX_POINTER_ID 32
-/** Amount that trackball needs to move in order to generate a key event. */
-#define TRACKBALL_MOVEMENT_THRESHOLD 6
-
-/* Slop distance for jumpy pointer detection.
- * The vertical range of the screen divided by this is our epsilon value. */
-#define JUMPY_EPSILON_DIVISOR 212
-
-/* Number of jumpy points to drop for touchscreens that need it. */
-#define JUMPY_TRANSITION_DROPS 3
-#define JUMPY_DROP_LIMIT 3
-
-/* Maximum squared distance for averaging.
- * If moving farther than this, turn of averaging to avoid lag in response. */
-#define AVERAGING_DISTANCE_LIMIT (75 * 75)
-
/* Maximum number of historical samples to average. */
#define AVERAGING_HISTORY_SIZE 5
@@ -335,8 +319,129 @@
};
-/* Processes raw input events and sends cooked event data to an input dispatcher
- * in accordance with the input dispatch policy. */
+/*
+ * Input reader policy interface.
+ *
+ * The input reader policy is used by the input reader to interact with the Window Manager
+ * and other system components.
+ *
+ * The actual implementation is partially supported by callbacks into the DVM
+ * via JNI. This interface is also mocked in the unit tests.
+ */
+class InputReaderPolicyInterface : public virtual RefBase {
+protected:
+ InputReaderPolicyInterface() { }
+ virtual ~InputReaderPolicyInterface() { }
+
+public:
+ /* Display orientations. */
+ enum {
+ ROTATION_0 = 0,
+ ROTATION_90 = 1,
+ ROTATION_180 = 2,
+ ROTATION_270 = 3
+ };
+
+ /* Actions returned by interceptXXX methods. */
+ enum {
+ // The input dispatcher should do nothing and discard the input unless other
+ // flags are set.
+ ACTION_NONE = 0,
+
+ // The input dispatcher should dispatch the input to the application.
+ ACTION_DISPATCH = 0x00000001,
+
+ // The input dispatcher should perform special filtering in preparation for
+ // a pending app switch.
+ ACTION_APP_SWITCH_COMING = 0x00000002,
+
+ // The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
+ // passes through the dispatch pipeline.
+ ACTION_WOKE_HERE = 0x00000004,
+
+ // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
+ // passes through the dispatch pipeline.
+ ACTION_BRIGHT_HERE = 0x00000008
+ };
+
+ /* Describes a virtual key. */
+ struct VirtualKeyDefinition {
+ int32_t scanCode;
+
+ // configured position data, specified in display coords
+ int32_t centerX;
+ int32_t centerY;
+ int32_t width;
+ int32_t height;
+ };
+
+ /* Gets information about the display with the specified id.
+ * Returns true if the display info is available, false otherwise.
+ */
+ virtual bool getDisplayInfo(int32_t displayId,
+ int32_t* width, int32_t* height, int32_t* orientation) = 0;
+
+ /* Provides feedback for a virtual key.
+ */
+ virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
+ int32_t action, int32_t flags, int32_t keyCode,
+ int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
+
+ /* Intercepts a key event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Returns a policy action constant such as ACTION_DISPATCH.
+ */
+ virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
+ bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
+
+ /* Intercepts a trackball event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Returns a policy action constant such as ACTION_DISPATCH.
+ */
+ virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
+ bool rolled) = 0;
+
+ /* Intercepts a touch event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Returns a policy action constant such as ACTION_DISPATCH.
+ */
+ virtual int32_t interceptTouch(nsecs_t when) = 0;
+
+ /* Intercepts a switch event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Switches are not dispatched to applications so this method should
+ * usually return ACTION_NONE.
+ */
+ virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) = 0;
+
+ /* Determines whether to turn on some hacks we have to improve the touch interaction with a
+ * certain device whose screen currently is not all that good.
+ */
+ virtual bool filterTouchEvents() = 0;
+
+ /* Determines whether to turn on some hacks to improve touch interaction with another device
+ * where touch coordinate data can get corrupted.
+ */
+ virtual bool filterJumpyTouchEvents() = 0;
+
+ /* Gets the configured virtual key definitions for an input device. */
+ virtual void getVirtualKeyDefinitions(const String8& deviceName,
+ Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
+
+ /* Gets the excluded device names for the platform. */
+ virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
+};
+
+
+/* Processes raw input events and sends cooked event data to an input dispatcher. */
class InputReaderInterface : public virtual RefBase {
protected:
InputReaderInterface() { }
@@ -355,16 +460,42 @@
* This method may be called on any thread (usually by the input manager).
*/
virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const = 0;
+
+ /* Gets the current input device configuration.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const = 0;
+
+ /*
+ * Query current input state.
+ * deviceId may be -1 to search for the device automatically, filtered by class.
+ * deviceClasses may be -1 to ignore device class while searching.
+ */
+ virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t scanCode) const = 0;
+ virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t keyCode) const = 0;
+ virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
+ int32_t sw) const = 0;
+
+ /* Determine whether physical keys exist for the given framework-domain key codes. */
+ virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
};
+
/* The input reader reads raw event data from the event hub and processes it into input events
- * that it sends to the input dispatcher. Some functions of the input reader are controlled
- * by the input dispatch policy, such as early event filtering in low power states.
+ * that it sends to the input dispatcher. Some functions of the input reader, such as early
+ * event filtering in low power states, are controlled by a separate policy object.
+ *
+ * IMPORTANT INVARIANT:
+ * Because the policy can potentially block or cause re-entrance into the input reader,
+ * the input reader never calls into the policy while holding its internal locks.
*/
class InputReader : public InputReaderInterface {
public:
InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputDispatchPolicyInterface>& policy,
+ const sp<InputReaderPolicyInterface>& policy,
const sp<InputDispatcherInterface>& dispatcher);
virtual ~InputReader();
@@ -372,6 +503,17 @@
virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const;
+ virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const;
+
+ virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t scanCode) const;
+ virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t keyCode) const;
+ virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
+ int32_t sw) const;
+
+ virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
+
private:
// Lock that must be acquired while manipulating state that may be concurrently accessed
// from other threads by input state query methods. It should be held for as short a
@@ -383,15 +525,18 @@
// (but not other internal device state)
mutable Mutex mExportedStateLock;
- // current virtual key information
- int32_t mGlobalVirtualKeyCode;
- int32_t mGlobalVirtualScanCode;
+ // current virtual key information (lock mExportedStateLock)
+ int32_t mExportedVirtualKeyCode;
+ int32_t mExportedVirtualScanCode;
+
+ // current input configuration (lock mExportedStateLock)
+ InputConfiguration mExportedInputConfiguration;
// combined key meta state
int32_t mGlobalMetaState;
sp<EventHubInterface> mEventHub;
- sp<InputDispatchPolicyInterface> mPolicy;
+ sp<InputReaderPolicyInterface> mPolicy;
sp<InputDispatcherInterface> mDispatcher;
KeyedVector<int32_t, InputDevice*> mDevices;
@@ -414,7 +559,7 @@
// input policy processing and dispatch
void onKey(nsecs_t when, InputDevice* device, bool down,
int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
- void onSwitch(nsecs_t when, InputDevice* device, bool down, int32_t code);
+ void onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode, int32_t switchValue);
void onSingleTouchScreenStateChanged(nsecs_t when, InputDevice* device);
void onMultiTouchScreenStateChanged(nsecs_t when, InputDevice* device);
void onTouchScreenChanged(nsecs_t when, InputDevice* device, bool havePointerIds);
@@ -445,13 +590,17 @@
void configureVirtualKeys(InputDevice* device);
void configureAbsoluteAxisInfo(InputDevice* device, int axis, const char* name,
InputDevice::AbsoluteAxisInfo* out);
+ void configureExcludedDevices();
// global meta state management for all devices
void resetGlobalMetaState();
int32_t globalMetaState();
// virtual key management
- void updateGlobalVirtualKeyState();
+ void updateExportedVirtualKeyState();
+
+ // input configuration management
+ void updateExportedInputConfiguration();
};
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 0ccde0d..f058271 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -19,6 +19,9 @@
// Log debug messages about the dispatch cycle.
#define DEBUG_DISPATCH_CYCLE 1
+// Log debug messages about registrations.
+#define DEBUG_REGISTRATION 1
+
// Log debug messages about performance statistics.
#define DEBUG_PERFORMANCE_STATISTICS 1
@@ -42,7 +45,7 @@
// --- InputDispatcher ---
-InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy) :
+InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy) {
mPollLoop = new PollLoop();
@@ -55,6 +58,8 @@
mInboundQueue.tail.eventTime = LONG_LONG_MAX;
mKeyRepeatState.lastKeyEntry = NULL;
+
+ mCurrentInputTargetsValid = false;
}
InputDispatcher::~InputDispatcher() {
@@ -72,8 +77,9 @@
}
void InputDispatcher::dispatchOnce() {
- bool allowKeyRepeat = mPolicy->allowKeyRepeat();
+ nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
+ bool skipPoll = false;
nsecs_t currentTime;
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
@@ -84,7 +90,7 @@
// is not a key. This is to ensure that we abort a key repeat if the device is just coming
// out of sleep.
// XXX we should handle resetting input state coming out of sleep more generally elsewhere
- if (! allowKeyRepeat) {
+ if (keyRepeatTimeout < 0) {
resetKeyRepeatLocked();
}
@@ -121,8 +127,8 @@
if (mInboundQueue.isEmpty()) {
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
- processKeyRepeatLocked(currentTime);
- return; // dispatched once
+ processKeyRepeatLockedInterruptible(currentTime, keyRepeatTimeout);
+ skipPoll = true;
} else {
if (mKeyRepeatState.nextRepeatTime < nextWakeupTime) {
nextWakeupTime = mKeyRepeatState.nextRepeatTime;
@@ -130,31 +136,30 @@
}
}
} else {
- // Inbound queue has at least one entry. Dequeue it and begin dispatching.
- // Note that we do not hold the lock for this process because dispatching may
- // involve making many callbacks.
- EventEntry* entry = mInboundQueue.dequeueAtHead();
+ // Inbound queue has at least one entry.
+ // Start processing it but leave it on the queue until later so that the
+ // input reader can keep appending samples onto a motion event between the
+ // time we started processing it and the time we finally enqueue dispatch
+ // entries for it.
+ EventEntry* entry = mInboundQueue.head.next;
switch (entry->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(entry);
- processConfigurationChangedLocked(currentTime, typedEntry);
- mAllocator.releaseConfigurationChangedEntry(typedEntry);
+ processConfigurationChangedLockedInterruptible(currentTime, typedEntry);
break;
}
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(entry);
- processKeyLocked(currentTime, typedEntry);
- mAllocator.releaseKeyEntry(typedEntry);
+ processKeyLockedInterruptible(currentTime, typedEntry, keyRepeatTimeout);
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(entry);
- processMotionLocked(currentTime, typedEntry);
- mAllocator.releaseMotionEntry(typedEntry);
+ processMotionLockedInterruptible(currentTime, typedEntry);
break;
}
@@ -162,30 +167,67 @@
assert(false);
break;
}
- return; // dispatched once
+
+ // Dequeue and release the event entry that we just processed.
+ mInboundQueue.dequeue(entry);
+ mAllocator.releaseEventEntry(entry);
+ skipPoll = true;
}
}
+
+ // Run any deferred commands.
+ skipPoll |= runCommandsLockedInterruptible();
} // release lock
+ // If we dispatched anything, don't poll just now. Wait for the next iteration.
+ // Contents may have shifted during flight.
+ if (skipPoll) {
+ return;
+ }
+
// Wait for callback or timeout or wake.
nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime);
int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0;
mPollLoop->pollOnce(timeoutMillis);
}
-void InputDispatcher::processConfigurationChangedLocked(nsecs_t currentTime,
- ConfigurationChangedEntry* entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("processConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, "
- "keyboardConfig=%d, navigationConfig=%d", entry->eventTime,
- entry->touchScreenConfig, entry->keyboardConfig, entry->navigationConfig);
-#endif
+bool InputDispatcher::runCommandsLockedInterruptible() {
+ if (mCommandQueue.isEmpty()) {
+ return false;
+ }
- mPolicy->notifyConfigurationChanged(entry->eventTime, entry->touchScreenConfig,
- entry->keyboardConfig, entry->navigationConfig);
+ do {
+ CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
+
+ Command command = commandEntry->command;
+ (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
+
+ mAllocator.releaseCommandEntry(commandEntry);
+ } while (! mCommandQueue.isEmpty());
+ return true;
}
-void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) {
+InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
+ CommandEntry* commandEntry = mAllocator.obtainCommandEntry(command);
+ mCommandQueue.enqueueAtTail(commandEntry);
+ return commandEntry;
+}
+
+void InputDispatcher::processConfigurationChangedLockedInterruptible(
+ nsecs_t currentTime, ConfigurationChangedEntry* entry) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("processConfigurationChanged - eventTime=%lld", entry->eventTime);
+#endif
+
+ mLock.unlock();
+
+ mPolicy->notifyConfigurationChanged(entry->eventTime);
+
+ mLock.lock();
+}
+
+void InputDispatcher::processKeyLockedInterruptible(
+ nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("processKey - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
@@ -209,7 +251,7 @@
} else {
// Not a repeat. Save key down state in case we do see a repeat later.
resetKeyRepeatLocked();
- mKeyRepeatState.nextRepeatTime = entry->eventTime + mPolicy->getKeyRepeatTimeout();
+ mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry;
entry->refCount += 1;
@@ -217,10 +259,11 @@
resetKeyRepeatLocked();
}
- identifyInputTargetsAndDispatchKeyLocked(currentTime, entry);
+ identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);
}
-void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) {
+void InputDispatcher::processKeyRepeatLockedInterruptible(
+ nsecs_t currentTime, nsecs_t keyRepeatTimeout) {
// TODO Old WindowManagerServer code sniffs the input queue for following key up
// events and drops the repeat if one is found. We should do something similar.
// One good place to do it is in notifyKey as soon as the key up enters the
@@ -252,7 +295,7 @@
entry->downTime = currentTime;
entry->policyFlags = 0;
- mKeyRepeatState.nextRepeatTime = currentTime + mPolicy->getKeyRepeatTimeout();
+ mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("processKeyRepeat - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, "
@@ -263,10 +306,11 @@
entry->repeatCount, entry->downTime);
#endif
- identifyInputTargetsAndDispatchKeyLocked(currentTime, entry);
+ identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);
}
-void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entry) {
+void InputDispatcher::processMotionLockedInterruptible(
+ nsecs_t currentTime, MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("processMotion - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
"metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
@@ -296,15 +340,19 @@
}
#endif
- identifyInputTargetsAndDispatchMotionLocked(currentTime, entry);
+ identifyInputTargetsAndDispatchMotionLockedInterruptible(currentTime, entry);
}
-void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked(
+void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(
nsecs_t currentTime, KeyEntry* entry) {
#if DEBUG_DISPATCH_CYCLE
LOGD("identifyInputTargetsAndDispatchKey");
#endif
+ entry->dispatchInProgress = true;
+ mCurrentInputTargetsValid = false;
+ mLock.unlock();
+
mReusableKeyEvent.initialize(entry->deviceId, entry->nature, entry->action, entry->flags,
entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
entry->downTime, entry->eventTime);
@@ -313,15 +361,22 @@
mPolicy->getKeyEventTargets(& mReusableKeyEvent, entry->policyFlags,
mCurrentInputTargets);
+ mLock.lock();
+ mCurrentInputTargetsValid = true;
+
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
}
-void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked(
+void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
nsecs_t currentTime, MotionEntry* entry) {
#if DEBUG_DISPATCH_CYCLE
LOGD("identifyInputTargetsAndDispatchMotion");
#endif
+ entry->dispatchInProgress = true;
+ mCurrentInputTargetsValid = false;
+ mLock.unlock();
+
mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action,
entry->edgeFlags, entry->metaState,
entry->firstSample.pointerCoords[0].x, entry->firstSample.pointerCoords[0].y,
@@ -333,17 +388,22 @@
mPolicy->getMotionEventTargets(& mReusableMotionEvent, entry->policyFlags,
mCurrentInputTargets);
+ mLock.lock();
+ mCurrentInputTargetsValid = true;
+
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
}
void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("dispatchEventToCurrentInputTargets, "
+ LOGD("dispatchEventToCurrentInputTargets - "
"resumeWithAppendedMotionSample=%s",
resumeWithAppendedMotionSample ? "true" : "false");
#endif
+ assert(eventEntry->dispatchInProgress); // should already have been set to true
+
for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
@@ -365,7 +425,7 @@
EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ prepareDispatchCycle, flags=%d, timeout=%lldns, "
+ LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, timeout=%lldns, "
"xOffset=%f, yOffset=%f, resumeWithAppendedMotionSample=%s",
connection->getInputChannelName(), inputTarget->flags, inputTarget->timeout,
inputTarget->xOffset, inputTarget->yOffset,
@@ -377,7 +437,7 @@
// not responding.
if (connection->status != Connection::STATUS_NORMAL) {
LOGV("channel '%s' ~ Dropping event because the channel status is %s",
- connection->status == Connection::STATUS_BROKEN ? "BROKEN" : "NOT RESPONDING");
+ connection->getStatusLabel());
return;
}
@@ -631,14 +691,15 @@
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ finishDispatchCycle: %01.1fms since event, "
+ LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
"%01.1fms since dispatch",
connection->getInputChannelName(),
connection->getEventLatencyMillis(currentTime),
connection->getDispatchLatencyMillis(currentTime));
#endif
- if (connection->status == Connection::STATUS_BROKEN) {
+ if (connection->status == Connection::STATUS_BROKEN
+ || connection->status == Connection::STATUS_ZOMBIE) {
return;
}
@@ -722,34 +783,37 @@
bool InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
bool broken) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ abortDispatchCycle, broken=%s",
+ LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",
connection->getInputChannelName(), broken ? "true" : "false");
#endif
- if (connection->status == Connection::STATUS_BROKEN) {
- return false;
- }
-
// Clear the pending timeout.
connection->nextTimeoutTime = LONG_LONG_MAX;
// Clear the outbound queue.
- while (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
- mAllocator.releaseDispatchEntry(dispatchEntry);
- }
+ bool deactivated = ! connection->outboundQueue.isEmpty();
+ if (deactivated) {
+ do {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
+ mAllocator.releaseDispatchEntry(dispatchEntry);
+ } while (! connection->outboundQueue.isEmpty());
- // Outbound queue is empty, deactivate the connection.
- deactivateConnectionLocked(connection);
+ deactivateConnectionLocked(connection);
+ }
// Handle the case where the connection appears to be unrecoverably broken.
+ // Ignore already broken or zombie connections.
if (broken) {
- connection->status = Connection::STATUS_BROKEN;
+ if (connection->status == Connection::STATUS_NORMAL
+ || connection->status == Connection::STATUS_NOT_RESPONDING) {
+ connection->status = Connection::STATUS_BROKEN;
- // Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
+ // Notify other system components.
+ onDispatchCycleBrokenLocked(currentTime, connection);
+ }
}
- return true; /*deactivated*/
+
+ return deactivated;
}
bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
@@ -772,6 +836,7 @@
LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName(), events);
d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+ d->runCommandsLockedInterruptible();
return false; // remove the callback
}
@@ -786,20 +851,19 @@
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+ d->runCommandsLockedInterruptible();
return false; // remove the callback
}
d->finishDispatchCycleLocked(currentTime, connection.get());
+ d->runCommandsLockedInterruptible();
return true;
} // release lock
}
-void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touchScreenConfig,
- int32_t keyboardConfig, int32_t navigationConfig) {
+void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, "
- "keyboardConfig=%d, navigationConfig=%d", eventTime,
- touchScreenConfig, keyboardConfig, navigationConfig);
+ LOGD("notifyConfigurationChanged - eventTime=%lld", eventTime);
#endif
bool wasEmpty;
@@ -808,9 +872,6 @@
ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry();
newEntry->eventTime = eventTime;
- newEntry->touchScreenConfig = touchScreenConfig;
- newEntry->keyboardConfig = keyboardConfig;
- newEntry->navigationConfig = navigationConfig;
wasEmpty = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(newEntry);
@@ -821,16 +882,6 @@
}
}
-void InputDispatcher::notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyLidSwitchChanged - eventTime=%lld, open=%s", eventTime,
- lidOpen ? "true" : "false");
-#endif
-
- // Send lid switch notification immediately and synchronously.
- mPolicy->notifyLidSwitchChanged(eventTime, lidOpen);
-}
-
void InputDispatcher::notifyAppSwitchComing(nsecs_t eventTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
LOGD("notifyAppSwitchComing - eventTime=%lld", eventTime);
@@ -949,13 +1000,25 @@
}
// The last motion event is a move and is compatible for appending.
- // Do the batching magic and exit.
+ // Do the batching magic.
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCount, pointerCoords);
#if DEBUG_BATCHING
LOGD("Appended motion sample onto batch for most recent "
"motion event for this device in the inbound queue.");
#endif
- return; // done
+
+ // Sanity check for special case because dispatch is interruptible.
+ // The dispatch logic is partially interruptible and releases its lock while
+ // identifying targets. However, as soon as the targets have been identified,
+ // the dispatcher proceeds to write a dispatch entry into all relevant outbound
+ // queues and then promptly removes the motion entry from the queue.
+ //
+ // Consequently, we should never observe the case where the inbound queue contains
+ // an in-progress motion entry unless the current input targets are invalid
+ // (currently being computed). Check for this!
+ assert(! (motionEntry->dispatchInProgress && mCurrentInputTargetsValid));
+
+ return; // done!
}
// STREAMING CASE
@@ -977,34 +1040,38 @@
// Note: This code crucially depends on the invariant that an outbound queue always
// contains at most one synchronous event and it is always last (but it might
// not be first!).
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- Connection* connection = mActiveConnections.itemAt(i);
- if (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
- if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
- goto NoBatchingOrStreaming;
- }
+ if (mCurrentInputTargetsValid) {
+ for (size_t i = 0; i < mActiveConnections.size(); i++) {
+ Connection* connection = mActiveConnections.itemAt(i);
+ if (! connection->outboundQueue.isEmpty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
+ if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
+ goto NoBatchingOrStreaming;
+ }
- MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
- dispatchEntry->eventEntry);
- if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
- || syncedMotionEntry->deviceId != deviceId
- || syncedMotionEntry->pointerCount != pointerCount) {
- goto NoBatchingOrStreaming;
- }
+ MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
+ dispatchEntry->eventEntry);
+ if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
+ || syncedMotionEntry->deviceId != deviceId
+ || syncedMotionEntry->pointerCount != pointerCount) {
+ goto NoBatchingOrStreaming;
+ }
- // Found synced move entry. Append sample and resume dispatch.
- mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
- pointerCount, pointerCoords);
-#if DEBUG_BATCHING
- LOGD("Appended motion sample onto batch for most recent synchronously "
- "dispatched motion event for this device in the outbound queues.");
-#endif
- nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
- dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
- true /*resumeWithAppendedMotionSample*/);
- return; // done!
+ // Found synced move entry. Append sample and resume dispatch.
+ mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
+ pointerCount, pointerCoords);
+ #if DEBUG_BATCHING
+ LOGD("Appended motion sample onto batch for most recent synchronously "
+ "dispatched motion event for this device in the outbound queues.");
+ #endif
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
+ true /*resumeWithAppendedMotionSample*/);
+
+ runCommandsLockedInterruptible();
+ return; // done!
+ }
}
}
}
@@ -1049,6 +1116,10 @@
}
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
+#if DEBUG_REGISTRATION
+ LOGD("channel '%s' - Registered", inputChannel->getName().string());
+#endif
+
int receiveFd;
{ // acquire lock
AutoMutex _l(mLock);
@@ -1069,6 +1140,8 @@
}
mConnectionsByReceiveFd.add(receiveFd, connection);
+
+ runCommandsLockedInterruptible();
} // release lock
mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
@@ -1076,6 +1149,10 @@
}
status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
+#if DEBUG_REGISTRATION
+ LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
+#endif
+
int32_t receiveFd;
{ // acquire lock
AutoMutex _l(mLock);
@@ -1095,6 +1172,8 @@
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
+
+ runCommandsLockedInterruptible();
} // release lock
mPollLoop->removeCallback(receiveFd);
@@ -1123,11 +1202,12 @@
}
}
-void InputDispatcher::onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::onDispatchCycleStartedLocked(
+ nsecs_t currentTime, Connection* connection) {
}
-void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
- Connection* connection, bool recoveredFromANR) {
+void InputDispatcher::onDispatchCycleFinishedLocked(
+ nsecs_t currentTime, Connection* connection, bool recoveredFromANR) {
if (recoveredFromANR) {
LOGI("channel '%s' ~ Recovered from ANR. %01.1fms since event, "
"%01.1fms since dispatch, %01.1fms since ANR",
@@ -1136,26 +1216,65 @@
connection->getDispatchLatencyMillis(currentTime),
connection->getANRLatencyMillis(currentTime));
- // TODO tell framework
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible);
+ commandEntry->inputChannel = connection->inputChannel;
}
}
-void InputDispatcher::onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::onDispatchCycleANRLocked(
+ nsecs_t currentTime, Connection* connection) {
LOGI("channel '%s' ~ Not responding! %01.1fms since event, %01.1fms since dispatch",
connection->getInputChannelName(),
connection->getEventLatencyMillis(currentTime),
connection->getDispatchLatencyMillis(currentTime));
- // TODO tell framework
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyInputChannelANRLockedInterruptible);
+ commandEntry->inputChannel = connection->inputChannel;
}
-void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection) {
+void InputDispatcher::onDispatchCycleBrokenLocked(
+ nsecs_t currentTime, Connection* connection) {
LOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
connection->getInputChannelName());
- // TODO tell framework
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
+ commandEntry->inputChannel = connection->inputChannel;
}
+void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(
+ CommandEntry* commandEntry) {
+ mLock.unlock();
+
+ mPolicy->notifyInputChannelBroken(commandEntry->inputChannel);
+ commandEntry->inputChannel.clear();
+
+ mLock.lock();
+}
+
+void InputDispatcher::doNotifyInputChannelANRLockedInterruptible(
+ CommandEntry* commandEntry) {
+ mLock.unlock();
+
+ mPolicy->notifyInputChannelANR(commandEntry->inputChannel);
+ commandEntry->inputChannel.clear();
+
+ mLock.lock();
+}
+
+void InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible(
+ CommandEntry* commandEntry) {
+ mLock.unlock();
+
+ mPolicy->notifyInputChannelRecoveredFromANR(commandEntry->inputChannel);
+ commandEntry->inputChannel.clear();
+
+ mLock.lock();
+}
+
+
// --- InputDispatcher::Allocator ---
InputDispatcher::Allocator::Allocator() {
@@ -1166,6 +1285,7 @@
ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();
entry->refCount = 1;
entry->type = EventEntry::TYPE_CONFIGURATION_CHANGED;
+ entry->dispatchInProgress = false;
return entry;
}
@@ -1173,6 +1293,7 @@
KeyEntry* entry = mKeyEntryPool.alloc();
entry->refCount = 1;
entry->type = EventEntry::TYPE_KEY;
+ entry->dispatchInProgress = false;
return entry;
}
@@ -1181,6 +1302,7 @@
entry->refCount = 1;
entry->type = EventEntry::TYPE_MOTION;
entry->firstSample.next = NULL;
+ entry->dispatchInProgress = false;
return entry;
}
@@ -1192,6 +1314,12 @@
return entry;
}
+InputDispatcher::CommandEntry* InputDispatcher::Allocator::obtainCommandEntry(Command command) {
+ CommandEntry* entry = mCommandEntryPool.alloc();
+ entry->command = command;
+ return entry;
+}
+
void InputDispatcher::Allocator::releaseEventEntry(EventEntry* entry) {
switch (entry->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED:
@@ -1231,7 +1359,11 @@
void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) {
entry->refCount -= 1;
if (entry->refCount == 0) {
- freeMotionSampleList(entry->firstSample.next);
+ for (MotionSample* sample = entry->firstSample.next; sample != NULL; ) {
+ MotionSample* next = sample->next;
+ mMotionSamplePool.free(sample);
+ sample = next;
+ }
mMotionEntryPool.free(entry);
} else {
assert(entry->refCount > 0);
@@ -1243,6 +1375,10 @@
mDispatchEntryPool.free(entry);
}
+void InputDispatcher::Allocator::releaseCommandEntry(CommandEntry* entry) {
+ mCommandEntryPool.free(entry);
+}
+
void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,
nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords) {
MotionSample* sample = mMotionSamplePool.alloc();
@@ -1256,18 +1392,6 @@
motionEntry->lastSample = sample;
}
-void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) {
- mMotionSamplePool.free(sample);
-}
-
-void InputDispatcher::Allocator::freeMotionSampleList(MotionSample* head) {
- while (head) {
- MotionSample* next = head->next;
- mMotionSamplePool.free(head);
- head = next;
- }
-}
-
// --- InputDispatcher::Connection ---
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) :
@@ -1284,6 +1408,25 @@
return inputPublisher.initialize();
}
+const char* InputDispatcher::Connection::getStatusLabel() const {
+ switch (status) {
+ case STATUS_NORMAL:
+ return "NORMAL";
+
+ case STATUS_BROKEN:
+ return "BROKEN";
+
+ case STATUS_NOT_RESPONDING:
+ return "NOT_RESPONDING";
+
+ case STATUS_ZOMBIE:
+ return "ZOMBIE";
+
+ default:
+ return "UNKNOWN";
+ }
+}
+
InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent(
const EventEntry* eventEntry) const {
for (DispatchEntry* dispatchEntry = outboundQueue.tail.prev;
@@ -1295,6 +1438,14 @@
return NULL;
}
+// --- InputDispatcher::CommandEntry ---
+
+InputDispatcher::CommandEntry::CommandEntry() {
+}
+
+InputDispatcher::CommandEntry::~CommandEntry() {
+}
+
// --- InputDispatcherThread ---
diff --git a/libs/ui/InputManager.cpp b/libs/ui/InputManager.cpp
index ab354a5..7538dd0 100644
--- a/libs/ui/InputManager.cpp
+++ b/libs/ui/InputManager.cpp
@@ -14,29 +14,30 @@
namespace android {
-InputManager::InputManager(const sp<EventHubInterface>& eventHub,
- const sp<InputDispatchPolicyInterface>& policy) :
- mEventHub(eventHub), mPolicy(policy) {
- mDispatcher = new InputDispatcher(policy);
- mReader = new InputReader(eventHub, policy, mDispatcher);
+InputManager::InputManager(
+ const sp<EventHubInterface>& eventHub,
+ const sp<InputReaderPolicyInterface>& readerPolicy,
+ const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
+ mDispatcher = new InputDispatcher(dispatcherPolicy);
+ mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
+ initialize();
+}
- mDispatcherThread = new InputDispatcherThread(mDispatcher);
- mReaderThread = new InputReaderThread(mReader);
-
- configureExcludedDevices();
+InputManager::InputManager(
+ const sp<InputReaderInterface>& reader,
+ const sp<InputDispatcherInterface>& dispatcher) :
+ mReader(reader),
+ mDispatcher(dispatcher) {
+ initialize();
}
InputManager::~InputManager() {
stop();
}
-void InputManager::configureExcludedDevices() {
- Vector<String8> excludedDeviceNames;
- mPolicy->getExcludedDeviceNames(excludedDeviceNames);
-
- for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
- mEventHub->addExcludedDevice(excludedDeviceNames[i]);
- }
+void InputManager::initialize() {
+ mReaderThread = new InputReaderThread(mReader);
+ mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
@@ -79,36 +80,26 @@
return mDispatcher->unregisterInputChannel(inputChannel);
}
-int32_t InputManager::getScanCodeState(int32_t deviceId, int32_t deviceClasses, int32_t scanCode)
- const {
- int32_t vkKeyCode, vkScanCode;
- if (mReader->getCurrentVirtualKey(& vkKeyCode, & vkScanCode)) {
- if (vkScanCode == scanCode) {
- return KEY_STATE_VIRTUAL;
- }
- }
-
- return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode);
+void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) const {
+ mReader->getCurrentInputConfiguration(outConfiguration);
}
-int32_t InputManager::getKeyCodeState(int32_t deviceId, int32_t deviceClasses, int32_t keyCode)
- const {
- int32_t vkKeyCode, vkScanCode;
- if (mReader->getCurrentVirtualKey(& vkKeyCode, & vkScanCode)) {
- if (vkKeyCode == keyCode) {
- return KEY_STATE_VIRTUAL;
- }
- }
+int32_t InputManager::getScanCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t scanCode) const {
+ return mReader->getCurrentScanCodeState(deviceId, deviceClasses, scanCode);
+}
- return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode);
+int32_t InputManager::getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t keyCode) const {
+ return mReader->getCurrentKeyCodeState(deviceId, deviceClasses, keyCode);
}
int32_t InputManager::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_t sw) const {
- return mEventHub->getSwitchState(deviceId, deviceClasses, sw);
+ return mReader->getCurrentSwitchState(deviceId, deviceClasses, sw);
}
bool InputManager::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
- return mEventHub->hasKeys(numCodes, keyCodes, outFlags);
+ return mReader->hasKeys(numCodes, keyCodes, outFlags);
}
} // namespace android
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 796abd0..62b5f28 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -27,6 +27,22 @@
#include <errno.h>
#include <limits.h>
+/** Amount that trackball needs to move in order to generate a key event. */
+#define TRACKBALL_MOVEMENT_THRESHOLD 6
+
+/* Slop distance for jumpy pointer detection.
+ * The vertical range of the screen divided by this is our epsilon value. */
+#define JUMPY_EPSILON_DIVISOR 212
+
+/* Number of jumpy points to drop for touchscreens that need it. */
+#define JUMPY_TRANSITION_DROPS 3
+#define JUMPY_DROP_LIMIT 3
+
+/* Maximum squared distance for averaging.
+ * If moving farther than this, turn of averaging to avoid lag in response. */
+#define AVERAGING_DISTANCE_LIMIT (75 * 75)
+
+
namespace android {
// --- Static Functions ---
@@ -89,7 +105,7 @@
sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
- if (orientation != InputDispatchPolicyInterface::ROTATION_0) {
+ if (orientation != InputReaderPolicyInterface::ROTATION_0) {
for (int i = 0; i < keyCodeRotationMapSize; i++) {
if (keyCode == keyCodeRotationMap[i][0]) {
return keyCodeRotationMap[i][orientation];
@@ -677,12 +693,13 @@
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputDispatchPolicyInterface>& policy,
+ const sp<InputReaderPolicyInterface>& policy,
const sp<InputDispatcherInterface>& dispatcher) :
mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher) {
+ configureExcludedDevices();
resetGlobalMetaState();
resetDisplayProperties();
- updateGlobalVirtualKeyState();
+ updateExportedVirtualKeyState();
}
InputReader::~InputReader() {
@@ -925,7 +942,7 @@
InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
if (! device) return;
- onSwitch(rawEvent->when, device, rawEvent->value != 0, rawEvent->scanCode);
+ onSwitch(rawEvent->when, device, rawEvent->scanCode, rawEvent->value);
}
void InputReader::onKey(nsecs_t when, InputDevice* device,
@@ -974,7 +991,7 @@
}
int32_t keyEventFlags = KEY_EVENT_FLAG_FROM_SYSTEM;
- if (policyActions & InputDispatchPolicyInterface::ACTION_WOKE_HERE) {
+ if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
keyEventFlags = keyEventFlags | KEY_EVENT_FLAG_WOKE_HERE;
}
@@ -984,12 +1001,12 @@
device->keyboard.current.downTime);
}
-void InputReader::onSwitch(nsecs_t when, InputDevice* device, bool down,
- int32_t code) {
- switch (code) {
- case SW_LID:
- mDispatcher->notifyLidSwitchChanged(when, ! down);
- }
+void InputReader::onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode,
+ int32_t switchValue) {
+ int32_t policyActions = mPolicy->interceptSwitch(when, switchCode, switchValue);
+
+ uint32_t policyFlags = 0;
+ applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags);
}
void InputReader::onMultiTouchScreenStateChanged(nsecs_t when,
@@ -1256,7 +1273,7 @@
nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
int32_t metaState = globalMetaState();
- updateGlobalVirtualKeyState();
+ updateExportedVirtualKeyState();
mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags,
keyCode, scanCode, metaState, downTime);
@@ -1333,8 +1350,8 @@
int32_t motionEventAction) {
int32_t orientedWidth, orientedHeight;
switch (mDisplayOrientation) {
- case InputDispatchPolicyInterface::ROTATION_90:
- case InputDispatchPolicyInterface::ROTATION_270:
+ case InputReaderPolicyInterface::ROTATION_90:
+ case InputReaderPolicyInterface::ROTATION_270:
orientedWidth = mDisplayHeight;
orientedHeight = mDisplayWidth;
break;
@@ -1369,18 +1386,18 @@
* device->touchScreen.precalculated.sizeScale;
switch (mDisplayOrientation) {
- case InputDispatchPolicyInterface::ROTATION_90: {
+ case InputReaderPolicyInterface::ROTATION_90: {
float xTemp = x;
x = y;
y = mDisplayHeight - xTemp;
break;
}
- case InputDispatchPolicyInterface::ROTATION_180: {
+ case InputReaderPolicyInterface::ROTATION_180: {
x = mDisplayWidth - x;
y = mDisplayHeight - y;
break;
}
- case InputDispatchPolicyInterface::ROTATION_270: {
+ case InputReaderPolicyInterface::ROTATION_270: {
float xTemp = x;
x = mDisplayWidth - y;
y = xTemp;
@@ -1483,18 +1500,18 @@
float temp;
switch (mDisplayOrientation) {
- case InputDispatchPolicyInterface::ROTATION_90:
+ case InputReaderPolicyInterface::ROTATION_90:
temp = pointerCoords.x;
pointerCoords.x = pointerCoords.y;
pointerCoords.y = - temp;
break;
- case InputDispatchPolicyInterface::ROTATION_180:
+ case InputReaderPolicyInterface::ROTATION_180:
pointerCoords.x = - pointerCoords.x;
pointerCoords.y = - pointerCoords.y;
break;
- case InputDispatchPolicyInterface::ROTATION_270:
+ case InputReaderPolicyInterface::ROTATION_270:
temp = pointerCoords.x;
pointerCoords.x = - pointerCoords.y;
pointerCoords.y = temp;
@@ -1514,51 +1531,30 @@
resetGlobalMetaState();
// Reset virtual keys, just in case.
- updateGlobalVirtualKeyState();
+ updateExportedVirtualKeyState();
+
+ // Update input configuration.
+ updateExportedInputConfiguration();
// Enqueue configuration changed.
- // XXX This stuff probably needs to be tracked elsewhere in an input device registry
- // of some kind that can be asynchronously updated and queried. (Same as above?)
- int32_t touchScreenConfig = InputDispatchPolicyInterface::TOUCHSCREEN_NOTOUCH;
- int32_t keyboardConfig = InputDispatchPolicyInterface::KEYBOARD_NOKEYS;
- int32_t navigationConfig = InputDispatchPolicyInterface::NAVIGATION_NONAV;
-
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- int32_t deviceClasses = device->classes;
-
- if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
- touchScreenConfig = InputDispatchPolicyInterface::TOUCHSCREEN_FINGER;
- }
- if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) {
- keyboardConfig = InputDispatchPolicyInterface::KEYBOARD_QWERTY;
- }
- if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) {
- navigationConfig = InputDispatchPolicyInterface::NAVIGATION_TRACKBALL;
- } else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) {
- navigationConfig = InputDispatchPolicyInterface::NAVIGATION_DPAD;
- }
- }
-
- mDispatcher->notifyConfigurationChanged(when, touchScreenConfig,
- keyboardConfig, navigationConfig);
+ mDispatcher->notifyConfigurationChanged(when);
}
bool InputReader::applyStandardInputDispatchPolicyActions(nsecs_t when,
int32_t policyActions, uint32_t* policyFlags) {
- if (policyActions & InputDispatchPolicyInterface::ACTION_APP_SWITCH_COMING) {
+ if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
mDispatcher->notifyAppSwitchComing(when);
}
- if (policyActions & InputDispatchPolicyInterface::ACTION_WOKE_HERE) {
+ if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
*policyFlags |= POLICY_FLAG_WOKE_HERE;
}
- if (policyActions & InputDispatchPolicyInterface::ACTION_BRIGHT_HERE) {
+ if (policyActions & InputReaderPolicyInterface::ACTION_BRIGHT_HERE) {
*policyFlags |= POLICY_FLAG_BRIGHT_HERE;
}
- return policyActions & InputDispatchPolicyInterface::ACTION_DISPATCH;
+ return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
}
void InputReader::resetDisplayProperties() {
@@ -1706,7 +1702,7 @@
void InputReader::configureVirtualKeys(InputDevice* device) {
device->touchScreen.virtualKeys.clear();
- Vector<InputDispatchPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
+ Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
mPolicy->getVirtualKeyDefinitions(device->name, virtualKeyDefinitions);
if (virtualKeyDefinitions.size() == 0) {
return;
@@ -1720,7 +1716,7 @@
int32_t touchScreenHeight = device->touchScreen.parameters.yAxis.range;
for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
- const InputDispatchPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
+ const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
virtualKeyDefinitions[i];
device->touchScreen.virtualKeys.add();
@@ -1779,6 +1775,15 @@
LOGI(" %s: unknown axis values, setting to zero", name);
}
+void InputReader::configureExcludedDevices() {
+ Vector<String8> excludedDeviceNames;
+ mPolicy->getExcludedDeviceNames(excludedDeviceNames);
+
+ for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
+ mEventHub->addExcludedDevice(excludedDeviceNames[i]);
+ }
+}
+
void InputReader::resetGlobalMetaState() {
mGlobalMetaState = -1;
}
@@ -1796,7 +1801,7 @@
return mGlobalMetaState;
}
-void InputReader::updateGlobalVirtualKeyState() {
+void InputReader::updateExportedVirtualKeyState() {
int32_t keyCode = -1, scanCode = -1;
for (size_t i = 0; i < mDevices.size(); i++) {
@@ -1809,20 +1814,96 @@
}
}
- {
+ { // acquire exported state lock
AutoMutex _l(mExportedStateLock);
- mGlobalVirtualKeyCode = keyCode;
- mGlobalVirtualScanCode = scanCode;
- }
+ mExportedVirtualKeyCode = keyCode;
+ mExportedVirtualScanCode = scanCode;
+ } // release exported state lock
}
bool InputReader::getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const {
- AutoMutex _l(mExportedStateLock);
+ { // acquire exported state lock
+ AutoMutex _l(mExportedStateLock);
- *outKeyCode = mGlobalVirtualKeyCode;
- *outScanCode = mGlobalVirtualScanCode;
- return mGlobalVirtualKeyCode != -1;
+ *outKeyCode = mExportedVirtualKeyCode;
+ *outScanCode = mExportedVirtualScanCode;
+ return mExportedVirtualKeyCode != -1;
+ } // release exported state lock
+}
+
+void InputReader::updateExportedInputConfiguration() {
+ int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH;
+ int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS;
+ int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV;
+
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ int32_t deviceClasses = device->classes;
+
+ if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
+ touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
+ }
+ if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) {
+ keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
+ }
+ if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) {
+ navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
+ } else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) {
+ navigationConfig = InputConfiguration::NAVIGATION_DPAD;
+ }
+ }
+
+ { // acquire exported state lock
+ AutoMutex _l(mExportedStateLock);
+
+ mExportedInputConfiguration.touchScreen = touchScreenConfig;
+ mExportedInputConfiguration.keyboard = keyboardConfig;
+ mExportedInputConfiguration.navigation = navigationConfig;
+ } // release exported state lock
+}
+
+void InputReader::getCurrentInputConfiguration(InputConfiguration* outConfiguration) const {
+ { // acquire exported state lock
+ AutoMutex _l(mExportedStateLock);
+
+ *outConfiguration = mExportedInputConfiguration;
+ } // release exported state lock
+}
+
+int32_t InputReader::getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t scanCode) const {
+ { // acquire exported state lock
+ AutoMutex _l(mExportedStateLock);
+
+ if (mExportedVirtualScanCode == scanCode) {
+ return KEY_STATE_VIRTUAL;
+ }
+ } // release exported state lock
+
+ return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode);
+}
+
+int32_t InputReader::getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t keyCode) const {
+ { // acquire exported state lock
+ AutoMutex _l(mExportedStateLock);
+
+ if (mExportedVirtualKeyCode == keyCode) {
+ return KEY_STATE_VIRTUAL;
+ }
+ } // release exported state lock
+
+ return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode);
+}
+
+int32_t InputReader::getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
+ int32_t sw) const {
+ return mEventHub->getSwitchState(deviceId, deviceClasses, sw);
+}
+
+bool InputReader::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
+ return mEventHub->hasKeys(numCodes, keyCodes, outFlags);
}
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 018f18d..1ff896b 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -5,7 +5,7 @@
test_src_files := \
InputDispatcher_test.cpp
-LOCAL_SHARED_LIBRARIES := \
+shared_libraries := \
libcutils \
libutils \
libEGL \
@@ -16,21 +16,26 @@
libui \
libstlport
-LOCAL_STATIC_LIBRARIES := \
+static_libraries := \
libgtest \
libgtest_main
-LOCAL_C_INCLUDES := \
+c_includes := \
bionic \
bionic/libstdc++/include \
external/gtest/include \
external/stlport/stlport
-LOCAL_MODULE_TAGS := eng tests
+module_tags := eng tests
$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+ $(eval LOCAL_C_INCLUDES := $(c_includes)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
$(eval include $(BUILD_EXECUTABLE)) \
)
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 45e8061..92ebfd7 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -5,18 +5,18 @@
test_src_files := \
PollLoop_test.cpp
-LOCAL_SHARED_LIBRARIES := \
+shared_libraries := \
libz \
liblog \
libcutils \
libutils \
libstlport
-LOCAL_STATIC_LIBRARIES := \
+static_libraries := \
libgtest \
libgtest_main
-LOCAL_C_INCLUDES := \
+c_includes := \
external/zlib \
external/icu4c/common \
bionic \
@@ -24,10 +24,15 @@
external/gtest/include \
external/stlport/stlport
-LOCAL_MODULE_TAGS := eng tests
+module_tags := eng tests
$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+ $(eval LOCAL_C_INCLUDES := $(c_includes)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
$(eval include $(BUILD_EXECUTABLE)) \
)