Merge "Support sorting in storage UI."
diff --git a/api/current.txt b/api/current.txt
index d40832c..d5ae85f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -33379,6 +33379,7 @@
method public static int getType(char);
method public static int getType(int);
method public static char highSurrogate(int);
+ method public static boolean isAlphabetic(int);
method public static boolean isBmpCodePoint(int);
method public static boolean isDefined(char);
method public static boolean isDefined(int);
@@ -33389,6 +33390,7 @@
method public static boolean isISOControl(int);
method public static boolean isIdentifierIgnorable(char);
method public static boolean isIdentifierIgnorable(int);
+ method public static boolean isIdeographic(int);
method public static boolean isJavaIdentifierPart(char);
method public static boolean isJavaIdentifierPart(int);
method public static boolean isJavaIdentifierStart(char);
@@ -33515,48 +33517,84 @@
method public static java.lang.Character.UnicodeBlock of(char);
method public static java.lang.Character.UnicodeBlock of(int);
field public static final java.lang.Character.UnicodeBlock AEGEAN_NUMBERS;
+ field public static final java.lang.Character.UnicodeBlock ALCHEMICAL_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock ALPHABETIC_PRESENTATION_FORMS;
+ field public static final java.lang.Character.UnicodeBlock ANCIENT_GREEK_MUSICAL_NOTATION;
+ field public static final java.lang.Character.UnicodeBlock ANCIENT_GREEK_NUMBERS;
+ field public static final java.lang.Character.UnicodeBlock ANCIENT_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock ARABIC;
field public static final java.lang.Character.UnicodeBlock ARABIC_PRESENTATION_FORMS_A;
field public static final java.lang.Character.UnicodeBlock ARABIC_PRESENTATION_FORMS_B;
+ field public static final java.lang.Character.UnicodeBlock ARABIC_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock ARMENIAN;
field public static final java.lang.Character.UnicodeBlock ARROWS;
+ field public static final java.lang.Character.UnicodeBlock AVESTAN;
+ field public static final java.lang.Character.UnicodeBlock BALINESE;
+ field public static final java.lang.Character.UnicodeBlock BAMUM;
+ field public static final java.lang.Character.UnicodeBlock BAMUM_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock BASIC_LATIN;
+ field public static final java.lang.Character.UnicodeBlock BATAK;
field public static final java.lang.Character.UnicodeBlock BENGALI;
field public static final java.lang.Character.UnicodeBlock BLOCK_ELEMENTS;
field public static final java.lang.Character.UnicodeBlock BOPOMOFO;
field public static final java.lang.Character.UnicodeBlock BOPOMOFO_EXTENDED;
field public static final java.lang.Character.UnicodeBlock BOX_DRAWING;
+ field public static final java.lang.Character.UnicodeBlock BRAHMI;
field public static final java.lang.Character.UnicodeBlock BRAILLE_PATTERNS;
+ field public static final java.lang.Character.UnicodeBlock BUGINESE;
field public static final java.lang.Character.UnicodeBlock BUHID;
field public static final java.lang.Character.UnicodeBlock BYZANTINE_MUSICAL_SYMBOLS;
+ field public static final java.lang.Character.UnicodeBlock CARIAN;
+ field public static final java.lang.Character.UnicodeBlock CHAM;
field public static final java.lang.Character.UnicodeBlock CHEROKEE;
field public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY;
field public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY_FORMS;
field public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS;
field public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock CJK_RADICALS_SUPPLEMENT;
+ field public static final java.lang.Character.UnicodeBlock CJK_STROKES;
field public static final java.lang.Character.UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION;
field public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS;
field public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A;
field public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B;
+ field public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C;
+ field public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D;
field public static final java.lang.Character.UnicodeBlock COMBINING_DIACRITICAL_MARKS;
+ field public static final java.lang.Character.UnicodeBlock COMBINING_DIACRITICAL_MARKS_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock COMBINING_HALF_MARKS;
field public static final java.lang.Character.UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS;
+ field public static final java.lang.Character.UnicodeBlock COMMON_INDIC_NUMBER_FORMS;
field public static final java.lang.Character.UnicodeBlock CONTROL_PICTURES;
+ field public static final java.lang.Character.UnicodeBlock COPTIC;
+ field public static final java.lang.Character.UnicodeBlock COUNTING_ROD_NUMERALS;
+ field public static final java.lang.Character.UnicodeBlock CUNEIFORM;
+ field public static final java.lang.Character.UnicodeBlock CUNEIFORM_NUMBERS_AND_PUNCTUATION;
field public static final java.lang.Character.UnicodeBlock CURRENCY_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock CYPRIOT_SYLLABARY;
field public static final java.lang.Character.UnicodeBlock CYRILLIC;
+ field public static final java.lang.Character.UnicodeBlock CYRILLIC_EXTENDED_A;
+ field public static final java.lang.Character.UnicodeBlock CYRILLIC_EXTENDED_B;
field public static final java.lang.Character.UnicodeBlock CYRILLIC_SUPPLEMENTARY;
field public static final java.lang.Character.UnicodeBlock DESERET;
field public static final java.lang.Character.UnicodeBlock DEVANAGARI;
+ field public static final java.lang.Character.UnicodeBlock DEVANAGARI_EXTENDED;
field public static final java.lang.Character.UnicodeBlock DINGBATS;
+ field public static final java.lang.Character.UnicodeBlock DOMINO_TILES;
+ field public static final java.lang.Character.UnicodeBlock EGYPTIAN_HIEROGLYPHS;
+ field public static final java.lang.Character.UnicodeBlock EMOTICONS;
field public static final java.lang.Character.UnicodeBlock ENCLOSED_ALPHANUMERICS;
+ field public static final java.lang.Character.UnicodeBlock ENCLOSED_ALPHANUMERIC_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS;
+ field public static final java.lang.Character.UnicodeBlock ENCLOSED_IDEOGRAPHIC_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock ETHIOPIC;
+ field public static final java.lang.Character.UnicodeBlock ETHIOPIC_EXTENDED;
+ field public static final java.lang.Character.UnicodeBlock ETHIOPIC_EXTENDED_A;
+ field public static final java.lang.Character.UnicodeBlock ETHIOPIC_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock GENERAL_PUNCTUATION;
field public static final java.lang.Character.UnicodeBlock GEOMETRIC_SHAPES;
field public static final java.lang.Character.UnicodeBlock GEORGIAN;
+ field public static final java.lang.Character.UnicodeBlock GEORGIAN_SUPPLEMENT;
+ field public static final java.lang.Character.UnicodeBlock GLAGOLITIC;
field public static final java.lang.Character.UnicodeBlock GOTHIC;
field public static final java.lang.Character.UnicodeBlock GREEK;
field public static final java.lang.Character.UnicodeBlock GREEK_EXTENDED;
@@ -33565,6 +33603,8 @@
field public static final java.lang.Character.UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS;
field public static final java.lang.Character.UnicodeBlock HANGUL_COMPATIBILITY_JAMO;
field public static final java.lang.Character.UnicodeBlock HANGUL_JAMO;
+ field public static final java.lang.Character.UnicodeBlock HANGUL_JAMO_EXTENDED_A;
+ field public static final java.lang.Character.UnicodeBlock HANGUL_JAMO_EXTENDED_B;
field public static final java.lang.Character.UnicodeBlock HANGUL_SYLLABLES;
field public static final java.lang.Character.UnicodeBlock HANUNOO;
field public static final java.lang.Character.UnicodeBlock HEBREW;
@@ -33572,12 +33612,20 @@
field public static final java.lang.Character.UnicodeBlock HIGH_SURROGATES;
field public static final java.lang.Character.UnicodeBlock HIRAGANA;
field public static final java.lang.Character.UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS;
+ field public static final java.lang.Character.UnicodeBlock IMPERIAL_ARAMAIC;
+ field public static final java.lang.Character.UnicodeBlock INSCRIPTIONAL_PAHLAVI;
+ field public static final java.lang.Character.UnicodeBlock INSCRIPTIONAL_PARTHIAN;
field public static final java.lang.Character.UnicodeBlock IPA_EXTENSIONS;
+ field public static final java.lang.Character.UnicodeBlock JAVANESE;
+ field public static final java.lang.Character.UnicodeBlock KAITHI;
+ field public static final java.lang.Character.UnicodeBlock KANA_SUPPLEMENT;
field public static final java.lang.Character.UnicodeBlock KANBUN;
field public static final java.lang.Character.UnicodeBlock KANGXI_RADICALS;
field public static final java.lang.Character.UnicodeBlock KANNADA;
field public static final java.lang.Character.UnicodeBlock KATAKANA;
field public static final java.lang.Character.UnicodeBlock KATAKANA_PHONETIC_EXTENSIONS;
+ field public static final java.lang.Character.UnicodeBlock KAYAH_LI;
+ field public static final java.lang.Character.UnicodeBlock KHAROSHTHI;
field public static final java.lang.Character.UnicodeBlock KHMER;
field public static final java.lang.Character.UnicodeBlock KHMER_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock LAO;
@@ -33585,58 +33633,96 @@
field public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_A;
field public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_ADDITIONAL;
field public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_B;
+ field public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_C;
+ field public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_D;
+ field public static final java.lang.Character.UnicodeBlock LEPCHA;
field public static final java.lang.Character.UnicodeBlock LETTERLIKE_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock LIMBU;
field public static final java.lang.Character.UnicodeBlock LINEAR_B_IDEOGRAMS;
field public static final java.lang.Character.UnicodeBlock LINEAR_B_SYLLABARY;
+ field public static final java.lang.Character.UnicodeBlock LISU;
field public static final java.lang.Character.UnicodeBlock LOW_SURROGATES;
+ field public static final java.lang.Character.UnicodeBlock LYCIAN;
+ field public static final java.lang.Character.UnicodeBlock LYDIAN;
+ field public static final java.lang.Character.UnicodeBlock MAHJONG_TILES;
field public static final java.lang.Character.UnicodeBlock MALAYALAM;
+ field public static final java.lang.Character.UnicodeBlock MANDAIC;
field public static final java.lang.Character.UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock MATHEMATICAL_OPERATORS;
+ field public static final java.lang.Character.UnicodeBlock MEETEI_MAYEK;
field public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A;
field public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B;
field public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_ARROWS;
+ field public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS;
field public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_TECHNICAL;
+ field public static final java.lang.Character.UnicodeBlock MODIFIER_TONE_LETTERS;
field public static final java.lang.Character.UnicodeBlock MONGOLIAN;
field public static final java.lang.Character.UnicodeBlock MUSICAL_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock MYANMAR;
+ field public static final java.lang.Character.UnicodeBlock MYANMAR_EXTENDED_A;
+ field public static final java.lang.Character.UnicodeBlock NEW_TAI_LUE;
+ field public static final java.lang.Character.UnicodeBlock NKO;
field public static final java.lang.Character.UnicodeBlock NUMBER_FORMS;
field public static final java.lang.Character.UnicodeBlock OGHAM;
field public static final java.lang.Character.UnicodeBlock OLD_ITALIC;
+ field public static final java.lang.Character.UnicodeBlock OLD_PERSIAN;
+ field public static final java.lang.Character.UnicodeBlock OLD_SOUTH_ARABIAN;
+ field public static final java.lang.Character.UnicodeBlock OLD_TURKIC;
+ field public static final java.lang.Character.UnicodeBlock OL_CHIKI;
field public static final java.lang.Character.UnicodeBlock OPTICAL_CHARACTER_RECOGNITION;
field public static final java.lang.Character.UnicodeBlock ORIYA;
field public static final java.lang.Character.UnicodeBlock OSMANYA;
+ field public static final java.lang.Character.UnicodeBlock PHAGS_PA;
+ field public static final java.lang.Character.UnicodeBlock PHAISTOS_DISC;
+ field public static final java.lang.Character.UnicodeBlock PHOENICIAN;
field public static final java.lang.Character.UnicodeBlock PHONETIC_EXTENSIONS;
+ field public static final java.lang.Character.UnicodeBlock PHONETIC_EXTENSIONS_SUPPLEMENT;
+ field public static final java.lang.Character.UnicodeBlock PLAYING_CARDS;
field public static final java.lang.Character.UnicodeBlock PRIVATE_USE_AREA;
+ field public static final java.lang.Character.UnicodeBlock REJANG;
+ field public static final java.lang.Character.UnicodeBlock RUMI_NUMERAL_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock RUNIC;
+ field public static final java.lang.Character.UnicodeBlock SAMARITAN;
+ field public static final java.lang.Character.UnicodeBlock SAURASHTRA;
field public static final java.lang.Character.UnicodeBlock SHAVIAN;
field public static final java.lang.Character.UnicodeBlock SINHALA;
field public static final java.lang.Character.UnicodeBlock SMALL_FORM_VARIANTS;
field public static final java.lang.Character.UnicodeBlock SPACING_MODIFIER_LETTERS;
field public static final java.lang.Character.UnicodeBlock SPECIALS;
+ field public static final java.lang.Character.UnicodeBlock SUNDANESE;
field public static final java.lang.Character.UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS;
field public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_ARROWS_A;
field public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_ARROWS_B;
field public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_MATHEMATICAL_OPERATORS;
+ field public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_PUNCTUATION;
field public static final java.lang.Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A;
field public static final java.lang.Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B;
field public static final deprecated java.lang.Character.UnicodeBlock SURROGATES_AREA;
+ field public static final java.lang.Character.UnicodeBlock SYLOTI_NAGRI;
field public static final java.lang.Character.UnicodeBlock SYRIAC;
field public static final java.lang.Character.UnicodeBlock TAGALOG;
field public static final java.lang.Character.UnicodeBlock TAGBANWA;
field public static final java.lang.Character.UnicodeBlock TAGS;
field public static final java.lang.Character.UnicodeBlock TAI_LE;
+ field public static final java.lang.Character.UnicodeBlock TAI_THAM;
+ field public static final java.lang.Character.UnicodeBlock TAI_VIET;
field public static final java.lang.Character.UnicodeBlock TAI_XUAN_JING_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock TAMIL;
field public static final java.lang.Character.UnicodeBlock TELUGU;
field public static final java.lang.Character.UnicodeBlock THAANA;
field public static final java.lang.Character.UnicodeBlock THAI;
field public static final java.lang.Character.UnicodeBlock TIBETAN;
+ field public static final java.lang.Character.UnicodeBlock TIFINAGH;
+ field public static final java.lang.Character.UnicodeBlock TRANSPORT_AND_MAP_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock UGARITIC;
field public static final java.lang.Character.UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS;
+ field public static final java.lang.Character.UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED;
+ field public static final java.lang.Character.UnicodeBlock VAI;
field public static final java.lang.Character.UnicodeBlock VARIATION_SELECTORS;
field public static final java.lang.Character.UnicodeBlock VARIATION_SELECTORS_SUPPLEMENT;
+ field public static final java.lang.Character.UnicodeBlock VEDIC_EXTENSIONS;
+ field public static final java.lang.Character.UnicodeBlock VERTICAL_FORMS;
field public static final java.lang.Character.UnicodeBlock YIJING_HEXAGRAM_SYMBOLS;
field public static final java.lang.Character.UnicodeBlock YI_RADICALS;
field public static final java.lang.Character.UnicodeBlock YI_SYLLABLES;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ffcc297..04ab0a5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -25,6 +25,7 @@
import android.os.Build.VERSION_CODES;
import android.os.Messenger;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.provider.Settings;
import java.net.InetAddress;
@@ -1309,4 +1310,67 @@
} catch (RemoteException e) {
}
}
+
+ /**
+ * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
+ */
+
+ /**
+ * No connection was possible to the network.
+ * {@hide}
+ */
+ public static final int CMP_RESULT_CODE_NO_CONNECTION = 0;
+
+ /**
+ * A connection was made to the internet, all is well.
+ * {@hide}
+ */
+ public static final int CMP_RESULT_CODE_CONNECTABLE = 1;
+
+ /**
+ * A connection was made but there was a redirection, we appear to be in walled garden.
+ * This is an indication of a warm sim on a mobile network.
+ * {@hide}
+ */
+ public static final int CMP_RESULT_CODE_REDIRECTED = 2;
+
+ /**
+ * A connection was made but no dns server was available to resolve a name to address.
+ * This is an indication of a warm sim on a mobile network.
+ *
+ * {@hide}
+ */
+ public static final int CMP_RESULT_CODE_NO_DNS = 3;
+
+ /**
+ * A connection was made but could not open a TCP connection.
+ * This is an indication of a warm sim on a mobile network.
+ * {@hide}
+ */
+ public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4;
+
+ /**
+ * Check mobile provisioning. The resultCode passed to
+ * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above.
+ * This may take a minute or more to complete.
+ *
+ * @param sendNotificaiton, when true a notification will be sent to user.
+ * @param suggestedTimeOutMs, timeout in milliseconds
+ * @param resultReceiver needs to be supplied to receive the result
+ *
+ * @return time out that will be used, maybe less that suggestedTimeOutMs
+ * -1 if an error.
+ *
+ * {@hide}
+ */
+ public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
+ ResultReceiver resultReceiver) {
+ int timeOutMs = -1;
+ try {
+ timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs,
+ resultReceiver);
+ } catch (RemoteException e) {
+ }
+ return timeOutMs;
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e5d6e51..3dbe078 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -24,6 +24,7 @@
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.ResultReceiver;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
@@ -131,4 +132,6 @@
void supplyMessenger(int networkType, in Messenger messenger);
int findConnectionTypeForIface(in String iface);
+
+ int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver);
}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index e85dbcd..5a1daed 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -494,6 +494,19 @@
}
/**
+ * Eanble/disable FailFast
+ *
+ * @param enabled is DctConstants.ENABLED/DISABLED
+ */
+ public void setEnableFailFastMobileData(int enabled) {
+ if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")");
+ final AsyncChannel channel = mDataConnectionTrackerAc;
+ if (channel != null) {
+ channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled);
+ }
+ }
+
+ /**
* carrier dependency is met/unmet
* @param met
*/
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 0a694c7..20e5011 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -194,6 +194,7 @@
libnetutils \
libui \
libgui \
+ libinput \
libcamera_client \
libskia \
libsqlite \
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 9fc01e1..f768ce8 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -25,7 +25,7 @@
#include <android_runtime/android_util_AssetManager.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/AndroidRuntime.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
#include <gui/Surface.h>
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 9fa9fe4..ce475e0 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -21,7 +21,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <binder/Parcel.h>
#include <utils/Log.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
#include "android_view_InputChannel.h"
#include "android_os_Parcel.h"
#include "android_util_Binder.h"
diff --git a/core/jni/android_view_InputChannel.h b/core/jni/android_view_InputChannel.h
index 0967021..2ba2dc0 100644
--- a/core/jni/android_view_InputChannel.h
+++ b/core/jni/android_view_InputChannel.h
@@ -19,7 +19,7 @@
#include "jni.h"
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
namespace android {
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index e3a54a8..8ef5d0b 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include <android_runtime/AndroidRuntime.h>
#include <nativehelper/jni.h>
diff --git a/core/jni/android_view_InputDevice.h b/core/jni/android_view_InputDevice.h
index 78651ba..ac38eb1 100644
--- a/core/jni/android_view_InputDevice.h
+++ b/core/jni/android_view_InputDevice.h
@@ -19,7 +19,7 @@
#include "jni.h"
-#include <androidfw/InputDevice.h>
+#include <input/InputDevice.h>
namespace android {
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 8e1e04a..b254de7 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -29,7 +29,7 @@
#include <utils/Looper.h>
#include <utils/Vector.h>
#include <utils/threads.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index b46eb4b..e4b65a1 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -29,7 +29,7 @@
#include <utils/Looper.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#include <androidfw/InputTransport.h>
+#include <input/InputTransport.h>
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index ec56afa..7532c9d 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -23,7 +23,7 @@
#include <android/input.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_InputQueue.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include <utils/Looper.h>
#include <utils/TypeHelpers.h>
#include <ScopedLocalRef.h>
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 3e56a89..ffe2dea 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -16,8 +16,8 @@
#include <android_runtime/AndroidRuntime.h>
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/Input.h>
+#include <input/KeyCharacterMap.h>
+#include <input/Input.h>
#include <binder/Parcel.h>
#include <nativehelper/jni.h>
diff --git a/core/jni/android_view_KeyCharacterMap.h b/core/jni/android_view_KeyCharacterMap.h
index 04024f6..e8465c2 100644
--- a/core/jni/android_view_KeyCharacterMap.h
+++ b/core/jni/android_view_KeyCharacterMap.h
@@ -19,7 +19,7 @@
#include "jni.h"
-#include <androidfw/KeyCharacterMap.h>
+#include <input/KeyCharacterMap.h>
namespace android {
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 36a98f9..17a0677 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -20,7 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include "android_view_KeyEvent.h"
namespace android {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index e69fb74..73c0683 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -20,7 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include "android_os_Parcel.h"
#include "android_view_MotionEvent.h"
#include "android_util_Binder.h"
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index c2fa3be..90ba2ba 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -20,8 +20,8 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <androidfw/Input.h>
-#include <androidfw/VelocityTracker.h>
+#include <input/Input.h>
+#include <input/VelocityTracker.h>
#include "android_view_MotionEvent.h"
#include <ScopedUtfChars.h>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d844076..7076922 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -783,6 +783,15 @@
<!-- IP address of the dns server to use if nobody else suggests one -->
<string name="config_default_dns_server" translatable="false">8.8.8.8</string>
+ <!-- The default mobile provisioning url. Empty by default, maybe overridden by
+ an mcc/mnc specific config.xml -->
+ <string name="mobile_provisioning_url" translatable="false"></string>
+
+ <!-- This url is used as the default url when redirection is detected. Any
+ should work as all url's get redirected. But maybe overridden by
+ if needed. -->
+ <string name="mobile_redirected_provisioning_url" translatable="false">http://google.com</string>
+
<!-- The default character set for GsmAlphabet -->
<!-- Empty string means MBCS is not considered -->
<string name="gsm_alphabet_default_charset" translatable="false"></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 38aa2a0..b58fcfc 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -682,6 +682,8 @@
<java-symbol type="string" name="preposition_for_time" />
<java-symbol type="string" name="progress_erasing" />
<java-symbol type="string" name="progress_unmounting" />
+ <java-symbol type="string" name="mobile_provisioning_url" />
+ <java-symbol type="string" name="mobile_redirected_provisioning_url" />
<java-symbol type="string" name="reboot_safemode_confirm" />
<java-symbol type="string" name="reboot_safemode_title" />
<java-symbol type="string" name="relationTypeAssistant" />
diff --git a/docs/downloads/training/BasicSyncAdapter.zip b/docs/downloads/training/BasicSyncAdapter.zip
new file mode 100644
index 0000000..25aa8bb
--- /dev/null
+++ b/docs/downloads/training/BasicSyncAdapter.zip
Binary files differ
diff --git a/docs/html/training/sync-adapters/creating-authenticator.jd b/docs/html/training/sync-adapters/creating-authenticator.jd
new file mode 100644
index 0000000..1b272e7
--- /dev/null
+++ b/docs/html/training/sync-adapters/creating-authenticator.jd
@@ -0,0 +1,290 @@
+page.title=Creating a Stub Authenticator
+
+trainingnavtop=true
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li>
+ <a href="#CreateAuthenticator">Add a Stub Authenticator Component</a>
+ </li>
+ <li>
+ <a href="#CreateAuthenticatorService">Bind the Authenticator to the Framework</a>
+ </li>
+ <li>
+ <a href="#CreateAuthenticatorFile">Add the Authenticator Metadata File</a>
+ </li>
+ <li>
+ <a href="#DeclareAuthenticator">Declare the Authenticator in the Manifest</a>
+ </li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/components/bound-services.html">Bound Services</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
+ <p class="filename">BasicSyncAdapter.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ The sync adapter framework assumes that your sync adapter transfers data between device storage
+ associated with an account and server storage that requires login access. For this reason, the
+ framework expects you to provide a component called an authenticator as part of your sync
+ adapter. This component plugs into the Android accounts and authentication framework and
+ provides a standard interface for handling user credentials such as login information.
+</p>
+<p>
+ Even if your app doesn't use accounts, you still need to provide an authenticator component.
+ If you don't use accounts or server login, the information handled by the authenticator is
+ ignored, so you can provide an authenticator component that contains stub method
+ implementations. You also need to provide a bound {@link android.app.Service} that
+ allows the sync adapter framework to call the authenticator's methods.
+</p>
+<p>
+ This lesson shows you how to define all the parts of a stub authenticator that you need to
+ satisfy the requirements of the sync adapter framework. If you need to provide a real
+ authenticator that handles user accounts, read the reference documentation for
+ {@link android.accounts.AbstractAccountAuthenticator}.
+</p>
+
+<h2 id="CreateAuthenticator">Add a Stub Authenticator Component</h2>
+<p>
+ To add a stub authenticator component to your app, create a class that extends
+ {@link android.accounts.AbstractAccountAuthenticator}, and then stub out the required methods,
+ either by returning {@code null} or by throwing an exception.
+</p>
+<p>
+ The following snippet shows an example of a stub authenticator class:
+</p>
+<pre>
+/*
+ * Implement AbstractAccountAuthenticator and stub out all
+ * of its methods
+ */
+public class Authenticator extends AbstractAccountAuthenticator {
+ // Simple constructor
+ public Authenticator(Context context) {
+ super(context);
+ }
+ // Editing properties is not supported
+ @Override
+ public Bundle editProperties(
+ AccountAuthenticatorResponse r, String s) {
+ throw new UnsupportedOperationException();
+ }
+ // Don't add additional accounts
+ @Override
+ public Bundle addAccount(
+ AccountAuthenticatorResponse r,
+ String s,
+ String s2,
+ String[] strings,
+ Bundle bundle) throws NetworkErrorException {
+ return null;
+ }
+ // Ignore attempts to confirm credentials
+ @Override
+ public Bundle confirmCredentials(
+ AccountAuthenticatorResponse r,
+ Account account,
+ Bundle bundle) throws NetworkErrorException {
+ return null;
+ }
+ // Getting an authentication token is not supported
+ @Override
+ public Bundle getAuthToken(
+ AccountAuthenticatorResponse r,
+ Account account,
+ String s,
+ Bundle bundle) throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+ // Getting a label for the auth token is not supported
+ @Override
+ public String getAuthTokenLabel(String s) {
+ throw new UnsupportedOperationException();
+ }
+ // Updating user credentials is not supported
+ @Override
+ public Bundle updateCredentials(
+ AccountAuthenticatorResponse r,
+ Account account,
+ String s, Bundle bundle) throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+ // Checking features for the account is not supported
+ @Override
+ public Bundle hasFeatures(
+ AccountAuthenticatorResponse r,
+ Account account, String[] strings) throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+}
+</pre>
+<h2 id="CreateAuthenticatorService">Bind the Authenticator to the Framework</h2>
+<p>
+ In order for the sync adapter framework to access your authenticator, you must create a bound
+ Service for it. This service provides an Android binder object that allows the framework
+ to call your authenticator and pass data between the authenticator and the framework.
+</p>
+<p>
+ Since the framework starts this {@link android.app.Service} the first time it needs to
+ access the authenticator, you can also use the service to instantiate the authenticator,
+ by calling the authenticator constructor in the
+ {@link android.app.Service#onCreate Service.onCreate()} method of the service.
+</p>
+<p>
+ The following snippet shows you how to define the bound {@link android.app.Service}:
+</p>
+<pre>
+/**
+ * A bound Service that instantiates the authenticator
+ * when started.
+ */
+public class AuthenticatorService extends Service {
+ ...
+ // Instance field that stores the authenticator object
+ private Authenticator mAuthenticator;
+ @Override
+ public void onCreate() {
+ // Create a new authenticator object
+ mAuthenticator = new Authenticator(this);
+ }
+ /*
+ * When the system binds to this Service to make the RPC call
+ * return the authenticator's IBinder.
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mAuthenticator.getIBinder();
+ }
+}
+</pre>
+
+<h2 id="CreateAuthenticatorFile">Add the Authenticator Metadata File</h2>
+<p>
+ To plug your authenticator component into the sync adapter and account frameworks, you need to
+ provide these framework with metadata that describes the component. This metadata declares the
+ account type you've created for your sync adapter and declares user interface elements
+ that the system displays if you want to make your account type visible to the user. Declare this
+ metadata in a XML file stored in the {@code /res/xml/} directory in your app project.
+ You can give any name to the file, although it's usually called {@code authenticator.xml}.
+</p>
+<p>
+ This XML file contains a single element <code><account-authenticator></code> that
+ has the following attributes:
+</p>
+<dl>
+ <dt>
+ <code>android:accountType</code>
+ </dt>
+ <dd>
+ The sync adapter framework requires each sync adapter to have an account type, in the form
+ of a domain name. The framework uses the account type as part of the sync adapter's
+ internal identification. For servers that require login, the account type along with a
+ user account is sent to the server as part of the login credentials.
+ <p>
+ If your server doesn't require login, you still have to provide an account type. For the
+ value, use a domain name that you control. While the framework uses it to manage your
+ sync adapter, the value is not sent to your server.
+ </p>
+ </dd>
+ <dt>
+ <code>android:icon</code>
+ </dt>
+ <dd>
+ Pointer to a <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable</a>
+ resource containing an icon. If you make the sync adapter visible by specifying the
+ attribute <code>android:userVisible="true"</code> in <code>res/xml/syncadapter.xml</code>,
+ then you must provide this icon resource. It appears in the <b>Accounts</b> section of
+ the system's Settings app.
+ </dd>
+ <dt>
+ <code>android:smallIcon</code>
+ </dt>
+ <dd>
+ Pointer to a <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable</a>
+ resource containing a small version of the icon. This resource may be used instead of
+ <code>android:icon</code> in the <b>Accounts</b> section of the system's Settings app,
+ depending on the screen size.
+ </dd>
+ <dt>
+ <code>android:label</code>
+ </dt>
+ <dd>
+ Localizable string that identifies the account type to users. If you make the sync adapter
+ visible by specifying the attribute <code>android:userVisible="true"</code> in
+ <code>res/xml/syncadapter.xml</code>, then you should provide this string. It appears in the
+ <b>Accounts</b> section of the system's Settings app, next to the icon you define for the
+ authenticator.
+ </dd>
+</dl>
+<p>
+ The following snippet shows the XML file for the authenticator you created previously:
+</p>
+<pre>the
+<?xml version="1.0" encoding="utf-8"?>
+<account-authenticator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="example.com"
+ android:icon="@drawable/ic_launcher"
+ android:smallIcon="@drawable/ic_launcher"
+ android:label="@string/app_name"/>
+</pre>
+
+<h2 id="DeclareAuthenticator">Declare the Authenticator in the Manifest</h2>
+<p>
+ In a previous step, you created a bound {@link android.app.Service} that links the authenticator
+ to the sync adapter framework. To identify this service to the system, declare it in your app
+ manifest by adding the following
+ <code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code>
+ element as a child element of
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>:
+</p>
+<pre>
+ <service
+ android:name="com.example.android.syncadapter.AuthenticatorService">
+ <intent-filter>
+ <action android:name="android.accounts.AccountAuthenticator"/>
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator" />
+ </service>
+</pre>
+<p>
+ The
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code>
+ element sets up a filter that's triggered by the intent action
+ {@code android.accounts.AccountAuthenticator}, which sent by the system to run the
+ authenticator. When the filter is triggered, the system starts {@code AuthenticatorService},
+ the bound {@link android.app.Service} you have provided to wrap the authenticator.
+</p>
+<p>
+ The
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code>
+ element declares the metadata for the authenticator. The
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
+ attribute links the meta-data to the authentication framework. The
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#rsrc">android:resource</a></code>
+ element specifies the name of the authenticator metadata file you created previously.
+</p>
+<p>
+ Besides an authenticator, a sync adapter also requires a content provider. If your app doesn't
+ use a content provider already, go to the next lesson to learn how to create a stub content
+ provider; otherwise, go to the lesson <a href="creating-sync-adapter.html"
+ >Creating a Sync Adapter</a>.
+</p>
diff --git a/docs/html/training/sync-adapters/creating-stub-provider.jd b/docs/html/training/sync-adapters/creating-stub-provider.jd
new file mode 100644
index 0000000..8f6eba0
--- /dev/null
+++ b/docs/html/training/sync-adapters/creating-stub-provider.jd
@@ -0,0 +1,203 @@
+page.title=Creating a Stub Content Provider
+
+trainingnavtop=true
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li>
+ <a href="#CreateProvider">Add a Stub Content Provider</a>
+ </li>
+ <li>
+ <a href="#DeclareProvider">Declare the Provider in the Manifest</a>
+ </li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"
+ >Content Provider Basics</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
+ <p class="filename">BasicSyncAdapter.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ The sync adapter framework is designed to work with device data managed by the flexible and
+ highly secure content provider framework. For this reason, the sync adapter framework expects
+ that an app that uses the framework has already defined a content provider for its local data.
+ If the sync adapter framework tries to run your sync adapter, and your app doesn't have a
+ content provider, your sync adapter crashes.
+</p>
+<p>
+ If you're developing a new app that transfers data from a server to the device, you should
+ strongly consider storing the local data in a content provider. Besides their importance for
+ sync adapters, content providers offer a variety of security benefits and are specifically
+ designed to handle data storage on Android systems. To learn more about creating a content
+ provider, see <a href="{@docRoot}guide/topics/providers/content-provider-creating.html"
+ >Creating a Content Provider</a>.
+</p>
+<p>
+ However, if you're already storing local data in another form, you can still use a sync
+ adapter to handle data transfer. To satisfy the sync adapter framework requirement for a
+ content provider, add a stub content provider to your app. A stub provider implements the
+ content provider class, but all of its required methods return {@code null} or {@code 0}. If you
+ add a stub provider, you can then use a sync adapter to transfer data from any storage
+ mechanism you choose.
+</p>
+<p>
+ If you already have a content provider in your app, you don't need a stub content provider.
+ In that case, you can skip this lesson and proceed to the lesson
+ <a href="creating-sync-adapter.html">Creating a Sync Adapter</a>. If you don't yet have a
+ content provider, this lesson shows you how to add a stub content provider that allows you to
+ plug your sync adapter into the framework.
+</p>
+<h2 id="CreateProvider">Add a Stub Content Provider</h2>
+<p>
+ To create a stub content provider for your app, extend the class
+ {@link android.content.ContentProvider} and stub out its required methods. The following
+ snippet shows you how to create the stub provider:
+</p>
+<pre>
+/*
+ * Define an implementation of ContentProvider that stubs out
+ * all methods
+ */
+public class StubProvider extends ContentProvider {
+ /*
+ * Always return true, indicating that the
+ * provider loaded correctly.
+ */
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+ /*
+ * Return an empty String for MIME type
+ */
+ @Override
+ public String getType() {
+ return new String();
+ }
+ /*
+ * query() always returns no results
+ *
+ */
+ @Override
+ public Cursor query(
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+ /*
+ * insert() always returns null (no URI)
+ */
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+ /*
+ * delete() always returns "no rows affected" (0)
+ */
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+ /*
+ * update() always returns "no rows affected" (0)
+ */
+ public int update(
+ Uri uri,
+ ContentValues values,
+ String selection,
+ String[] selectionArgs) {
+ return 0;
+ }
+}
+</pre>
+<h2 id="DeclareProvider">Declare the Provider in the Manifest</h2>
+<p>
+ The sync adapter framework verifies that your app has a content provider by checking that your
+ app has declared a provider in its app manifest. To declare the stub provider in the
+ manifest, add a <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
+ ><provider></a></code> element with the following attributes:
+</p>
+<dl>
+ <dt>
+ <code>android:name="com.example.android.datasync.provider.StubProvider"</code>
+ </dt>
+ <dd>
+ Specifies the fully-qualified name of the class that implements the stub content provider.
+ </dd>
+ <dt>
+ <code>android:authorities="com.example.android.datasync.provider"</code>
+ </dt>
+ <dd>
+ A URI authority that identifies the stub content provider. Make this value your app's
+ package name with the string ".provider" appended to it. Even though you're declaring your
+ stub provider to the system, nothing tries to access the provider itself.
+ </dd>
+ <dt>
+ <code>android:exported="false"</code>
+ </dt>
+ <dd>
+ Determines whether other apps can access the content provider. For your stub content
+ provider, set the value to {@code false}, since there's no need to allow other apps to see
+ the provider. This value doesn't affect the interaction between the sync adapter framework
+ and the content provider.
+ </dd>
+ <dt>
+ <code>android:syncable="true"</code>
+ </dt>
+ <dd>
+ Sets a flag that indicates that the provider is syncable. If you set this flag to
+ {@code true}, you don't have to call {@link android.content.ContentResolver#setIsSyncable
+ setIsSyncable()} in your code. The flag allows the sync adapter framework to make data
+ transfers with the content provider, but transfers only occur if you do them explicitly.
+ </dd>
+</dl>
+<p>
+ The following snippet shows you how to add the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
+ ><provider></a></code> element to the app manifest:
+</p>
+<pre>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.network.sync.BasicSyncAdapter"
+ android:versionCode="1"
+ android:versionName="1.0" >
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ ...
+ <provider
+ android:name="com.example.android.datasync.provider.StubProvider"
+ android:authorities="com.example.android.datasync.provider"
+ android:export="false"
+ android:syncable="true"/>
+ ...
+ </application>
+</manifest>
+</pre>
+<p>
+ Now that you have created the dependencies required by the sync adapter framework, you can
+ create the component that encapsulates your data transfer code. This component is called a
+ sync adapter. The next lesson shows you how to add this component to your app.
+</p>
diff --git a/docs/html/training/sync-adapters/creating-sync-adapter.jd b/docs/html/training/sync-adapters/creating-sync-adapter.jd
new file mode 100644
index 0000000..7c59c8c
--- /dev/null
+++ b/docs/html/training/sync-adapters/creating-sync-adapter.jd
@@ -0,0 +1,658 @@
+page.title=Creating a Sync Adapter
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li>
+ <a href="#CreateSyncAdapter"
+ >Create the Sync Adapter Class</a>
+ </li>
+ <li>
+ <a href="#CreateSyncAdapterService">Bind the Sync Adapter to the Framework</a>
+ </li>
+ <li>
+ <a href="#CreateAccountTypeAccount"
+ >Add the Account Required by the Framework</a>
+ </li>
+ <li>
+ <a href="#CreateSyncAdapterMetadata">Add the Sync Adapter Metadata File</a>
+ </li>
+ <li>
+ <a href="#DeclareSyncAdapterManifest">Declare the Sync Adapter in the Manifest</a>
+ </li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/components/bound-services.html">Bound Services</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
+ </li>
+ <li>
+ <a href="{@docRoot}training/id-auth/custom_auth.html">Creating a Custom Account Type</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
+ <p class="filename">BasicSyncAdapter.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ The sync adapter component in your app encapsulates the code for the tasks that transfer
+ data between the device and a server. Based on the scheduling and triggers you provide in
+ your app, the sync adapter framework runs the code in the sync adapter component. To add a
+ sync adapter component to your app, you need to add the following pieces:
+<dl>
+ <dt>
+ Sync adapter class.
+ </dt>
+ <dd>
+ A class that wraps your data transfer code in an interface compatible with the sync adapter
+ framework.
+ </dd>
+ <dt>
+ Bound {@link android.app.Service}.
+ </dt>
+ <dd>
+ A component that allows the sync adapter framework to run the code in your sync adapter
+ class.
+ </dd>
+ <dt>
+ Sync adapter XML metadata file.
+ </dt>
+ <dd>
+ A file containing information about your sync adapter. The framework reads this file to
+ find out how to load and schedule your data transfer.
+ </dd>
+ <dt>
+ Declarations in the app manifest.
+ </dt>
+ <dd>
+ XML that declares the bound service and points to sync adapter-specific metadata.
+ </dd>
+</dl>
+<p>
+ This lesson shows you how to define these elements.
+</p>
+<h2 id="CreateSyncAdapter">Create a Sync Adapter Class</h2>
+<p>
+ In this part of the lesson you learn how to create the sync adapter class that encapsulates the
+ data transfer code. Creating the class includes extending the sync adapter base class, defining
+ constructors for the class, and implementing the method where you define the data transfer
+ tasks.
+</p>
+<h3>Extend the base sync adapter class AbstractThreadedSyncAdapter</h3>
+<p>
+ To create the sync adapter component, start by extending
+ {@link android.content.AbstractThreadedSyncAdapter} and writing its constructors. Use the
+ constructors to run setup tasks each time your sync adapter component is created from
+ scratch, just as you use {@link android.app.Activity#onCreate Activity.onCreate()} to set up an
+ activity. For example, if your app uses a content provider to store data, use the constructors
+ to get a {@link android.content.ContentResolver} instance. Since a second form of the
+ constructor was added in Android platform version 3.0 to support the {@code parallelSyncs}
+ argument, you need to create two forms of the constructor to maintain compatibility.
+</p>
+<p class="note">
+ <strong>Note:</strong> The sync adapter framework is designed to work with sync adapter
+ components that are singleton instances. Instantiating the sync adapter component is covered
+ in more detail in the section
+ <a href="#CreateSyncAdapterService">Bind the Sync Adapter to the Framework</a>.
+</p>
+<p>
+ The following example shows you how to implement
+ {@link android.content.AbstractThreadedSyncAdapter}and its constructors:
+</p>
+<pre style="clear: right">
+/**
+ * Handle the transfer of data between a server and an
+ * app, using the Android sync adapter framework.
+ */
+public class SyncAdapter extends AbstractThreadedSyncAdapter {
+ ...
+ // Global variables
+ // Define a variable to contain a content resolver instance
+ ContentResolver mContentResolver;
+ /**
+ * Set up the sync adapter
+ */
+ public SyncAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ /*
+ * If your app uses a content resolver, get an instance of it
+ * from the incoming Context
+ */
+ mContentResolver = context.getContentResolver();
+ }
+ ...
+ /**
+ * Set up the sync adapter. This form of the
+ * constructor maintains compatibility with Android 3.0
+ * and later platform versions
+ */
+ public SyncAdapter(
+ Context context,
+ boolean autoInitialize,
+ boolean allowParallelSyncs) {
+ super(context, autoInitialize, allowParallelSyncs);
+ /*
+ * If your app uses a content resolver, get an instance of it
+ * from the incoming Context
+ */
+ mContentResolver = context.getContentResolver();
+ ...
+ }
+</pre>
+<h3>Add the data transfer code to onPerformSync()</h3>
+<p>
+ The sync adapter component does not automatically do data transfer. Instead, it
+ encapsulates your data transfer code, so that the sync adapter framework can run the
+ data transfer in the background, without involvement from your app. When the framework is ready
+ to sync your application's data, it invokes your implementation of the method
+ {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}.
+</p>
+<p>
+ To facilitate the transfer of data from your main app code to the sync adapter component,
+ the sync adapter framework calls
+ {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} with the
+ following arguments:
+</p>
+<dl>
+ <dt>
+ Account
+ </dt>
+ <dd>
+ An {@link android.accounts.Account} object associated with the event that triggered
+ the sync adapter. If your server doesn't use accounts, you don't need to use the
+ information in this object.
+ </dd>
+ <dt>
+ Extras
+ </dt>
+ <dd>
+ A {@link android.os.Bundle} containing flags sent by the event that triggered the sync
+ adapter.
+ </dd>
+ <dt>
+ Authority
+ </dt>
+ <dd>
+ The authority of a content provider in the system. Your app has to have access to
+ this provider. Usually, the authority corresponds to a content provider in your own app.
+ </dd>
+ <dt>
+ Content provider client
+ </dt>
+ <dd>
+ A {@link android.content.ContentProviderClient} for the content provider pointed to by the
+ authority argument. A {@link android.content.ContentProviderClient} is a lightweight public
+ interface to a content provider. It has the same basic functionality as a
+ {@link android.content.ContentResolver}. If you're using a content provider to store data
+ for your app, you can connect to the provider with this object. Otherwise, you can ignore
+ it.
+ </dd>
+ <dt>
+ Sync result
+ </dt>
+ <dd>
+ A {@link android.content.SyncResult} object that you use to send information to the sync
+ adapter framework.
+ </dd>
+</dl>
+<p>
+ The following snippet shows the overall structure of
+ {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}:
+</p>
+<pre>
+ /*
+ * Specify the code you want to run in the sync adapter. The entire
+ * sync adapter runs in a background thread, so you don't have to set
+ * up your own background processing.
+ */
+ @Override
+ public void onPerformSync(
+ Account account,
+ Bundle extras,
+ String authority,
+ ContentProviderClient provider,
+ SyncResult syncResult) {
+ /*
+ * Put the data transfer code here.
+ */
+ ...
+ }
+</pre>
+<p>
+ While the actual implementation of
+ {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} is specific to
+ your app's data synchronization requirements and server connection protocols, there are a few
+ general tasks your implementation should perform:
+</p>
+<dl>
+ <dt>
+ Connecting to a server
+ </dt>
+ <dd>
+ Although you can assume that the network is available when your data transfer starts, the
+ sync adapter framework doesn't automatically connect to a server.
+ </dd>
+ <dt>
+ Downloading and uploading data
+ </dt>
+ <dd>
+ A sync adapter doesn't automate any data transfer tasks. If you want to download
+ data from a server and store it in a content provider, you have to provide the code that
+ requests the data, downloads it, and inserts it in the provider. Similarly, if you want to
+ send data to a server, you have to read it from a file, database, or provider, and send
+ the necessary upload request. You also have to handle network errors that occur while your
+ data transfer is running.
+ </dd>
+ <dt>
+ Handling data conflicts or determining how current the data is
+ </dt>
+ <dd>
+ A sync adapter doesn't automatically handle conflicts between data on the server and data
+ on the device. Also, it doesn't automatically detect if the data on the server is newer than
+ the data on the device, or vice versa. Instead, you have to provide your own algorithms for
+ handling this situation.
+ </dd>
+ <dt>
+ Clean up.
+ </dt>
+ <dd>
+ Always close connections to a server and clean up temp files and caches at the end of
+ your data transfer.
+ </dd>
+</dl>
+<p class="note">
+ <strong>Note:</strong> The sync adapter framework runs
+ {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} on a
+ background thread, so you don't have to set up your own background processing.
+</p>
+<p>
+ In addition to your sync-related tasks, you should try to combine your regular
+ network-related tasks and add them to
+ {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}.
+ By concentrating all of your network tasks in this method, you conserve the battery power that's
+ needed to start and stop the network interfaces. To learn more about making network access more
+ efficient, see the training class <a href="{@docRoot}training/efficient-downloads/index.html"
+ >Transferring Data Without Draining the Battery</a>, which describes several network access
+ tasks you can include in your data transfer code.
+</p>
+<h2 id="CreateSyncAdapterService">Bind the Sync Adapter to the Framework</h2>
+<p>
+ You now have your data transfer code encapsulated in a sync adapter component, but you have
+ to provide the framework with access to your code. To do this, you need to create a bound
+ {@link android.app.Service} that passes a special Android binder object from the sync adapter
+ component to the framework. With this binder object, the framework can invoke the
+ {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} method and
+ pass data to it.
+</p>
+<p>
+ Instantiate your sync adapter component as a singleton in the
+ {@link android.app.Service#onCreate onCreate()} method of the service. By instantiating
+ the component in {@link android.app.Service#onCreate onCreate()}, you defer
+ creating it until the service starts, which happens when the framework first tries to run your
+ data transfer. You need to instantiate the component in a thread-safe manner, in case the sync
+ adapter framework queues up multiple executions of your sync adapter in response to triggers or
+ scheduling.
+</p>
+<p>
+ For example, the following snippet shows you how to create a class that implements the
+ bound {@link android.app.Service}, instantiates your sync adapter component, and gets the
+ Android binder object:
+</p>
+<pre>
+package com.example.android.syncadapter;
+/**
+ * Define a Service that returns an {@link android.os.IBinder} for the
+ * sync adapter class, allowing the sync adapter framework to call
+ * onPerformSync().
+ */
+public class SyncService extends Service {
+ // Storage for an instance of the sync adapter
+ private static SyncAdapter sSyncAdapter = null;
+ // Object to use as a thread-safe lock
+ private static final Object sSyncAdapterLock = new Object();
+ /*
+ * Instantiate the sync adapter object.
+ */
+ @Override
+ public void onCreate() {
+ /*
+ * Create the sync adapter as a singleton.
+ * Set the sync adapter as syncable
+ * Disallow parallel syncs
+ */
+ synchronized (sSyncAdapterLock) {
+ if (sSyncAdapter == null) {
+ sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
+ }
+ }
+ }
+ /**
+ * Return an object that allows the system to invoke
+ * the sync adapter.
+ *
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ /*
+ * Get the object that allows external processes
+ * to call onPerformSync(). The object is created
+ * in the base class code when the SyncAdapter
+ * constructors call super()
+ */
+ return sSyncAdapter.getSyncAdapterBinder();
+ }
+}
+</pre>
+<p class="note">
+ <strong>Note:</strong> To see a more detailed example of a bound service for a sync adapter,
+ see the sample app.
+</p>
+<h2 id="CreateAccountTypeAccount">Add the Account Required by the Framework</h2>
+<p>
+ The sync adapter framework requires each sync adapter to have an account type. You declared
+ the account type value in the section
+ <a href="creating-authenticator.html#CreateAuthenticatorFile"
+ >Add the Authenticator Metadata File</a>. Now you have to set up this account type in the
+ Android system. To set up the account type, add a dummy account that uses the account type
+ by calling {@link android.accounts.AccountManager#addAccountExplicitly addAccountExplicitly()}.
+</p>
+<p>
+ The best place to call the method is in the
+ {@link android.support.v4.app.FragmentActivity#onCreate onCreate()} method of your app's
+ opening activity. The following code snippet shows you how to do this:
+</p>
+<pre>
+public class MainActivity extends FragmentActivity {
+ ...
+ ...
+ // Constants
+ // The authority for the sync adapter's content provider
+ public static final String AUTHORITY = "com.example.android.datasync.provider"
+ // An account type, in the form of a domain name
+ public static final String ACCOUNT_TYPE = "example.com";
+ // The account name
+ public static final String ACCOUNT = "dummyaccount";
+ // Instance fields
+ Account mAccount;
+ ...
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ...
+ // Create the dummy account
+ mAccount = CreateSyncAccount(this);
+ ...
+ }
+ ...
+ /**
+ * Create a new dummy account for the sync adapter
+ *
+ * @param context The application context
+ */
+ public static Account CreateSyncAccount(Context context) {
+ // Create the account type and default account
+ Account newAccount = new Account(
+ ACCOUNT, ACCOUNT_TYPE);
+ // Get an instance of the Android account manager
+ AccountManager accountManager =
+ (AccountManager) context.getSystemService(
+ ACCOUNT_SERVICE);
+ /*
+ * Add the account and account type, no password or user data
+ * If successful, return the Account object, otherwise report an error.
+ */
+ if (accountManager.addAccountExplicitly(newAccount, null, null))) {
+ /*
+ * If you don't set android:syncable="true" in
+ * in your <provider> element in the manifest,
+ * then call context.setIsSyncable(account, AUTHORITY, 1)
+ * here.
+ */
+ } else {
+ /*
+ * The account exists or some other error occurred. Log this, report it,
+ * or handle it internally.
+ */
+ }
+ }
+ ...
+}
+</pre>
+<h2 id="CreateSyncAdapterMetadata">Add the Sync Adapter Metadata File</h2>
+<p>
+ To plug your sync adapter component into the framework, you need to provide the framework
+ with metadata that describes the component and provides additional flags. The metadata specifies
+ the account type you've created for your sync adapter, declares a content provider authority
+ associated with your app, controls a part of the system user interface related to sync adapters,
+ and declares other sync-related flags. Declare this metadata in a special XML file stored in
+ the {@code /res/xml/} directory in your app project. You can give any name to the file,
+ although it's usually called {@code syncadapter.xml}.
+</p>
+<p>
+ This XML file contains a single XML element <code><sync-adapter></code> that has the
+ following attributes:
+</p>
+<dl>
+ <dt><code>android:contentAuthority</code></dt>
+ <dd>
+ The URI authority for your content provider. If you created a stub content provider for
+ your app in the previous lesson <a href="creating-stub-provider.html"
+ >Creating a Stub Content Provider</a>, use the value you specified for the
+ attribute
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">android:authorities</a></code>
+ in the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
+ ><provider></a></code> element you added to your app manifest. This attribute is
+ described in more detail in the section
+ <a href="creating-stub-provider.html#DeclareProvider"
+ >Declare the Provider in the Manifest</a>.
+ <br/>
+ If you're transferring data from a content provider to a server with your sync adapter, this
+ value should be the same as the content URI authority you're using for that data. This value
+ is also one of the authorities you specify in the
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">android:authorities</a></code>
+ attribute of the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
+ ><provider></a></code> element that declares your provider in your app manifest.
+ </dd>
+ <dt><code>android:accountType</code></dt>
+ <dd>
+ The account type required by the sync adapter framework. The value must be the same
+ as the account type value you provided when you created the authenticator metadata file, as
+ described in the section <a href="creating-authenticator.html#CreateAuthenticatorFile"
+ >Add the Authenticator Metadata File</a>. It's also the value you specified for the
+ constant {@code ACCOUNT_TYPE} in the code snippet in the section
+ <a href="#CreateAccountTypeAccount">Add the Account Required by the Framework</a>.
+ </dd>
+ <dt>Settings attributes</dt>
+ <dd>
+ <dl>
+ <dt>
+ {@code android:userVisible}
+ </dt>
+ <dd>
+ Sets the visibility of the sync adapter's account type. By default, the
+ account icon and label associated with the account type are visible in the
+ <b>Accounts</b> section of the system's Settings app, so you should make your sync
+ adapter invisible unless you have an account type or domain that's easily associated
+ with your app. If you make your account type invisible, you can still allow users to
+ control your sync adapter with a user interface in one of your app's activities.
+ </dd>
+ <dt>
+ {@code android:supportsUploading}
+ </dt>
+ <dd>
+ Allows you to upload data to the cloud. Set this to {@code false} if your app only
+ downloads data.
+ </dd>
+ <dt>
+ {@code android:allowParallelSyncs}
+ </dt>
+ <dd>
+ Allows multiple instances of your sync adapter component to run at the same time.
+ Use this if your app supports multiple user accounts and you want to allow multiple
+ users to transfer data in parallel. This flag has no effect if you never run
+ multiple data transfers.
+ </dd>
+ <dt>
+ {@code android:isAlwaysSyncable}
+ </dt>
+ <dd>
+ Indicates to the sync adapter framework that it can run your sync adapter at any
+ time you've specified. If you want to programmatically control when your sync
+ adapter can run, set this flag to {@code false}, and then call
+ {@link android.content.ContentResolver#requestSync requestSync()} to run the
+ sync adapter. To learn more about running a sync adapter, see the lesson
+ <a href="running-sync-adapter.html">Running a Sync Adapter</a>
+ </dd>
+ </dl>
+ </dd>
+</dl>
+<p>
+ The following example shows the XML for a sync adapter that uses a single dummy account and
+ only does downloads.
+</p>
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<sync-adapter
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:contentAuthority="com.example.android.datasync.provider"
+ android:accountType="com.android.example.datasync"
+ android:userVisible="false"
+ android:supportsUploading="false"
+ android:allowParallelSyncs="false"
+ android:isAlwaysSyncable="true"/>
+</pre>
+
+<h2 id="DeclareSyncAdapterManifest">Declare the Sync Adapter in the Manifest</h2>
+<p>
+ Once you've added the sync adapter component to your app, you have to request permissions
+ related to using the component, and you have to declare the bound {@link android.app.Service}
+ you've added.
+</p>
+<p>
+ Since the sync adapter component runs code that transfers data between the network and the
+ device, you need to request permission to access the Internet. In addition, your app needs
+ to request permission to read and write sync adapter settings, so you can control the sync
+ adapter programmatically from other components in your app. You also need to request a
+ special permission that allows your app to use the authenticator component you created
+ in the lesson <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
+</p>
+<p>
+ To request these permissions, add the following to your app manifest as child elements of
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>:
+</p>
+<dl>
+ <dt>
+ {@link android.Manifest.permission#INTERNET android.permission.INTERNET}
+ </dt>
+ <dd>
+ Allows the sync adapter code to access the Internet so that it can download or upload data
+ from the device to a server. You don't need to add this permission again if you were
+ requesting it previously.
+ </dd>
+ <dt>
+{@link android.Manifest.permission#READ_SYNC_SETTINGS android.permission.READ_SYNC_SETTINGS}
+ </dt>
+ <dd>
+ Allows your app to read the current sync adapter settings. For example, you need this
+ permission in order to call {@link android.content.ContentResolver#getIsSyncable
+ getIsSyncable()}.
+ </dd>
+ <dt>
+{@link android.Manifest.permission#WRITE_SYNC_SETTINGS android.permission.WRITE_SYNC_SETTINGS}
+ </dt>
+ <dd>
+ Allows your app to control sync adapter settings. You need this permission in order to
+ set periodic sync adapter runs using {@link android.content.ContentResolver#addPeriodicSync
+ addPeriodicSync()}. This permission is <b>not</b> required to call
+ {@link android.content.ContentResolver#requestSync requestSync()}. To learn more about
+ running the sync adapter, see <a href="running-sync-adapter.html"
+ >Running A Sync Adapter</a>.
+ </dd>
+ <dt>
+{@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS android.permission.AUTHENTICATE_ACCOUNTS}
+ </dt>
+ <dd>
+ Allows you to use the authenticator component you created in the lesson
+ <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
+ </dd>
+</dl>
+<p>
+ The following snippet shows how to add the permissions:
+</p>
+<pre>
+<manifest>
+...
+ <uses-permission
+ android:name="android.permission.INTERNET"/>
+ <uses-permission
+ android:name="android.permission.READ_SYNC_SETTINGS"/>
+ <uses-permission
+ android:name="android.permission.WRITE_SYNC_SETTINGS"/>
+ <uses-permission
+ android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
+...
+</manifest>
+</pre>
+<p>
+ Finally, to declare the bound {@link android.app.Service} that the framework uses to
+ interact with your sync adapter, add the following XML to your app manifest as a child element
+ of <code><a href="{@docRoot}guide/topics/manifest/application-element.html"
+ ><application></a></code>:
+</p>
+<pre>
+ <service
+ android:name="com.example.android.datasync.SyncService"
+ android:exported="true"
+ android:process=":sync">
+ <intent-filter>com.example.android.datasync.provider
+ <action android:name="android.content.SyncAdapter"/>
+ </intent-filter>
+ <meta-data android:name="android.content.SyncAdapter"
+ android:resource="@xml/syncadapter" />
+ </service>
+</pre>
+<p>
+ The
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code>
+ element sets up a filter that's triggered by the intent action
+ {@code android.content.SyncAdapter}, sent by the system to run the sync adapter. When the filter
+ is triggered, the system starts the bound service you've created, which in this example is
+ {@code SyncService}. The attribute
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html#exported">android:exported="true"</a></code>
+ allows processes other than your app (including the system) to access the
+ {@link android.app.Service}. The attribute
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html#proc">android:process=":sync"</a></code>
+ tells the system to run the {@link android.app.Service} in a global shared process named
+ {@code sync}. If you have multiple sync adapters in your app they can share this process,
+ which reduces overhead.
+</p>
+<p>
+ The
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code>
+ element provides provides the name of the sync adapter metadata XML file you created previously.
+ The
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
+ attribute indicates that this metadata is for the sync adapter framework. The
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#rsrc">android:resource</a></code>
+ element specifies the name of the metadata file.
+</p>
+<p>
+ You now have all of the components for your sync adapter. The next lesson shows you how to
+ tell the sync adapter framework to run your sync adapter, either in response to an event or on
+ a regular schedule.
+</p>
diff --git a/docs/html/training/sync-adapters/index.jd b/docs/html/training/sync-adapters/index.jd
new file mode 100644
index 0000000..1f7977b
--- /dev/null
+++ b/docs/html/training/sync-adapters/index.jd
@@ -0,0 +1,135 @@
+page.title=Transferring Data Using Sync Adapters
+
+trainingnavtop=true
+startpage=true
+
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 3.0 (API Level 11) or higher</li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/components/bound-services.html">Bound Services</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
+ </li>
+ <li>
+ <a href="{@docRoot}training/id-auth/custom_auth.html">Creating a Custom Account Type</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
+ <p class="filename">BasicSyncAdapter.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ Synchronizing data between an Android device and web servers can make your application
+ significantly more useful and compelling for your users. For example, transferring data to a web
+ server makes a useful backup, and transferring data from a server makes it available to the user
+ even when the device is offline. In some cases, users may find it easier to enter and edit their
+ data in a web interface and then have that data available on their device, or they may want to
+ collect data over time and then upload it to a central storage area.
+</p>
+<p>
+ Although you can design your own system for doing data transfers in your app, you should
+ consider using Android's sync adapter framework. This framework helps manage and automate data
+ transfers, and coordinates synchronization operations across different apps. When you use
+ this framework, you can take advantage of several features that aren't available to data
+ transfer schemes you design yourself:
+</p>
+<dl>
+ <dt>
+ Plug-in architecture
+ </dt>
+ <dd>
+ Allows you to add data transfer code to the system in the form of callable components.
+ </dd>
+ <dt>
+ Automated execution
+ </dt>
+ <dd>
+ Allows you to automate data transfer based on a variety of criteria, including data changes,
+ elapsed time, or time of day. In addition, the system adds transfers that are unable to
+ run to a queue, and runs them when possible.
+ </dd>
+ <dt>
+ Automated network checking
+ </dt>
+ <dd>
+ The system only runs your data transfer when the device has network connectivity.
+ </dd>
+ <dt>
+ Improved battery performance
+ </dt>
+ <dd>
+ Allows you to centralize all of your app's data transfer tasks in one place, so that they
+ all run at the same time. Your data transfer is also scheduled in conjunction with data
+ transfers from other apps. These factors reduce the number of times the system has to
+ switch on the network, which reduces battery usage.
+ </dd>
+ <dt>
+ Account management and authentication
+ </dt>
+ <dd>
+ If your app requires user credentials or server login, you can optionally
+ integrate account management and authentication into your data transfer.
+ </dd>
+</dl>
+<p>
+ This class shows you how to create a sync adapter and the bound {@link android.app.Service} that
+ wraps it, how to provide the other components that help you plug the sync adapter into the
+ framework, and how to run the sync adapter to run in various ways.
+</p>
+<p class="note">
+ <strong>Note:</strong> Sync adapters run asynchronously, so you should use them with the
+ expectation that they transfer data regularly and efficiently, but not instantaneously. If
+ you need to do real-time data transfer, you should do it in an {@link android.os.AsyncTask} or
+ an {@link android.app.IntentService}.
+</p>
+<h2>Lessons</h2>
+<dl>
+ <dt>
+ <b><a href="creating-authenticator.html">Creating a Stub Authenticator</a></b>
+ </dt>
+ <dd>
+ Learn how to add an account-handling component that the sync adapter framework expects to be
+ part of your app. This lesson shows you how to create a stub authentication component for
+ simplicity.
+ </dd>
+ <dt>
+ <b><a href="creating-stub-provider.html">Creating a Stub Content Provider</a></b>
+ </dt>
+ <dd>
+ Learn how to add a content provider component that the sync adapter framework expects to be
+ part of your app. This lesson assumes that your app doesn't use a content provider, so it
+ shows you how to add a stub component. If you have a content provider already in your app,
+ you can skip this lesson.
+ </dd>
+ <dt>
+ <b><a href="creating-sync-adapter.html">Creating a Sync Adapter</a></b>
+ </dt>
+ <dd>
+ Learn how to encapsulate your data transfer code in a component that the sync
+ adapter framework can run automatically.
+ </dd>
+ <dt>
+ <b><a href="running-sync-adapter.html">Running a Sync Adapter</a></b>
+ </dt>
+ <dd>
+ Learn how to trigger and schedule data transfers using the sync adapter framework.
+ </dd>
+</dl>
diff --git a/docs/html/training/sync-adapters/running-sync-adapter.jd b/docs/html/training/sync-adapters/running-sync-adapter.jd
new file mode 100644
index 0000000..8fb7e80c
--- /dev/null
+++ b/docs/html/training/sync-adapters/running-sync-adapter.jd
@@ -0,0 +1,524 @@
+page.title=Running a Sync Adapter
+
+trainingnavtop=true
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you how to:</h2>
+<ol>
+ <li><a href="#RunByMessage">Run the Sync Adapter When Server Data Changes</a>
+ <li><a href="#RunDataChange">Run the Sync Adapter When Content Provider Data Changes</a></li>
+ <li><a href="#RunByNetwork">Run the Sync Adapter After a Network Message</a></li>
+ <li><a href="#RunPeriodic">Run the Sync Adapter Periodically</a></li>
+ <li><a href="#RunOnDemand">Run the Sync Adapter On Demand</a></li>
+</ol>
+
+
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
+ <p class="filename">BasicSyncAdapter.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ In the previous lessons in this class, you learned how to create a sync adapter component that
+ encapsulates data transfer code, and how to add the additional components that allow you to
+ plug the sync adapter into the system. You now have everything you need to install an app that
+ includes a sync adapter, but none of the code you've seen actually runs the sync adapter.
+</p>
+<p>
+ You should try to run your sync adapter based on a schedule or as the indirect result of some
+ event. For example, you may want your sync adapter to run on a regular schedule, either after a
+ certain period of time or at a particular time of the day. You may also want to run your sync
+ adapter when there are changes to data stored on the device. You should avoid running your
+ sync adapter as the direct result of a user action, because by doing this you don't get the full
+ benefit of the sync adapter framework's scheduling ability. For example, you should avoid
+ providing a refresh button in your user interface.
+</p>
+<p>
+ You have the following options for running your sync adapter:
+</p>
+<dl>
+ <dt>
+ When server data changes
+ </dt>
+ <dd>
+ Run the sync adapter in response to a message from a server, indicating that server-based
+ data has changed. This option allows you to refresh data from the server to the device
+ without degrading performance or wasting battery life by polling the server.
+ </dd>
+ <dt>When device data changes</dt>
+ <dd>
+ Run a sync adapter when data changes on the device. This option allows you to send
+ modified data from the device to a server, and is especially useful if you need to ensure
+ that the server always has the latest device data. This option is straightforward to
+ implement if you actually store data in your content provider. If you're using a stub
+ content provider, detecting data changes may be more difficult.
+ </dd>
+ <dt>
+ When the system sends out a network message
+ </dt>
+ <dd>
+ Run a sync adapter when the Android system sends out a network message that keeps the
+ TCP/IP connection open; this message is a basic part of the networking framework. Using
+ this option is one way to run the sync adapter automatically. Consider using it in
+ conjunction with interval-based sync adapter runs.
+ </dd>
+ <dt>
+ At regular intervals
+ </dt>
+ <dd>
+ Run a sync adapter after the expiration of an interval you choose, or run it at a certain
+ time every day.
+ </dd>
+ <dt>On demand</dt>
+ <dd>
+ Run the sync adapter in response to a user action. However, to provide the best user
+ experience you should rely primarily on one of the more automated options. By using
+ automated options, you conserve battery and network resources.
+ </dd>
+</dl>
+<p>
+ The rest of this lesson describes each of the options in more detail.
+</p>
+<h2 id="RunByMessage">Run the Sync Adapter When Server Data Changes</h2>
+<p>
+ If your app transfers data from a server and the server data changes frequently, you can use
+ a sync adapter to do downloads in response to data changes. To run the sync adapter, have
+ the server send a special message to a {@link android.content.BroadcastReceiver} in your app.
+ In response to this message, call {@link android.content.ContentResolver#requestSync
+ ContentResolver.requestSync()} to signal the sync adapter framework to run your
+ sync adapter.
+</p>
+<p>
+ <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> (GCM) provides both the
+ server and device components you need to make this messaging system work. Using GCM to trigger
+ transfers is more reliable and more efficient than polling servers for status. While polling
+ requires a {@link android.app.Service} that is always active, GCM uses a
+ {@link android.content.BroadcastReceiver} that's activated when a message arrives. While polling
+ at regular intervals uses battery power even if no updates are available, GCM only sends
+ messages when needed.
+</p>
+<p class="note">
+ <strong>Note:</strong> If you use GCM to trigger your sync adapter via a broadcast to all
+ devices where your app is installed, remember that they receive your message at
+ roughly the same time. This situation can cause multiple instance of your sync adapter to run
+ at the same time, causing server and network overload. To avoid this situation for a broadcast
+ to all devices, you should consider deferring the start of the sync adapter for a period
+ that's unique for each device.
+<p>
+ The following code snippet shows you how to run
+ {@link android.content.ContentResolver#requestSync requestSync()} in response to an
+ incoming GCM message:
+</p>
+<pre>
+public class GcmBroadcastReceiver extends BroadcastReceiver {
+ ...
+ // Constants
+ // Content provider authority
+ public static final String AUTHORITY = "com.example.android.datasync.provider"
+ // Account type
+ public static final String ACCOUNT_TYPE = "com.example.android.datasync";
+ // Account
+ public static final String ACCOUNT = "default_account";
+ // Incoming Intent key for extended data
+ public static final String KEY_SYNC_REQUEST =
+ "com.example.android.datasync.KEY_SYNC_REQUEST";
+ ...
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Get a GCM object instance
+ GoogleCloudMessaging gcm =
+ GoogleCloudMessaging.getInstance(context);
+ // Get the type of GCM message
+ String messageType = gcm.getMessageType(intent);
+ /*
+ * Test the message type and examine the message contents.
+ * Since GCM is a general-purpose messaging system, you
+ * may receive normal messages that don't require a sync
+ * adapter run.
+ * The following code tests for a a boolean flag indicating
+ * that the message is requesting a transfer from the device.
+ */
+ if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)
+ &&
+ intent.getBooleanExtra(KEY_SYNC_REQUEST)) {
+ /*
+ * Signal the framework to run your sync adapter. Assume that
+ * app initialization has already created the account.
+ */
+ ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
+ ...
+ }
+ ...
+ }
+ ...
+}
+</pre>
+<h2 id="RunDataChange">Run the Sync Adapter When Content Provider Data Changes</h2>
+<p>
+ If your app collects data in a content provider, and you want to update the server whenever
+ you update the provider, you can set up your app to run your sync adapter automatically. To do
+ this, you register an observer for the content provider. When data in your content provider
+ changes, the content provider framework calls the observer. In the observer, call
+ {@link android.content.ContentResolver#requestSync requestSync()} to tell the framework to run
+ your sync adapter.
+</p>
+<p class="note">
+ <strong>Note:</strong> If you're using a stub content provider, you don't have any data in
+ the content provider and {@link android.database.ContentObserver#onChange onChange()} is
+ never called. In this case, you have to provide your own mechanism for detecting changes to
+ device data. This mechanism is also responsible for calling
+ {@link android.content.ContentResolver#requestSync requestSync()} when the data changes.
+</p>
+<p>
+ To create an observer for your content provider, extend the class
+ {@link android.database.ContentObserver} and implement both forms of its
+ {@link android.database.ContentObserver#onChange onChange()} method. In
+ {@link android.database.ContentObserver#onChange onChange()}, call
+ {@link android.content.ContentResolver#requestSync requestSync()} to start the sync adapter.
+</p>
+<p>
+ To register the observer, pass it as an argument in a call to
+ {@link android.content.ContentResolver#registerContentObserver registerContentObserver()}. In
+ this call, you also have to pass in a content URI for the data you want to watch. The content
+ provider framework compares this watch URI to content URIs passed in as arguments to
+ {@link android.content.ContentResolver} methods that modify your provider, such as
+ {@link android.content.ContentResolver#insert ContentResolver.insert()}. If there's a match, your
+ implementation of {@link android.database.ContentObserver#onChange ContentObserver.onChange()}
+ is called.
+</p>
+
+<p>
+ The following code snippet shows you how to define a {@link android.database.ContentObserver}
+ that calls {@link android.content.ContentResolver#requestSync requestSync()} when a table
+ changes:
+</p>
+<pre>
+public class MainActivity extends FragmentActivity {
+ ...
+ // Constants
+ // Content provider scheme
+ public static final String SCHEME = "content://";
+ // Content provider authority
+ public static final String AUTHORITY = "com.example.android.datasync.provider";
+ // Path for the content provider table
+ public static final String TABLE_PATH = "data_table";
+ // Account
+ public static final String ACCOUNT = "default_account";
+ // Global variables
+ // A content URI for the content provider's data table
+ Uri mUri;
+ // A content resolver for accessing the provider
+ ContentResolver mResolver;
+ ...
+ public class TableObserver extends ContentObserver {
+ /*
+ * Define a method that's called when data in the
+ * observed content provider changes.
+ * This method signature is provided for compatibility with
+ * older platforms.
+ */
+ @Override
+ public void onChange(boolean selfChange) {
+ /*
+ * Invoke the method signature available as of
+ * Android platform version 4.1, with a null URI.
+ */
+ onChange(selfChange, null);
+ }
+ /*
+ * Define a method that's called when data in the
+ * observed content provider changes.
+ */
+ @Override
+ public void onChange(boolean selfChange, Uri changeUri) {
+ /*
+ * Ask the framework to run your sync adapter.
+ * To maintain backward compatibility, assume that
+ * changeUri is null.
+ ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
+ }
+ ...
+ }
+ ...
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ...
+ // Get the content resolver object for your app
+ mResolver = getContentResolver();
+ // Construct a URI that points to the content provider data table
+ mUri = new Uri.Builder()
+ .scheme(SCHEME)
+ .authority(AUTHORITY)
+ .path(TABLE_PATH)
+ .build();
+ /*
+ * Create a content observer object.
+ * Its code does not mutate the provider, so set
+ * selfChange to "false"
+ */
+ TableObserver observer = new TableObserver(false);
+ /*
+ * Register the observer for the data table. The table's path
+ * and any of its subpaths trigger the observer.
+ */
+ mResolver.registerContentObserver(mUri, true, observer);
+ ...
+ }
+ ...
+}
+</pre>
+<h2 id="RunByNetwork">Run the Sync Adapter After a Network Message</h2>
+<p>
+ When a network connection is available, the Android system sends out a message
+ every few seconds to keep the device's TCP/IP connection open. This message also goes to
+ the {@link android.content.ContentResolver} of each app. By calling
+ {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()},
+ you can run the sync adapter whenever the {@link android.content.ContentResolver}
+ receives the message.
+</p>
+<p>
+ By scheduling your sync adapter to run when the network message is sent, you ensure that your
+ sync adapter is always scheduled to run while the network is available. Use this option if you
+ don't have to force a data transfer in response to data changes, but you do want to ensure
+ your data is regularly updated. Similarly, you can use this option if you don't want a fixed
+ schedule for your sync adapter, but you do want it to run frequently.
+</p>
+<p>
+ Since the method
+ {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()}
+ doesn't disable {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}, your
+ sync adapter may be triggered repeatedly in a short period of time. If you do want to run
+ your sync adapter periodically on a regular schedule, you should disable
+ {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()}.
+</p>
+<p>
+ The following code snippet shows you how to configure your
+ {@link android.content.ContentResolver} to run your sync adapter in response to a network
+ message:
+</p>
+<pre>
+public class MainActivity extends FragmentActivity {
+ ...
+ // Constants
+ // Content provider authority
+ public static final String AUTHORITY = "com.example.android.datasync.provider";
+ // Account
+ public static final String ACCOUNT = "default_account";
+ // Global variables
+ // A content resolver for accessing the provider
+ ContentResolver mResolver;
+ ...
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ...
+ // Get the content resolver for your app
+ mResolver = getContentResolver();
+ // Turn on automatic syncing for the default account and authority
+ mResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, true);
+ ...
+ }
+ ...
+}
+</pre>
+<h2 id="RunPeriodic">Run the Sync Adapter Periodically</h2>
+<p>
+ You can run your sync adapter periodically by setting a period of time to wait between runs,
+ or by running it at certain times of the day, or both. Running your sync adapter
+ periodically allows you to roughly match the update interval of your server.
+</p>
+<p>
+ Similarly, you can upload data from the device when your server is relatively idle, by
+ scheduling your sync adapter to run at night. Most users leave their powered on and plugged in
+ at night, so this time is usually available. Moreover, the device is not running other tasks at
+ the same time as your sync adapter. If you take this approach, however, you need to ensure that
+ each device triggers a data transfer at a slightly different time. If all devices run your
+ sync adapter at the same time, you are likely to overload your server and cell provider data
+ networks.
+</p>
+<p>
+ In general, periodic runs make sense if your users don't need instant updates, but expect to
+ have regular updates. Periodic runs also make sense if you want to balance the availability of
+ up-to-date data with the efficiency of smaller sync adapter runs that don't over-use device
+ resources.
+</p>
+<p>
+ To run your sync adapter at regular intervals, call
+ {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}. This schedules your
+ sync adapter to run after a certain amount of time has elapsed. Since the sync adapter framework
+ has to account for other sync adapter executions and tries to maximize battery efficiency, the
+ elapsed time may vary by a few seconds. Also, the framework won't run your sync adapter if the
+ network is not available.
+</p>
+<p>
+ Notice that {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()} doesn't
+ run the sync adapter at a particular time of day. To run your sync adapter at roughly the
+ same time every day, use a repeating alarm as a trigger. Repeating alarms are described in more
+ detail in the reference documentation for {@link android.app.AlarmManager}. If you use the
+ method {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} to set
+ time-of-day triggers that have some variation, you should still randomize the start time to
+ ensure that sync adapter runs from different devices are staggered.
+</p>
+<p>
+ The method {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()} doesn't
+ disable {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()},
+ so you may get multiple sync runs in a relatively short period of time. Also, only a few
+ sync adapter control flags are allowed in a call to
+ {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}; the flags that are
+ not allowed are described in the referenced documentation for
+ {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}.
+</p>
+<p>
+ The following code snippet shows you how to schedule periodic sync adapter runs:
+</p>
+<pre>
+public class MainActivity extends FragmentActivity {
+ ...
+ // Constants
+ // Content provider authority
+ public static final String AUTHORITY = "com.example.android.datasync.provider";
+ // Account
+ public static final String ACCOUNT = "default_account";
+ // Sync interval constants
+ public static final long MILLISECONDS_PER_SECOND = 1000L;
+ public static final long SECONDS_PER_MINUTE = 60L;
+ public static final long SYNC_INTERVAL_IN_MINUTES = 60L;
+ public static final long SYNC_INTERVAL =
+ SYNC_INTERVAL_IN_MINUTES *
+ SECONDS_PER_MINUTE *
+ MILLISECONDS_PER_SECOND;
+ // Global variables
+ // A content resolver for accessing the provider
+ ContentResolver mResolver;
+ ...
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ...
+ // Get the content resolver for your app
+ mResolver = getContentResolver();
+ /*
+ * Turn on periodic syncing
+ */
+ ContentResolver.addPeriodicSync(
+ ACCOUNT,
+ AUTHORITY,
+ null,
+ SYNC_INTERVAL);
+ ...
+ }
+ ...
+}
+</pre>
+<h2 id="RunOnDemand">Run the Sync Adapter On Demand</h2>
+<p>
+ Running your sync adapter in response to a user request is the least preferable strategy
+ for running a sync adapter. The framework is specifically designed to conserve battery power
+ when it runs sync adapters according to a schedule. Options that run a sync in response to data
+ changes use battery power effectively, since the power is used to provide new data.
+</p>
+<p>
+ In comparison, allowing users to run a sync on demand means that the sync runs by itself, which
+ is inefficient use of network and power resources. Also, providing sync on demand leads users to
+ request a sync even if there's no evidence that the data has changed, and running a sync that
+ doesn't refresh data is an ineffective use of battery power. In general, your app should either
+ use other signals to trigger a sync or schedule them at regular intervals, without user input.
+</p>
+<p>
+ However, if you still want to run the sync adapter on demand, set the sync adapter flags for a
+ manual sync adapter run, then call
+ {@link android.content.ContentResolver#requestSync ContentResolver.requestSync()}.
+</p>
+<p>
+ Run on demand transfers with the following flags:
+</p>
+<dl>
+ <dt>
+ {@link android.content.ContentResolver#SYNC_EXTRAS_MANUAL SYNC_EXTRAS_MANUAL}
+ </dt>
+ <dd>
+ Forces a manual sync. The sync adapter framework ignores the existing settings,
+ such as the flag set by {@link android.content.ContentResolver#setSyncAutomatically
+ setSyncAutomatically()}.
+ </dd>
+ <dt>
+ {@link android.content.ContentResolver#SYNC_EXTRAS_EXPEDITED SYNC_EXTRAS_EXPEDITED}
+ </dt>
+ <dd>
+ Forces the sync to start immediately. If you don't set this, the system may wait several
+ seconds before running the sync request, because it tries to optimize battery use by
+ scheduling many requests in a short period of time.
+ </dd>
+</dl>
+<p>
+ The following code snippet shows you how to call
+ {@link android.content.ContentResolver#requestSync requestSync()} in response to a button
+ click:
+</p>
+<pre>
+public class MainActivity extends FragmentActivity {
+ ...
+ // Constants
+ // Content provider authority
+ public static final String AUTHORITY =
+ "com.example.android.datasync.provider"
+ // Account type
+ public static final String ACCOUNT_TYPE = "com.example.android.datasync";
+ // Account
+ public static final String ACCOUNT = "default_account";
+ // Instance fields
+ Account mAccount;
+ ...
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ...
+ /*
+ * Create the dummy account. The code for CreateSyncAccount
+ * is listed in the lesson Creating a Sync Adapter
+ */
+
+ mAccount = CreateSyncAccount(this);
+ ...
+ }
+ /**
+ * Respond to a button click by calling requestSync(). This is an
+ * asynchronous operation.
+ *
+ * This method is attached to the refresh button in the layout
+ * XML file
+ *
+ * @param v The View associated with the method call,
+ * in this case a Button
+ */
+ public void onRefreshButtonClick(View v) {
+ ...
+ // Pass the settings flags by inserting them in a bundle
+ Bundle settingsBundle = new Bundle();
+ settingsBundle.putBoolean(
+ ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ settingsBundle.putBoolean(
+ ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ /*
+ * Request the sync for the default account, authority, and
+ * manual sync settings
+ */
+ ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);
+ }
+</pre>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 58db404..cb57752 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -475,6 +475,37 @@
</a>
</li>
</li>
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/sync-adapters/index.html"
+ description="How to transfer data between the cloud and the device using the Android
+ sync adapter framework"
+ >Transferring Data Using Sync Adapters</a>
+ </div>
+ <ul>
+ <li>
+ <a href="<?cs var:toroot ?>training/sync-adapters/creating-authenticator.html">
+ Creating a Stub Authenticator
+ </a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/sync-adapters/creating-stub-provider.html">
+ Creating a Stub Content Provider
+ </a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/sync-adapters/creating-sync-adapter.html">
+ Creating a Sync Adapter
+ </a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/sync-adapters/running-sync-adapter.html">
+ Running a Sync Adapter
+ </a>
+ </li>
+ </ul>
+ </li>
+
</ul>
</li>
<!-- End connectivity and cloud -->
diff --git a/include/android_runtime/android_view_InputQueue.h b/include/android_runtime/android_view_InputQueue.h
index ba2d02d..ed37b0a 100644
--- a/include/android_runtime/android_view_InputQueue.h
+++ b/include/android_runtime/android_view_InputQueue.h
@@ -17,7 +17,7 @@
#ifndef _ANDROID_VIEW_INPUTQUEUE_H
#define _ANDROID_VIEW_INPUTQUEUE_H
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include <utils/Looper.h>
#include <utils/TypeHelpers.h>
#include <utils/Vector.h>
diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h
deleted file mode 100644
index 37ab279..0000000
--- a/include/androidfw/Input.h
+++ /dev/null
@@ -1,622 +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 _ANDROIDFW_INPUT_H
-#define _ANDROIDFW_INPUT_H
-
-/**
- * Native input event structures.
- */
-
-#include <android/input.h>
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-
-#ifdef HAVE_ANDROID_OS
-class SkMatrix;
-#endif
-
-/*
- * Additional private constants not defined in ndk/ui/input.h.
- */
-enum {
- /* Signifies that the key is being predispatched */
- AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000,
-
- /* Private control to determine when an app is tracking a key sequence. */
- AKEY_EVENT_FLAG_START_TRACKING = 0x40000000,
-
- /* Key event is inconsistent with previously sent key events. */
- AKEY_EVENT_FLAG_TAINTED = 0x80000000,
-};
-
-enum {
- /* Motion event is inconsistent with previously sent motion events. */
- AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
-};
-
-enum {
- /* Used when a motion event is not associated with any display.
- * Typically used for non-pointer events. */
- ADISPLAY_ID_NONE = -1,
-
- /* The default display id. */
- ADISPLAY_ID_DEFAULT = 0,
-};
-
-enum {
- /*
- * Indicates that an input device has switches.
- * This input source flag is hidden from the API because switches are only used by the system
- * and applications have no way to interact with them.
- */
- AINPUT_SOURCE_SWITCH = 0x80000000,
-};
-
-/*
- * SystemUiVisibility constants from View.
- */
-enum {
- ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
- ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
-};
-
-/*
- * Maximum number of pointers supported per motion event.
- * Smallest number of pointers is 1.
- * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
- * will occasionally emit 11. There is not much harm making this constant bigger.)
- */
-#define MAX_POINTERS 16
-
-/*
- * Maximum pointer id value supported in a motion event.
- * Smallest pointer id is 0.
- * (This is limited by our use of BitSet32 to track pointer assignments.)
- */
-#define MAX_POINTER_ID 31
-
-/*
- * Declare a concrete type for the NDK's input event forward declaration.
- */
-struct AInputEvent {
- virtual ~AInputEvent() { }
-};
-
-/*
- * Declare a concrete type for the NDK's input device forward declaration.
- */
-struct AInputDevice {
- virtual ~AInputDevice() { }
-};
-
-
-namespace android {
-
-#ifdef HAVE_ANDROID_OS
-class Parcel;
-#endif
-
-/*
- * Flags that flow alongside events in the input dispatch system to help with certain
- * policy decisions such as waking from device sleep.
- *
- * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java.
- */
-enum {
- /* These flags originate in RawEvents and are generally set in the key map.
- * NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */
-
- POLICY_FLAG_WAKE = 0x00000001,
- POLICY_FLAG_WAKE_DROPPED = 0x00000002,
- POLICY_FLAG_SHIFT = 0x00000004,
- POLICY_FLAG_CAPS_LOCK = 0x00000008,
- POLICY_FLAG_ALT = 0x00000010,
- POLICY_FLAG_ALT_GR = 0x00000020,
- POLICY_FLAG_MENU = 0x00000040,
- POLICY_FLAG_LAUNCHER = 0x00000080,
- POLICY_FLAG_VIRTUAL = 0x00000100,
- POLICY_FLAG_FUNCTION = 0x00000200,
-
- POLICY_FLAG_RAW_MASK = 0x0000ffff,
-
- /* These flags are set by the input dispatcher. */
-
- // Indicates that the input event was injected.
- POLICY_FLAG_INJECTED = 0x01000000,
-
- // Indicates that the input event is from a trusted source such as a directly attached
- // input device or an application with system-wide event injection permission.
- POLICY_FLAG_TRUSTED = 0x02000000,
-
- // Indicates that the input event has passed through an input filter.
- POLICY_FLAG_FILTERED = 0x04000000,
-
- // Disables automatic key repeating behavior.
- POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000,
-
- /* 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.
- POLICY_FLAG_WOKE_HERE = 0x10000000,
-
- // Indicates that the screen was dim when the event was received and the event
- // should brighten the device.
- POLICY_FLAG_BRIGHT_HERE = 0x20000000,
-
- // Indicates that the event should be dispatched to applications.
- // The input event should still be sent to the InputDispatcher so that it can see all
- // input events received include those that it will not deliver.
- POLICY_FLAG_PASS_TO_USER = 0x40000000,
-};
-
-/*
- * Pointer coordinate data.
- */
-struct PointerCoords {
- enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64
-
- // Bitfield of axes that are present in this structure.
- uint64_t bits;
-
- // Values of axes that are stored in this structure packed in order by axis id
- // for each axis that is present in the structure according to 'bits'.
- float values[MAX_AXES];
-
- inline void clear() {
- bits = 0;
- }
-
- float getAxisValue(int32_t axis) const;
- status_t setAxisValue(int32_t axis, float value);
-
- void scale(float scale);
-
- inline float getX() const {
- return getAxisValue(AMOTION_EVENT_AXIS_X);
- }
-
- inline float getY() const {
- return getAxisValue(AMOTION_EVENT_AXIS_Y);
- }
-
-#ifdef HAVE_ANDROID_OS
- status_t readFromParcel(Parcel* parcel);
- status_t writeToParcel(Parcel* parcel) const;
-#endif
-
- bool operator==(const PointerCoords& other) const;
- inline bool operator!=(const PointerCoords& other) const {
- return !(*this == other);
- }
-
- void copyFrom(const PointerCoords& other);
-
-private:
- void tooManyAxes(int axis);
-};
-
-/*
- * Pointer property data.
- */
-struct PointerProperties {
- // The id of the pointer.
- int32_t id;
-
- // The pointer tool type.
- int32_t toolType;
-
- inline void clear() {
- id = -1;
- toolType = 0;
- }
-
- bool operator==(const PointerProperties& other) const;
- inline bool operator!=(const PointerProperties& other) const {
- return !(*this == other);
- }
-
- void copyFrom(const PointerProperties& other);
-};
-
-/*
- * Input events.
- */
-class InputEvent : public AInputEvent {
-public:
- virtual ~InputEvent() { }
-
- virtual int32_t getType() const = 0;
-
- inline int32_t getDeviceId() const { return mDeviceId; }
-
- inline int32_t getSource() const { return mSource; }
-
- inline void setSource(int32_t source) { mSource = source; }
-
-protected:
- void initialize(int32_t deviceId, int32_t source);
- void initialize(const InputEvent& from);
-
- int32_t mDeviceId;
- int32_t mSource;
-};
-
-/*
- * Key events.
- */
-class KeyEvent : public InputEvent {
-public:
- virtual ~KeyEvent() { }
-
- virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; }
-
- inline int32_t getAction() const { return mAction; }
-
- inline int32_t getFlags() const { return mFlags; }
-
- inline void setFlags(int32_t flags) { mFlags = flags; }
-
- inline int32_t getKeyCode() const { return mKeyCode; }
-
- inline int32_t getScanCode() const { return mScanCode; }
-
- inline int32_t getMetaState() const { return mMetaState; }
-
- inline int32_t getRepeatCount() const { return mRepeatCount; }
-
- inline nsecs_t getDownTime() const { return mDownTime; }
-
- inline nsecs_t getEventTime() const { return mEventTime; }
-
- // Return true if this event may have a default action implementation.
- static bool hasDefaultAction(int32_t keyCode);
- bool hasDefaultAction() const;
-
- // Return true if this event represents a system key.
- static bool isSystemKey(int32_t keyCode);
- bool isSystemKey() const;
-
- void initialize(
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t keyCode,
- int32_t scanCode,
- int32_t metaState,
- int32_t repeatCount,
- nsecs_t downTime,
- nsecs_t eventTime);
- void initialize(const KeyEvent& from);
-
-protected:
- int32_t mAction;
- int32_t mFlags;
- int32_t mKeyCode;
- int32_t mScanCode;
- int32_t mMetaState;
- int32_t mRepeatCount;
- nsecs_t mDownTime;
- nsecs_t mEventTime;
-};
-
-/*
- * Motion events.
- */
-class MotionEvent : public InputEvent {
-public:
- virtual ~MotionEvent() { }
-
- virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; }
-
- inline int32_t getAction() const { return mAction; }
-
- inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
-
- inline int32_t getActionIndex() const {
- return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
- >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
- }
-
- inline void setAction(int32_t action) { mAction = action; }
-
- inline int32_t getFlags() const { return mFlags; }
-
- inline void setFlags(int32_t flags) { mFlags = flags; }
-
- inline int32_t getEdgeFlags() const { return mEdgeFlags; }
-
- inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; }
-
- inline int32_t getMetaState() const { return mMetaState; }
-
- inline void setMetaState(int32_t metaState) { mMetaState = metaState; }
-
- inline int32_t getButtonState() const { return mButtonState; }
-
- inline float getXOffset() const { return mXOffset; }
-
- inline float getYOffset() const { return mYOffset; }
-
- inline float getXPrecision() const { return mXPrecision; }
-
- inline float getYPrecision() const { return mYPrecision; }
-
- inline nsecs_t getDownTime() const { return mDownTime; }
-
- inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
-
- inline size_t getPointerCount() const { return mPointerProperties.size(); }
-
- inline const PointerProperties* getPointerProperties(size_t pointerIndex) const {
- return &mPointerProperties[pointerIndex];
- }
-
- inline int32_t getPointerId(size_t pointerIndex) const {
- return mPointerProperties[pointerIndex].id;
- }
-
- inline int32_t getToolType(size_t pointerIndex) const {
- return mPointerProperties[pointerIndex].toolType;
- }
-
- inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
-
- const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
-
- float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
-
- inline float getRawX(size_t pointerIndex) const {
- return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
- }
-
- inline float getRawY(size_t pointerIndex) const {
- return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
- }
-
- float getAxisValue(int32_t axis, size_t pointerIndex) const;
-
- inline float getX(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
- }
-
- inline float getY(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
- }
-
- inline float getPressure(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex);
- }
-
- inline float getSize(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex);
- }
-
- inline float getTouchMajor(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex);
- }
-
- inline float getTouchMinor(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex);
- }
-
- inline float getToolMajor(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex);
- }
-
- inline float getToolMinor(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex);
- }
-
- inline float getOrientation(size_t pointerIndex) const {
- return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex);
- }
-
- inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; }
-
- inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const {
- return mSampleEventTimes[historicalIndex];
- }
-
- const PointerCoords* getHistoricalRawPointerCoords(
- size_t pointerIndex, size_t historicalIndex) const;
-
- float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
- size_t historicalIndex) const;
-
- inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalRawAxisValue(
- AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalRawAxisValue(
- AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
- }
-
- float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const;
-
- inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex);
- }
-
- inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const {
- return getHistoricalAxisValue(
- AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex);
- }
-
- ssize_t findPointerIndex(int32_t pointerId) const;
-
- void initialize(
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- size_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords);
-
- void copyFrom(const MotionEvent* other, bool keepHistory);
-
- void addSample(
- nsecs_t eventTime,
- const PointerCoords* pointerCoords);
-
- void offsetLocation(float xOffset, float yOffset);
-
- void scale(float scaleFactor);
-
-#ifdef HAVE_ANDROID_OS
- void transform(const SkMatrix* matrix);
-
- status_t readFromParcel(Parcel* parcel);
- status_t writeToParcel(Parcel* parcel) const;
-#endif
-
- static bool isTouchEvent(int32_t source, int32_t action);
- inline bool isTouchEvent() const {
- return isTouchEvent(mSource, mAction);
- }
-
- // Low-level accessors.
- inline const PointerProperties* getPointerProperties() const {
- return mPointerProperties.array();
- }
- inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
- inline const PointerCoords* getSamplePointerCoords() const {
- return mSamplePointerCoords.array();
- }
-
-protected:
- int32_t mAction;
- int32_t mFlags;
- int32_t mEdgeFlags;
- int32_t mMetaState;
- int32_t mButtonState;
- float mXOffset;
- float mYOffset;
- float mXPrecision;
- float mYPrecision;
- nsecs_t mDownTime;
- Vector<PointerProperties> mPointerProperties;
- Vector<nsecs_t> mSampleEventTimes;
- Vector<PointerCoords> mSamplePointerCoords;
-};
-
-/*
- * Input event factory.
- */
-class InputEventFactoryInterface {
-protected:
- virtual ~InputEventFactoryInterface() { }
-
-public:
- InputEventFactoryInterface() { }
-
- virtual KeyEvent* createKeyEvent() = 0;
- virtual MotionEvent* createMotionEvent() = 0;
-};
-
-/*
- * A simple input event factory implementation that uses a single preallocated instance
- * of each type of input event that are reused for each request.
- */
-class PreallocatedInputEventFactory : public InputEventFactoryInterface {
-public:
- PreallocatedInputEventFactory() { }
- virtual ~PreallocatedInputEventFactory() { }
-
- virtual KeyEvent* createKeyEvent() { return & mKeyEvent; }
- virtual MotionEvent* createMotionEvent() { return & mMotionEvent; }
-
-private:
- KeyEvent mKeyEvent;
- MotionEvent mMotionEvent;
-};
-
-/*
- * An input event factory implementation that maintains a pool of input events.
- */
-class PooledInputEventFactory : public InputEventFactoryInterface {
-public:
- PooledInputEventFactory(size_t maxPoolSize = 20);
- virtual ~PooledInputEventFactory();
-
- virtual KeyEvent* createKeyEvent();
- virtual MotionEvent* createMotionEvent();
-
- void recycle(InputEvent* event);
-
-private:
- const size_t mMaxPoolSize;
-
- Vector<KeyEvent*> mKeyEventPool;
- Vector<MotionEvent*> mMotionEventPool;
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_INPUT_H
diff --git a/include/androidfw/InputDevice.h b/include/androidfw/InputDevice.h
deleted file mode 100644
index 45dc2db..0000000
--- a/include/androidfw/InputDevice.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2012 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 _ANDROIDFW_INPUT_DEVICE_H
-#define _ANDROIDFW_INPUT_DEVICE_H
-
-#include <androidfw/Input.h>
-#include <androidfw/KeyCharacterMap.h>
-
-namespace android {
-
-/*
- * Identifies a device.
- */
-struct InputDeviceIdentifier {
- inline InputDeviceIdentifier() :
- bus(0), vendor(0), product(0), version(0) {
- }
-
- // Information provided by the kernel.
- String8 name;
- String8 location;
- String8 uniqueId;
- uint16_t bus;
- uint16_t vendor;
- uint16_t product;
- uint16_t version;
-
- // A composite input device descriptor string that uniquely identifies the device
- // even across reboots or reconnections. The value of this field is used by
- // upper layers of the input system to associate settings with individual devices.
- // It is hashed from whatever kernel provided information is available.
- // Ideally, the way this value is computed should not change between Android releases
- // because that would invalidate persistent settings that rely on it.
- String8 descriptor;
-};
-
-/*
- * Describes the characteristics and capabilities of an input device.
- */
-class InputDeviceInfo {
-public:
- InputDeviceInfo();
- InputDeviceInfo(const InputDeviceInfo& other);
- ~InputDeviceInfo();
-
- struct MotionRange {
- int32_t axis;
- uint32_t source;
- float min;
- float max;
- float flat;
- float fuzz;
- float resolution;
- };
-
- void initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier,
- const String8& alias, bool isExternal);
-
- inline int32_t getId() const { return mId; }
- inline int32_t getGeneration() const { return mGeneration; }
- inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; }
- inline const String8& getAlias() const { return mAlias; }
- inline const String8& getDisplayName() const {
- return mAlias.isEmpty() ? mIdentifier.name : mAlias;
- }
- inline bool isExternal() const { return mIsExternal; }
- inline uint32_t getSources() const { return mSources; }
-
- const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
-
- void addSource(uint32_t source);
- void addMotionRange(int32_t axis, uint32_t source,
- float min, float max, float flat, float fuzz, float resolution);
- void addMotionRange(const MotionRange& range);
-
- inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
- inline int32_t getKeyboardType() const { return mKeyboardType; }
-
- inline void setKeyCharacterMap(const sp<KeyCharacterMap>& value) {
- mKeyCharacterMap = value;
- }
-
- inline sp<KeyCharacterMap> getKeyCharacterMap() const {
- return mKeyCharacterMap;
- }
-
- inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
- inline bool hasVibrator() const { return mHasVibrator; }
-
- inline const Vector<MotionRange>& getMotionRanges() const {
- return mMotionRanges;
- }
-
-private:
- int32_t mId;
- int32_t mGeneration;
- InputDeviceIdentifier mIdentifier;
- String8 mAlias;
- bool mIsExternal;
- uint32_t mSources;
- int32_t mKeyboardType;
- sp<KeyCharacterMap> mKeyCharacterMap;
- bool mHasVibrator;
-
- Vector<MotionRange> mMotionRanges;
-};
-
-/* Types of input device configuration files. */
-enum InputDeviceConfigurationFileType {
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
-};
-
-/*
- * Gets the path of an input device configuration file, if one is available.
- * Considers both system provided and user installed configuration files.
- *
- * The device identifier is used to construct several default configuration file
- * names to try based on the device name, vendor, product, and version.
- *
- * Returns an empty string if not found.
- */
-extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
- const InputDeviceIdentifier& deviceIdentifier,
- InputDeviceConfigurationFileType type);
-
-/*
- * Gets the path of an input device configuration file, if one is available.
- * Considers both system provided and user installed configuration files.
- *
- * The name is case-sensitive and is used to construct the filename to resolve.
- * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
- *
- * Returns an empty string if not found.
- */
-extern String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type);
-
-} // namespace android
-
-#endif // _ANDROIDFW_INPUT_DEVICE_H
diff --git a/include/androidfw/InputTransport.h b/include/androidfw/InputTransport.h
deleted file mode 100644
index 8712995..0000000
--- a/include/androidfw/InputTransport.h
+++ /dev/null
@@ -1,443 +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 _ANDROIDFW_INPUT_TRANSPORT_H
-#define _ANDROIDFW_INPUT_TRANSPORT_H
-
-/**
- * Native input transport.
- *
- * The InputChannel provides a mechanism for exchanging InputMessage structures across processes.
- *
- * The InputPublisher and InputConsumer each handle one end-point of an input channel.
- * The InputPublisher is used by the input dispatcher to send events to the application.
- * The InputConsumer is used by the application to receive events from the input dispatcher.
- */
-
-#include <androidfw/Input.h>
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/BitSet.h>
-
-namespace android {
-
-/*
- * Intermediate representation used to send input events and related signals.
- */
-struct InputMessage {
- enum {
- TYPE_KEY = 1,
- TYPE_MOTION = 2,
- TYPE_FINISHED = 3,
- };
-
- struct Header {
- uint32_t type;
- uint32_t padding; // 8 byte alignment for the body that follows
- } header;
-
- union Body {
- struct Key {
- uint32_t seq;
- nsecs_t eventTime;
- int32_t deviceId;
- int32_t source;
- int32_t action;
- int32_t flags;
- int32_t keyCode;
- int32_t scanCode;
- int32_t metaState;
- int32_t repeatCount;
- nsecs_t downTime;
-
- inline size_t size() const {
- return sizeof(Key);
- }
- } key;
-
- struct Motion {
- uint32_t seq;
- nsecs_t eventTime;
- int32_t deviceId;
- int32_t source;
- int32_t action;
- int32_t flags;
- int32_t metaState;
- int32_t buttonState;
- int32_t edgeFlags;
- nsecs_t downTime;
- float xOffset;
- float yOffset;
- float xPrecision;
- float yPrecision;
- size_t pointerCount;
- struct Pointer {
- PointerProperties properties;
- PointerCoords coords;
- } pointers[MAX_POINTERS];
-
- int32_t getActionId() const {
- uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
- >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
- return pointers[index].properties.id;
- }
-
- inline size_t size() const {
- return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
- + sizeof(Pointer) * pointerCount;
- }
- } motion;
-
- struct Finished {
- uint32_t seq;
- bool handled;
-
- inline size_t size() const {
- return sizeof(Finished);
- }
- } finished;
- } body;
-
- bool isValid(size_t actualSize) const;
- size_t size() const;
-};
-
-/*
- * An input channel consists of a local unix domain socket used to send and receive
- * input messages across processes. Each channel has a descriptive name for debugging purposes.
- *
- * Each endpoint has its own InputChannel object that specifies its file descriptor.
- *
- * The input channel is closed when all references to it are released.
- */
-class InputChannel : public RefBase {
-protected:
- virtual ~InputChannel();
-
-public:
- InputChannel(const String8& name, int fd);
-
- /* Creates a pair of input channels.
- *
- * Returns OK on success.
- */
- static status_t openInputChannelPair(const String8& name,
- sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
-
- inline String8 getName() const { return mName; }
- inline int getFd() const { return mFd; }
-
- /* Sends a message to the other endpoint.
- *
- * If the channel is full then the message is guaranteed not to have been sent at all.
- * Try again after the consumer has sent a finished signal indicating that it has
- * consumed some of the pending messages from the channel.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if the channel is full.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Other errors probably indicate that the channel is broken.
- */
- status_t sendMessage(const InputMessage* msg);
-
- /* Receives a message sent by the other endpoint.
- *
- * If there is no message present, try again after poll() indicates that the fd
- * is readable.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no message present.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Other errors probably indicate that the channel is broken.
- */
- status_t receiveMessage(InputMessage* msg);
-
- /* Returns a new object that has a duplicate of this channel's fd. */
- sp<InputChannel> dup() const;
-
-private:
- String8 mName;
- int mFd;
-};
-
-/*
- * Publishes input events to an input channel.
- */
-class InputPublisher {
-public:
- /* Creates a publisher associated with an input channel. */
- explicit InputPublisher(const sp<InputChannel>& channel);
-
- /* Destroys the publisher and releases its input channel. */
- ~InputPublisher();
-
- /* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
-
- /* Publishes a key event to the input channel.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if the channel is full.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Returns BAD_VALUE if seq is 0.
- * Other errors probably indicate that the channel is broken.
- */
- status_t publishKeyEvent(
- uint32_t seq,
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t keyCode,
- int32_t scanCode,
- int32_t metaState,
- int32_t repeatCount,
- nsecs_t downTime,
- nsecs_t eventTime);
-
- /* Publishes a motion event to the input channel.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if the channel is full.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
- * Other errors probably indicate that the channel is broken.
- */
- status_t publishMotionEvent(
- uint32_t seq,
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- size_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords);
-
- /* Receives the finished signal from the consumer in reply to the original dispatch signal.
- * If a signal was received, returns the message sequence number,
- * and whether the consumer handled the message.
- *
- * The returned sequence number is never 0 unless the operation failed.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Other errors probably indicate that the channel is broken.
- */
- status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
-
-private:
- sp<InputChannel> mChannel;
-};
-
-/*
- * Consumes input events from an input channel.
- */
-class InputConsumer {
-public:
- /* Creates a consumer associated with an input channel. */
- explicit InputConsumer(const sp<InputChannel>& channel);
-
- /* Destroys the consumer and releases its input channel. */
- ~InputConsumer();
-
- /* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
-
- /* Consumes an input event from the input channel and copies its contents into
- * an InputEvent object created using the specified factory.
- *
- * Tries to combine a series of move events into larger batches whenever possible.
- *
- * If consumeBatches is false, then defers consuming pending batched events if it
- * is possible for additional samples to be added to them later. Call hasPendingBatch()
- * to determine whether a pending batch is available to be consumed.
- *
- * If consumeBatches is true, then events are still batched but they are consumed
- * immediately as soon as the input channel is exhausted.
- *
- * The frameTime parameter specifies the time when the current display frame started
- * rendering in the CLOCK_MONOTONIC time base, or -1 if unknown.
- *
- * The returned sequence number is never 0 unless the operation failed.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no event present.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Returns NO_MEMORY if the event could not be created.
- * Other errors probably indicate that the channel is broken.
- */
- status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
-
- /* Sends a finished signal to the publisher to inform it that the message
- * with the specified sequence number has finished being process and whether
- * the message was handled by the consumer.
- *
- * Returns OK on success.
- * Returns BAD_VALUE if seq is 0.
- * Other errors probably indicate that the channel is broken.
- */
- status_t sendFinishedSignal(uint32_t seq, bool handled);
-
- /* Returns true if there is a deferred event waiting.
- *
- * Should be called after calling consume() to determine whether the consumer
- * has a deferred event to be processed. Deferred events are somewhat special in
- * that they have already been removed from the input channel. If the input channel
- * becomes empty, the client may need to do extra work to ensure that it processes
- * the deferred event despite the fact that the input channel's file descriptor
- * is not readable.
- *
- * One option is simply to call consume() in a loop until it returns WOULD_BLOCK.
- * This guarantees that all deferred events will be processed.
- *
- * Alternately, the caller can call hasDeferredEvent() to determine whether there is
- * a deferred event waiting and then ensure that its event loop wakes up at least
- * one more time to consume the deferred event.
- */
- bool hasDeferredEvent() const;
-
- /* Returns true if there is a pending batch.
- *
- * Should be called after calling consume() with consumeBatches == false to determine
- * whether consume() should be called again later on with consumeBatches == true.
- */
- bool hasPendingBatch() const;
-
-private:
- // True if touch resampling is enabled.
- const bool mResampleTouch;
-
- // The input channel.
- sp<InputChannel> mChannel;
-
- // The current input message.
- InputMessage mMsg;
-
- // True if mMsg contains a valid input message that was deferred from the previous
- // call to consume and that still needs to be handled.
- bool mMsgDeferred;
-
- // Batched motion events per device and source.
- struct Batch {
- Vector<InputMessage> samples;
- };
- Vector<Batch> mBatches;
-
- // Touch state per device and source, only for sources of class pointer.
- struct History {
- nsecs_t eventTime;
- BitSet32 idBits;
- int32_t idToIndex[MAX_POINTER_ID + 1];
- PointerCoords pointers[MAX_POINTERS];
-
- void initializeFrom(const InputMessage* msg) {
- eventTime = msg->body.motion.eventTime;
- idBits.clear();
- for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
- uint32_t id = msg->body.motion.pointers[i].properties.id;
- idBits.markBit(id);
- idToIndex[id] = i;
- pointers[i].copyFrom(msg->body.motion.pointers[i].coords);
- }
- }
-
- const PointerCoords& getPointerById(uint32_t id) const {
- return pointers[idToIndex[id]];
- }
- };
- struct TouchState {
- int32_t deviceId;
- int32_t source;
- size_t historyCurrent;
- size_t historySize;
- History history[2];
- History lastResample;
-
- void initialize(int32_t deviceId, int32_t source) {
- this->deviceId = deviceId;
- this->source = source;
- historyCurrent = 0;
- historySize = 0;
- lastResample.eventTime = 0;
- lastResample.idBits.clear();
- }
-
- void addHistory(const InputMessage* msg) {
- historyCurrent ^= 1;
- if (historySize < 2) {
- historySize += 1;
- }
- history[historyCurrent].initializeFrom(msg);
- }
-
- const History* getHistory(size_t index) const {
- return &history[(historyCurrent + index) & 1];
- }
- };
- Vector<TouchState> mTouchStates;
-
- // Chain of batched sequence numbers. When multiple input messages are combined into
- // a batch, we append a record here that associates the last sequence number in the
- // batch with the previous one. When the finished signal is sent, we traverse the
- // chain to individually finish all input messages that were part of the batch.
- struct SeqChain {
- uint32_t seq; // sequence number of batched input message
- uint32_t chain; // sequence number of previous batched input message
- };
- Vector<SeqChain> mSeqChains;
-
- status_t consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
- status_t consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
-
- void updateTouchState(InputMessage* msg);
- void rewriteMessage(const TouchState& state, InputMessage* msg);
- void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
- const InputMessage *next);
-
- ssize_t findBatch(int32_t deviceId, int32_t source) const;
- ssize_t findTouchState(int32_t deviceId, int32_t source) const;
-
- status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
-
- static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
- static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
- static void addSample(MotionEvent* event, const InputMessage* msg);
- static bool canAddSample(const Batch& batch, const InputMessage* msg);
- static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
- static bool shouldResampleTool(int32_t toolType);
-
- static bool isTouchResamplingEnabled();
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_INPUT_TRANSPORT_H
diff --git a/include/androidfw/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
deleted file mode 100644
index 06799f9..0000000
--- a/include/androidfw/KeyCharacterMap.h
+++ /dev/null
@@ -1,257 +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.
- */
-
-#ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H
-#define _ANDROIDFW_KEY_CHARACTER_MAP_H
-
-#include <stdint.h>
-
-#if HAVE_ANDROID_OS
-#include <binder/IBinder.h>
-#endif
-
-#include <androidfw/Input.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/Tokenizer.h>
-#include <utils/String8.h>
-#include <utils/Unicode.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-/**
- * Describes a mapping from Android key codes to characters.
- * Also specifies other functions of the keyboard such as the keyboard type
- * and key modifier semantics.
- *
- * This object is immutable after it has been loaded.
- */
-class KeyCharacterMap : public RefBase {
-public:
- enum KeyboardType {
- KEYBOARD_TYPE_UNKNOWN = 0,
- KEYBOARD_TYPE_NUMERIC = 1,
- KEYBOARD_TYPE_PREDICTIVE = 2,
- KEYBOARD_TYPE_ALPHA = 3,
- KEYBOARD_TYPE_FULL = 4,
- KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
- KEYBOARD_TYPE_OVERLAY = 6,
- };
-
- enum Format {
- // Base keyboard layout, may contain device-specific options, such as "type" declaration.
- FORMAT_BASE = 0,
- // Overlay keyboard layout, more restrictive, may be published by applications,
- // cannot override device-specific options.
- FORMAT_OVERLAY = 1,
- // Either base or overlay layout ok.
- FORMAT_ANY = 2,
- };
-
- // Substitute key code and meta state for fallback action.
- struct FallbackAction {
- int32_t keyCode;
- int32_t metaState;
- };
-
- /* Loads a key character map from a file. */
- static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap);
-
- /* Loads a key character map from its string contents. */
- static status_t loadContents(const String8& filename,
- const char* contents, Format format, sp<KeyCharacterMap>* outMap);
-
- /* Combines a base key character map and an overlay. */
- static sp<KeyCharacterMap> combine(const sp<KeyCharacterMap>& base,
- const sp<KeyCharacterMap>& overlay);
-
- /* Returns an empty key character map. */
- static sp<KeyCharacterMap> empty();
-
- /* Gets the keyboard type. */
- int32_t getKeyboardType() const;
-
- /* Gets the primary character for this key as in the label physically printed on it.
- * Returns 0 if none (eg. for non-printing keys). */
- char16_t getDisplayLabel(int32_t keyCode) const;
-
- /* Gets the Unicode character for the number or symbol generated by the key
- * when the keyboard is used as a dialing pad.
- * Returns 0 if no number or symbol is generated.
- */
- char16_t getNumber(int32_t keyCode) const;
-
- /* Gets the Unicode character generated by the key and meta key modifiers.
- * Returns 0 if no character is generated.
- */
- char16_t getCharacter(int32_t keyCode, int32_t metaState) const;
-
- /* Gets the fallback action to use by default if the application does not
- * handle the specified key.
- * Returns true if an action was available, false if none.
- */
- bool getFallbackAction(int32_t keyCode, int32_t metaState,
- FallbackAction* outFallbackAction) const;
-
- /* Gets the first matching Unicode character that can be generated by the key,
- * preferring the one with the specified meta key modifiers.
- * Returns 0 if no matching character is generated.
- */
- char16_t getMatch(int32_t keyCode, const char16_t* chars,
- size_t numChars, int32_t metaState) const;
-
- /* Gets a sequence of key events that could plausibly generate the specified
- * character sequence. Returns false if some of the characters cannot be generated.
- */
- bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
- Vector<KeyEvent>& outEvents) const;
-
- /* Maps a scan code and usage code to a key code, in case this key map overrides
- * the mapping in some way. */
- status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
-
-#if HAVE_ANDROID_OS
- /* Reads a key map from a parcel. */
- static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
-
- /* Writes a key map to a parcel. */
- void writeToParcel(Parcel* parcel) const;
-#endif
-
-protected:
- virtual ~KeyCharacterMap();
-
-private:
- struct Behavior {
- Behavior();
- Behavior(const Behavior& other);
-
- /* The next behavior in the list, or NULL if none. */
- Behavior* next;
-
- /* The meta key modifiers for this behavior. */
- int32_t metaState;
-
- /* The character to insert. */
- char16_t character;
-
- /* The fallback keycode if the key is not handled. */
- int32_t fallbackKeyCode;
- };
-
- struct Key {
- Key();
- Key(const Key& other);
- ~Key();
-
- /* The single character label printed on the key, or 0 if none. */
- char16_t label;
-
- /* The number or symbol character generated by the key, or 0 if none. */
- char16_t number;
-
- /* The list of key behaviors sorted from most specific to least specific
- * meta key binding. */
- Behavior* firstBehavior;
- };
-
- class Parser {
- enum State {
- STATE_TOP = 0,
- STATE_KEY = 1,
- };
-
- enum {
- PROPERTY_LABEL = 1,
- PROPERTY_NUMBER = 2,
- PROPERTY_META = 3,
- };
-
- struct Property {
- inline Property(int32_t property = 0, int32_t metaState = 0) :
- property(property), metaState(metaState) { }
-
- int32_t property;
- int32_t metaState;
- };
-
- KeyCharacterMap* mMap;
- Tokenizer* mTokenizer;
- Format mFormat;
- State mState;
- int32_t mKeyCode;
-
- public:
- Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format);
- ~Parser();
- status_t parse();
-
- private:
- status_t parseType();
- status_t parseMap();
- status_t parseMapKey();
- status_t parseKey();
- status_t parseKeyProperty();
- status_t finishKey(Key* key);
- status_t parseModifier(const String8& token, int32_t* outMetaState);
- status_t parseCharacterLiteral(char16_t* outCharacter);
- };
-
- static sp<KeyCharacterMap> sEmpty;
-
- KeyedVector<int32_t, Key*> mKeys;
- int mType;
-
- KeyedVector<int32_t, int32_t> mKeysByScanCode;
- KeyedVector<int32_t, int32_t> mKeysByUsageCode;
-
- KeyCharacterMap();
- KeyCharacterMap(const KeyCharacterMap& other);
-
- bool getKey(int32_t keyCode, const Key** outKey) const;
- bool getKeyBehavior(int32_t keyCode, int32_t metaState,
- const Key** outKey, const Behavior** outBehavior) const;
- static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState);
-
- bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
-
- static status_t load(Tokenizer* tokenizer, Format format, sp<KeyCharacterMap>* outMap);
-
- static void addKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
- static void addMetaKeys(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
- int32_t* currentMetaState);
- static bool addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
- int32_t keyCode, int32_t keyMetaState,
- int32_t* currentMetaState);
- static void addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
- int32_t leftKeyCode, int32_t leftKeyMetaState,
- int32_t rightKeyCode, int32_t rightKeyMetaState,
- int32_t eitherKeyMetaState,
- int32_t* currentMetaState);
- static void addLockedMetaKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, nsecs_t time,
- int32_t keyCode, int32_t keyMetaState,
- int32_t* currentMetaState);
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/include/androidfw/KeyLayoutMap.h b/include/androidfw/KeyLayoutMap.h
deleted file mode 100644
index e7f22a2..0000000
--- a/include/androidfw/KeyLayoutMap.h
+++ /dev/null
@@ -1,107 +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.
- */
-
-#ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H
-#define _ANDROIDFW_KEY_LAYOUT_MAP_H
-
-#include <stdint.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/Tokenizer.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct AxisInfo {
- enum Mode {
- // Axis value is reported directly.
- MODE_NORMAL = 0,
- // Axis value should be inverted before reporting.
- MODE_INVERT = 1,
- // Axis value should be split into two axes
- MODE_SPLIT = 2,
- };
-
- // Axis mode.
- Mode mode;
-
- // Axis id.
- // When split, this is the axis used for values smaller than the split position.
- int32_t axis;
-
- // When split, this is the axis used for values after higher than the split position.
- int32_t highAxis;
-
- // The split value, or 0 if not split.
- int32_t splitValue;
-
- // The flat value, or -1 if none.
- int32_t flatOverride;
-
- AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
- }
-};
-
-/**
- * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
- *
- * This object is immutable after it has been loaded.
- */
-class KeyLayoutMap : public RefBase {
-public:
- static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap);
-
- status_t mapKey(int32_t scanCode, int32_t usageCode,
- int32_t* outKeyCode, uint32_t* outFlags) const;
- status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
-
- status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
-
-protected:
- virtual ~KeyLayoutMap();
-
-private:
- struct Key {
- int32_t keyCode;
- uint32_t flags;
- };
-
- KeyedVector<int32_t, Key> mKeysByScanCode;
- KeyedVector<int32_t, Key> mKeysByUsageCode;
- KeyedVector<int32_t, AxisInfo> mAxes;
-
- KeyLayoutMap();
-
- const Key* getKey(int32_t scanCode, int32_t usageCode) const;
-
- class Parser {
- KeyLayoutMap* mMap;
- Tokenizer* mTokenizer;
-
- public:
- Parser(KeyLayoutMap* map, Tokenizer* tokenizer);
- ~Parser();
- status_t parse();
-
- private:
- status_t parseKey();
- status_t parseAxis();
- };
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEY_LAYOUT_MAP_H
diff --git a/include/androidfw/Keyboard.h b/include/androidfw/Keyboard.h
deleted file mode 100644
index 6537a8f..0000000
--- a/include/androidfw/Keyboard.h
+++ /dev/null
@@ -1,120 +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 _ANDROIDFW_KEYBOARD_H
-#define _ANDROIDFW_KEYBOARD_H
-
-#include <androidfw/Input.h>
-#include <androidfw/InputDevice.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/PropertyMap.h>
-
-namespace android {
-
-enum {
- /* Device id of the built in keyboard. */
- DEVICE_ID_BUILT_IN_KEYBOARD = 0,
-
- /* Device id of a generic virtual keyboard with a full layout that can be used
- * to synthesize key events. */
- DEVICE_ID_VIRTUAL_KEYBOARD = -1,
-};
-
-class KeyLayoutMap;
-class KeyCharacterMap;
-
-/**
- * Loads the key layout map and key character map for a keyboard device.
- */
-class KeyMap {
-public:
- String8 keyLayoutFile;
- sp<KeyLayoutMap> keyLayoutMap;
-
- String8 keyCharacterMapFile;
- sp<KeyCharacterMap> keyCharacterMap;
-
- KeyMap();
- ~KeyMap();
-
- status_t load(const InputDeviceIdentifier& deviceIdenfier,
- const PropertyMap* deviceConfiguration);
-
- inline bool haveKeyLayout() const {
- return !keyLayoutFile.isEmpty();
- }
-
- inline bool haveKeyCharacterMap() const {
- return !keyCharacterMapFile.isEmpty();
- }
-
- inline bool isComplete() const {
- return haveKeyLayout() && haveKeyCharacterMap();
- }
-
-private:
- bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
- status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
- status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name);
- String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name, InputDeviceConfigurationFileType type);
-};
-
-/**
- * Returns true if the keyboard is eligible for use as a built-in keyboard.
- */
-extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
- const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
-
-/**
- * Gets a key code by its short form label, eg. "HOME".
- * Returns 0 if unknown.
- */
-extern int32_t getKeyCodeByLabel(const char* label);
-
-/**
- * Gets a key flag by its short form label, eg. "WAKE".
- * Returns 0 if unknown.
- */
-extern uint32_t getKeyFlagByLabel(const char* label);
-
-/**
- * Gets a axis by its short form label, eg. "X".
- * Returns -1 if unknown.
- */
-extern int32_t getAxisByLabel(const char* label);
-
-/**
- * Gets a axis label by its id.
- * Returns NULL if unknown.
- */
-extern const char* getAxisLabel(int32_t axisId);
-
-/**
- * Updates a meta state field when a key is pressed or released.
- */
-extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
-
-/**
- * Returns true if a key is a meta key like ALT or CAPS_LOCK.
- */
-extern bool isMetaKey(int32_t keyCode);
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEYBOARD_H
diff --git a/include/androidfw/KeycodeLabels.h b/include/androidfw/KeycodeLabels.h
deleted file mode 100644
index 3e12f26..0000000
--- a/include/androidfw/KeycodeLabels.h
+++ /dev/null
@@ -1,321 +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.
- */
-
-#ifndef _ANDROIDFW_KEYCODE_LABELS_H
-#define _ANDROIDFW_KEYCODE_LABELS_H
-
-#include <android/keycodes.h>
-
-struct KeycodeLabel {
- const char *literal;
- int value;
-};
-
-static const KeycodeLabel KEYCODES[] = {
- { "SOFT_LEFT", 1 },
- { "SOFT_RIGHT", 2 },
- { "HOME", 3 },
- { "BACK", 4 },
- { "CALL", 5 },
- { "ENDCALL", 6 },
- { "0", 7 },
- { "1", 8 },
- { "2", 9 },
- { "3", 10 },
- { "4", 11 },
- { "5", 12 },
- { "6", 13 },
- { "7", 14 },
- { "8", 15 },
- { "9", 16 },
- { "STAR", 17 },
- { "POUND", 18 },
- { "DPAD_UP", 19 },
- { "DPAD_DOWN", 20 },
- { "DPAD_LEFT", 21 },
- { "DPAD_RIGHT", 22 },
- { "DPAD_CENTER", 23 },
- { "VOLUME_UP", 24 },
- { "VOLUME_DOWN", 25 },
- { "POWER", 26 },
- { "CAMERA", 27 },
- { "CLEAR", 28 },
- { "A", 29 },
- { "B", 30 },
- { "C", 31 },
- { "D", 32 },
- { "E", 33 },
- { "F", 34 },
- { "G", 35 },
- { "H", 36 },
- { "I", 37 },
- { "J", 38 },
- { "K", 39 },
- { "L", 40 },
- { "M", 41 },
- { "N", 42 },
- { "O", 43 },
- { "P", 44 },
- { "Q", 45 },
- { "R", 46 },
- { "S", 47 },
- { "T", 48 },
- { "U", 49 },
- { "V", 50 },
- { "W", 51 },
- { "X", 52 },
- { "Y", 53 },
- { "Z", 54 },
- { "COMMA", 55 },
- { "PERIOD", 56 },
- { "ALT_LEFT", 57 },
- { "ALT_RIGHT", 58 },
- { "SHIFT_LEFT", 59 },
- { "SHIFT_RIGHT", 60 },
- { "TAB", 61 },
- { "SPACE", 62 },
- { "SYM", 63 },
- { "EXPLORER", 64 },
- { "ENVELOPE", 65 },
- { "ENTER", 66 },
- { "DEL", 67 },
- { "GRAVE", 68 },
- { "MINUS", 69 },
- { "EQUALS", 70 },
- { "LEFT_BRACKET", 71 },
- { "RIGHT_BRACKET", 72 },
- { "BACKSLASH", 73 },
- { "SEMICOLON", 74 },
- { "APOSTROPHE", 75 },
- { "SLASH", 76 },
- { "AT", 77 },
- { "NUM", 78 },
- { "HEADSETHOOK", 79 },
- { "FOCUS", 80 },
- { "PLUS", 81 },
- { "MENU", 82 },
- { "NOTIFICATION", 83 },
- { "SEARCH", 84 },
- { "MEDIA_PLAY_PAUSE", 85 },
- { "MEDIA_STOP", 86 },
- { "MEDIA_NEXT", 87 },
- { "MEDIA_PREVIOUS", 88 },
- { "MEDIA_REWIND", 89 },
- { "MEDIA_FAST_FORWARD", 90 },
- { "MUTE", 91 },
- { "PAGE_UP", 92 },
- { "PAGE_DOWN", 93 },
- { "PICTSYMBOLS", 94 },
- { "SWITCH_CHARSET", 95 },
- { "BUTTON_A", 96 },
- { "BUTTON_B", 97 },
- { "BUTTON_C", 98 },
- { "BUTTON_X", 99 },
- { "BUTTON_Y", 100 },
- { "BUTTON_Z", 101 },
- { "BUTTON_L1", 102 },
- { "BUTTON_R1", 103 },
- { "BUTTON_L2", 104 },
- { "BUTTON_R2", 105 },
- { "BUTTON_THUMBL", 106 },
- { "BUTTON_THUMBR", 107 },
- { "BUTTON_START", 108 },
- { "BUTTON_SELECT", 109 },
- { "BUTTON_MODE", 110 },
- { "ESCAPE", 111 },
- { "FORWARD_DEL", 112 },
- { "CTRL_LEFT", 113 },
- { "CTRL_RIGHT", 114 },
- { "CAPS_LOCK", 115 },
- { "SCROLL_LOCK", 116 },
- { "META_LEFT", 117 },
- { "META_RIGHT", 118 },
- { "FUNCTION", 119 },
- { "SYSRQ", 120 },
- { "BREAK", 121 },
- { "MOVE_HOME", 122 },
- { "MOVE_END", 123 },
- { "INSERT", 124 },
- { "FORWARD", 125 },
- { "MEDIA_PLAY", 126 },
- { "MEDIA_PAUSE", 127 },
- { "MEDIA_CLOSE", 128 },
- { "MEDIA_EJECT", 129 },
- { "MEDIA_RECORD", 130 },
- { "F1", 131 },
- { "F2", 132 },
- { "F3", 133 },
- { "F4", 134 },
- { "F5", 135 },
- { "F6", 136 },
- { "F7", 137 },
- { "F8", 138 },
- { "F9", 139 },
- { "F10", 140 },
- { "F11", 141 },
- { "F12", 142 },
- { "NUM_LOCK", 143 },
- { "NUMPAD_0", 144 },
- { "NUMPAD_1", 145 },
- { "NUMPAD_2", 146 },
- { "NUMPAD_3", 147 },
- { "NUMPAD_4", 148 },
- { "NUMPAD_5", 149 },
- { "NUMPAD_6", 150 },
- { "NUMPAD_7", 151 },
- { "NUMPAD_8", 152 },
- { "NUMPAD_9", 153 },
- { "NUMPAD_DIVIDE", 154 },
- { "NUMPAD_MULTIPLY", 155 },
- { "NUMPAD_SUBTRACT", 156 },
- { "NUMPAD_ADD", 157 },
- { "NUMPAD_DOT", 158 },
- { "NUMPAD_COMMA", 159 },
- { "NUMPAD_ENTER", 160 },
- { "NUMPAD_EQUALS", 161 },
- { "NUMPAD_LEFT_PAREN", 162 },
- { "NUMPAD_RIGHT_PAREN", 163 },
- { "VOLUME_MUTE", 164 },
- { "INFO", 165 },
- { "CHANNEL_UP", 166 },
- { "CHANNEL_DOWN", 167 },
- { "ZOOM_IN", 168 },
- { "ZOOM_OUT", 169 },
- { "TV", 170 },
- { "WINDOW", 171 },
- { "GUIDE", 172 },
- { "DVR", 173 },
- { "BOOKMARK", 174 },
- { "CAPTIONS", 175 },
- { "SETTINGS", 176 },
- { "TV_POWER", 177 },
- { "TV_INPUT", 178 },
- { "STB_POWER", 179 },
- { "STB_INPUT", 180 },
- { "AVR_POWER", 181 },
- { "AVR_INPUT", 182 },
- { "PROG_RED", 183 },
- { "PROG_GREEN", 184 },
- { "PROG_YELLOW", 185 },
- { "PROG_BLUE", 186 },
- { "APP_SWITCH", 187 },
- { "BUTTON_1", 188 },
- { "BUTTON_2", 189 },
- { "BUTTON_3", 190 },
- { "BUTTON_4", 191 },
- { "BUTTON_5", 192 },
- { "BUTTON_6", 193 },
- { "BUTTON_7", 194 },
- { "BUTTON_8", 195 },
- { "BUTTON_9", 196 },
- { "BUTTON_10", 197 },
- { "BUTTON_11", 198 },
- { "BUTTON_12", 199 },
- { "BUTTON_13", 200 },
- { "BUTTON_14", 201 },
- { "BUTTON_15", 202 },
- { "BUTTON_16", 203 },
- { "LANGUAGE_SWITCH", 204 },
- { "MANNER_MODE", 205 },
- { "3D_MODE", 206 },
- { "CONTACTS", 207 },
- { "CALENDAR", 208 },
- { "MUSIC", 209 },
- { "CALCULATOR", 210 },
- { "ZENKAKU_HANKAKU", 211 },
- { "EISU", 212 },
- { "MUHENKAN", 213 },
- { "HENKAN", 214 },
- { "KATAKANA_HIRAGANA", 215 },
- { "YEN", 216 },
- { "RO", 217 },
- { "KANA", 218 },
- { "ASSIST", 219 },
- { "BRIGHTNESS_DOWN", 220 },
- { "BRIGHTNESS_UP", 221 },
-
- // NOTE: If you add a new keycode here you must also add it to several other files.
- // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
-
- { NULL, 0 }
-};
-
-// NOTE: If you edit these flags, also edit policy flags in Input.h.
-static const KeycodeLabel FLAGS[] = {
- { "WAKE", 0x00000001 },
- { "WAKE_DROPPED", 0x00000002 },
- { "SHIFT", 0x00000004 },
- { "CAPS_LOCK", 0x00000008 },
- { "ALT", 0x00000010 },
- { "ALT_GR", 0x00000020 },
- { "MENU", 0x00000040 },
- { "LAUNCHER", 0x00000080 },
- { "VIRTUAL", 0x00000100 },
- { "FUNCTION", 0x00000200 },
- { NULL, 0 }
-};
-
-static const KeycodeLabel AXES[] = {
- { "X", 0 },
- { "Y", 1 },
- { "PRESSURE", 2 },
- { "SIZE", 3 },
- { "TOUCH_MAJOR", 4 },
- { "TOUCH_MINOR", 5 },
- { "TOOL_MAJOR", 6 },
- { "TOOL_MINOR", 7 },
- { "ORIENTATION", 8 },
- { "VSCROLL", 9 },
- { "HSCROLL", 10 },
- { "Z", 11 },
- { "RX", 12 },
- { "RY", 13 },
- { "RZ", 14 },
- { "HAT_X", 15 },
- { "HAT_Y", 16 },
- { "LTRIGGER", 17 },
- { "RTRIGGER", 18 },
- { "THROTTLE", 19 },
- { "RUDDER", 20 },
- { "WHEEL", 21 },
- { "GAS", 22 },
- { "BRAKE", 23 },
- { "DISTANCE", 24 },
- { "TILT", 25 },
- { "GENERIC_1", 32 },
- { "GENERIC_2", 33 },
- { "GENERIC_3", 34 },
- { "GENERIC_4", 35 },
- { "GENERIC_5", 36 },
- { "GENERIC_6", 37 },
- { "GENERIC_7", 38 },
- { "GENERIC_8", 39 },
- { "GENERIC_9", 40 },
- { "GENERIC_10", 41 },
- { "GENERIC_11", 42 },
- { "GENERIC_12", 43 },
- { "GENERIC_13", 44 },
- { "GENERIC_14", 45 },
- { "GENERIC_15", 46 },
- { "GENERIC_16", 47 },
-
- // NOTE: If you add a new axis here you must also add it to several other files.
- // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
-
- { NULL, -1 }
-};
-
-#endif // _ANDROIDFW_KEYCODE_LABELS_H
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index ccccc2e..a305fc3 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1553,10 +1553,8 @@
static bool getIdmapInfo(const void* idmap, size_t size,
uint32_t* pOriginalCrc, uint32_t* pOverlayCrc);
-#ifdef STATIC_ANDROIDFW_FOR_TOOLS
void print(bool inclValues) const;
static String8 normalizeForOutput(const char* input);
-#endif
private:
struct Header;
diff --git a/include/androidfw/VelocityControl.h b/include/androidfw/VelocityControl.h
deleted file mode 100644
index 84e0444..0000000
--- a/include/androidfw/VelocityControl.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2012 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 _ANDROIDFW_VELOCITY_CONTROL_H
-#define _ANDROIDFW_VELOCITY_CONTROL_H
-
-#include <androidfw/Input.h>
-#include <androidfw/VelocityTracker.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-/*
- * Specifies parameters that govern pointer or wheel acceleration.
- */
-struct VelocityControlParameters {
- // A scale factor that is multiplied with the raw velocity deltas
- // prior to applying any other velocity control factors. The scale
- // factor should be used to adapt the input device resolution
- // (eg. counts per inch) to the output device resolution (eg. pixels per inch).
- //
- // Must be a positive value.
- // Default is 1.0 (no scaling).
- float scale;
-
- // The scaled speed at which acceleration begins to be applied.
- // This value establishes the upper bound of a low speed regime for
- // small precise motions that are performed without any acceleration.
- //
- // Must be a non-negative value.
- // Default is 0.0 (no low threshold).
- float lowThreshold;
-
- // The scaled speed at which maximum acceleration is applied.
- // The difference between highThreshold and lowThreshold controls
- // the range of speeds over which the acceleration factor is interpolated.
- // The wider the range, the smoother the acceleration.
- //
- // Must be a non-negative value greater than or equal to lowThreshold.
- // Default is 0.0 (no high threshold).
- float highThreshold;
-
- // The acceleration factor.
- // When the speed is above the low speed threshold, the velocity will scaled
- // by an interpolated value between 1.0 and this amount.
- //
- // Must be a positive greater than or equal to 1.0.
- // Default is 1.0 (no acceleration).
- float acceleration;
-
- VelocityControlParameters() :
- scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) {
- }
-
- VelocityControlParameters(float scale, float lowThreshold,
- float highThreshold, float acceleration) :
- scale(scale), lowThreshold(lowThreshold),
- highThreshold(highThreshold), acceleration(acceleration) {
- }
-};
-
-/*
- * Implements mouse pointer and wheel speed control and acceleration.
- */
-class VelocityControl {
-public:
- VelocityControl();
-
- /* Sets the various parameters. */
- void setParameters(const VelocityControlParameters& parameters);
-
- /* Resets the current movement counters to zero.
- * This has the effect of nullifying any acceleration. */
- void reset();
-
- /* Translates a raw movement delta into an appropriately
- * scaled / accelerated delta based on the current velocity. */
- void move(nsecs_t eventTime, float* deltaX, float* deltaY);
-
-private:
- // If no movements are received within this amount of time,
- // we assume the movement has stopped and reset the movement counters.
- static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms
-
- VelocityControlParameters mParameters;
-
- nsecs_t mLastMovementTime;
- VelocityTracker::Position mRawPosition;
- VelocityTracker mVelocityTracker;
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_VELOCITY_CONTROL_H
diff --git a/include/androidfw/VelocityTracker.h b/include/androidfw/VelocityTracker.h
deleted file mode 100644
index 8c24219..0000000
--- a/include/androidfw/VelocityTracker.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2012 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 _ANDROIDFW_VELOCITY_TRACKER_H
-#define _ANDROIDFW_VELOCITY_TRACKER_H
-
-#include <androidfw/Input.h>
-#include <utils/Timers.h>
-#include <utils/BitSet.h>
-
-namespace android {
-
-class VelocityTrackerStrategy;
-
-/*
- * Calculates the velocity of pointer movements over time.
- */
-class VelocityTracker {
-public:
- struct Position {
- float x, y;
- };
-
- struct Estimator {
- static const size_t MAX_DEGREE = 4;
-
- // Estimator time base.
- nsecs_t time;
-
- // Polynomial coefficients describing motion in X and Y.
- float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
-
- // Polynomial degree (number of coefficients), or zero if no information is
- // available.
- uint32_t degree;
-
- // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit).
- float confidence;
-
- inline void clear() {
- time = 0;
- degree = 0;
- confidence = 0;
- for (size_t i = 0; i <= MAX_DEGREE; i++) {
- xCoeff[i] = 0;
- yCoeff[i] = 0;
- }
- }
- };
-
- // Creates a velocity tracker using the specified strategy.
- // If strategy is NULL, uses the default strategy for the platform.
- VelocityTracker(const char* strategy = NULL);
-
- ~VelocityTracker();
-
- // Resets the velocity tracker state.
- void clear();
-
- // Resets the velocity tracker state for specific pointers.
- // Call this method when some pointers have changed and may be reusing
- // an id that was assigned to a different pointer earlier.
- void clearPointers(BitSet32 idBits);
-
- // Adds movement information for a set of pointers.
- // The idBits bitfield specifies the pointer ids of the pointers whose positions
- // are included in the movement.
- // The positions array contains position information for each pointer in order by
- // increasing id. Its size should be equal to the number of one bits in idBits.
- void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
-
- // Adds movement information for all pointers in a MotionEvent, including historical samples.
- void addMovement(const MotionEvent* event);
-
- // Gets the velocity of the specified pointer id in position units per second.
- // Returns false and sets the velocity components to zero if there is
- // insufficient movement information for the pointer.
- bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
-
- // Gets an estimator for the recent movements of the specified pointer id.
- // Returns false and clears the estimator if there is no information available
- // about the pointer.
- bool getEstimator(uint32_t id, Estimator* outEstimator) const;
-
- // Gets the active pointer id, or -1 if none.
- inline int32_t getActivePointerId() const { return mActivePointerId; }
-
- // Gets a bitset containing all pointer ids from the most recent movement.
- inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
-
-private:
- static const char* DEFAULT_STRATEGY;
-
- nsecs_t mLastEventTime;
- BitSet32 mCurrentPointerIdBits;
- int32_t mActivePointerId;
- VelocityTrackerStrategy* mStrategy;
-
- bool configureStrategy(const char* strategy);
-
- static VelocityTrackerStrategy* createStrategy(const char* strategy);
-};
-
-
-/*
- * Implements a particular velocity tracker algorithm.
- */
-class VelocityTrackerStrategy {
-protected:
- VelocityTrackerStrategy() { }
-
-public:
- virtual ~VelocityTrackerStrategy() { }
-
- virtual void clear() = 0;
- virtual void clearPointers(BitSet32 idBits) = 0;
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) = 0;
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
-};
-
-
-/*
- * Velocity tracker algorithm based on least-squares linear regression.
- */
-class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
-public:
- enum Weighting {
- // No weights applied. All data points are equally reliable.
- WEIGHTING_NONE,
-
- // Weight by time delta. Data points clustered together are weighted less.
- WEIGHTING_DELTA,
-
- // Weight such that points within a certain horizon are weighed more than those
- // outside of that horizon.
- WEIGHTING_CENTRAL,
-
- // Weight such that points older than a certain amount are weighed less.
- WEIGHTING_RECENT,
- };
-
- // Degree must be no greater than Estimator::MAX_DEGREE.
- LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE);
- virtual ~LeastSquaresVelocityTrackerStrategy();
-
- virtual void clear();
- virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
-
-private:
- // Sample horizon.
- // We don't use too much history by default since we want to react to quick
- // changes in direction.
- static const nsecs_t HORIZON = 100 * 1000000; // 100 ms
-
- // Number of samples to keep.
- static const uint32_t HISTORY_SIZE = 20;
-
- struct Movement {
- nsecs_t eventTime;
- BitSet32 idBits;
- VelocityTracker::Position positions[MAX_POINTERS];
-
- inline const VelocityTracker::Position& getPosition(uint32_t id) const {
- return positions[idBits.getIndexOfBit(id)];
- }
- };
-
- float chooseWeight(uint32_t index) const;
-
- const uint32_t mDegree;
- const Weighting mWeighting;
- uint32_t mIndex;
- Movement mMovements[HISTORY_SIZE];
-};
-
-
-/*
- * Velocity tracker algorithm that uses an IIR filter.
- */
-class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
-public:
- // Degree must be 1 or 2.
- IntegratingVelocityTrackerStrategy(uint32_t degree);
- ~IntegratingVelocityTrackerStrategy();
-
- virtual void clear();
- virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
-
-private:
- // Current state estimate for a particular pointer.
- struct State {
- nsecs_t updateTime;
- uint32_t degree;
-
- float xpos, xvel, xaccel;
- float ypos, yvel, yaccel;
- };
-
- const uint32_t mDegree;
- BitSet32 mPointerIdBits;
- State mPointerState[MAX_POINTER_ID + 1];
-
- void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
- void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
- void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const;
-};
-
-
-/*
- * Velocity tracker strategy used prior to ICS.
- */
-class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy {
-public:
- LegacyVelocityTrackerStrategy();
- virtual ~LegacyVelocityTrackerStrategy();
-
- virtual void clear();
- virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
-
-private:
- // Oldest sample to consider when calculating the velocity.
- static const nsecs_t HORIZON = 200 * 1000000; // 100 ms
-
- // Number of samples to keep.
- static const uint32_t HISTORY_SIZE = 20;
-
- // The minimum duration between samples when estimating velocity.
- static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
-
- struct Movement {
- nsecs_t eventTime;
- BitSet32 idBits;
- VelocityTracker::Position positions[MAX_POINTERS];
-
- inline const VelocityTracker::Position& getPosition(uint32_t id) const {
- return positions[idBits.getIndexOfBit(id)];
- }
- };
-
- uint32_t mIndex;
- Movement mMovements[HISTORY_SIZE];
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_VELOCITY_TRACKER_H
diff --git a/include/androidfw/VirtualKeyMap.h b/include/androidfw/VirtualKeyMap.h
deleted file mode 100644
index dd3ad1e9..0000000
--- a/include/androidfw/VirtualKeyMap.h
+++ /dev/null
@@ -1,81 +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 _ANDROIDFW_VIRTUAL_KEY_MAP_H
-#define _ANDROIDFW_VIRTUAL_KEY_MAP_H
-
-#include <stdint.h>
-
-#include <androidfw/Input.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/Tokenizer.h>
-#include <utils/String8.h>
-#include <utils/Unicode.h>
-
-namespace android {
-
-/* 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;
-};
-
-
-/**
- * Describes a collection of virtual keys on a touch screen in terms of
- * virtual scan codes and hit rectangles.
- *
- * This object is immutable after it has been loaded.
- */
-class VirtualKeyMap {
-public:
- ~VirtualKeyMap();
-
- static status_t load(const String8& filename, VirtualKeyMap** outMap);
-
- inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
- return mVirtualKeys;
- }
-
-private:
- class Parser {
- VirtualKeyMap* mMap;
- Tokenizer* mTokenizer;
-
- public:
- Parser(VirtualKeyMap* map, Tokenizer* tokenizer);
- ~Parser();
- status_t parse();
-
- private:
- bool consumeFieldDelimiterAndSkipWhitespace();
- bool parseNextIntField(int32_t* outValue);
- };
-
- Vector<VirtualKeyDefinition> mVirtualKeys;
-
- VirtualKeyMap();
-};
-
-} // namespace android
-
-#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index c06b144..4e126b8 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -14,11 +14,10 @@
LOCAL_PATH:= $(call my-dir)
-# libandroidfw is partially built for the host (used by build time keymap validation tool)
+# libandroidfw is partially built for the host (used by obbtool and others)
# These files are common to host and target builds.
-# formerly in libutils
-commonUtilsSources:= \
+commonSources := \
Asset.cpp \
AssetDir.cpp \
AssetManager.cpp \
@@ -30,26 +29,21 @@
ZipFileRO.cpp \
ZipUtils.cpp
-# formerly in libui
-commonUiSources:= \
- Input.cpp \
- InputDevice.cpp \
- Keyboard.cpp \
- KeyCharacterMap.cpp \
- KeyLayoutMap.cpp \
- VelocityControl.cpp \
- VirtualKeyMap.cpp
+deviceSources := \
+ $(commonSources) \
+ BackupData.cpp \
+ BackupHelpers.cpp \
+ CursorWindow.cpp
-commonSources:= \
- $(commonUtilsSources) \
- $(commonUiSources)
+hostSources := \
+ $(commonSources)
# For the host
# =====================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources)
+LOCAL_SRC_FILES:= $(hostSources)
LOCAL_MODULE:= libandroidfw
@@ -68,24 +62,16 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- $(commonSources) \
- BackupData.cpp \
- BackupHelpers.cpp \
- CursorWindow.cpp \
- InputTransport.cpp \
- VelocityTracker.cpp
+LOCAL_SRC_FILES:= $(deviceSources)
LOCAL_SHARED_LIBRARIES := \
+ libbinder \
liblog \
libcutils \
libutils \
- libbinder \
- libskia \
libz
LOCAL_C_INCLUDES := \
- external/skia/include/core \
external/icu4c/common \
external/zlib
@@ -96,21 +82,6 @@
include $(BUILD_SHARED_LIBRARY)
-ifeq ($(TARGET_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
-LOCAL_C_INCLUDES += \
- external/skia/include/core \
- external/zlib \
- external/icu4c/common \
- bionic/libc/private
-LOCAL_LDLIBS := -lrt -ldl -lpthread
-LOCAL_MODULE := libandroidfw
-LOCAL_SRC_FILES := $(commonUtilsSources) BackupData.cpp BackupHelpers.cpp
-include $(BUILD_STATIC_LIBRARY)
-endif
-
-
# Include subdirectory makefiles
# ============================================================
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 047a4c8..0f54edb 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -17,8 +17,9 @@
#undef LOG_TAG
#define LOG_TAG "CursorWindow"
-#include <utils/Log.h>
#include <androidfw/CursorWindow.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
#include <cutils/ashmem.h>
#include <sys/mman.h>
diff --git a/libs/androidfw/Input.cpp b/libs/androidfw/Input.cpp
deleted file mode 100644
index eca692a..0000000
--- a/libs/androidfw/Input.cpp
+++ /dev/null
@@ -1,634 +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.
- */
-
-#define LOG_TAG "Input"
-//#define LOG_NDEBUG 0
-
-#include <math.h>
-#include <limits.h>
-
-#include <androidfw/Input.h>
-
-#ifdef HAVE_ANDROID_OS
-#include <binder/Parcel.h>
-
-#include "SkPoint.h"
-#include "SkMatrix.h"
-#include "SkScalar.h"
-#endif
-
-namespace android {
-
-// --- InputEvent ---
-
-void InputEvent::initialize(int32_t deviceId, int32_t source) {
- mDeviceId = deviceId;
- mSource = source;
-}
-
-void InputEvent::initialize(const InputEvent& from) {
- mDeviceId = from.mDeviceId;
- mSource = from.mSource;
-}
-
-// --- KeyEvent ---
-
-bool KeyEvent::hasDefaultAction(int32_t keyCode) {
- switch (keyCode) {
- case AKEYCODE_HOME:
- case AKEYCODE_BACK:
- case AKEYCODE_CALL:
- case AKEYCODE_ENDCALL:
- case AKEYCODE_VOLUME_UP:
- case AKEYCODE_VOLUME_DOWN:
- case AKEYCODE_VOLUME_MUTE:
- case AKEYCODE_POWER:
- case AKEYCODE_CAMERA:
- case AKEYCODE_HEADSETHOOK:
- case AKEYCODE_MENU:
- case AKEYCODE_NOTIFICATION:
- case AKEYCODE_FOCUS:
- case AKEYCODE_SEARCH:
- case AKEYCODE_MEDIA_PLAY:
- case AKEYCODE_MEDIA_PAUSE:
- case AKEYCODE_MEDIA_PLAY_PAUSE:
- case AKEYCODE_MEDIA_STOP:
- case AKEYCODE_MEDIA_NEXT:
- case AKEYCODE_MEDIA_PREVIOUS:
- case AKEYCODE_MEDIA_REWIND:
- case AKEYCODE_MEDIA_RECORD:
- case AKEYCODE_MEDIA_FAST_FORWARD:
- case AKEYCODE_MUTE:
- case AKEYCODE_BRIGHTNESS_DOWN:
- case AKEYCODE_BRIGHTNESS_UP:
- return true;
- }
-
- return false;
-}
-
-bool KeyEvent::hasDefaultAction() const {
- return hasDefaultAction(getKeyCode());
-}
-
-bool KeyEvent::isSystemKey(int32_t keyCode) {
- switch (keyCode) {
- case AKEYCODE_MENU:
- case AKEYCODE_SOFT_RIGHT:
- case AKEYCODE_HOME:
- case AKEYCODE_BACK:
- case AKEYCODE_CALL:
- case AKEYCODE_ENDCALL:
- case AKEYCODE_VOLUME_UP:
- case AKEYCODE_VOLUME_DOWN:
- case AKEYCODE_VOLUME_MUTE:
- case AKEYCODE_MUTE:
- case AKEYCODE_POWER:
- case AKEYCODE_HEADSETHOOK:
- case AKEYCODE_MEDIA_PLAY:
- case AKEYCODE_MEDIA_PAUSE:
- case AKEYCODE_MEDIA_PLAY_PAUSE:
- case AKEYCODE_MEDIA_STOP:
- case AKEYCODE_MEDIA_NEXT:
- case AKEYCODE_MEDIA_PREVIOUS:
- case AKEYCODE_MEDIA_REWIND:
- case AKEYCODE_MEDIA_RECORD:
- case AKEYCODE_MEDIA_FAST_FORWARD:
- case AKEYCODE_CAMERA:
- case AKEYCODE_FOCUS:
- case AKEYCODE_SEARCH:
- case AKEYCODE_BRIGHTNESS_DOWN:
- case AKEYCODE_BRIGHTNESS_UP:
- return true;
- }
-
- return false;
-}
-
-bool KeyEvent::isSystemKey() const {
- return isSystemKey(getKeyCode());
-}
-
-void KeyEvent::initialize(
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t keyCode,
- int32_t scanCode,
- int32_t metaState,
- int32_t repeatCount,
- nsecs_t downTime,
- nsecs_t eventTime) {
- InputEvent::initialize(deviceId, source);
- mAction = action;
- mFlags = flags;
- mKeyCode = keyCode;
- mScanCode = scanCode;
- mMetaState = metaState;
- mRepeatCount = repeatCount;
- mDownTime = downTime;
- mEventTime = eventTime;
-}
-
-void KeyEvent::initialize(const KeyEvent& from) {
- InputEvent::initialize(from);
- mAction = from.mAction;
- mFlags = from.mFlags;
- mKeyCode = from.mKeyCode;
- mScanCode = from.mScanCode;
- mMetaState = from.mMetaState;
- mRepeatCount = from.mRepeatCount;
- mDownTime = from.mDownTime;
- mEventTime = from.mEventTime;
-}
-
-
-// --- PointerCoords ---
-
-float PointerCoords::getAxisValue(int32_t axis) const {
- if (axis < 0 || axis > 63) {
- return 0;
- }
-
- uint64_t axisBit = 1LL << axis;
- if (!(bits & axisBit)) {
- return 0;
- }
- uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
- return values[index];
-}
-
-status_t PointerCoords::setAxisValue(int32_t axis, float value) {
- if (axis < 0 || axis > 63) {
- return NAME_NOT_FOUND;
- }
-
- uint64_t axisBit = 1LL << axis;
- uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
- if (!(bits & axisBit)) {
- if (value == 0) {
- return OK; // axes with value 0 do not need to be stored
- }
- uint32_t count = __builtin_popcountll(bits);
- if (count >= MAX_AXES) {
- tooManyAxes(axis);
- return NO_MEMORY;
- }
- bits |= axisBit;
- for (uint32_t i = count; i > index; i--) {
- values[i] = values[i - 1];
- }
- }
- values[index] = value;
- return OK;
-}
-
-static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
- float value = c.getAxisValue(axis);
- if (value != 0) {
- c.setAxisValue(axis, value * scaleFactor);
- }
-}
-
-void PointerCoords::scale(float scaleFactor) {
- // No need to scale pressure or size since they are normalized.
- // No need to scale orientation since it is meaningless to do so.
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
- scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
-}
-
-#ifdef HAVE_ANDROID_OS
-status_t PointerCoords::readFromParcel(Parcel* parcel) {
- bits = parcel->readInt64();
-
- uint32_t count = __builtin_popcountll(bits);
- if (count > MAX_AXES) {
- return BAD_VALUE;
- }
-
- for (uint32_t i = 0; i < count; i++) {
- values[i] = parcel->readFloat();
- }
- return OK;
-}
-
-status_t PointerCoords::writeToParcel(Parcel* parcel) const {
- parcel->writeInt64(bits);
-
- uint32_t count = __builtin_popcountll(bits);
- for (uint32_t i = 0; i < count; i++) {
- parcel->writeFloat(values[i]);
- }
- return OK;
-}
-#endif
-
-void PointerCoords::tooManyAxes(int axis) {
- ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
- "cannot contain more than %d axis values.", axis, int(MAX_AXES));
-}
-
-bool PointerCoords::operator==(const PointerCoords& other) const {
- if (bits != other.bits) {
- return false;
- }
- uint32_t count = __builtin_popcountll(bits);
- for (uint32_t i = 0; i < count; i++) {
- if (values[i] != other.values[i]) {
- return false;
- }
- }
- return true;
-}
-
-void PointerCoords::copyFrom(const PointerCoords& other) {
- bits = other.bits;
- uint32_t count = __builtin_popcountll(bits);
- for (uint32_t i = 0; i < count; i++) {
- values[i] = other.values[i];
- }
-}
-
-
-// --- PointerProperties ---
-
-bool PointerProperties::operator==(const PointerProperties& other) const {
- return id == other.id
- && toolType == other.toolType;
-}
-
-void PointerProperties::copyFrom(const PointerProperties& other) {
- id = other.id;
- toolType = other.toolType;
-}
-
-
-// --- MotionEvent ---
-
-void MotionEvent::initialize(
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- size_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords) {
- InputEvent::initialize(deviceId, source);
- mAction = action;
- mFlags = flags;
- mEdgeFlags = edgeFlags;
- mMetaState = metaState;
- mButtonState = buttonState;
- mXOffset = xOffset;
- mYOffset = yOffset;
- mXPrecision = xPrecision;
- mYPrecision = yPrecision;
- mDownTime = downTime;
- mPointerProperties.clear();
- mPointerProperties.appendArray(pointerProperties, pointerCount);
- mSampleEventTimes.clear();
- mSamplePointerCoords.clear();
- addSample(eventTime, pointerCoords);
-}
-
-void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
- InputEvent::initialize(other->mDeviceId, other->mSource);
- mAction = other->mAction;
- mFlags = other->mFlags;
- mEdgeFlags = other->mEdgeFlags;
- mMetaState = other->mMetaState;
- mButtonState = other->mButtonState;
- mXOffset = other->mXOffset;
- mYOffset = other->mYOffset;
- mXPrecision = other->mXPrecision;
- mYPrecision = other->mYPrecision;
- mDownTime = other->mDownTime;
- mPointerProperties = other->mPointerProperties;
-
- if (keepHistory) {
- mSampleEventTimes = other->mSampleEventTimes;
- mSamplePointerCoords = other->mSamplePointerCoords;
- } else {
- mSampleEventTimes.clear();
- mSampleEventTimes.push(other->getEventTime());
- mSamplePointerCoords.clear();
- size_t pointerCount = other->getPointerCount();
- size_t historySize = other->getHistorySize();
- mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
- + (historySize * pointerCount), pointerCount);
- }
-}
-
-void MotionEvent::addSample(
- int64_t eventTime,
- const PointerCoords* pointerCoords) {
- mSampleEventTimes.push(eventTime);
- mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
-}
-
-const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
- return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
-}
-
-float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
- return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
-}
-
-float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
- float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
- switch (axis) {
- case AMOTION_EVENT_AXIS_X:
- return value + mXOffset;
- case AMOTION_EVENT_AXIS_Y:
- return value + mYOffset;
- }
- return value;
-}
-
-const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
- size_t pointerIndex, size_t historicalIndex) const {
- return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
-}
-
-float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
- size_t historicalIndex) const {
- return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
-}
-
-float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
- size_t historicalIndex) const {
- float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
- switch (axis) {
- case AMOTION_EVENT_AXIS_X:
- return value + mXOffset;
- case AMOTION_EVENT_AXIS_Y:
- return value + mYOffset;
- }
- return value;
-}
-
-ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
- size_t pointerCount = mPointerProperties.size();
- for (size_t i = 0; i < pointerCount; i++) {
- if (mPointerProperties.itemAt(i).id == pointerId) {
- return i;
- }
- }
- return -1;
-}
-
-void MotionEvent::offsetLocation(float xOffset, float yOffset) {
- mXOffset += xOffset;
- mYOffset += yOffset;
-}
-
-void MotionEvent::scale(float scaleFactor) {
- mXOffset *= scaleFactor;
- mYOffset *= scaleFactor;
- mXPrecision *= scaleFactor;
- mYPrecision *= scaleFactor;
-
- size_t numSamples = mSamplePointerCoords.size();
- for (size_t i = 0; i < numSamples; i++) {
- mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
- }
-}
-
-#ifdef HAVE_ANDROID_OS
-static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
- // Construct and transform a vector oriented at the specified clockwise angle from vertical.
- // Coordinate system: down is increasing Y, right is increasing X.
- SkPoint vector;
- vector.fX = SkFloatToScalar(sinf(angleRadians));
- vector.fY = SkFloatToScalar(-cosf(angleRadians));
- matrix->mapVectors(& vector, 1);
-
- // Derive the transformed vector's clockwise angle from vertical.
- float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
- if (result < - M_PI_2) {
- result += M_PI;
- } else if (result > M_PI_2) {
- result -= M_PI;
- }
- return result;
-}
-
-void MotionEvent::transform(const SkMatrix* matrix) {
- float oldXOffset = mXOffset;
- float oldYOffset = mYOffset;
-
- // The tricky part of this implementation is to preserve the value of
- // rawX and rawY. So we apply the transformation to the first point
- // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
- SkPoint point;
- float rawX = getRawX(0);
- float rawY = getRawY(0);
- matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
- & point);
- float newX = SkScalarToFloat(point.fX);
- float newY = SkScalarToFloat(point.fY);
- float newXOffset = newX - rawX;
- float newYOffset = newY - rawY;
-
- mXOffset = newXOffset;
- mYOffset = newYOffset;
-
- // Apply the transformation to all samples.
- size_t numSamples = mSamplePointerCoords.size();
- for (size_t i = 0; i < numSamples; i++) {
- PointerCoords& c = mSamplePointerCoords.editItemAt(i);
- float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
- float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
- matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
- c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
- c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
-
- float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
- c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
- }
-}
-
-status_t MotionEvent::readFromParcel(Parcel* parcel) {
- size_t pointerCount = parcel->readInt32();
- size_t sampleCount = parcel->readInt32();
- if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
- return BAD_VALUE;
- }
-
- mDeviceId = parcel->readInt32();
- mSource = parcel->readInt32();
- mAction = parcel->readInt32();
- mFlags = parcel->readInt32();
- mEdgeFlags = parcel->readInt32();
- mMetaState = parcel->readInt32();
- mButtonState = parcel->readInt32();
- mXOffset = parcel->readFloat();
- mYOffset = parcel->readFloat();
- mXPrecision = parcel->readFloat();
- mYPrecision = parcel->readFloat();
- mDownTime = parcel->readInt64();
-
- mPointerProperties.clear();
- mPointerProperties.setCapacity(pointerCount);
- mSampleEventTimes.clear();
- mSampleEventTimes.setCapacity(sampleCount);
- mSamplePointerCoords.clear();
- mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
-
- for (size_t i = 0; i < pointerCount; i++) {
- mPointerProperties.push();
- PointerProperties& properties = mPointerProperties.editTop();
- properties.id = parcel->readInt32();
- properties.toolType = parcel->readInt32();
- }
-
- while (sampleCount-- > 0) {
- mSampleEventTimes.push(parcel->readInt64());
- for (size_t i = 0; i < pointerCount; i++) {
- mSamplePointerCoords.push();
- status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
- if (status) {
- return status;
- }
- }
- }
- return OK;
-}
-
-status_t MotionEvent::writeToParcel(Parcel* parcel) const {
- size_t pointerCount = mPointerProperties.size();
- size_t sampleCount = mSampleEventTimes.size();
-
- parcel->writeInt32(pointerCount);
- parcel->writeInt32(sampleCount);
-
- parcel->writeInt32(mDeviceId);
- parcel->writeInt32(mSource);
- parcel->writeInt32(mAction);
- parcel->writeInt32(mFlags);
- parcel->writeInt32(mEdgeFlags);
- parcel->writeInt32(mMetaState);
- parcel->writeInt32(mButtonState);
- parcel->writeFloat(mXOffset);
- parcel->writeFloat(mYOffset);
- parcel->writeFloat(mXPrecision);
- parcel->writeFloat(mYPrecision);
- parcel->writeInt64(mDownTime);
-
- for (size_t i = 0; i < pointerCount; i++) {
- const PointerProperties& properties = mPointerProperties.itemAt(i);
- parcel->writeInt32(properties.id);
- parcel->writeInt32(properties.toolType);
- }
-
- const PointerCoords* pc = mSamplePointerCoords.array();
- for (size_t h = 0; h < sampleCount; h++) {
- parcel->writeInt64(mSampleEventTimes.itemAt(h));
- for (size_t i = 0; i < pointerCount; i++) {
- status_t status = (pc++)->writeToParcel(parcel);
- if (status) {
- return status;
- }
- }
- }
- return OK;
-}
-#endif
-
-bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
- if (source & AINPUT_SOURCE_CLASS_POINTER) {
- // Specifically excludes HOVER_MOVE and SCROLL.
- switch (action & AMOTION_EVENT_ACTION_MASK) {
- case AMOTION_EVENT_ACTION_DOWN:
- case AMOTION_EVENT_ACTION_MOVE:
- case AMOTION_EVENT_ACTION_UP:
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- case AMOTION_EVENT_ACTION_POINTER_UP:
- case AMOTION_EVENT_ACTION_CANCEL:
- case AMOTION_EVENT_ACTION_OUTSIDE:
- return true;
- }
- }
- return false;
-}
-
-
-// --- PooledInputEventFactory ---
-
-PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
- mMaxPoolSize(maxPoolSize) {
-}
-
-PooledInputEventFactory::~PooledInputEventFactory() {
- for (size_t i = 0; i < mKeyEventPool.size(); i++) {
- delete mKeyEventPool.itemAt(i);
- }
- for (size_t i = 0; i < mMotionEventPool.size(); i++) {
- delete mMotionEventPool.itemAt(i);
- }
-}
-
-KeyEvent* PooledInputEventFactory::createKeyEvent() {
- if (!mKeyEventPool.isEmpty()) {
- KeyEvent* event = mKeyEventPool.top();
- mKeyEventPool.pop();
- return event;
- }
- return new KeyEvent();
-}
-
-MotionEvent* PooledInputEventFactory::createMotionEvent() {
- if (!mMotionEventPool.isEmpty()) {
- MotionEvent* event = mMotionEventPool.top();
- mMotionEventPool.pop();
- return event;
- }
- return new MotionEvent();
-}
-
-void PooledInputEventFactory::recycle(InputEvent* event) {
- switch (event->getType()) {
- case AINPUT_EVENT_TYPE_KEY:
- if (mKeyEventPool.size() < mMaxPoolSize) {
- mKeyEventPool.push(static_cast<KeyEvent*>(event));
- return;
- }
- break;
- case AINPUT_EVENT_TYPE_MOTION:
- if (mMotionEventPool.size() < mMaxPoolSize) {
- mMotionEventPool.push(static_cast<MotionEvent*>(event));
- return;
- }
- break;
- }
- delete event;
-}
-
-} // namespace android
diff --git a/libs/androidfw/InputDevice.cpp b/libs/androidfw/InputDevice.cpp
deleted file mode 100644
index f742052..0000000
--- a/libs/androidfw/InputDevice.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "InputDevice"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <androidfw/InputDevice.h>
-
-namespace android {
-
-static const char* CONFIGURATION_FILE_DIR[] = {
- "idc/",
- "keylayout/",
- "keychars/",
-};
-
-static const char* CONFIGURATION_FILE_EXTENSION[] = {
- ".idc",
- ".kl",
- ".kcm",
-};
-
-static bool isValidNameChar(char ch) {
- return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
-}
-
-static void appendInputDeviceConfigurationFileRelativePath(String8& path,
- const String8& name, InputDeviceConfigurationFileType type) {
- path.append(CONFIGURATION_FILE_DIR[type]);
- for (size_t i = 0; i < name.length(); i++) {
- char ch = name[i];
- if (!isValidNameChar(ch)) {
- ch = '_';
- }
- path.append(&ch, 1);
- }
- path.append(CONFIGURATION_FILE_EXTENSION[type]);
-}
-
-String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
- const InputDeviceIdentifier& deviceIdentifier,
- InputDeviceConfigurationFileType type) {
- if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
- if (deviceIdentifier.version != 0) {
- // Try vendor product version.
- String8 versionPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x_Version_%04x",
- deviceIdentifier.vendor, deviceIdentifier.product,
- deviceIdentifier.version),
- type));
- if (!versionPath.isEmpty()) {
- return versionPath;
- }
- }
-
- // Try vendor product.
- String8 productPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x",
- deviceIdentifier.vendor, deviceIdentifier.product),
- type));
- if (!productPath.isEmpty()) {
- return productPath;
- }
- }
-
- // Try device name.
- return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
-}
-
-String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type) {
- // Search system repository.
- String8 path;
- path.setTo(getenv("ANDROID_ROOT"));
- path.append("/usr/");
- appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
- ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
-#endif
- if (!access(path.string(), R_OK)) {
-#if DEBUG_PROBE
- ALOGD("Found");
-#endif
- return path;
- }
-
- // Search user repository.
- // TODO Should only look here if not in safe mode.
- path.setTo(getenv("ANDROID_DATA"));
- path.append("/system/devices/");
- appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
- ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
-#endif
- if (!access(path.string(), R_OK)) {
-#if DEBUG_PROBE
- ALOGD("Found");
-#endif
- return path;
- }
-
- // Not found.
-#if DEBUG_PROBE
- ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
- name.string(), type);
-#endif
- return String8();
-}
-
-
-// --- InputDeviceInfo ---
-
-InputDeviceInfo::InputDeviceInfo() {
- initialize(-1, -1, InputDeviceIdentifier(), String8(), false);
-}
-
-InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
- mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier),
- mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources),
- mKeyboardType(other.mKeyboardType),
- mKeyCharacterMap(other.mKeyCharacterMap),
- mHasVibrator(other.mHasVibrator),
- mMotionRanges(other.mMotionRanges) {
-}
-
-InputDeviceInfo::~InputDeviceInfo() {
-}
-
-void InputDeviceInfo::initialize(int32_t id, int32_t generation,
- const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) {
- mId = id;
- mGeneration = generation;
- mIdentifier = identifier;
- mAlias = alias;
- mIsExternal = isExternal;
- mSources = 0;
- mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
- mHasVibrator = false;
- mMotionRanges.clear();
-}
-
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
- int32_t axis, uint32_t source) const {
- size_t numRanges = mMotionRanges.size();
- for (size_t i = 0; i < numRanges; i++) {
- const MotionRange& range = mMotionRanges.itemAt(i);
- if (range.axis == axis && range.source == source) {
- return ⦥
- }
- }
- return NULL;
-}
-
-void InputDeviceInfo::addSource(uint32_t source) {
- mSources |= source;
-}
-
-void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
- float flat, float fuzz, float resolution) {
- MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
- mMotionRanges.add(range);
-}
-
-void InputDeviceInfo::addMotionRange(const MotionRange& range) {
- mMotionRanges.add(range);
-}
-
-} // namespace android
diff --git a/libs/androidfw/InputTransport.cpp b/libs/androidfw/InputTransport.cpp
deleted file mode 100644
index cfbc923..0000000
--- a/libs/androidfw/InputTransport.cpp
+++ /dev/null
@@ -1,957 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// Provides a shared memory transport for input events.
-//
-#define LOG_TAG "InputTransport"
-
-//#define LOG_NDEBUG 0
-
-// Log debug messages about channel messages (send message, receive message)
-#define DEBUG_CHANNEL_MESSAGES 0
-
-// Log debug messages whenever InputChannel objects are created/destroyed
-#define DEBUG_CHANNEL_LIFECYCLE 0
-
-// Log debug messages about transport actions
-#define DEBUG_TRANSPORT_ACTIONS 0
-
-// Log debug messages about touch event resampling
-#define DEBUG_RESAMPLING 0
-
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <androidfw/InputTransport.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <math.h>
-
-
-namespace android {
-
-// Socket buffer size. The default is typically about 128KB, which is much larger than
-// we really need. So we make it smaller. It just needs to be big enough to hold
-// a few dozen large multi-finger motion events in the case where an application gets
-// behind processing touches.
-static const size_t SOCKET_BUFFER_SIZE = 32 * 1024;
-
-// Nanoseconds per milliseconds.
-static const nsecs_t NANOS_PER_MS = 1000000;
-
-// Latency added during resampling. A few milliseconds doesn't hurt much but
-// reduces the impact of mispredicted touch positions.
-static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS;
-
-// Minimum time difference between consecutive samples before attempting to resample.
-static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS;
-
-// Maximum time to predict forward from the last known state, to avoid predicting too
-// far into the future. This time is further bounded by 50% of the last time delta.
-static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
-
-template<typename T>
-inline static T min(const T& a, const T& b) {
- return a < b ? a : b;
-}
-
-inline static float lerp(float a, float b, float alpha) {
- return a + alpha * (b - a);
-}
-
-// --- InputMessage ---
-
-bool InputMessage::isValid(size_t actualSize) const {
- if (size() == actualSize) {
- switch (header.type) {
- case TYPE_KEY:
- return true;
- case TYPE_MOTION:
- return body.motion.pointerCount > 0
- && body.motion.pointerCount <= MAX_POINTERS;
- case TYPE_FINISHED:
- return true;
- }
- }
- return false;
-}
-
-size_t InputMessage::size() const {
- switch (header.type) {
- case TYPE_KEY:
- return sizeof(Header) + body.key.size();
- case TYPE_MOTION:
- return sizeof(Header) + body.motion.size();
- case TYPE_FINISHED:
- return sizeof(Header) + body.finished.size();
- }
- return sizeof(Header);
-}
-
-
-// --- InputChannel ---
-
-InputChannel::InputChannel(const String8& name, int fd) :
- mName(name), mFd(fd) {
-#if DEBUG_CHANNEL_LIFECYCLE
- ALOGD("Input channel constructed: name='%s', fd=%d",
- mName.string(), fd);
-#endif
-
- int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
- "non-blocking. errno=%d", mName.string(), errno);
-}
-
-InputChannel::~InputChannel() {
-#if DEBUG_CHANNEL_LIFECYCLE
- ALOGD("Input channel destroyed: name='%s', fd=%d",
- mName.string(), mFd);
-#endif
-
- ::close(mFd);
-}
-
-status_t InputChannel::openInputChannelPair(const String8& name,
- sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
- int sockets[2];
- if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
- status_t result = -errno;
- ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
- name.string(), errno);
- outServerChannel.clear();
- outClientChannel.clear();
- return result;
- }
-
- int bufferSize = SOCKET_BUFFER_SIZE;
- setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
- setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
- setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
- setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
-
- String8 serverChannelName = name;
- serverChannelName.append(" (server)");
- outServerChannel = new InputChannel(serverChannelName, sockets[0]);
-
- String8 clientChannelName = name;
- clientChannelName.append(" (client)");
- outClientChannel = new InputChannel(clientChannelName, sockets[1]);
- return OK;
-}
-
-status_t InputChannel::sendMessage(const InputMessage* msg) {
- size_t msgLength = msg->size();
- ssize_t nWrite;
- do {
- nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
- } while (nWrite == -1 && errno == EINTR);
-
- if (nWrite < 0) {
- int error = errno;
-#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
- msg->header.type, error);
-#endif
- if (error == EAGAIN || error == EWOULDBLOCK) {
- return WOULD_BLOCK;
- }
- if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
- return DEAD_OBJECT;
- }
- return -error;
- }
-
- if (size_t(nWrite) != msgLength) {
-#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
- mName.string(), msg->header.type);
-#endif
- return DEAD_OBJECT;
- }
-
-#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
-#endif
- return OK;
-}
-
-status_t InputChannel::receiveMessage(InputMessage* msg) {
- ssize_t nRead;
- do {
- nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
- } while (nRead == -1 && errno == EINTR);
-
- if (nRead < 0) {
- int error = errno;
-#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
-#endif
- if (error == EAGAIN || error == EWOULDBLOCK) {
- return WOULD_BLOCK;
- }
- if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
- return DEAD_OBJECT;
- }
- return -error;
- }
-
- if (nRead == 0) { // check for EOF
-#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
-#endif
- return DEAD_OBJECT;
- }
-
- if (!msg->isValid(nRead)) {
-#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ received invalid message", mName.string());
-#endif
- return BAD_VALUE;
- }
-
-#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
-#endif
- return OK;
-}
-
-sp<InputChannel> InputChannel::dup() const {
- int fd = ::dup(getFd());
- return fd >= 0 ? new InputChannel(getName(), fd) : NULL;
-}
-
-
-// --- InputPublisher ---
-
-InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
- mChannel(channel) {
-}
-
-InputPublisher::~InputPublisher() {
-}
-
-status_t InputPublisher::publishKeyEvent(
- uint32_t seq,
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t keyCode,
- int32_t scanCode,
- int32_t metaState,
- int32_t repeatCount,
- nsecs_t downTime,
- nsecs_t eventTime) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
- "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
- "downTime=%lld, eventTime=%lld",
- mChannel->getName().string(), seq,
- deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
- downTime, eventTime);
-#endif
-
- if (!seq) {
- ALOGE("Attempted to publish a key event with sequence number 0.");
- return BAD_VALUE;
- }
-
- InputMessage msg;
- msg.header.type = InputMessage::TYPE_KEY;
- msg.body.key.seq = seq;
- msg.body.key.deviceId = deviceId;
- msg.body.key.source = source;
- msg.body.key.action = action;
- msg.body.key.flags = flags;
- msg.body.key.keyCode = keyCode;
- msg.body.key.scanCode = scanCode;
- msg.body.key.metaState = metaState;
- msg.body.key.repeatCount = repeatCount;
- msg.body.key.downTime = downTime;
- msg.body.key.eventTime = eventTime;
- return mChannel->sendMessage(&msg);
-}
-
-status_t InputPublisher::publishMotionEvent(
- uint32_t seq,
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- size_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
- "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
- "xOffset=%f, yOffset=%f, "
- "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
- "pointerCount=%d",
- mChannel->getName().string(), seq,
- deviceId, source, action, flags, edgeFlags, metaState, buttonState,
- xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
-#endif
-
- if (!seq) {
- ALOGE("Attempted to publish a motion event with sequence number 0.");
- return BAD_VALUE;
- }
-
- if (pointerCount > MAX_POINTERS || pointerCount < 1) {
- ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
- mChannel->getName().string(), pointerCount);
- return BAD_VALUE;
- }
-
- InputMessage msg;
- msg.header.type = InputMessage::TYPE_MOTION;
- msg.body.motion.seq = seq;
- msg.body.motion.deviceId = deviceId;
- msg.body.motion.source = source;
- msg.body.motion.action = action;
- msg.body.motion.flags = flags;
- msg.body.motion.edgeFlags = edgeFlags;
- msg.body.motion.metaState = metaState;
- msg.body.motion.buttonState = buttonState;
- msg.body.motion.xOffset = xOffset;
- msg.body.motion.yOffset = yOffset;
- msg.body.motion.xPrecision = xPrecision;
- msg.body.motion.yPrecision = yPrecision;
- msg.body.motion.downTime = downTime;
- msg.body.motion.eventTime = eventTime;
- msg.body.motion.pointerCount = pointerCount;
- for (size_t i = 0; i < pointerCount; i++) {
- msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
- msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
- }
- return mChannel->sendMessage(&msg);
-}
-
-status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
- mChannel->getName().string());
-#endif
-
- InputMessage msg;
- status_t result = mChannel->receiveMessage(&msg);
- if (result) {
- *outSeq = 0;
- *outHandled = false;
- return result;
- }
- if (msg.header.type != InputMessage::TYPE_FINISHED) {
- ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
- mChannel->getName().string(), msg.header.type);
- return UNKNOWN_ERROR;
- }
- *outSeq = msg.body.finished.seq;
- *outHandled = msg.body.finished.handled;
- return OK;
-}
-
-// --- InputConsumer ---
-
-InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
- mResampleTouch(isTouchResamplingEnabled()),
- mChannel(channel), mMsgDeferred(false) {
-}
-
-InputConsumer::~InputConsumer() {
-}
-
-bool InputConsumer::isTouchResamplingEnabled() {
- char value[PROPERTY_VALUE_MAX];
- int length = property_get("debug.inputconsumer.resample", value, NULL);
- if (length > 0) {
- if (!strcmp("0", value)) {
- return false;
- }
- if (strcmp("1", value)) {
- ALOGD("Unrecognized property value for 'debug.inputconsumer.resample'. "
- "Use '1' or '0'.");
- }
- }
- return true;
-}
-
-status_t InputConsumer::consume(InputEventFactoryInterface* factory,
- bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
- mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
-#endif
-
- *outSeq = 0;
- *outEvent = NULL;
-
- // Fetch the next input message.
- // Loop until an event can be returned or no additional events are received.
- while (!*outEvent) {
- if (mMsgDeferred) {
- // mMsg contains a valid input message from the previous call to consume
- // that has not yet been processed.
- mMsgDeferred = false;
- } else {
- // Receive a fresh message.
- status_t result = mChannel->receiveMessage(&mMsg);
- if (result) {
- // Consume the next batched event unless batches are being held for later.
- if (consumeBatches || result != WOULD_BLOCK) {
- result = consumeBatch(factory, frameTime, outSeq, outEvent);
- if (*outEvent) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
- mChannel->getName().string(), *outSeq);
-#endif
- break;
- }
- }
- return result;
- }
- }
-
- switch (mMsg.header.type) {
- case InputMessage::TYPE_KEY: {
- KeyEvent* keyEvent = factory->createKeyEvent();
- if (!keyEvent) return NO_MEMORY;
-
- initializeKeyEvent(keyEvent, &mMsg);
- *outSeq = mMsg.body.key.seq;
- *outEvent = keyEvent;
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
- mChannel->getName().string(), *outSeq);
-#endif
- break;
- }
-
- case AINPUT_EVENT_TYPE_MOTION: {
- ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
- if (batchIndex >= 0) {
- Batch& batch = mBatches.editItemAt(batchIndex);
- if (canAddSample(batch, &mMsg)) {
- batch.samples.push(mMsg);
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ appended to batch event",
- mChannel->getName().string());
-#endif
- break;
- } else {
- // We cannot append to the batch in progress, so we need to consume
- // the previous batch right now and defer the new message until later.
- mMsgDeferred = true;
- status_t result = consumeSamples(factory,
- batch, batch.samples.size(), outSeq, outEvent);
- mBatches.removeAt(batchIndex);
- if (result) {
- return result;
- }
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consumed batch event and "
- "deferred current event, seq=%u",
- mChannel->getName().string(), *outSeq);
-#endif
- break;
- }
- }
-
- // Start a new batch if needed.
- if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
- || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- mBatches.push();
- Batch& batch = mBatches.editTop();
- batch.samples.push(mMsg);
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ started batch event",
- mChannel->getName().string());
-#endif
- break;
- }
-
- MotionEvent* motionEvent = factory->createMotionEvent();
- if (! motionEvent) return NO_MEMORY;
-
- updateTouchState(&mMsg);
- initializeMotionEvent(motionEvent, &mMsg);
- *outSeq = mMsg.body.motion.seq;
- *outEvent = motionEvent;
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
- mChannel->getName().string(), *outSeq);
-#endif
- break;
- }
-
- default:
- ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
- mChannel->getName().string(), mMsg.header.type);
- return UNKNOWN_ERROR;
- }
- }
- return OK;
-}
-
-status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
- status_t result;
- for (size_t i = mBatches.size(); i-- > 0; ) {
- Batch& batch = mBatches.editItemAt(i);
- if (frameTime < 0) {
- result = consumeSamples(factory, batch, batch.samples.size(),
- outSeq, outEvent);
- mBatches.removeAt(i);
- return result;
- }
-
- nsecs_t sampleTime = frameTime - RESAMPLE_LATENCY;
- ssize_t split = findSampleNoLaterThan(batch, sampleTime);
- if (split < 0) {
- continue;
- }
-
- result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
- const InputMessage* next;
- if (batch.samples.isEmpty()) {
- mBatches.removeAt(i);
- next = NULL;
- } else {
- next = &batch.samples.itemAt(0);
- }
- if (!result) {
- resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
- }
- return result;
- }
-
- return WOULD_BLOCK;
-}
-
-status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
- MotionEvent* motionEvent = factory->createMotionEvent();
- if (! motionEvent) return NO_MEMORY;
-
- uint32_t chain = 0;
- for (size_t i = 0; i < count; i++) {
- InputMessage& msg = batch.samples.editItemAt(i);
- updateTouchState(&msg);
- if (i) {
- SeqChain seqChain;
- seqChain.seq = msg.body.motion.seq;
- seqChain.chain = chain;
- mSeqChains.push(seqChain);
- addSample(motionEvent, &msg);
- } else {
- initializeMotionEvent(motionEvent, &msg);
- }
- chain = msg.body.motion.seq;
- }
- batch.samples.removeItemsAt(0, count);
-
- *outSeq = chain;
- *outEvent = motionEvent;
- return OK;
-}
-
-void InputConsumer::updateTouchState(InputMessage* msg) {
- if (!mResampleTouch ||
- !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
- return;
- }
-
- int32_t deviceId = msg->body.motion.deviceId;
- int32_t source = msg->body.motion.source;
- nsecs_t eventTime = msg->body.motion.eventTime;
-
- // Update the touch state history to incorporate the new input message.
- // If the message is in the past relative to the most recently produced resampled
- // touch, then use the resampled time and coordinates instead.
- switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) {
- case AMOTION_EVENT_ACTION_DOWN: {
- ssize_t index = findTouchState(deviceId, source);
- if (index < 0) {
- mTouchStates.push();
- index = mTouchStates.size() - 1;
- }
- TouchState& touchState = mTouchStates.editItemAt(index);
- touchState.initialize(deviceId, source);
- touchState.addHistory(msg);
- break;
- }
-
- case AMOTION_EVENT_ACTION_MOVE: {
- ssize_t index = findTouchState(deviceId, source);
- if (index >= 0) {
- TouchState& touchState = mTouchStates.editItemAt(index);
- touchState.addHistory(msg);
- if (eventTime < touchState.lastResample.eventTime) {
- rewriteMessage(touchState, msg);
- } else {
- touchState.lastResample.idBits.clear();
- }
- }
- break;
- }
-
- case AMOTION_EVENT_ACTION_POINTER_DOWN: {
- ssize_t index = findTouchState(deviceId, source);
- if (index >= 0) {
- TouchState& touchState = mTouchStates.editItemAt(index);
- touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
- rewriteMessage(touchState, msg);
- }
- break;
- }
-
- case AMOTION_EVENT_ACTION_POINTER_UP: {
- ssize_t index = findTouchState(deviceId, source);
- if (index >= 0) {
- TouchState& touchState = mTouchStates.editItemAt(index);
- rewriteMessage(touchState, msg);
- touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
- }
- break;
- }
-
- case AMOTION_EVENT_ACTION_SCROLL: {
- ssize_t index = findTouchState(deviceId, source);
- if (index >= 0) {
- const TouchState& touchState = mTouchStates.itemAt(index);
- rewriteMessage(touchState, msg);
- }
- break;
- }
-
- case AMOTION_EVENT_ACTION_UP:
- case AMOTION_EVENT_ACTION_CANCEL: {
- ssize_t index = findTouchState(deviceId, source);
- if (index >= 0) {
- const TouchState& touchState = mTouchStates.itemAt(index);
- rewriteMessage(touchState, msg);
- mTouchStates.removeAt(index);
- }
- break;
- }
- }
-}
-
-void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) {
- for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
- uint32_t id = msg->body.motion.pointers[i].properties.id;
- if (state.lastResample.idBits.hasBit(id)) {
- PointerCoords& msgCoords = msg->body.motion.pointers[i].coords;
- const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
-#if DEBUG_RESAMPLING
- ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
- resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
- resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y),
- msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
- msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
-#endif
- msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
- msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
- }
- }
-}
-
-void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
- const InputMessage* next) {
- if (!mResampleTouch
- || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER)
- || event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
- return;
- }
-
- ssize_t index = findTouchState(event->getDeviceId(), event->getSource());
- if (index < 0) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, no touch state for device.");
-#endif
- return;
- }
-
- TouchState& touchState = mTouchStates.editItemAt(index);
- if (touchState.historySize < 1) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, no history for device.");
-#endif
- return;
- }
-
- // Ensure that the current sample has all of the pointers that need to be reported.
- const History* current = touchState.getHistory(0);
- size_t pointerCount = event->getPointerCount();
- for (size_t i = 0; i < pointerCount; i++) {
- uint32_t id = event->getPointerId(i);
- if (!current->idBits.hasBit(id)) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, missing id %d", id);
-#endif
- return;
- }
- }
-
- // Find the data to use for resampling.
- const History* other;
- History future;
- float alpha;
- if (next) {
- // Interpolate between current sample and future sample.
- // So current->eventTime <= sampleTime <= future.eventTime.
- future.initializeFrom(next);
- other = &future;
- nsecs_t delta = future.eventTime - current->eventTime;
- if (delta < RESAMPLE_MIN_DELTA) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, delta time is %lld ns.", delta);
-#endif
- return;
- }
- alpha = float(sampleTime - current->eventTime) / delta;
- } else if (touchState.historySize >= 2) {
- // Extrapolate future sample using current sample and past sample.
- // So other->eventTime <= current->eventTime <= sampleTime.
- other = touchState.getHistory(1);
- nsecs_t delta = current->eventTime - other->eventTime;
- if (delta < RESAMPLE_MIN_DELTA) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, delta time is %lld ns.", delta);
-#endif
- return;
- }
- nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION);
- if (sampleTime > maxPredict) {
-#if DEBUG_RESAMPLING
- ALOGD("Sample time is too far in the future, adjusting prediction "
- "from %lld to %lld ns.",
- sampleTime - current->eventTime, maxPredict - current->eventTime);
-#endif
- sampleTime = maxPredict;
- }
- alpha = float(current->eventTime - sampleTime) / delta;
- } else {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, insufficient data.");
-#endif
- return;
- }
-
- // Resample touch coordinates.
- touchState.lastResample.eventTime = sampleTime;
- touchState.lastResample.idBits.clear();
- for (size_t i = 0; i < pointerCount; i++) {
- uint32_t id = event->getPointerId(i);
- touchState.lastResample.idToIndex[id] = i;
- touchState.lastResample.idBits.markBit(id);
- PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
- const PointerCoords& currentCoords = current->getPointerById(id);
- if (other->idBits.hasBit(id)
- && shouldResampleTool(event->getToolType(i))) {
- const PointerCoords& otherCoords = other->getPointerById(id);
- resampledCoords.copyFrom(currentCoords);
- resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
- lerp(currentCoords.getX(), otherCoords.getX(), alpha));
- resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
- lerp(currentCoords.getY(), otherCoords.getY(), alpha));
-#if DEBUG_RESAMPLING
- ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), "
- "other (%0.3f, %0.3f), alpha %0.3f",
- id, resampledCoords.getX(), resampledCoords.getY(),
- currentCoords.getX(), currentCoords.getY(),
- otherCoords.getX(), otherCoords.getY(),
- alpha);
-#endif
- } else {
- resampledCoords.copyFrom(currentCoords);
-#if DEBUG_RESAMPLING
- ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)",
- id, resampledCoords.getX(), resampledCoords.getY(),
- currentCoords.getX(), currentCoords.getY());
-#endif
- }
- }
-
- event->addSample(sampleTime, touchState.lastResample.pointers);
-}
-
-bool InputConsumer::shouldResampleTool(int32_t toolType) {
- return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
- || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
-}
-
-status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
- mChannel->getName().string(), seq, handled ? "true" : "false");
-#endif
-
- if (!seq) {
- ALOGE("Attempted to send a finished signal with sequence number 0.");
- return BAD_VALUE;
- }
-
- // Send finished signals for the batch sequence chain first.
- size_t seqChainCount = mSeqChains.size();
- if (seqChainCount) {
- uint32_t currentSeq = seq;
- uint32_t chainSeqs[seqChainCount];
- size_t chainIndex = 0;
- for (size_t i = seqChainCount; i-- > 0; ) {
- const SeqChain& seqChain = mSeqChains.itemAt(i);
- if (seqChain.seq == currentSeq) {
- currentSeq = seqChain.chain;
- chainSeqs[chainIndex++] = currentSeq;
- mSeqChains.removeAt(i);
- }
- }
- status_t status = OK;
- while (!status && chainIndex-- > 0) {
- status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
- }
- if (status) {
- // An error occurred so at least one signal was not sent, reconstruct the chain.
- do {
- SeqChain seqChain;
- seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
- seqChain.chain = chainSeqs[chainIndex];
- mSeqChains.push(seqChain);
- } while (chainIndex-- > 0);
- return status;
- }
- }
-
- // Send finished signal for the last message in the batch.
- return sendUnchainedFinishedSignal(seq, handled);
-}
-
-status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
- InputMessage msg;
- msg.header.type = InputMessage::TYPE_FINISHED;
- msg.body.finished.seq = seq;
- msg.body.finished.handled = handled;
- return mChannel->sendMessage(&msg);
-}
-
-bool InputConsumer::hasDeferredEvent() const {
- return mMsgDeferred;
-}
-
-bool InputConsumer::hasPendingBatch() const {
- return !mBatches.isEmpty();
-}
-
-ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
- for (size_t i = 0; i < mBatches.size(); i++) {
- const Batch& batch = mBatches.itemAt(i);
- const InputMessage& head = batch.samples.itemAt(0);
- if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) {
- return i;
- }
- }
- return -1;
-}
-
-ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const {
- for (size_t i = 0; i < mTouchStates.size(); i++) {
- const TouchState& touchState = mTouchStates.itemAt(i);
- if (touchState.deviceId == deviceId && touchState.source == source) {
- return i;
- }
- }
- return -1;
-}
-
-void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
- event->initialize(
- msg->body.key.deviceId,
- msg->body.key.source,
- msg->body.key.action,
- msg->body.key.flags,
- msg->body.key.keyCode,
- msg->body.key.scanCode,
- msg->body.key.metaState,
- msg->body.key.repeatCount,
- msg->body.key.downTime,
- msg->body.key.eventTime);
-}
-
-void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
- size_t pointerCount = msg->body.motion.pointerCount;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
- pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
- }
-
- event->initialize(
- msg->body.motion.deviceId,
- msg->body.motion.source,
- msg->body.motion.action,
- msg->body.motion.flags,
- msg->body.motion.edgeFlags,
- msg->body.motion.metaState,
- msg->body.motion.buttonState,
- msg->body.motion.xOffset,
- msg->body.motion.yOffset,
- msg->body.motion.xPrecision,
- msg->body.motion.yPrecision,
- msg->body.motion.downTime,
- msg->body.motion.eventTime,
- pointerCount,
- pointerProperties,
- pointerCoords);
-}
-
-void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
- size_t pointerCount = msg->body.motion.pointerCount;
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
- }
-
- event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
- event->addSample(msg->body.motion.eventTime, pointerCoords);
-}
-
-bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) {
- const InputMessage& head = batch.samples.itemAt(0);
- size_t pointerCount = msg->body.motion.pointerCount;
- if (head.body.motion.pointerCount != pointerCount
- || head.body.motion.action != msg->body.motion.action) {
- return false;
- }
- for (size_t i = 0; i < pointerCount; i++) {
- if (head.body.motion.pointers[i].properties
- != msg->body.motion.pointers[i].properties) {
- return false;
- }
- }
- return true;
-}
-
-ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) {
- size_t numSamples = batch.samples.size();
- size_t index = 0;
- while (index < numSamples
- && batch.samples.itemAt(index).body.motion.eventTime <= time) {
- index += 1;
- }
- return ssize_t(index) - 1;
-}
-
-} // namespace android
diff --git a/libs/androidfw/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
deleted file mode 100644
index 36cb6e1..0000000
--- a/libs/androidfw/KeyCharacterMap.cpp
+++ /dev/null
@@ -1,1153 +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.
- */
-
-#define LOG_TAG "KeyCharacterMap"
-
-#include <stdlib.h>
-#include <string.h>
-#include <android/keycodes.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeyCharacterMap.h>
-
-#if HAVE_ANDROID_OS
-#include <binder/Parcel.h>
-#endif
-
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-#include <utils/Timers.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-// Enables debug output for mapping.
-#define DEBUG_MAPPING 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
-
-struct Modifier {
- const char* label;
- int32_t metaState;
-};
-static const Modifier modifiers[] = {
- { "shift", AMETA_SHIFT_ON },
- { "lshift", AMETA_SHIFT_LEFT_ON },
- { "rshift", AMETA_SHIFT_RIGHT_ON },
- { "alt", AMETA_ALT_ON },
- { "lalt", AMETA_ALT_LEFT_ON },
- { "ralt", AMETA_ALT_RIGHT_ON },
- { "ctrl", AMETA_CTRL_ON },
- { "lctrl", AMETA_CTRL_LEFT_ON },
- { "rctrl", AMETA_CTRL_RIGHT_ON },
- { "meta", AMETA_META_ON },
- { "lmeta", AMETA_META_LEFT_ON },
- { "rmeta", AMETA_META_RIGHT_ON },
- { "sym", AMETA_SYM_ON },
- { "fn", AMETA_FUNCTION_ON },
- { "capslock", AMETA_CAPS_LOCK_ON },
- { "numlock", AMETA_NUM_LOCK_ON },
- { "scrolllock", AMETA_SCROLL_LOCK_ON },
-};
-
-#if DEBUG_MAPPING
-static String8 toString(const char16_t* chars, size_t numChars) {
- String8 result;
- for (size_t i = 0; i < numChars; i++) {
- result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
- }
- return result;
-}
-#endif
-
-
-// --- KeyCharacterMap ---
-
-sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap();
-
-KeyCharacterMap::KeyCharacterMap() :
- mType(KEYBOARD_TYPE_UNKNOWN) {
-}
-
-KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) :
- RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode),
- mKeysByUsageCode(other.mKeysByUsageCode) {
- for (size_t i = 0; i < other.mKeys.size(); i++) {
- mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
- }
-}
-
-KeyCharacterMap::~KeyCharacterMap() {
- for (size_t i = 0; i < mKeys.size(); i++) {
- Key* key = mKeys.editValueAt(i);
- delete key;
- }
-}
-
-status_t KeyCharacterMap::load(const String8& filename,
- Format format, sp<KeyCharacterMap>* outMap) {
- outMap->clear();
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
- if (status) {
- ALOGE("Error %d opening key character map file %s.", status, filename.string());
- } else {
- status = load(tokenizer, format, outMap);
- delete tokenizer;
- }
- return status;
-}
-
-status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
- Format format, sp<KeyCharacterMap>* outMap) {
- outMap->clear();
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
- if (status) {
- ALOGE("Error %d opening key character map.", status);
- } else {
- status = load(tokenizer, format, outMap);
- delete tokenizer;
- }
- return status;
-}
-
-status_t KeyCharacterMap::load(Tokenizer* tokenizer,
- Format format, sp<KeyCharacterMap>* outMap) {
- status_t status = OK;
- sp<KeyCharacterMap> map = new KeyCharacterMap();
- if (!map.get()) {
- ALOGE("Error allocating key character map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map.get(), tokenizer, format);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (!status) {
- *outMap = map;
- }
- }
- return status;
-}
-
-sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
- const sp<KeyCharacterMap>& overlay) {
- if (overlay == NULL) {
- return base;
- }
- if (base == NULL) {
- return overlay;
- }
-
- sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get());
- for (size_t i = 0; i < overlay->mKeys.size(); i++) {
- int32_t keyCode = overlay->mKeys.keyAt(i);
- Key* key = overlay->mKeys.valueAt(i);
- ssize_t oldIndex = map->mKeys.indexOfKey(keyCode);
- if (oldIndex >= 0) {
- delete map->mKeys.valueAt(oldIndex);
- map->mKeys.editValueAt(oldIndex) = new Key(*key);
- } else {
- map->mKeys.add(keyCode, new Key(*key));
- }
- }
-
- for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) {
- map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i),
- overlay->mKeysByScanCode.valueAt(i));
- }
-
- for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) {
- map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i),
- overlay->mKeysByUsageCode.valueAt(i));
- }
- return map;
-}
-
-sp<KeyCharacterMap> KeyCharacterMap::empty() {
- return sEmpty;
-}
-
-int32_t KeyCharacterMap::getKeyboardType() const {
- return mType;
-}
-
-char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
- char16_t result = 0;
- const Key* key;
- if (getKey(keyCode, &key)) {
- result = key->label;
- }
-#if DEBUG_MAPPING
- ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
-#endif
- return result;
-}
-
-char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
- char16_t result = 0;
- const Key* key;
- if (getKey(keyCode, &key)) {
- result = key->number;
- }
-#if DEBUG_MAPPING
- ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
-#endif
- return result;
-}
-
-char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
- char16_t result = 0;
- const Key* key;
- const Behavior* behavior;
- if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
- result = behavior->character;
- }
-#if DEBUG_MAPPING
- ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
-#endif
- return result;
-}
-
-bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
- FallbackAction* outFallbackAction) const {
- outFallbackAction->keyCode = 0;
- outFallbackAction->metaState = 0;
-
- bool result = false;
- const Key* key;
- const Behavior* behavior;
- if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
- if (behavior->fallbackKeyCode) {
- outFallbackAction->keyCode = behavior->fallbackKeyCode;
- outFallbackAction->metaState = metaState & ~behavior->metaState;
- result = true;
- }
- }
-#if DEBUG_MAPPING
- ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
- "fallback keyCode=%d, fallback metaState=0x%08x.",
- keyCode, metaState, result ? "true" : "false",
- outFallbackAction->keyCode, outFallbackAction->metaState);
-#endif
- return result;
-}
-
-char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
- int32_t metaState) const {
- char16_t result = 0;
- const Key* key;
- if (getKey(keyCode, &key)) {
- // Try to find the most general behavior that maps to this character.
- // For example, the base key behavior will usually be last in the list.
- // However, if we find a perfect meta state match for one behavior then use that one.
- for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
- if (behavior->character) {
- for (size_t i = 0; i < numChars; i++) {
- if (behavior->character == chars[i]) {
- result = behavior->character;
- if ((behavior->metaState & metaState) == behavior->metaState) {
- goto ExactMatch;
- }
- break;
- }
- }
- }
- }
- ExactMatch: ;
- }
-#if DEBUG_MAPPING
- ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
- keyCode, toString(chars, numChars).string(), metaState, result);
-#endif
- return result;
-}
-
-bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
- Vector<KeyEvent>& outEvents) const {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-
- for (size_t i = 0; i < numChars; i++) {
- int32_t keyCode, metaState;
- char16_t ch = chars[i];
- if (!findKey(ch, &keyCode, &metaState)) {
-#if DEBUG_MAPPING
- ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
- deviceId, toString(chars, numChars).string(), ch);
-#endif
- return false;
- }
-
- int32_t currentMetaState = 0;
- addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState);
- addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
- addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
- addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState);
- }
-#if DEBUG_MAPPING
- ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
- deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
- for (size_t i = 0; i < outEvents.size(); i++) {
- ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
- outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
- outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
- }
-#endif
- return true;
-}
-
-status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
- if (usageCode) {
- ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
- if (index >= 0) {
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
- scanCode, usageCode, *outKeyCode);
-#endif
- *outKeyCode = mKeysByUsageCode.valueAt(index);
- return OK;
- }
- }
- if (scanCode) {
- ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
- if (index >= 0) {
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
- scanCode, usageCode, *outKeyCode);
-#endif
- *outKeyCode = mKeysByScanCode.valueAt(index);
- return OK;
- }
- }
-
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
-#endif
- *outKeyCode = AKEYCODE_UNKNOWN;
- return NAME_NOT_FOUND;
-}
-
-bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
- ssize_t index = mKeys.indexOfKey(keyCode);
- if (index >= 0) {
- *outKey = mKeys.valueAt(index);
- return true;
- }
- return false;
-}
-
-bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
- const Key** outKey, const Behavior** outBehavior) const {
- const Key* key;
- if (getKey(keyCode, &key)) {
- const Behavior* behavior = key->firstBehavior;
- while (behavior) {
- if (matchesMetaState(metaState, behavior->metaState)) {
- *outKey = key;
- *outBehavior = behavior;
- return true;
- }
- behavior = behavior->next;
- }
- }
- return false;
-}
-
-bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
- // Behavior must have at least the set of meta states specified.
- // And if the key event has CTRL, ALT or META then the behavior must exactly
- // match those, taking into account that a behavior can specify that it handles
- // one, both or either of a left/right modifier pair.
- if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
- const int32_t EXACT_META_STATES =
- AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
- | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
- | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
- int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
- if (behaviorMetaState & AMETA_CTRL_ON) {
- unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
- } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
- unmatchedMetaState &= ~AMETA_CTRL_ON;
- }
- if (behaviorMetaState & AMETA_ALT_ON) {
- unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
- } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
- unmatchedMetaState &= ~AMETA_ALT_ON;
- }
- if (behaviorMetaState & AMETA_META_ON) {
- unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
- } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
- unmatchedMetaState &= ~AMETA_META_ON;
- }
- return !unmatchedMetaState;
- }
- return false;
-}
-
-bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
- if (!ch) {
- return false;
- }
-
- for (size_t i = 0; i < mKeys.size(); i++) {
- const Key* key = mKeys.valueAt(i);
-
- // Try to find the most general behavior that maps to this character.
- // For example, the base key behavior will usually be last in the list.
- const Behavior* found = NULL;
- for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
- if (behavior->character == ch) {
- found = behavior;
- }
- }
- if (found) {
- *outKeyCode = mKeys.keyAt(i);
- *outMetaState = found->metaState;
- return true;
- }
- }
- return false;
-}
-
-void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
- outEvents.push();
- KeyEvent& event = outEvents.editTop();
- event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
- down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- 0, keyCode, 0, metaState, 0, time, time);
-}
-
-void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
- int32_t* currentMetaState) {
- // Add and remove meta keys symmetrically.
- if (down) {
- addLockedMetaKey(outEvents, deviceId, metaState, time,
- AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
- addLockedMetaKey(outEvents, deviceId, metaState, time,
- AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
- addLockedMetaKey(outEvents, deviceId, metaState, time,
- AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
-
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
- AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
- AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
- AMETA_SHIFT_ON, currentMetaState);
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
- AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
- AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
- AMETA_ALT_ON, currentMetaState);
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
- AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
- AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
- AMETA_CTRL_ON, currentMetaState);
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
- AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
- AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
- AMETA_META_ON, currentMetaState);
-
- addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
- AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
- addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
- AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
- } else {
- addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
- AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
- addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
- AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
-
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
- AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
- AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
- AMETA_META_ON, currentMetaState);
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
- AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
- AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
- AMETA_CTRL_ON, currentMetaState);
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
- AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
- AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
- AMETA_ALT_ON, currentMetaState);
- addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
- AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
- AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
- AMETA_SHIFT_ON, currentMetaState);
-
- addLockedMetaKey(outEvents, deviceId, metaState, time,
- AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
- addLockedMetaKey(outEvents, deviceId, metaState, time,
- AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
- addLockedMetaKey(outEvents, deviceId, metaState, time,
- AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
- }
-}
-
-bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
- int32_t keyCode, int32_t keyMetaState,
- int32_t* currentMetaState) {
- if ((metaState & keyMetaState) == keyMetaState) {
- *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
- addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
- return true;
- }
- return false;
-}
-
-void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
- int32_t leftKeyCode, int32_t leftKeyMetaState,
- int32_t rightKeyCode, int32_t rightKeyMetaState,
- int32_t eitherKeyMetaState,
- int32_t* currentMetaState) {
- bool specific = false;
- specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
- leftKeyCode, leftKeyMetaState, currentMetaState);
- specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
- rightKeyCode, rightKeyMetaState, currentMetaState);
-
- if (!specific) {
- addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
- leftKeyCode, eitherKeyMetaState, currentMetaState);
- }
-}
-
-void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
- int32_t deviceId, int32_t metaState, nsecs_t time,
- int32_t keyCode, int32_t keyMetaState,
- int32_t* currentMetaState) {
- if ((metaState & keyMetaState) == keyMetaState) {
- *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
- addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
- *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
- addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
- }
-}
-
-#if HAVE_ANDROID_OS
-sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
- sp<KeyCharacterMap> map = new KeyCharacterMap();
- map->mType = parcel->readInt32();
- size_t numKeys = parcel->readInt32();
- if (parcel->errorCheck()) {
- return NULL;
- }
-
- for (size_t i = 0; i < numKeys; i++) {
- int32_t keyCode = parcel->readInt32();
- char16_t label = parcel->readInt32();
- char16_t number = parcel->readInt32();
- if (parcel->errorCheck()) {
- return NULL;
- }
-
- Key* key = new Key();
- key->label = label;
- key->number = number;
- map->mKeys.add(keyCode, key);
-
- Behavior* lastBehavior = NULL;
- while (parcel->readInt32()) {
- int32_t metaState = parcel->readInt32();
- char16_t character = parcel->readInt32();
- int32_t fallbackKeyCode = parcel->readInt32();
- if (parcel->errorCheck()) {
- return NULL;
- }
-
- Behavior* behavior = new Behavior();
- behavior->metaState = metaState;
- behavior->character = character;
- behavior->fallbackKeyCode = fallbackKeyCode;
- if (lastBehavior) {
- lastBehavior->next = behavior;
- } else {
- key->firstBehavior = behavior;
- }
- lastBehavior = behavior;
- }
-
- if (parcel->errorCheck()) {
- return NULL;
- }
- }
- return map;
-}
-
-void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
- parcel->writeInt32(mType);
-
- size_t numKeys = mKeys.size();
- parcel->writeInt32(numKeys);
- for (size_t i = 0; i < numKeys; i++) {
- int32_t keyCode = mKeys.keyAt(i);
- const Key* key = mKeys.valueAt(i);
- parcel->writeInt32(keyCode);
- parcel->writeInt32(key->label);
- parcel->writeInt32(key->number);
- for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
- behavior = behavior->next) {
- parcel->writeInt32(1);
- parcel->writeInt32(behavior->metaState);
- parcel->writeInt32(behavior->character);
- parcel->writeInt32(behavior->fallbackKeyCode);
- }
- parcel->writeInt32(0);
- }
-}
-#endif
-
-
-// --- KeyCharacterMap::Key ---
-
-KeyCharacterMap::Key::Key() :
- label(0), number(0), firstBehavior(NULL) {
-}
-
-KeyCharacterMap::Key::Key(const Key& other) :
- label(other.label), number(other.number),
- firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
-}
-
-KeyCharacterMap::Key::~Key() {
- Behavior* behavior = firstBehavior;
- while (behavior) {
- Behavior* next = behavior->next;
- delete behavior;
- behavior = next;
- }
-}
-
-
-// --- KeyCharacterMap::Behavior ---
-
-KeyCharacterMap::Behavior::Behavior() :
- next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
-}
-
-KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
- next(other.next ? new Behavior(*other.next) : NULL),
- metaState(other.metaState), character(other.character),
- fallbackKeyCode(other.fallbackKeyCode) {
-}
-
-
-// --- KeyCharacterMap::Parser ---
-
-KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
- mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
-}
-
-KeyCharacterMap::Parser::~Parser() {
-}
-
-status_t KeyCharacterMap::Parser::parse() {
- while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
-#endif
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
- switch (mState) {
- case STATE_TOP: {
- String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
- if (keywordToken == "type") {
- mTokenizer->skipDelimiters(WHITESPACE);
- status_t status = parseType();
- if (status) return status;
- } else if (keywordToken == "map") {
- mTokenizer->skipDelimiters(WHITESPACE);
- status_t status = parseMap();
- if (status) return status;
- } else if (keywordToken == "key") {
- mTokenizer->skipDelimiters(WHITESPACE);
- status_t status = parseKey();
- if (status) return status;
- } else {
- ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
- keywordToken.string());
- return BAD_VALUE;
- }
- break;
- }
-
- case STATE_KEY: {
- status_t status = parseKeyProperty();
- if (status) return status;
- break;
- }
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
- ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
- return BAD_VALUE;
- }
- }
-
- mTokenizer->nextLine();
- }
-
- if (mState != STATE_TOP) {
- ALOGE("%s: Unterminated key description at end of file.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
- ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- if (mFormat == FORMAT_BASE) {
- if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
- ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- } else if (mFormat == FORMAT_OVERLAY) {
- if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
- ALOGE("%s: Overlay keyboard layout missing required keyboard "
- "'type OVERLAY' declaration.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- }
-
- return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseType() {
- if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
- ALOGE("%s: Duplicate keyboard 'type' declaration.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- KeyboardType type;
- String8 typeToken = mTokenizer->nextToken(WHITESPACE);
- if (typeToken == "NUMERIC") {
- type = KEYBOARD_TYPE_NUMERIC;
- } else if (typeToken == "PREDICTIVE") {
- type = KEYBOARD_TYPE_PREDICTIVE;
- } else if (typeToken == "ALPHA") {
- type = KEYBOARD_TYPE_ALPHA;
- } else if (typeToken == "FULL") {
- type = KEYBOARD_TYPE_FULL;
- } else if (typeToken == "SPECIAL_FUNCTION") {
- type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
- } else if (typeToken == "OVERLAY") {
- type = KEYBOARD_TYPE_OVERLAY;
- } else {
- ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
- typeToken.string());
- return BAD_VALUE;
- }
-
-#if DEBUG_PARSER
- ALOGD("Parsed type: type=%d.", type);
-#endif
- mMap->mType = type;
- return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseMap() {
- String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
- if (keywordToken == "key") {
- mTokenizer->skipDelimiters(WHITESPACE);
- return parseMapKey();
- }
- ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
- keywordToken.string());
- return BAD_VALUE;
-}
-
-status_t KeyCharacterMap::Parser::parseMapKey() {
- String8 codeToken = mTokenizer->nextToken(WHITESPACE);
- bool mapUsage = false;
- if (codeToken == "usage") {
- mapUsage = true;
- mTokenizer->skipDelimiters(WHITESPACE);
- codeToken = mTokenizer->nextToken(WHITESPACE);
- }
-
- char* end;
- int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
- if (*end) {
- ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
- return BAD_VALUE;
- }
- KeyedVector<int32_t, int32_t>& map =
- mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
- if (map.indexOfKey(code) >= 0) {
- ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
- if (!keyCode) {
- ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
- return BAD_VALUE;
- }
-
-#if DEBUG_PARSER
- ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
- mapUsage ? "usage" : "scan code", code, keyCode);
-#endif
- map.add(code, keyCode);
- return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseKey() {
- String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
- if (!keyCode) {
- ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
- return BAD_VALUE;
- }
- if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
- ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
- if (openBraceToken != "{") {
- ALOGE("%s: Expected '{' after key code label, got '%s'.",
- mTokenizer->getLocation().string(), openBraceToken.string());
- return BAD_VALUE;
- }
-
-#if DEBUG_PARSER
- ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
-#endif
- mKeyCode = keyCode;
- mMap->mKeys.add(keyCode, new Key());
- mState = STATE_KEY;
- return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseKeyProperty() {
- Key* key = mMap->mKeys.valueFor(mKeyCode);
- String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
- if (token == "}") {
- mState = STATE_TOP;
- return finishKey(key);
- }
-
- Vector<Property> properties;
-
- // Parse all comma-delimited property names up to the first colon.
- for (;;) {
- if (token == "label") {
- properties.add(Property(PROPERTY_LABEL));
- } else if (token == "number") {
- properties.add(Property(PROPERTY_NUMBER));
- } else {
- int32_t metaState;
- status_t status = parseModifier(token, &metaState);
- if (status) {
- ALOGE("%s: Expected a property name or modifier, got '%s'.",
- mTokenizer->getLocation().string(), token.string());
- return status;
- }
- properties.add(Property(PROPERTY_META, metaState));
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- if (!mTokenizer->isEol()) {
- char ch = mTokenizer->nextChar();
- if (ch == ':') {
- break;
- } else if (ch == ',') {
- mTokenizer->skipDelimiters(WHITESPACE);
- token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
- continue;
- }
- }
-
- ALOGE("%s: Expected ',' or ':' after property name.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- // Parse behavior after the colon.
- mTokenizer->skipDelimiters(WHITESPACE);
-
- Behavior behavior;
- bool haveCharacter = false;
- bool haveFallback = false;
-
- do {
- char ch = mTokenizer->peekChar();
- if (ch == '\'') {
- char16_t character;
- status_t status = parseCharacterLiteral(&character);
- if (status || !character) {
- ALOGE("%s: Invalid character literal for key.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- if (haveCharacter) {
- ALOGE("%s: Cannot combine multiple character literals or 'none'.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- behavior.character = character;
- haveCharacter = true;
- } else {
- token = mTokenizer->nextToken(WHITESPACE);
- if (token == "none") {
- if (haveCharacter) {
- ALOGE("%s: Cannot combine multiple character literals or 'none'.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- haveCharacter = true;
- } else if (token == "fallback") {
- mTokenizer->skipDelimiters(WHITESPACE);
- token = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = getKeyCodeByLabel(token.string());
- if (!keyCode) {
- ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
- mTokenizer->getLocation().string(),
- token.string());
- return BAD_VALUE;
- }
- if (haveFallback) {
- ALOGE("%s: Cannot combine multiple fallback key codes.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- behavior.fallbackKeyCode = keyCode;
- haveFallback = true;
- } else {
- ALOGE("%s: Expected a key behavior after ':'.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
-
- // Add the behavior.
- for (size_t i = 0; i < properties.size(); i++) {
- const Property& property = properties.itemAt(i);
- switch (property.property) {
- case PROPERTY_LABEL:
- if (key->label) {
- ALOGE("%s: Duplicate label for key.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- key->label = behavior.character;
-#if DEBUG_PARSER
- ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
-#endif
- break;
- case PROPERTY_NUMBER:
- if (key->number) {
- ALOGE("%s: Duplicate number for key.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- key->number = behavior.character;
-#if DEBUG_PARSER
- ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
-#endif
- break;
- case PROPERTY_META: {
- for (Behavior* b = key->firstBehavior; b; b = b->next) {
- if (b->metaState == property.metaState) {
- ALOGE("%s: Duplicate key behavior for modifier.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- }
- Behavior* newBehavior = new Behavior(behavior);
- newBehavior->metaState = property.metaState;
- newBehavior->next = key->firstBehavior;
- key->firstBehavior = newBehavior;
-#if DEBUG_PARSER
- ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
- newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
-#endif
- break;
- }
- }
- }
- return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::finishKey(Key* key) {
- // Fill in default number property.
- if (!key->number) {
- char16_t digit = 0;
- char16_t symbol = 0;
- for (Behavior* b = key->firstBehavior; b; b = b->next) {
- char16_t ch = b->character;
- if (ch) {
- if (ch >= '0' && ch <= '9') {
- digit = ch;
- } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
- || ch == '-' || ch == '+' || ch == ',' || ch == '.'
- || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
- symbol = ch;
- }
- }
- }
- key->number = digit ? digit : symbol;
- }
- return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
- if (token == "base") {
- *outMetaState = 0;
- return NO_ERROR;
- }
-
- int32_t combinedMeta = 0;
-
- const char* str = token.string();
- const char* start = str;
- for (const char* cur = str; ; cur++) {
- char ch = *cur;
- if (ch == '+' || ch == '\0') {
- size_t len = cur - start;
- int32_t metaState = 0;
- for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
- if (strlen(modifiers[i].label) == len
- && strncmp(modifiers[i].label, start, len) == 0) {
- metaState = modifiers[i].metaState;
- break;
- }
- }
- if (!metaState) {
- return BAD_VALUE;
- }
- if (combinedMeta & metaState) {
- ALOGE("%s: Duplicate modifier combination '%s'.",
- mTokenizer->getLocation().string(), token.string());
- return BAD_VALUE;
- }
-
- combinedMeta |= metaState;
- start = cur + 1;
-
- if (ch == '\0') {
- break;
- }
- }
- }
- *outMetaState = combinedMeta;
- return NO_ERROR;
-}
-
-status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
- char ch = mTokenizer->nextChar();
- if (ch != '\'') {
- goto Error;
- }
-
- ch = mTokenizer->nextChar();
- if (ch == '\\') {
- // Escape sequence.
- ch = mTokenizer->nextChar();
- if (ch == 'n') {
- *outCharacter = '\n';
- } else if (ch == 't') {
- *outCharacter = '\t';
- } else if (ch == '\\') {
- *outCharacter = '\\';
- } else if (ch == '\'') {
- *outCharacter = '\'';
- } else if (ch == '"') {
- *outCharacter = '"';
- } else if (ch == 'u') {
- *outCharacter = 0;
- for (int i = 0; i < 4; i++) {
- ch = mTokenizer->nextChar();
- int digit;
- if (ch >= '0' && ch <= '9') {
- digit = ch - '0';
- } else if (ch >= 'A' && ch <= 'F') {
- digit = ch - 'A' + 10;
- } else if (ch >= 'a' && ch <= 'f') {
- digit = ch - 'a' + 10;
- } else {
- goto Error;
- }
- *outCharacter = (*outCharacter << 4) | digit;
- }
- } else {
- goto Error;
- }
- } else if (ch >= 32 && ch <= 126 && ch != '\'') {
- // ASCII literal character.
- *outCharacter = ch;
- } else {
- goto Error;
- }
-
- ch = mTokenizer->nextChar();
- if (ch != '\'') {
- goto Error;
- }
-
- // Ensure that we consumed the entire token.
- if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
- return NO_ERROR;
- }
-
-Error:
- ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
- return BAD_VALUE;
-}
-
-} // namespace android
diff --git a/libs/androidfw/KeyLayoutMap.cpp b/libs/androidfw/KeyLayoutMap.cpp
deleted file mode 100644
index ae14f23..0000000
--- a/libs/androidfw/KeyLayoutMap.cpp
+++ /dev/null
@@ -1,366 +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.
- */
-
-#define LOG_TAG "KeyLayoutMap"
-
-#include <stdlib.h>
-#include <android/keycodes.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-#include <utils/Timers.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-// Enables debug output for mapping.
-#define DEBUG_MAPPING 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-
-// --- KeyLayoutMap ---
-
-KeyLayoutMap::KeyLayoutMap() {
-}
-
-KeyLayoutMap::~KeyLayoutMap() {
-}
-
-status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
- outMap->clear();
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
- if (status) {
- ALOGE("Error %d opening key layout map file %s.", status, filename.string());
- } else {
- sp<KeyLayoutMap> map = new KeyLayoutMap();
- if (!map.get()) {
- ALOGE("Error allocating key layout map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map.get(), tokenizer);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (!status) {
- *outMap = map;
- }
- }
- delete tokenizer;
- }
- return status;
-}
-
-status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode,
- int32_t* outKeyCode, uint32_t* outFlags) const {
- const Key* key = getKey(scanCode, usageCode);
- if (!key) {
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
-#endif
- *outKeyCode = AKEYCODE_UNKNOWN;
- *outFlags = 0;
- return NAME_NOT_FOUND;
- }
-
- *outKeyCode = key->keyCode;
- *outFlags = key->flags;
-
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
- scanCode, usageCode, *outKeyCode, *outFlags);
-#endif
- return NO_ERROR;
-}
-
-const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
- if (usageCode) {
- ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
- if (index >= 0) {
- return &mKeysByUsageCode.valueAt(index);
- }
- }
- if (scanCode) {
- ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
- if (index >= 0) {
- return &mKeysByScanCode.valueAt(index);
- }
- }
- return NULL;
-}
-
-status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
- const size_t N = mKeysByScanCode.size();
- for (size_t i=0; i<N; i++) {
- if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
- outScanCodes->add(mKeysByScanCode.keyAt(i));
- }
- }
- return NO_ERROR;
-}
-
-status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
- ssize_t index = mAxes.indexOfKey(scanCode);
- if (index < 0) {
-#if DEBUG_MAPPING
- ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
-#endif
- return NAME_NOT_FOUND;
- }
-
- *outAxisInfo = mAxes.valueAt(index);
-
-#if DEBUG_MAPPING
- ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
- "splitValue=%d, flatOverride=%d.",
- scanCode,
- outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
- outAxisInfo->splitValue, outAxisInfo->flatOverride);
-#endif
- return NO_ERROR;
-}
-
-
-// --- KeyLayoutMap::Parser ---
-
-KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
- mMap(map), mTokenizer(tokenizer) {
-}
-
-KeyLayoutMap::Parser::~Parser() {
-}
-
-status_t KeyLayoutMap::Parser::parse() {
- while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
-#endif
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
- String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
- if (keywordToken == "key") {
- mTokenizer->skipDelimiters(WHITESPACE);
- status_t status = parseKey();
- if (status) return status;
- } else if (keywordToken == "axis") {
- mTokenizer->skipDelimiters(WHITESPACE);
- status_t status = parseAxis();
- if (status) return status;
- } else {
- ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
- keywordToken.string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
- ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
- return BAD_VALUE;
- }
- }
-
- mTokenizer->nextLine();
- }
- return NO_ERROR;
-}
-
-status_t KeyLayoutMap::Parser::parseKey() {
- String8 codeToken = mTokenizer->nextToken(WHITESPACE);
- bool mapUsage = false;
- if (codeToken == "usage") {
- mapUsage = true;
- mTokenizer->skipDelimiters(WHITESPACE);
- codeToken = mTokenizer->nextToken(WHITESPACE);
- }
-
- char* end;
- int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
- if (*end) {
- ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
- return BAD_VALUE;
- }
- KeyedVector<int32_t, Key>& map =
- mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
- if (map.indexOfKey(code) >= 0) {
- ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
- if (!keyCode) {
- ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
- return BAD_VALUE;
- }
-
- uint32_t flags = 0;
- for (;;) {
- mTokenizer->skipDelimiters(WHITESPACE);
- if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
-
- String8 flagToken = mTokenizer->nextToken(WHITESPACE);
- uint32_t flag = getKeyFlagByLabel(flagToken.string());
- if (!flag) {
- ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
- flagToken.string());
- return BAD_VALUE;
- }
- if (flags & flag) {
- ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
- flagToken.string());
- return BAD_VALUE;
- }
- flags |= flag;
- }
-
-#if DEBUG_PARSER
- ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
- mapUsage ? "usage" : "scan code", code, keyCode, flags);
-#endif
- Key key;
- key.keyCode = keyCode;
- key.flags = flags;
- map.add(code, key);
- return NO_ERROR;
-}
-
-status_t KeyLayoutMap::Parser::parseAxis() {
- String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
- char* end;
- int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
- if (*end) {
- ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
- scanCodeToken.string());
- return BAD_VALUE;
- }
- if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
- ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
- scanCodeToken.string());
- return BAD_VALUE;
- }
-
- AxisInfo axisInfo;
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 token = mTokenizer->nextToken(WHITESPACE);
- if (token == "invert") {
- axisInfo.mode = AxisInfo::MODE_INVERT;
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 axisToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.axis = getAxisByLabel(axisToken.string());
- if (axisInfo.axis < 0) {
- ALOGE("%s: Expected inverted axis label, got '%s'.",
- mTokenizer->getLocation().string(), axisToken.string());
- return BAD_VALUE;
- }
- } else if (token == "split") {
- axisInfo.mode = AxisInfo::MODE_SPLIT;
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 splitToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
- if (*end) {
- ALOGE("%s: Expected split value, got '%s'.",
- mTokenizer->getLocation().string(), splitToken.string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.axis = getAxisByLabel(lowAxisToken.string());
- if (axisInfo.axis < 0) {
- ALOGE("%s: Expected low axis label, got '%s'.",
- mTokenizer->getLocation().string(), lowAxisToken.string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
- if (axisInfo.highAxis < 0) {
- ALOGE("%s: Expected high axis label, got '%s'.",
- mTokenizer->getLocation().string(), highAxisToken.string());
- return BAD_VALUE;
- }
- } else {
- axisInfo.axis = getAxisByLabel(token.string());
- if (axisInfo.axis < 0) {
- ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
- mTokenizer->getLocation().string(), token.string());
- return BAD_VALUE;
- }
- }
-
- for (;;) {
- mTokenizer->skipDelimiters(WHITESPACE);
- if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
- break;
- }
- String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
- if (keywordToken == "flat") {
- mTokenizer->skipDelimiters(WHITESPACE);
- String8 flatToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
- if (*end) {
- ALOGE("%s: Expected flat value, got '%s'.",
- mTokenizer->getLocation().string(), flatToken.string());
- return BAD_VALUE;
- }
- } else {
- ALOGE("%s: Expected keyword 'flat', got '%s'.",
- mTokenizer->getLocation().string(), keywordToken.string());
- return BAD_VALUE;
- }
- }
-
-#if DEBUG_PARSER
- ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
- "splitValue=%d, flatOverride=%d.",
- scanCode,
- axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
- axisInfo.splitValue, axisInfo.flatOverride);
-#endif
- mMap->mAxes.add(scanCode, axisInfo);
- return NO_ERROR;
-}
-
-};
diff --git a/libs/androidfw/Keyboard.cpp b/libs/androidfw/Keyboard.cpp
deleted file mode 100644
index 26a4e6a..0000000
--- a/libs/androidfw/Keyboard.cpp
+++ /dev/null
@@ -1,297 +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.
- */
-
-#define LOG_TAG "Keyboard"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeycodeLabels.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/InputDevice.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-namespace android {
-
-// --- KeyMap ---
-
-KeyMap::KeyMap() {
-}
-
-KeyMap::~KeyMap() {
-}
-
-status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
- const PropertyMap* deviceConfiguration) {
- // Use the configured key layout if available.
- if (deviceConfiguration) {
- String8 keyLayoutName;
- if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
- keyLayoutName)) {
- status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
- if (status == NAME_NOT_FOUND) {
- ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
- "it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
- }
- }
-
- String8 keyCharacterMapName;
- if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
- keyCharacterMapName)) {
- status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
- if (status == NAME_NOT_FOUND) {
- ALOGE("Configuration for keyboard device '%s' requested keyboard character "
- "map '%s' but it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
- }
- }
-
- if (isComplete()) {
- return OK;
- }
- }
-
- // Try searching by device identifier.
- if (probeKeyMap(deviceIdenfifier, String8::empty())) {
- return OK;
- }
-
- // Fall back on the Generic key map.
- // TODO Apply some additional heuristics here to figure out what kind of
- // generic key map to use (US English, etc.) for typical external keyboards.
- if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
- return OK;
- }
-
- // Try the Virtual key map as a last resort.
- if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
- return OK;
- }
-
- // Give up!
- ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
- deviceIdenfifier.name.string());
- return NAME_NOT_FOUND;
-}
-
-bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& keyMapName) {
- if (!haveKeyLayout()) {
- loadKeyLayout(deviceIdentifier, keyMapName);
- }
- if (!haveKeyCharacterMap()) {
- loadKeyCharacterMap(deviceIdentifier, keyMapName);
- }
- return isComplete();
-}
-
-status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name) {
- String8 path(getPath(deviceIdentifier, name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
- if (path.isEmpty()) {
- return NAME_NOT_FOUND;
- }
-
- status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
- if (status) {
- return status;
- }
-
- keyLayoutFile.setTo(path);
- return OK;
-}
-
-status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name) {
- String8 path(getPath(deviceIdentifier, name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
- if (path.isEmpty()) {
- return NAME_NOT_FOUND;
- }
-
- status_t status = KeyCharacterMap::load(path,
- KeyCharacterMap::FORMAT_BASE, &keyCharacterMap);
- if (status) {
- return status;
- }
-
- keyCharacterMapFile.setTo(path);
- return OK;
-}
-
-String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name, InputDeviceConfigurationFileType type) {
- return name.isEmpty()
- ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
- : getInputDeviceConfigurationFilePathByName(name, type);
-}
-
-
-// --- Global functions ---
-
-bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
- const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
- if (!keyMap->haveKeyCharacterMap()
- || keyMap->keyCharacterMap->getKeyboardType()
- == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
- return false;
- }
-
- if (deviceConfiguration) {
- bool builtIn = false;
- if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
- && builtIn) {
- return true;
- }
- }
-
- return strstr(deviceIdentifier.name.string(), "-keypad");
-}
-
-static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
- while (list->literal) {
- if (strcmp(literal, list->literal) == 0) {
- return list->value;
- }
- list++;
- }
- return list->value;
-}
-
-static const char* lookupLabelByValue(int value, const KeycodeLabel *list) {
- while (list->literal) {
- if (list->value == value) {
- return list->literal;
- }
- list++;
- }
- return NULL;
-}
-
-int32_t getKeyCodeByLabel(const char* label) {
- return int32_t(lookupValueByLabel(label, KEYCODES));
-}
-
-uint32_t getKeyFlagByLabel(const char* label) {
- return uint32_t(lookupValueByLabel(label, FLAGS));
-}
-
-int32_t getAxisByLabel(const char* label) {
- return int32_t(lookupValueByLabel(label, AXES));
-}
-
-const char* getAxisLabel(int32_t axisId) {
- return lookupLabelByValue(axisId, AXES);
-}
-
-static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
- int32_t newMetaState;
- if (down) {
- newMetaState = oldMetaState | mask;
- } else {
- newMetaState = oldMetaState &
- ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
- }
-
- if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
- newMetaState |= AMETA_ALT_ON;
- }
-
- if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
- newMetaState |= AMETA_SHIFT_ON;
- }
-
- if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
- newMetaState |= AMETA_CTRL_ON;
- }
-
- if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
- newMetaState |= AMETA_META_ON;
- }
- return newMetaState;
-}
-
-static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
- if (down) {
- return oldMetaState;
- } else {
- return oldMetaState ^ mask;
- }
-}
-
-int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
- int32_t mask;
- switch (keyCode) {
- case AKEYCODE_ALT_LEFT:
- return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
- case AKEYCODE_ALT_RIGHT:
- return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
- case AKEYCODE_SHIFT_LEFT:
- return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
- case AKEYCODE_SHIFT_RIGHT:
- return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
- case AKEYCODE_SYM:
- return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
- case AKEYCODE_FUNCTION:
- return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
- case AKEYCODE_CTRL_LEFT:
- return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
- case AKEYCODE_CTRL_RIGHT:
- return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
- case AKEYCODE_META_LEFT:
- return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
- case AKEYCODE_META_RIGHT:
- return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
- case AKEYCODE_CAPS_LOCK:
- return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
- case AKEYCODE_NUM_LOCK:
- return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
- case AKEYCODE_SCROLL_LOCK:
- return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
- default:
- return oldMetaState;
- }
-}
-
-bool isMetaKey(int32_t keyCode) {
- switch (keyCode) {
- case AKEYCODE_ALT_LEFT:
- case AKEYCODE_ALT_RIGHT:
- case AKEYCODE_SHIFT_LEFT:
- case AKEYCODE_SHIFT_RIGHT:
- case AKEYCODE_SYM:
- case AKEYCODE_FUNCTION:
- case AKEYCODE_CTRL_LEFT:
- case AKEYCODE_CTRL_RIGHT:
- case AKEYCODE_META_LEFT:
- case AKEYCODE_META_RIGHT:
- case AKEYCODE_CAPS_LOCK:
- case AKEYCODE_NUM_LOCK:
- case AKEYCODE_SCROLL_LOCK:
- return true;
- default:
- return false;
- }
-}
-
-
-} // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index e31246f..1128e02 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -5323,13 +5323,12 @@
}
-#ifdef STATIC_ANDROIDFW_FOR_TOOLS
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
#define CHAR16_ARRAY_EQ(constant, var, len) \
((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
-void print_complex(uint32_t complex, bool isFraction)
+static void print_complex(uint32_t complex, bool isFraction)
{
const float MANTISSA_MULT =
1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
@@ -5620,6 +5619,4 @@
}
}
-#endif // STATIC_ANDROIDFW_FOR_TOOLS
-
} // namespace android
diff --git a/libs/androidfw/VelocityControl.cpp b/libs/androidfw/VelocityControl.cpp
deleted file mode 100644
index cde2b76..0000000
--- a/libs/androidfw/VelocityControl.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "VelocityControl"
-//#define LOG_NDEBUG 0
-
-// Log debug messages about acceleration.
-#define DEBUG_ACCELERATION 0
-
-#include <math.h>
-#include <limits.h>
-
-#include <androidfw/VelocityControl.h>
-#include <utils/BitSet.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-// --- VelocityControl ---
-
-const nsecs_t VelocityControl::STOP_TIME;
-
-VelocityControl::VelocityControl() {
- reset();
-}
-
-void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
- mParameters = parameters;
- reset();
-}
-
-void VelocityControl::reset() {
- mLastMovementTime = LLONG_MIN;
- mRawPosition.x = 0;
- mRawPosition.y = 0;
- mVelocityTracker.clear();
-}
-
-void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
- if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
- if (eventTime >= mLastMovementTime + STOP_TIME) {
-#if DEBUG_ACCELERATION
- ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
- (eventTime - mLastMovementTime) * 0.000001f);
-#endif
- reset();
- }
-
- mLastMovementTime = eventTime;
- if (deltaX) {
- mRawPosition.x += *deltaX;
- }
- if (deltaY) {
- mRawPosition.y += *deltaY;
- }
- mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
-
- float vx, vy;
- float scale = mParameters.scale;
- if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
- float speed = hypotf(vx, vy) * scale;
- if (speed >= mParameters.highThreshold) {
- // Apply full acceleration above the high speed threshold.
- scale *= mParameters.acceleration;
- } else if (speed > mParameters.lowThreshold) {
- // Linearly interpolate the acceleration to apply between the low and high
- // speed thresholds.
- scale *= 1 + (speed - mParameters.lowThreshold)
- / (mParameters.highThreshold - mParameters.lowThreshold)
- * (mParameters.acceleration - 1);
- }
-
-#if DEBUG_ACCELERATION
- ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
- "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration,
- vx, vy, speed, scale / mParameters.scale);
-#endif
- } else {
-#if DEBUG_ACCELERATION
- ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration);
-#endif
- }
-
- if (deltaX) {
- *deltaX *= scale;
- }
- if (deltaY) {
- *deltaY *= scale;
- }
- }
-}
-
-} // namespace android
diff --git a/libs/androidfw/VelocityTracker.cpp b/libs/androidfw/VelocityTracker.cpp
deleted file mode 100644
index f48ec62..0000000
--- a/libs/androidfw/VelocityTracker.cpp
+++ /dev/null
@@ -1,928 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "VelocityTracker"
-//#define LOG_NDEBUG 0
-
-// Log debug messages about velocity tracking.
-#define DEBUG_VELOCITY 0
-
-// Log debug messages about the progress of the algorithm itself.
-#define DEBUG_STRATEGY 0
-
-#include <math.h>
-#include <limits.h>
-
-#include <androidfw/VelocityTracker.h>
-#include <utils/BitSet.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-
-#include <cutils/properties.h>
-
-namespace android {
-
-// Nanoseconds per milliseconds.
-static const nsecs_t NANOS_PER_MS = 1000000;
-
-// Threshold for determining that a pointer has stopped moving.
-// Some input devices do not send ACTION_MOVE events in the case where a pointer has
-// stopped. We need to detect this case so that we can accurately predict the
-// velocity after the pointer starts moving again.
-static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS;
-
-
-static float vectorDot(const float* a, const float* b, uint32_t m) {
- float r = 0;
- while (m--) {
- r += *(a++) * *(b++);
- }
- return r;
-}
-
-static float vectorNorm(const float* a, uint32_t m) {
- float r = 0;
- while (m--) {
- float t = *(a++);
- r += t * t;
- }
- return sqrtf(r);
-}
-
-#if DEBUG_STRATEGY || DEBUG_VELOCITY
-static String8 vectorToString(const float* a, uint32_t m) {
- String8 str;
- str.append("[");
- while (m--) {
- str.appendFormat(" %f", *(a++));
- if (m) {
- str.append(",");
- }
- }
- str.append(" ]");
- return str;
-}
-
-static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
- String8 str;
- str.append("[");
- for (size_t i = 0; i < m; i++) {
- if (i) {
- str.append(",");
- }
- str.append(" [");
- for (size_t j = 0; j < n; j++) {
- if (j) {
- str.append(",");
- }
- str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
- }
- str.append(" ]");
- }
- str.append(" ]");
- return str;
-}
-#endif
-
-
-// --- VelocityTracker ---
-
-// The default velocity tracker strategy.
-// Although other strategies are available for testing and comparison purposes,
-// this is the strategy that applications will actually use. Be very careful
-// when adjusting the default strategy because it can dramatically affect
-// (often in a bad way) the user experience.
-const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2";
-
-VelocityTracker::VelocityTracker(const char* strategy) :
- mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
- char value[PROPERTY_VALUE_MAX];
-
- // Allow the default strategy to be overridden using a system property for debugging.
- if (!strategy) {
- int length = property_get("debug.velocitytracker.strategy", value, NULL);
- if (length > 0) {
- strategy = value;
- } else {
- strategy = DEFAULT_STRATEGY;
- }
- }
-
- // Configure the strategy.
- if (!configureStrategy(strategy)) {
- ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy);
- if (!configureStrategy(DEFAULT_STRATEGY)) {
- LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!",
- strategy);
- }
- }
-}
-
-VelocityTracker::~VelocityTracker() {
- delete mStrategy;
-}
-
-bool VelocityTracker::configureStrategy(const char* strategy) {
- mStrategy = createStrategy(strategy);
- return mStrategy != NULL;
-}
-
-VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
- if (!strcmp("lsq1", strategy)) {
- // 1st order least squares. Quality: POOR.
- // Frequently underfits the touch data especially when the finger accelerates
- // or changes direction. Often underestimates velocity. The direction
- // is overly influenced by historical touch points.
- return new LeastSquaresVelocityTrackerStrategy(1);
- }
- if (!strcmp("lsq2", strategy)) {
- // 2nd order least squares. Quality: VERY GOOD.
- // Pretty much ideal, but can be confused by certain kinds of touch data,
- // particularly if the panel has a tendency to generate delayed,
- // duplicate or jittery touch coordinates when the finger is released.
- return new LeastSquaresVelocityTrackerStrategy(2);
- }
- if (!strcmp("lsq3", strategy)) {
- // 3rd order least squares. Quality: UNUSABLE.
- // Frequently overfits the touch data yielding wildly divergent estimates
- // of the velocity when the finger is released.
- return new LeastSquaresVelocityTrackerStrategy(3);
- }
- if (!strcmp("wlsq2-delta", strategy)) {
- // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL
- return new LeastSquaresVelocityTrackerStrategy(2,
- LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA);
- }
- if (!strcmp("wlsq2-central", strategy)) {
- // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL
- return new LeastSquaresVelocityTrackerStrategy(2,
- LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL);
- }
- if (!strcmp("wlsq2-recent", strategy)) {
- // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL
- return new LeastSquaresVelocityTrackerStrategy(2,
- LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT);
- }
- if (!strcmp("int1", strategy)) {
- // 1st order integrating filter. Quality: GOOD.
- // Not as good as 'lsq2' because it cannot estimate acceleration but it is
- // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate
- // the velocity of a fling but this strategy tends to respond to changes in
- // direction more quickly and accurately.
- return new IntegratingVelocityTrackerStrategy(1);
- }
- if (!strcmp("int2", strategy)) {
- // 2nd order integrating filter. Quality: EXPERIMENTAL.
- // For comparison purposes only. Unlike 'int1' this strategy can compensate
- // for acceleration but it typically overestimates the effect.
- return new IntegratingVelocityTrackerStrategy(2);
- }
- if (!strcmp("legacy", strategy)) {
- // Legacy velocity tracker algorithm. Quality: POOR.
- // For comparison purposes only. This algorithm is strongly influenced by
- // old data points, consistently underestimates velocity and takes a very long
- // time to adjust to changes in direction.
- return new LegacyVelocityTrackerStrategy();
- }
- return NULL;
-}
-
-void VelocityTracker::clear() {
- mCurrentPointerIdBits.clear();
- mActivePointerId = -1;
-
- mStrategy->clear();
-}
-
-void VelocityTracker::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value);
- mCurrentPointerIdBits = remainingIdBits;
-
- if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
- mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
- }
-
- mStrategy->clearPointers(idBits);
-}
-
-void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
- while (idBits.count() > MAX_POINTERS) {
- idBits.clearLastMarkedBit();
- }
-
- if ((mCurrentPointerIdBits.value & idBits.value)
- && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
-#if DEBUG_VELOCITY
- ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
- (eventTime - mLastEventTime) * 0.000001f);
-#endif
- // We have not received any movements for too long. Assume that all pointers
- // have stopped.
- mStrategy->clear();
- }
- mLastEventTime = eventTime;
-
- mCurrentPointerIdBits = idBits;
- if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
- mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
- }
-
- mStrategy->addMovement(eventTime, idBits, positions);
-
-#if DEBUG_VELOCITY
- ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
- eventTime, idBits.value, mActivePointerId);
- for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
- uint32_t id = iterBits.firstMarkedBit();
- uint32_t index = idBits.getIndexOfBit(id);
- iterBits.clearBit(id);
- Estimator estimator;
- getEstimator(id, &estimator);
- ALOGD(" %d: position (%0.3f, %0.3f), "
- "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
- id, positions[index].x, positions[index].y,
- int(estimator.degree),
- vectorToString(estimator.xCoeff, estimator.degree + 1).string(),
- vectorToString(estimator.yCoeff, estimator.degree + 1).string(),
- estimator.confidence);
- }
-#endif
-}
-
-void VelocityTracker::addMovement(const MotionEvent* event) {
- int32_t actionMasked = event->getActionMasked();
-
- switch (actionMasked) {
- case AMOTION_EVENT_ACTION_DOWN:
- case AMOTION_EVENT_ACTION_HOVER_ENTER:
- // Clear all pointers on down before adding the new movement.
- clear();
- break;
- case AMOTION_EVENT_ACTION_POINTER_DOWN: {
- // Start a new movement trace for a pointer that just went down.
- // We do this on down instead of on up because the client may want to query the
- // final velocity for a pointer that just went up.
- BitSet32 downIdBits;
- downIdBits.markBit(event->getPointerId(event->getActionIndex()));
- clearPointers(downIdBits);
- break;
- }
- case AMOTION_EVENT_ACTION_MOVE:
- case AMOTION_EVENT_ACTION_HOVER_MOVE:
- break;
- default:
- // Ignore all other actions because they do not convey any new information about
- // pointer movement. We also want to preserve the last known velocity of the pointers.
- // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
- // of the pointers that went up. ACTION_POINTER_UP does include the new position of
- // pointers that remained down but we will also receive an ACTION_MOVE with this
- // information if any of them actually moved. Since we don't know how many pointers
- // will be going up at once it makes sense to just wait for the following ACTION_MOVE
- // before adding the movement.
- return;
- }
-
- size_t pointerCount = event->getPointerCount();
- if (pointerCount > MAX_POINTERS) {
- pointerCount = MAX_POINTERS;
- }
-
- BitSet32 idBits;
- for (size_t i = 0; i < pointerCount; i++) {
- idBits.markBit(event->getPointerId(i));
- }
-
- uint32_t pointerIndex[MAX_POINTERS];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
- }
-
- nsecs_t eventTime;
- Position positions[pointerCount];
-
- size_t historySize = event->getHistorySize();
- for (size_t h = 0; h < historySize; h++) {
- eventTime = event->getHistoricalEventTime(h);
- for (size_t i = 0; i < pointerCount; i++) {
- uint32_t index = pointerIndex[i];
- positions[index].x = event->getHistoricalX(i, h);
- positions[index].y = event->getHistoricalY(i, h);
- }
- addMovement(eventTime, idBits, positions);
- }
-
- eventTime = event->getEventTime();
- for (size_t i = 0; i < pointerCount; i++) {
- uint32_t index = pointerIndex[i];
- positions[index].x = event->getX(i);
- positions[index].y = event->getY(i);
- }
- addMovement(eventTime, idBits, positions);
-}
-
-bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
- Estimator estimator;
- if (getEstimator(id, &estimator) && estimator.degree >= 1) {
- *outVx = estimator.xCoeff[1];
- *outVy = estimator.yCoeff[1];
- return true;
- }
- *outVx = 0;
- *outVy = 0;
- return false;
-}
-
-bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const {
- return mStrategy->getEstimator(id, outEstimator);
-}
-
-
-// --- LeastSquaresVelocityTrackerStrategy ---
-
-const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
-const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
-
-LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
- uint32_t degree, Weighting weighting) :
- mDegree(degree), mWeighting(weighting) {
- clear();
-}
-
-LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {
-}
-
-void LeastSquaresVelocityTrackerStrategy::clear() {
- mIndex = 0;
- mMovements[0].idBits.clear();
-}
-
-void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
- mMovements[mIndex].idBits = remainingIdBits;
-}
-
-void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
- if (++mIndex == HISTORY_SIZE) {
- mIndex = 0;
- }
-
- Movement& movement = mMovements[mIndex];
- movement.eventTime = eventTime;
- movement.idBits = idBits;
- uint32_t count = idBits.count();
- for (uint32_t i = 0; i < count; i++) {
- movement.positions[i] = positions[i];
- }
-}
-
-/**
- * Solves a linear least squares problem to obtain a N degree polynomial that fits
- * the specified input data as nearly as possible.
- *
- * Returns true if a solution is found, false otherwise.
- *
- * The input consists of two vectors of data points X and Y with indices 0..m-1
- * along with a weight vector W of the same size.
- *
- * The output is a vector B with indices 0..n that describes a polynomial
- * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i]
- * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized.
- *
- * Accordingly, the weight vector W should be initialized by the caller with the
- * reciprocal square root of the variance of the error in each input data point.
- * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]).
- * The weights express the relative importance of each data point. If the weights are
- * all 1, then the data points are considered to be of equal importance when fitting
- * the polynomial. It is a good idea to choose weights that diminish the importance
- * of data points that may have higher than usual error margins.
- *
- * Errors among data points are assumed to be independent. W is represented here
- * as a vector although in the literature it is typically taken to be a diagonal matrix.
- *
- * That is to say, the function that generated the input data can be approximated
- * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
- *
- * The coefficient of determination (R^2) is also returned to describe the goodness
- * of fit of the model for the given data. It is a value between 0 and 1, where 1
- * indicates perfect correspondence.
- *
- * This function first expands the X vector to a m by n matrix A such that
- * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then
- * multiplies it by w[i]./
- *
- * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q
- * and an m by n upper triangular matrix R. Because R is upper triangular (lower
- * part is all zeroes), we can simplify the decomposition into an m by n matrix
- * Q1 and a n by n matrix R1 such that A = Q1 R1.
- *
- * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y)
- * to find B.
- *
- * For efficiency, we lay out A and Q column-wise in memory because we frequently
- * operate on the column vectors. Conversely, we lay out R row-wise.
- *
- * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
- * http://en.wikipedia.org/wiki/Gram-Schmidt
- */
-static bool solveLeastSquares(const float* x, const float* y,
- const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) {
-#if DEBUG_STRATEGY
- ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
- vectorToString(x, m).string(), vectorToString(y, m).string(),
- vectorToString(w, m).string());
-#endif
-
- // Expand the X vector to a matrix A, pre-multiplied by the weights.
- float a[n][m]; // column-major order
- for (uint32_t h = 0; h < m; h++) {
- a[0][h] = w[h];
- for (uint32_t i = 1; i < n; i++) {
- a[i][h] = a[i - 1][h] * x[h];
- }
- }
-#if DEBUG_STRATEGY
- ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
-#endif
-
- // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
- float q[n][m]; // orthonormal basis, column-major order
- float r[n][n]; // upper triangular matrix, row-major order
- for (uint32_t j = 0; j < n; j++) {
- for (uint32_t h = 0; h < m; h++) {
- q[j][h] = a[j][h];
- }
- for (uint32_t i = 0; i < j; i++) {
- float dot = vectorDot(&q[j][0], &q[i][0], m);
- for (uint32_t h = 0; h < m; h++) {
- q[j][h] -= dot * q[i][h];
- }
- }
-
- float norm = vectorNorm(&q[j][0], m);
- if (norm < 0.000001f) {
- // vectors are linearly dependent or zero so no solution
-#if DEBUG_STRATEGY
- ALOGD(" - no solution, norm=%f", norm);
-#endif
- return false;
- }
-
- float invNorm = 1.0f / norm;
- for (uint32_t h = 0; h < m; h++) {
- q[j][h] *= invNorm;
- }
- for (uint32_t i = 0; i < n; i++) {
- r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
- }
- }
-#if DEBUG_STRATEGY
- ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
- ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
-
- // calculate QR, if we factored A correctly then QR should equal A
- float qr[n][m];
- for (uint32_t h = 0; h < m; h++) {
- for (uint32_t i = 0; i < n; i++) {
- qr[i][h] = 0;
- for (uint32_t j = 0; j < n; j++) {
- qr[i][h] += q[j][h] * r[j][i];
- }
- }
- }
- ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
-#endif
-
- // Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
- // We just work from bottom-right to top-left calculating B's coefficients.
- float wy[m];
- for (uint32_t h = 0; h < m; h++) {
- wy[h] = y[h] * w[h];
- }
- for (uint32_t i = n; i-- != 0; ) {
- outB[i] = vectorDot(&q[i][0], wy, m);
- for (uint32_t j = n - 1; j > i; j--) {
- outB[i] -= r[i][j] * outB[j];
- }
- outB[i] /= r[i][i];
- }
-#if DEBUG_STRATEGY
- ALOGD(" - b=%s", vectorToString(outB, n).string());
-#endif
-
- // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
- // SSerr is the residual sum of squares (variance of the error),
- // and SStot is the total sum of squares (variance of the data) where each
- // has been weighted.
- float ymean = 0;
- for (uint32_t h = 0; h < m; h++) {
- ymean += y[h];
- }
- ymean /= m;
-
- float sserr = 0;
- float sstot = 0;
- for (uint32_t h = 0; h < m; h++) {
- float err = y[h] - outB[0];
- float term = 1;
- for (uint32_t i = 1; i < n; i++) {
- term *= x[h];
- err -= term * outB[i];
- }
- sserr += w[h] * w[h] * err * err;
- float var = y[h] - ymean;
- sstot += w[h] * w[h] * var * var;
- }
- *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
-#if DEBUG_STRATEGY
- ALOGD(" - sserr=%f", sserr);
- ALOGD(" - sstot=%f", sstot);
- ALOGD(" - det=%f", *outDet);
-#endif
- return true;
-}
-
-bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
- VelocityTracker::Estimator* outEstimator) const {
- outEstimator->clear();
-
- // Iterate over movement samples in reverse time order and collect samples.
- float x[HISTORY_SIZE];
- float y[HISTORY_SIZE];
- float w[HISTORY_SIZE];
- float time[HISTORY_SIZE];
- uint32_t m = 0;
- uint32_t index = mIndex;
- const Movement& newestMovement = mMovements[mIndex];
- do {
- const Movement& movement = mMovements[index];
- if (!movement.idBits.hasBit(id)) {
- break;
- }
-
- nsecs_t age = newestMovement.eventTime - movement.eventTime;
- if (age > HORIZON) {
- break;
- }
-
- const VelocityTracker::Position& position = movement.getPosition(id);
- x[m] = position.x;
- y[m] = position.y;
- w[m] = chooseWeight(index);
- time[m] = -age * 0.000000001f;
- index = (index == 0 ? HISTORY_SIZE : index) - 1;
- } while (++m < HISTORY_SIZE);
-
- if (m == 0) {
- return false; // no data
- }
-
- // Calculate a least squares polynomial fit.
- uint32_t degree = mDegree;
- if (degree > m - 1) {
- degree = m - 1;
- }
- if (degree >= 1) {
- float xdet, ydet;
- uint32_t n = degree + 1;
- if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
- && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) {
- outEstimator->time = newestMovement.eventTime;
- outEstimator->degree = degree;
- outEstimator->confidence = xdet * ydet;
-#if DEBUG_STRATEGY
- ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
- int(outEstimator->degree),
- vectorToString(outEstimator->xCoeff, n).string(),
- vectorToString(outEstimator->yCoeff, n).string(),
- outEstimator->confidence);
-#endif
- return true;
- }
- }
-
- // No velocity data available for this pointer, but we do have its current position.
- outEstimator->xCoeff[0] = x[0];
- outEstimator->yCoeff[0] = y[0];
- outEstimator->time = newestMovement.eventTime;
- outEstimator->degree = 0;
- outEstimator->confidence = 1;
- return true;
-}
-
-float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const {
- switch (mWeighting) {
- case WEIGHTING_DELTA: {
- // Weight points based on how much time elapsed between them and the next
- // point so that points that "cover" a shorter time span are weighed less.
- // delta 0ms: 0.5
- // delta 10ms: 1.0
- if (index == mIndex) {
- return 1.0f;
- }
- uint32_t nextIndex = (index + 1) % HISTORY_SIZE;
- float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime)
- * 0.000001f;
- if (deltaMillis < 0) {
- return 0.5f;
- }
- if (deltaMillis < 10) {
- return 0.5f + deltaMillis * 0.05;
- }
- return 1.0f;
- }
-
- case WEIGHTING_CENTRAL: {
- // Weight points based on their age, weighing very recent and very old points less.
- // age 0ms: 0.5
- // age 10ms: 1.0
- // age 50ms: 1.0
- // age 60ms: 0.5
- float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime)
- * 0.000001f;
- if (ageMillis < 0) {
- return 0.5f;
- }
- if (ageMillis < 10) {
- return 0.5f + ageMillis * 0.05;
- }
- if (ageMillis < 50) {
- return 1.0f;
- }
- if (ageMillis < 60) {
- return 0.5f + (60 - ageMillis) * 0.05;
- }
- return 0.5f;
- }
-
- case WEIGHTING_RECENT: {
- // Weight points based on their age, weighing older points less.
- // age 0ms: 1.0
- // age 50ms: 1.0
- // age 100ms: 0.5
- float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime)
- * 0.000001f;
- if (ageMillis < 50) {
- return 1.0f;
- }
- if (ageMillis < 100) {
- return 0.5f + (100 - ageMillis) * 0.01f;
- }
- return 0.5f;
- }
-
- case WEIGHTING_NONE:
- default:
- return 1.0f;
- }
-}
-
-
-// --- IntegratingVelocityTrackerStrategy ---
-
-IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) :
- mDegree(degree) {
-}
-
-IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
-}
-
-void IntegratingVelocityTrackerStrategy::clear() {
- mPointerIdBits.clear();
-}
-
-void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
- mPointerIdBits.value &= ~idBits.value;
-}
-
-void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
- uint32_t index = 0;
- for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
- uint32_t id = iterIdBits.clearFirstMarkedBit();
- State& state = mPointerState[id];
- const VelocityTracker::Position& position = positions[index++];
- if (mPointerIdBits.hasBit(id)) {
- updateState(state, eventTime, position.x, position.y);
- } else {
- initState(state, eventTime, position.x, position.y);
- }
- }
-
- mPointerIdBits = idBits;
-}
-
-bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id,
- VelocityTracker::Estimator* outEstimator) const {
- outEstimator->clear();
-
- if (mPointerIdBits.hasBit(id)) {
- const State& state = mPointerState[id];
- populateEstimator(state, outEstimator);
- return true;
- }
-
- return false;
-}
-
-void IntegratingVelocityTrackerStrategy::initState(State& state,
- nsecs_t eventTime, float xpos, float ypos) const {
- state.updateTime = eventTime;
- state.degree = 0;
-
- state.xpos = xpos;
- state.xvel = 0;
- state.xaccel = 0;
- state.ypos = ypos;
- state.yvel = 0;
- state.yaccel = 0;
-}
-
-void IntegratingVelocityTrackerStrategy::updateState(State& state,
- nsecs_t eventTime, float xpos, float ypos) const {
- const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
- const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
-
- if (eventTime <= state.updateTime + MIN_TIME_DELTA) {
- return;
- }
-
- float dt = (eventTime - state.updateTime) * 0.000000001f;
- state.updateTime = eventTime;
-
- float xvel = (xpos - state.xpos) / dt;
- float yvel = (ypos - state.ypos) / dt;
- if (state.degree == 0) {
- state.xvel = xvel;
- state.yvel = yvel;
- state.degree = 1;
- } else {
- float alpha = dt / (FILTER_TIME_CONSTANT + dt);
- if (mDegree == 1) {
- state.xvel += (xvel - state.xvel) * alpha;
- state.yvel += (yvel - state.yvel) * alpha;
- } else {
- float xaccel = (xvel - state.xvel) / dt;
- float yaccel = (yvel - state.yvel) / dt;
- if (state.degree == 1) {
- state.xaccel = xaccel;
- state.yaccel = yaccel;
- state.degree = 2;
- } else {
- state.xaccel += (xaccel - state.xaccel) * alpha;
- state.yaccel += (yaccel - state.yaccel) * alpha;
- }
- state.xvel += (state.xaccel * dt) * alpha;
- state.yvel += (state.yaccel * dt) * alpha;
- }
- }
- state.xpos = xpos;
- state.ypos = ypos;
-}
-
-void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
- VelocityTracker::Estimator* outEstimator) const {
- outEstimator->time = state.updateTime;
- outEstimator->confidence = 1.0f;
- outEstimator->degree = state.degree;
- outEstimator->xCoeff[0] = state.xpos;
- outEstimator->xCoeff[1] = state.xvel;
- outEstimator->xCoeff[2] = state.xaccel / 2;
- outEstimator->yCoeff[0] = state.ypos;
- outEstimator->yCoeff[1] = state.yvel;
- outEstimator->yCoeff[2] = state.yaccel / 2;
-}
-
-
-// --- LegacyVelocityTrackerStrategy ---
-
-const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
-const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
-const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
-
-LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
- clear();
-}
-
-LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() {
-}
-
-void LegacyVelocityTrackerStrategy::clear() {
- mIndex = 0;
- mMovements[0].idBits.clear();
-}
-
-void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
- mMovements[mIndex].idBits = remainingIdBits;
-}
-
-void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
- if (++mIndex == HISTORY_SIZE) {
- mIndex = 0;
- }
-
- Movement& movement = mMovements[mIndex];
- movement.eventTime = eventTime;
- movement.idBits = idBits;
- uint32_t count = idBits.count();
- for (uint32_t i = 0; i < count; i++) {
- movement.positions[i] = positions[i];
- }
-}
-
-bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id,
- VelocityTracker::Estimator* outEstimator) const {
- outEstimator->clear();
-
- const Movement& newestMovement = mMovements[mIndex];
- if (!newestMovement.idBits.hasBit(id)) {
- return false; // no data
- }
-
- // Find the oldest sample that contains the pointer and that is not older than HORIZON.
- nsecs_t minTime = newestMovement.eventTime - HORIZON;
- uint32_t oldestIndex = mIndex;
- uint32_t numTouches = 1;
- do {
- uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
- const Movement& nextOldestMovement = mMovements[nextOldestIndex];
- if (!nextOldestMovement.idBits.hasBit(id)
- || nextOldestMovement.eventTime < minTime) {
- break;
- }
- oldestIndex = nextOldestIndex;
- } while (++numTouches < HISTORY_SIZE);
-
- // Calculate an exponentially weighted moving average of the velocity estimate
- // at different points in time measured relative to the oldest sample.
- // This is essentially an IIR filter. Newer samples are weighted more heavily
- // than older samples. Samples at equal time points are weighted more or less
- // equally.
- //
- // One tricky problem is that the sample data may be poorly conditioned.
- // Sometimes samples arrive very close together in time which can cause us to
- // overestimate the velocity at that time point. Most samples might be measured
- // 16ms apart but some consecutive samples could be only 0.5sm apart because
- // the hardware or driver reports them irregularly or in bursts.
- float accumVx = 0;
- float accumVy = 0;
- uint32_t index = oldestIndex;
- uint32_t samplesUsed = 0;
- const Movement& oldestMovement = mMovements[oldestIndex];
- const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id);
- nsecs_t lastDuration = 0;
-
- while (numTouches-- > 1) {
- if (++index == HISTORY_SIZE) {
- index = 0;
- }
- const Movement& movement = mMovements[index];
- nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
-
- // If the duration between samples is small, we may significantly overestimate
- // the velocity. Consequently, we impose a minimum duration constraint on the
- // samples that we include in the calculation.
- if (duration >= MIN_DURATION) {
- const VelocityTracker::Position& position = movement.getPosition(id);
- float scale = 1000000000.0f / duration; // one over time delta in seconds
- float vx = (position.x - oldestPosition.x) * scale;
- float vy = (position.y - oldestPosition.y) * scale;
- accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
- accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
- lastDuration = duration;
- samplesUsed += 1;
- }
- }
-
- // Report velocity.
- const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id);
- outEstimator->time = newestMovement.eventTime;
- outEstimator->confidence = 1;
- outEstimator->xCoeff[0] = newestPosition.x;
- outEstimator->yCoeff[0] = newestPosition.y;
- if (samplesUsed) {
- outEstimator->xCoeff[1] = accumVx;
- outEstimator->yCoeff[1] = accumVy;
- outEstimator->degree = 1;
- } else {
- outEstimator->degree = 0;
- }
- return true;
-}
-
-} // namespace android
diff --git a/libs/androidfw/VirtualKeyMap.cpp b/libs/androidfw/VirtualKeyMap.cpp
deleted file mode 100644
index 2ba1673..0000000
--- a/libs/androidfw/VirtualKeyMap.cpp
+++ /dev/null
@@ -1,171 +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.
- */
-
-#define LOG_TAG "VirtualKeyMap"
-
-#include <stdlib.h>
-#include <string.h>
-#include <androidfw/VirtualKeyMap.h>
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-#include <utils/Timers.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
-
-
-// --- VirtualKeyMap ---
-
-VirtualKeyMap::VirtualKeyMap() {
-}
-
-VirtualKeyMap::~VirtualKeyMap() {
-}
-
-status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
- *outMap = NULL;
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
- if (status) {
- ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
- } else {
- VirtualKeyMap* map = new VirtualKeyMap();
- if (!map) {
- ALOGE("Error allocating virtual key map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map, tokenizer);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (status) {
- delete map;
- } else {
- *outMap = map;
- }
- }
- delete tokenizer;
- }
- return status;
-}
-
-
-// --- VirtualKeyMap::Parser ---
-
-VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
- mMap(map), mTokenizer(tokenizer) {
-}
-
-VirtualKeyMap::Parser::~Parser() {
-}
-
-status_t VirtualKeyMap::Parser::parse() {
- while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
-#endif
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
- // Multiple keys can appear on one line or they can be broken up across multiple lines.
- do {
- String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
- if (token != "0x01") {
- ALOGE("%s: Unknown virtual key type, expected 0x01.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- VirtualKeyDefinition defn;
- bool success = parseNextIntField(&defn.scanCode)
- && parseNextIntField(&defn.centerX)
- && parseNextIntField(&defn.centerY)
- && parseNextIntField(&defn.width)
- && parseNextIntField(&defn.height);
- if (!success) {
- ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
-#if DEBUG_PARSER
- ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
- "width=%d, height=%d",
- defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
-#endif
- mMap->mVirtualKeys.push(defn);
- } while (consumeFieldDelimiterAndSkipWhitespace());
-
- if (!mTokenizer->isEol()) {
- ALOGE("%s: Expected end of line, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
- return BAD_VALUE;
- }
- }
-
- mTokenizer->nextLine();
- }
-
- return NO_ERROR;
-}
-
-bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
- mTokenizer->skipDelimiters(WHITESPACE);
- if (mTokenizer->peekChar() == ':') {
- mTokenizer->nextChar();
- mTokenizer->skipDelimiters(WHITESPACE);
- return true;
- }
- return false;
-}
-
-bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
- if (!consumeFieldDelimiterAndSkipWhitespace()) {
- return false;
- }
-
- String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
- char* end;
- *outValue = strtol(token.string(), &end, 0);
- if (token.isEmpty() || *end != '\0') {
- ALOGE("Expected an integer, got '%s'.", token.string());
- return false;
- }
- return true;
-}
-
-} // namespace android
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 6be7c5b..0522212 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -4,9 +4,6 @@
# Build the unit tests.
test_src_files := \
- InputChannel_test.cpp \
- InputEvent_test.cpp \
- InputPublisherAndConsumer_test.cpp \
ObbFile_test.cpp \
ZipFileRO_test.cpp
@@ -14,10 +11,8 @@
libandroidfw \
libcutils \
libutils \
- libbinder \
libui \
- libstlport \
- libskia
+ libstlport
static_libraries := \
libgtest \
diff --git a/libs/androidfw/tests/InputChannel_test.cpp b/libs/androidfw/tests/InputChannel_test.cpp
deleted file mode 100644
index 7fff8af..0000000
--- a/libs/androidfw/tests/InputChannel_test.cpp
+++ /dev/null
@@ -1,158 +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.
- */
-
-#include <androidfw/InputTransport.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
-#include <utils/StrongPointer.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <time.h>
-#include <errno.h>
-
-#include "TestHelpers.h"
-
-namespace android {
-
-class InputChannelTest : public testing::Test {
-protected:
- virtual void SetUp() { }
- virtual void TearDown() { }
-};
-
-
-TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
- // Our purpose here is to verify that the input channel destructor closes the
- // file descriptor provided to it. One easy way is to provide it with one end
- // of a pipe and to check for EPIPE on the other end after the channel is destroyed.
- Pipe pipe;
-
- sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
-
- EXPECT_STREQ("channel name", inputChannel->getName().string())
- << "channel should have provided name";
- EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
- << "channel should have provided fd";
-
- inputChannel.clear(); // destroys input channel
-
- EXPECT_EQ(-EPIPE, pipe.readSignal())
- << "channel should have closed fd when destroyed";
-
- // clean up fds of Pipe endpoints that were closed so we don't try to close them again
- pipe.sendFd = -1;
-}
-
-TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
- sp<InputChannel> serverChannel, clientChannel;
-
- status_t result = InputChannel::openInputChannelPair(String8("channel name"),
- serverChannel, clientChannel);
-
- ASSERT_EQ(OK, result)
- << "should have successfully opened a channel pair";
-
- // Name
- EXPECT_STREQ("channel name (server)", serverChannel->getName().string())
- << "server channel should have suffixed name";
- EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
- << "client channel should have suffixed name";
-
- // Server->Client communication
- InputMessage serverMsg;
- memset(&serverMsg, 0, sizeof(InputMessage));
- serverMsg.header.type = InputMessage::TYPE_KEY;
- serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
- EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
- << "server channel should be able to send message to client channel";
-
- InputMessage clientMsg;
- EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
- << "client channel should be able to receive message from server channel";
- EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
- << "client channel should receive the correct message from server channel";
- EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
- << "client channel should receive the correct message from server channel";
-
- // Client->Server communication
- InputMessage clientReply;
- memset(&clientReply, 0, sizeof(InputMessage));
- clientReply.header.type = InputMessage::TYPE_FINISHED;
- clientReply.body.finished.seq = 0x11223344;
- clientReply.body.finished.handled = true;
- EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
- << "client channel should be able to send message to server channel";
-
- InputMessage serverReply;
- EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply))
- << "server channel should be able to receive message from client channel";
- EXPECT_EQ(clientReply.header.type, serverReply.header.type)
- << "server channel should receive the correct message from client channel";
- EXPECT_EQ(clientReply.body.finished.seq, serverReply.body.finished.seq)
- << "server channel should receive the correct message from client channel";
- EXPECT_EQ(clientReply.body.finished.handled, serverReply.body.finished.handled)
- << "server channel should receive the correct message from client channel";
-}
-
-TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
- sp<InputChannel> serverChannel, clientChannel;
-
- status_t result = InputChannel::openInputChannelPair(String8("channel name"),
- serverChannel, clientChannel);
-
- ASSERT_EQ(OK, result)
- << "should have successfully opened a channel pair";
-
- InputMessage msg;
- EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg))
- << "receiveMessage should have returned WOULD_BLOCK";
-}
-
-TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
- sp<InputChannel> serverChannel, clientChannel;
-
- status_t result = InputChannel::openInputChannelPair(String8("channel name"),
- serverChannel, clientChannel);
-
- ASSERT_EQ(OK, result)
- << "should have successfully opened a channel pair";
-
- serverChannel.clear(); // close server channel
-
- InputMessage msg;
- EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
- << "receiveMessage should have returned DEAD_OBJECT";
-}
-
-TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
- sp<InputChannel> serverChannel, clientChannel;
-
- status_t result = InputChannel::openInputChannelPair(String8("channel name"),
- serverChannel, clientChannel);
-
- ASSERT_EQ(OK, result)
- << "should have successfully opened a channel pair";
-
- serverChannel.clear(); // close server channel
-
- InputMessage msg;
- msg.header.type = InputMessage::TYPE_KEY;
- EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
- << "sendMessage should have returned DEAD_OBJECT";
-}
-
-
-} // namespace android
diff --git a/libs/androidfw/tests/InputEvent_test.cpp b/libs/androidfw/tests/InputEvent_test.cpp
deleted file mode 100644
index e9164d1..0000000
--- a/libs/androidfw/tests/InputEvent_test.cpp
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#include <androidfw/Input.h>
-#include <gtest/gtest.h>
-#include <binder/Parcel.h>
-
-#include <math.h>
-#include <core/SkMatrix.h>
-
-namespace android {
-
-class BaseTest : public testing::Test {
-protected:
- virtual void SetUp() { }
- virtual void TearDown() { }
-};
-
-// --- PointerCoordsTest ---
-
-class PointerCoordsTest : public BaseTest {
-};
-
-TEST_F(PointerCoordsTest, ClearSetsBitsToZero) {
- PointerCoords coords;
- coords.clear();
-
- ASSERT_EQ(0ULL, coords.bits);
-}
-
-TEST_F(PointerCoordsTest, AxisValues) {
- float* valuePtr;
- PointerCoords coords;
- coords.clear();
-
- // Check invariants when no axes are present.
- ASSERT_EQ(0, coords.getAxisValue(0))
- << "getAxisValue should return zero because axis is not present";
- ASSERT_EQ(0, coords.getAxisValue(1))
- << "getAxisValue should return zero because axis is not present";
-
- // Set first axis.
- ASSERT_EQ(OK, coords.setAxisValue(1, 5));
- ASSERT_EQ(0x00000002ULL, coords.bits);
- ASSERT_EQ(5, coords.values[0]);
-
- ASSERT_EQ(0, coords.getAxisValue(0))
- << "getAxisValue should return zero because axis is not present";
- ASSERT_EQ(5, coords.getAxisValue(1))
- << "getAxisValue should return value of axis";
-
- // Set an axis with a higher id than all others. (appending value at the end)
- ASSERT_EQ(OK, coords.setAxisValue(3, 2));
- ASSERT_EQ(0x0000000aULL, coords.bits);
- ASSERT_EQ(5, coords.values[0]);
- ASSERT_EQ(2, coords.values[1]);
-
- ASSERT_EQ(0, coords.getAxisValue(0))
- << "getAxisValue should return zero because axis is not present";
- ASSERT_EQ(5, coords.getAxisValue(1))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(0, coords.getAxisValue(2))
- << "getAxisValue should return zero because axis is not present";
- ASSERT_EQ(2, coords.getAxisValue(3))
- << "getAxisValue should return value of axis";
-
- // Set an axis with an id lower than all others. (prepending value at beginning)
- ASSERT_EQ(OK, coords.setAxisValue(0, 4));
- ASSERT_EQ(0x0000000bULL, coords.bits);
- ASSERT_EQ(4, coords.values[0]);
- ASSERT_EQ(5, coords.values[1]);
- ASSERT_EQ(2, coords.values[2]);
-
- ASSERT_EQ(4, coords.getAxisValue(0))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(5, coords.getAxisValue(1))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(0, coords.getAxisValue(2))
- << "getAxisValue should return zero because axis is not present";
- ASSERT_EQ(2, coords.getAxisValue(3))
- << "getAxisValue should return value of axis";
-
- // Set an axis with an id between the others. (inserting value in the middle)
- ASSERT_EQ(OK, coords.setAxisValue(2, 1));
- ASSERT_EQ(0x0000000fULL, coords.bits);
- ASSERT_EQ(4, coords.values[0]);
- ASSERT_EQ(5, coords.values[1]);
- ASSERT_EQ(1, coords.values[2]);
- ASSERT_EQ(2, coords.values[3]);
-
- ASSERT_EQ(4, coords.getAxisValue(0))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(5, coords.getAxisValue(1))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(1, coords.getAxisValue(2))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(2, coords.getAxisValue(3))
- << "getAxisValue should return value of axis";
-
- // Set an existing axis value in place.
- ASSERT_EQ(OK, coords.setAxisValue(1, 6));
- ASSERT_EQ(0x0000000fULL, coords.bits);
- ASSERT_EQ(4, coords.values[0]);
- ASSERT_EQ(6, coords.values[1]);
- ASSERT_EQ(1, coords.values[2]);
- ASSERT_EQ(2, coords.values[3]);
-
- ASSERT_EQ(4, coords.getAxisValue(0))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(6, coords.getAxisValue(1))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(1, coords.getAxisValue(2))
- << "getAxisValue should return value of axis";
- ASSERT_EQ(2, coords.getAxisValue(3))
- << "getAxisValue should return value of axis";
-
- // Set maximum number of axes.
- for (size_t axis = 4; axis < PointerCoords::MAX_AXES; axis++) {
- ASSERT_EQ(OK, coords.setAxisValue(axis, axis));
- }
- ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
-
- // Try to set one more axis beyond maximum number.
- // Ensure bits are unchanged.
- ASSERT_EQ(NO_MEMORY, coords.setAxisValue(PointerCoords::MAX_AXES, 100));
- ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
-}
-
-TEST_F(PointerCoordsTest, Parcel) {
- Parcel parcel;
-
- PointerCoords inCoords;
- inCoords.clear();
- PointerCoords outCoords;
-
- // Round trip with empty coords.
- inCoords.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- outCoords.readFromParcel(&parcel);
-
- ASSERT_EQ(0ULL, outCoords.bits);
-
- // Round trip with some values.
- parcel.freeData();
- inCoords.setAxisValue(2, 5);
- inCoords.setAxisValue(5, 8);
-
- inCoords.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- outCoords.readFromParcel(&parcel);
-
- ASSERT_EQ(outCoords.bits, inCoords.bits);
- ASSERT_EQ(outCoords.values[0], inCoords.values[0]);
- ASSERT_EQ(outCoords.values[1], inCoords.values[1]);
-}
-
-
-// --- KeyEventTest ---
-
-class KeyEventTest : public BaseTest {
-};
-
-TEST_F(KeyEventTest, Properties) {
- KeyEvent event;
-
- // Initialize and get properties.
- const nsecs_t ARBITRARY_DOWN_TIME = 1;
- const nsecs_t ARBITRARY_EVENT_TIME = 2;
- event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN,
- AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121,
- AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
-
- ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
- ASSERT_EQ(2, event.getDeviceId());
- ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
- ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
- ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
- ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
- ASSERT_EQ(121, event.getScanCode());
- ASSERT_EQ(AMETA_ALT_ON, event.getMetaState());
- ASSERT_EQ(1, event.getRepeatCount());
- ASSERT_EQ(ARBITRARY_DOWN_TIME, event.getDownTime());
- ASSERT_EQ(ARBITRARY_EVENT_TIME, event.getEventTime());
-
- // Set source.
- event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
-}
-
-
-// --- MotionEventTest ---
-
-class MotionEventTest : public BaseTest {
-protected:
- static const nsecs_t ARBITRARY_DOWN_TIME;
- static const nsecs_t ARBITRARY_EVENT_TIME;
- static const float X_OFFSET;
- static const float Y_OFFSET;
-
- void initializeEventWithHistory(MotionEvent* event);
- void assertEqualsEventWithHistory(const MotionEvent* event);
-};
-
-const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1;
-const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2;
-const float MotionEventTest::X_OFFSET = 1.0f;
-const float MotionEventTest::Y_OFFSET = 1.1f;
-
-void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
- PointerProperties pointerProperties[2];
- pointerProperties[0].clear();
- pointerProperties[0].id = 1;
- pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
- pointerProperties[1].clear();
- pointerProperties[1].id = 2;
- pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
-
- PointerCoords pointerCoords[2];
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
- pointerCoords[1].clear();
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
- event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
- AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
- X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
- ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
- 2, pointerProperties, pointerCoords);
-
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
- event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords);
-
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
- event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords);
-}
-
-void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
- // Check properties.
- ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
- ASSERT_EQ(2, event->getDeviceId());
- ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
- ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
- ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
- ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
- ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
- ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
- ASSERT_EQ(X_OFFSET, event->getXOffset());
- ASSERT_EQ(Y_OFFSET, event->getYOffset());
- ASSERT_EQ(2.0f, event->getXPrecision());
- ASSERT_EQ(2.1f, event->getYPrecision());
- ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime());
-
- ASSERT_EQ(2U, event->getPointerCount());
- ASSERT_EQ(1, event->getPointerId(0));
- ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0));
- ASSERT_EQ(2, event->getPointerId(1));
- ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1));
-
- ASSERT_EQ(2U, event->getHistorySize());
-
- // Check data.
- ASSERT_EQ(ARBITRARY_EVENT_TIME, event->getHistoricalEventTime(0));
- ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1));
- ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime());
-
- ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->
- getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->
- getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->
- getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->
- getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(211, event->getRawPointerCoords(0)->
- getAxisValue(AMOTION_EVENT_AXIS_Y));
- ASSERT_EQ(221, event->getRawPointerCoords(1)->
- getAxisValue(AMOTION_EVENT_AXIS_Y));
-
- ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0));
- ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0));
- ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1));
- ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1));
- ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0));
- ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1));
-
- ASSERT_EQ(10, event->getHistoricalRawX(0, 0));
- ASSERT_EQ(20, event->getHistoricalRawX(1, 0));
- ASSERT_EQ(110, event->getHistoricalRawX(0, 1));
- ASSERT_EQ(120, event->getHistoricalRawX(1, 1));
- ASSERT_EQ(210, event->getRawX(0));
- ASSERT_EQ(220, event->getRawX(1));
-
- ASSERT_EQ(11, event->getHistoricalRawY(0, 0));
- ASSERT_EQ(21, event->getHistoricalRawY(1, 0));
- ASSERT_EQ(111, event->getHistoricalRawY(0, 1));
- ASSERT_EQ(121, event->getHistoricalRawY(1, 1));
- ASSERT_EQ(211, event->getRawY(0));
- ASSERT_EQ(221, event->getRawY(1));
-
- ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0));
- ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0));
- ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1));
- ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1));
- ASSERT_EQ(X_OFFSET + 210, event->getX(0));
- ASSERT_EQ(X_OFFSET + 220, event->getX(1));
-
- ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0));
- ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0));
- ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1));
- ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1));
- ASSERT_EQ(Y_OFFSET + 211, event->getY(0));
- ASSERT_EQ(Y_OFFSET + 221, event->getY(1));
-
- ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
- ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
- ASSERT_EQ(112, event->getHistoricalPressure(0, 1));
- ASSERT_EQ(122, event->getHistoricalPressure(1, 1));
- ASSERT_EQ(212, event->getPressure(0));
- ASSERT_EQ(222, event->getPressure(1));
-
- ASSERT_EQ(13, event->getHistoricalSize(0, 0));
- ASSERT_EQ(23, event->getHistoricalSize(1, 0));
- ASSERT_EQ(113, event->getHistoricalSize(0, 1));
- ASSERT_EQ(123, event->getHistoricalSize(1, 1));
- ASSERT_EQ(213, event->getSize(0));
- ASSERT_EQ(223, event->getSize(1));
-
- ASSERT_EQ(14, event->getHistoricalTouchMajor(0, 0));
- ASSERT_EQ(24, event->getHistoricalTouchMajor(1, 0));
- ASSERT_EQ(114, event->getHistoricalTouchMajor(0, 1));
- ASSERT_EQ(124, event->getHistoricalTouchMajor(1, 1));
- ASSERT_EQ(214, event->getTouchMajor(0));
- ASSERT_EQ(224, event->getTouchMajor(1));
-
- ASSERT_EQ(15, event->getHistoricalTouchMinor(0, 0));
- ASSERT_EQ(25, event->getHistoricalTouchMinor(1, 0));
- ASSERT_EQ(115, event->getHistoricalTouchMinor(0, 1));
- ASSERT_EQ(125, event->getHistoricalTouchMinor(1, 1));
- ASSERT_EQ(215, event->getTouchMinor(0));
- ASSERT_EQ(225, event->getTouchMinor(1));
-
- ASSERT_EQ(16, event->getHistoricalToolMajor(0, 0));
- ASSERT_EQ(26, event->getHistoricalToolMajor(1, 0));
- ASSERT_EQ(116, event->getHistoricalToolMajor(0, 1));
- ASSERT_EQ(126, event->getHistoricalToolMajor(1, 1));
- ASSERT_EQ(216, event->getToolMajor(0));
- ASSERT_EQ(226, event->getToolMajor(1));
-
- ASSERT_EQ(17, event->getHistoricalToolMinor(0, 0));
- ASSERT_EQ(27, event->getHistoricalToolMinor(1, 0));
- ASSERT_EQ(117, event->getHistoricalToolMinor(0, 1));
- ASSERT_EQ(127, event->getHistoricalToolMinor(1, 1));
- ASSERT_EQ(217, event->getToolMinor(0));
- ASSERT_EQ(227, event->getToolMinor(1));
-
- ASSERT_EQ(18, event->getHistoricalOrientation(0, 0));
- ASSERT_EQ(28, event->getHistoricalOrientation(1, 0));
- ASSERT_EQ(118, event->getHistoricalOrientation(0, 1));
- ASSERT_EQ(128, event->getHistoricalOrientation(1, 1));
- ASSERT_EQ(218, event->getOrientation(0));
- ASSERT_EQ(228, event->getOrientation(1));
-}
-
-TEST_F(MotionEventTest, Properties) {
- MotionEvent event;
-
- // Initialize, add samples and check properties.
- initializeEventWithHistory(&event);
- ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
-
- // Set source.
- event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
-
- // Set action.
- event.setAction(AMOTION_EVENT_ACTION_CANCEL);
- ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
-
- // Set meta state.
- event.setMetaState(AMETA_CTRL_ON);
- ASSERT_EQ(AMETA_CTRL_ON, event.getMetaState());
-}
-
-TEST_F(MotionEventTest, CopyFrom_KeepHistory) {
- MotionEvent event;
- initializeEventWithHistory(&event);
-
- MotionEvent copy;
- copy.copyFrom(&event, true /*keepHistory*/);
-
- ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
-}
-
-TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) {
- MotionEvent event;
- initializeEventWithHistory(&event);
-
- MotionEvent copy;
- copy.copyFrom(&event, false /*keepHistory*/);
-
- ASSERT_EQ(event.getPointerCount(), copy.getPointerCount());
- ASSERT_EQ(0U, copy.getHistorySize());
-
- ASSERT_EQ(event.getPointerId(0), copy.getPointerId(0));
- ASSERT_EQ(event.getPointerId(1), copy.getPointerId(1));
-
- ASSERT_EQ(event.getEventTime(), copy.getEventTime());
-
- ASSERT_EQ(event.getX(0), copy.getX(0));
-}
-
-TEST_F(MotionEventTest, OffsetLocation) {
- MotionEvent event;
- initializeEventWithHistory(&event);
-
- event.offsetLocation(5.0f, -2.0f);
-
- ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset());
- ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset());
-}
-
-TEST_F(MotionEventTest, Scale) {
- MotionEvent event;
- initializeEventWithHistory(&event);
-
- event.scale(2.0f);
-
- ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
- ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
-
- ASSERT_EQ(210 * 2, event.getRawX(0));
- ASSERT_EQ(211 * 2, event.getRawY(0));
- ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0));
- ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0));
- ASSERT_EQ(212, event.getPressure(0));
- ASSERT_EQ(213, event.getSize(0));
- ASSERT_EQ(214 * 2, event.getTouchMajor(0));
- ASSERT_EQ(215 * 2, event.getTouchMinor(0));
- ASSERT_EQ(216 * 2, event.getToolMajor(0));
- ASSERT_EQ(217 * 2, event.getToolMinor(0));
- ASSERT_EQ(218, event.getOrientation(0));
-}
-
-TEST_F(MotionEventTest, Parcel) {
- Parcel parcel;
-
- MotionEvent inEvent;
- initializeEventWithHistory(&inEvent);
- MotionEvent outEvent;
-
- // Round trip.
- inEvent.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- outEvent.readFromParcel(&parcel);
-
- ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent));
-}
-
-TEST_F(MotionEventTest, Transform) {
- // Generate some points on a circle.
- // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle
- // of ARC * i degrees clockwise relative to the Y axis.
- // The geometrical representation is irrelevant to the test, it's just easy to generate
- // and check rotation. We set the orientation to the same angle.
- // Coordinate system: down is increasing Y, right is increasing X.
- const float PI_180 = float(M_PI / 180);
- const float RADIUS = 10;
- const float ARC = 36;
- const float ROTATION = ARC * 2;
-
- const size_t pointerCount = 11;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- float angle = float(i * ARC * PI_180);
- pointerProperties[i].clear();
- pointerProperties[i].id = i;
- pointerCoords[i].clear();
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
- }
- MotionEvent event;
- event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- float originalRawX = 0 + 3;
- float originalRawY = -RADIUS + 2;
-
- // Check original raw X and Y assumption.
- ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
- ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
-
- // Now translate the motion event so the circle's origin is at (0,0).
- event.offsetLocation(-3, -2);
-
- // Offsetting the location should preserve the raw X and Y of the first point.
- ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
- ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
-
- // Apply a rotation about the origin by ROTATION degrees clockwise.
- SkMatrix matrix;
- matrix.setRotate(ROTATION);
- event.transform(&matrix);
-
- // Check the points.
- for (size_t i = 0; i < pointerCount; i++) {
- float angle = float((i * ARC + ROTATION) * PI_180);
- ASSERT_NEAR(sinf(angle) * RADIUS, event.getX(i), 0.001);
- ASSERT_NEAR(-cosf(angle) * RADIUS, event.getY(i), 0.001);
- ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
- }
-
- // Applying the transformation should preserve the raw X and Y of the first point.
- ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
- ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
-}
-
-} // namespace android
diff --git a/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp b/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp
deleted file mode 100644
index f45774b..0000000
--- a/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp
+++ /dev/null
@@ -1,287 +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.
- */
-
-#include <androidfw/InputTransport.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <time.h>
-#include <sys/mman.h>
-#include <cutils/ashmem.h>
-
-#include "TestHelpers.h"
-
-namespace android {
-
-class InputPublisherAndConsumerTest : public testing::Test {
-protected:
- sp<InputChannel> serverChannel, clientChannel;
- InputPublisher* mPublisher;
- InputConsumer* mConsumer;
- PreallocatedInputEventFactory mEventFactory;
-
- virtual void SetUp() {
- status_t result = InputChannel::openInputChannelPair(String8("channel name"),
- serverChannel, clientChannel);
-
- mPublisher = new InputPublisher(serverChannel);
- mConsumer = new InputConsumer(clientChannel);
- }
-
- virtual void TearDown() {
- if (mPublisher) {
- delete mPublisher;
- mPublisher = NULL;
- }
-
- if (mConsumer) {
- delete mConsumer;
- mConsumer = NULL;
- }
-
- serverChannel.clear();
- clientChannel.clear();
- }
-
- void PublishAndConsumeKeyEvent();
- void PublishAndConsumeMotionEvent();
-};
-
-TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
- EXPECT_EQ(serverChannel.get(), mPublisher->getChannel().get());
- EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
-}
-
-void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
- status_t status;
-
- const uint32_t seq = 15;
- const int32_t deviceId = 1;
- const int32_t source = AINPUT_SOURCE_KEYBOARD;
- const int32_t action = AKEY_EVENT_ACTION_DOWN;
- const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
- const int32_t keyCode = AKEYCODE_ENTER;
- const int32_t scanCode = 13;
- const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
- const int32_t repeatCount = 1;
- const nsecs_t downTime = 3;
- const nsecs_t eventTime = 4;
-
- status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
- keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
- ASSERT_EQ(OK, status)
- << "publisher publishKeyEvent should return OK";
-
- uint32_t consumeSeq;
- InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
- ASSERT_EQ(OK, status)
- << "consumer consume should return OK";
-
- ASSERT_TRUE(event != NULL)
- << "consumer should have returned non-NULL event";
- ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType())
- << "consumer should have returned a key event";
-
- KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
- EXPECT_EQ(seq, consumeSeq);
- EXPECT_EQ(deviceId, keyEvent->getDeviceId());
- EXPECT_EQ(source, keyEvent->getSource());
- EXPECT_EQ(action, keyEvent->getAction());
- EXPECT_EQ(flags, keyEvent->getFlags());
- EXPECT_EQ(keyCode, keyEvent->getKeyCode());
- EXPECT_EQ(scanCode, keyEvent->getScanCode());
- EXPECT_EQ(metaState, keyEvent->getMetaState());
- EXPECT_EQ(repeatCount, keyEvent->getRepeatCount());
- EXPECT_EQ(downTime, keyEvent->getDownTime());
- EXPECT_EQ(eventTime, keyEvent->getEventTime());
-
- status = mConsumer->sendFinishedSignal(seq, true);
- ASSERT_EQ(OK, status)
- << "consumer sendFinishedSignal should return OK";
-
- uint32_t finishedSeq = 0;
- bool handled = false;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
- ASSERT_EQ(OK, status)
- << "publisher receiveFinishedSignal should return OK";
- ASSERT_EQ(seq, finishedSeq)
- << "publisher receiveFinishedSignal should have returned the original sequence number";
- ASSERT_TRUE(handled)
- << "publisher receiveFinishedSignal should have set handled to consumer's reply";
-}
-
-void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
- status_t status;
-
- const uint32_t seq = 15;
- const int32_t deviceId = 1;
- const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
- const int32_t action = AMOTION_EVENT_ACTION_MOVE;
- const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
- const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
- const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
- const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
- const float xOffset = -10;
- const float yOffset = -20;
- const float xPrecision = 0.25;
- const float yPrecision = 0.5;
- const nsecs_t downTime = 3;
- const size_t pointerCount = 3;
- const nsecs_t eventTime = 4;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerProperties[i].id = (i + 2) % pointerCount;
- pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-
- pointerCoords[i].clear();
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
- pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
- }
-
- status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags,
- metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
- downTime, eventTime, pointerCount,
- pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status)
- << "publisher publishMotionEvent should return OK";
-
- uint32_t consumeSeq;
- InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
- ASSERT_EQ(OK, status)
- << "consumer consume should return OK";
-
- ASSERT_TRUE(event != NULL)
- << "consumer should have returned non-NULL event";
- ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
- << "consumer should have returned a motion event";
-
- MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
- EXPECT_EQ(seq, consumeSeq);
- EXPECT_EQ(deviceId, motionEvent->getDeviceId());
- EXPECT_EQ(source, motionEvent->getSource());
- EXPECT_EQ(action, motionEvent->getAction());
- EXPECT_EQ(flags, motionEvent->getFlags());
- EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
- EXPECT_EQ(metaState, motionEvent->getMetaState());
- EXPECT_EQ(buttonState, motionEvent->getButtonState());
- EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
- EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
- EXPECT_EQ(downTime, motionEvent->getDownTime());
- EXPECT_EQ(eventTime, motionEvent->getEventTime());
- EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
- EXPECT_EQ(0U, motionEvent->getHistorySize());
-
- for (size_t i = 0; i < pointerCount; i++) {
- SCOPED_TRACE(i);
- EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
- EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
-
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
- motionEvent->getRawX(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
- motionEvent->getRawY(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
- motionEvent->getX(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
- motionEvent->getY(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- motionEvent->getPressure(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- motionEvent->getSize(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- motionEvent->getTouchMajor(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- motionEvent->getTouchMinor(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- motionEvent->getToolMajor(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- motionEvent->getToolMinor(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
- motionEvent->getOrientation(i));
- }
-
- status = mConsumer->sendFinishedSignal(seq, false);
- ASSERT_EQ(OK, status)
- << "consumer sendFinishedSignal should return OK";
-
- uint32_t finishedSeq = 0;
- bool handled = true;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
- ASSERT_EQ(OK, status)
- << "publisher receiveFinishedSignal should return OK";
- ASSERT_EQ(seq, finishedSeq)
- << "publisher receiveFinishedSignal should have returned the original sequence number";
- ASSERT_FALSE(handled)
- << "publisher receiveFinishedSignal should have set handled to consumer's reply";
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
- status_t status;
- const size_t pointerCount = 0;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
-
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(BAD_VALUE, status)
- << "publisher publishMotionEvent should return BAD_VALUE";
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
- status_t status;
- const size_t pointerCount = MAX_POINTERS + 1;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(BAD_VALUE, status)
- << "publisher publishMotionEvent should return BAD_VALUE";
-}
-
-TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
-}
-
-} // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
deleted file mode 100644
index d8e985e..0000000
--- a/libs/androidfw/tests/TestHelpers.h
+++ /dev/null
@@ -1,79 +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 TESTHELPERS_H
-#define TESTHELPERS_H
-
-#include <utils/threads.h>
-
-namespace android {
-
-class Pipe {
-public:
- int sendFd;
- int receiveFd;
-
- Pipe() {
- int fds[2];
- ::pipe(fds);
-
- receiveFd = fds[0];
- sendFd = fds[1];
- }
-
- ~Pipe() {
- if (sendFd != -1) {
- ::close(sendFd);
- }
-
- if (receiveFd != -1) {
- ::close(receiveFd);
- }
- }
-
- status_t writeSignal() {
- ssize_t nWritten = ::write(sendFd, "*", 1);
- return nWritten == 1 ? 0 : -errno;
- }
-
- status_t readSignal() {
- char buf[1];
- ssize_t nRead = ::read(receiveFd, buf, 1);
- return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
- }
-};
-
-class DelayedTask : public Thread {
- int mDelayMillis;
-
-public:
- DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
-
-protected:
- virtual ~DelayedTask() { }
-
- virtual void doTask() = 0;
-
- virtual bool threadLoop() {
- usleep(mDelayMillis * 1000);
- doTask();
- return false;
- }
-};
-
-} // namespace android
-
-#endif // TESTHELPERS_H
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 01b3174..63a61e2 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -57,6 +57,8 @@
frameworks/av/media/libstagefright/codecs/amrnb/common/include \
frameworks/av/media/mtp \
frameworks/native/include/media/openmax \
+ $(call include-path-for, libhardware)/hardware \
+ system/media/camera/include \
$(PV_INCLUDES) \
$(JNI_H_INCLUDE) \
$(call include-path-for, corecg graphics)
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index bdb07a6..7866df4 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -24,6 +24,7 @@
#include <gui/CpuConsumer.h>
#include <gui/Surface.h>
+#include <camera3.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
@@ -268,6 +269,29 @@
return format;
}
+static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer)
+{
+ ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
+ uint32_t size = 0;
+ uint32_t width = buffer->width;
+ uint8_t* jpegBuffer = buffer->data;
+
+ // First check for JPEG transport header at the end of the buffer
+ uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
+ struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
+ if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
+ size = blob->jpeg_size;
+ ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
+ }
+
+ // failed to find size, default to whole buffer
+ if (size == 0) {
+ size = width;
+ }
+
+ return size;
+}
+
static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
uint8_t **base, uint32_t *size)
{
@@ -353,7 +377,7 @@
ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height);
pData = buffer->data;
- dataSize = buffer->width;
+ dataSize = Image_getJpegSize(buffer);
break;
case HAL_PIXEL_FORMAT_RAW_SENSOR:
// Single plane 16bpp bayer data.
@@ -624,8 +648,17 @@
// Check if the producer buffer configurations match what ImageReader configured.
// We want to fail for the very first image because this case is too bad.
- int outputWidth = buffer->crop.getWidth() + 1;
- int outputHeight = buffer->crop.getHeight() + 1;
+ int outputWidth = buffer->width;
+ int outputHeight = buffer->height;
+
+ // Correct with/height when crop is set.
+ if (buffer->crop.getWidth() > 0) {
+ outputWidth = buffer->crop.getWidth() + 1;
+ }
+ if (buffer->crop.getHeight() > 0) {
+ outputHeight = buffer->crop.getHeight() + 1;
+ }
+
int imageReaderWidth = ctx->getBufferWidth();
int imageReaderHeight = ctx->getBufferHeight();
if ((imageReaderWidth != outputWidth) ||
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 207cc4b..cda38e0 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -20,6 +20,7 @@
liblog \
libcutils \
libandroidfw \
+ libinput \
libutils \
libbinder \
libui \
diff --git a/native/android/input.cpp b/native/android/input.cpp
index f6ea576..e9d08b4 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -18,8 +18,8 @@
#include <utils/Log.h>
#include <android/input.h>
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 5838526..b65a9a0 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2239,14 +2239,11 @@
// Set default cdma call auto retry
loadSetting(stmt, Settings.Global.CALL_AUTO_RETRY, 0);
- // Set the preferred network mode to 0 = Global, CDMA default
+ // Set the preferred network mode to target desired value or Default
+ // value defined in RILConstants
int type;
- if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
- type = Phone.NT_MODE_GLOBAL;
- } else {
- type = SystemProperties.getInt("ro.telephony.default_network",
+ type = SystemProperties.getInt("ro.telephony.default_network",
RILConstants.PREFERRED_NETWORK_MODE);
- }
loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type);
// --- New global settings start here
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 71855b2..5a95f4c 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -646,9 +646,6 @@
}
}
- Slog.d(TAG, "openPanel: b9404689 setting isOpen true, st=" + st + " decorView="
- + st.decorView);
- st.isOpen = true;
st.isHandled = false;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -666,8 +663,11 @@
}
lp.windowAnimations = st.windowAnimations;
-
+
wm.addView(st.decorView, lp);
+ Slog.d(TAG, "openPanel: b9404689 setting isOpen true, st=" + st + " decorView="
+ + st.decorView);
+ st.isOpen = true;
// Log.v(TAG, "Adding main menu to window manager.");
}
@@ -696,7 +696,8 @@
*/
public final void closePanel(PanelFeatureState st, boolean doCallback) {
// System.out.println("Close panel: isOpen=" + st.isOpen);
- Slog.d(TAG, "closePanel: b9404689 entry, st=" + st + " decorView=" + st.decorView);
+ Slog.d(TAG, "closePanel: b9404689 entry, st=" + st + " isOpen=" + st.isOpen
+ + " decorView=" + st.decorView + " Callers=" + Debug.getCallers(4));
if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL &&
mActionBar != null && mActionBar.isOverflowMenuShowing()) {
checkCloseActionMenu(st.menu);
@@ -717,6 +718,8 @@
if (doCallback) {
callOnPanelClosed(st.featureId, st, null);
}
+ } else {
+ Slog.d(TAG, "closePanel: b9404689 not removing wm=" + wm);
}
st.isPrepared = false;
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 5d913f3..6e944ef 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -36,12 +36,13 @@
libhardware_legacy \
libskia \
libgui \
- libui
+ libui \
+ libinput
LOCAL_C_INCLUDES := \
external/skia/include/core
-LOCAL_MODULE:= libinput
+LOCAL_MODULE:= libinputservice
LOCAL_MODULE_TAGS := optional
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 376de96..65749b3 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -36,9 +36,9 @@
#include <errno.h>
#include <assert.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/KeyCharacterMap.h>
+#include <input/VirtualKeyMap.h>
#include <string.h>
#include <stdint.h>
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index c93fc7a..daa1bea 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -18,12 +18,12 @@
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
-#include <androidfw/Input.h>
-#include <androidfw/InputDevice.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/Input.h>
+#include <input/InputDevice.h>
+#include <input/Keyboard.h>
+#include <input/KeyLayoutMap.h>
+#include <input/KeyCharacterMap.h>
+#include <input/VirtualKeyMap.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Log.h>
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index c04a935..1f5504c 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -17,7 +17,7 @@
#ifndef _UI_INPUT_APPLICATION_H
#define _UI_INPUT_APPLICATION_H
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 430721e..63ea781 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -17,8 +17,8 @@
#ifndef _UI_INPUT_DISPATCHER_H
#define _UI_INPUT_DISPATCHER_H
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/threads.h>
diff --git a/services/input/InputListener.h b/services/input/InputListener.h
index cd7c25a..78ae10f 100644
--- a/services/input/InputListener.h
+++ b/services/input/InputListener.h
@@ -17,7 +17,7 @@
#ifndef _UI_INPUT_LISTENER_H
#define _UI_INPUT_LISTENER_H
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
diff --git a/services/input/InputManager.h b/services/input/InputManager.h
index 29584c9..a213b2d 100644
--- a/services/input/InputManager.h
+++ b/services/input/InputManager.h
@@ -25,8 +25,8 @@
#include "InputReader.h"
#include "InputDispatcher.h"
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index e229755..5b64d8a 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -42,8 +42,8 @@
#include "InputReader.h"
#include <cutils/log.h>
-#include <androidfw/Keyboard.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/Keyboard.h>
+#include <input/VirtualKeyMap.h>
#include <stddef.h>
#include <stdlib.h>
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 0189ba7..7e303e4 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -21,9 +21,9 @@
#include "PointerController.h"
#include "InputListener.h"
-#include <androidfw/Input.h>
-#include <androidfw/VelocityControl.h>
-#include <androidfw/VelocityTracker.h>
+#include <input/Input.h>
+#include <input/VelocityControl.h>
+#include <input/VelocityTracker.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Timers.h>
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 7bd3af7..136870a 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -17,8 +17,8 @@
#ifndef _UI_INPUT_WINDOW_H
#define _UI_INPUT_WINDOW_H
-#include <androidfw/Input.h>
-#include <androidfw/InputTransport.h>
+#include <input/Input.h>
+#include <input/InputTransport.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <utils/String8.h>
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index fd68b61..790c0bb 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -20,7 +20,7 @@
#include "SpriteController.h"
#include <ui/DisplayInfo.h>
-#include <androidfw/Input.h>
+#include <input/Input.h>
#include <utils/BitSet.h>
#include <utils/RefBase.h>
#include <utils/Looper.h>
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
index f3e2dee..9278f41 100644
--- a/services/input/tests/Android.mk
+++ b/services/input/tests/Android.mk
@@ -17,7 +17,8 @@
libui \
libskia \
libstlport \
- libinput
+ libinput \
+ libinputservice
static_libraries := \
libgtest \
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 54f6118..fc346a2 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -31,6 +31,9 @@
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -52,11 +55,13 @@
import android.net.INetworkStatsService;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.Uri;
import android.net.LinkProperties.CompareResult;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkInfo.State;
import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
import android.net.NetworkStateTracker;
@@ -66,6 +71,7 @@
import android.net.RouteInfo;
import android.net.wifi.WifiStateTracker;
import android.net.wimax.WimaxManagerConstants;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.FileUtils;
import android.os.Handler;
@@ -79,6 +85,7 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -86,13 +93,16 @@
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseIntArray;
+import com.android.internal.R;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.internal.telephony.DctConstants;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.IndentingPrintWriter;
@@ -112,9 +122,11 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
+import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -122,6 +134,8 @@
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* @hide
@@ -142,6 +156,12 @@
private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
"android.telephony.apn-restore";
+ // Default value if FAIL_FAST_TIME_MS is not set
+ private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000;
+ // system property that can override DEFAULT_FAIL_FAST_TIME_MS
+ private static final String FAIL_FAST_TIME_MS =
+ "persist.radio.fail_fast_time_ms";
+
// used in recursive route setting to add gateways for the host for which
// a host route was requested.
private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
@@ -293,6 +313,11 @@
private static final int EVENT_VPN_STATE_CHANGED = 14;
+ /**
+ * Used internally to disable fail fast of mobile data
+ */
+ private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15;
+
/** Handler used for internal events. */
private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */
@@ -348,6 +373,9 @@
List mProtectedNetworks;
private DataConnectionStats mDataConnectionStats;
+ private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
+
+ TelephonyManager mTelephonyManager;
public ConnectivityService(Context context, INetworkManagementService netd,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
@@ -397,6 +425,7 @@
mNetd = checkNotNull(netManager, "missing INetworkManagementService");
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
mKeyStore = KeyStore.getInstance();
+ mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
try {
mPolicyManager.registerListener(mPolicyListener);
@@ -1414,8 +1443,12 @@
netState != DetailedState.CAPTIVE_PORTAL_CHECK) ||
tracker.isTeardownRequested()) {
if (VDBG) {
- log("requestRouteToHostAddress on down network " +
- "(" + networkType + ") - dropped");
+ log("requestRouteToHostAddress on down network "
+ + "(" + networkType + ") - dropped"
+ + " tracker=" + tracker
+ + " netState=" + netState
+ + " isTeardownRequested="
+ + ((tracker != null) ? tracker.isTeardownRequested() : "tracker:null"));
}
return false;
}
@@ -1423,12 +1456,15 @@
try {
InetAddress addr = InetAddress.getByAddress(hostAddress);
LinkProperties lp = tracker.getLinkProperties();
- return addRouteToAddress(lp, addr);
+ boolean ok = addRouteToAddress(lp, addr);
+ if (DBG) log("requestRouteToHostAddress ok=" + ok);
+ return ok;
} catch (UnknownHostException e) {
if (DBG) log("requestRouteToHostAddress got " + e.toString());
} finally {
Binder.restoreCallingIdentity(token);
}
+ if (DBG) log("requestRouteToHostAddress X bottom return false");
return false;
}
@@ -2830,6 +2866,19 @@
}
break;
}
+ case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: {
+ int tag = mEnableFailFastMobileDataTag.get();
+ if (msg.arg1 == tag) {
+ MobileDataStateTracker mobileDst =
+ (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+ if (mobileDst != null) {
+ mobileDst.setEnableFailFastMobileData(msg.arg2);
+ }
+ } else {
+ log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1
+ + " != tag:" + tag);
+ }
+ }
}
}
}
@@ -3484,4 +3533,460 @@
}
return ConnectivityManager.TYPE_NONE;
}
+
+ /**
+ * Have mobile data fail fast if enabled.
+ *
+ * @param enabled DctConstants.ENABLED/DISABLED
+ */
+ private void setEnableFailFastMobileData(int enabled) {
+ int tag;
+
+ if (enabled == DctConstants.ENABLED) {
+ tag = mEnableFailFastMobileDataTag.incrementAndGet();
+ } else {
+ tag = mEnableFailFastMobileDataTag.get();
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag,
+ enabled));
+ }
+
+ @Override
+ public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
+ final ResultReceiver resultReceiver) {
+ log("checkMobileProvisioning: E sendNotification=" + sendNotification
+ + " suggestedTimeOutMs=" + suggestedTimeOutMs
+ + " resultReceiver=" + resultReceiver);
+ enforceChangePermission();
+
+ int timeOutMs = suggestedTimeOutMs;
+ if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
+ timeOutMs = CheckMp.MAX_TIMEOUT_MS;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ CheckMp checkMp = new CheckMp(mContext, this);
+ CheckMp.CallBack cb = new CheckMp.CallBack() {
+ @Override
+ void onComplete(Integer result) {
+ log("CheckMp.onComplete: result=" + result);
+ if (resultReceiver != null) {
+ log("CheckMp.onComplete: send result");
+ resultReceiver.send(result, null);
+ }
+ NetworkInfo ni =
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo();
+ switch(result) {
+ case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE:
+ case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: {
+ log("CheckMp.onComplete: ignore, connected or no connection");
+ break;
+ }
+ case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: {
+ log("CheckMp.onComplete: warm sim");
+ String url = getProvisioningUrl();
+ if (TextUtils.isEmpty(url)) {
+ url = mContext.getResources()
+ .getString(R.string.mobile_redirected_provisioning_url);
+ }
+ if (TextUtils.isEmpty(url) == false) {
+ log("CheckMp.onComplete: warm sim (redirected), url=" + url);
+ setNotificationVisible(true, ni, url);
+ } else {
+ log("CheckMp.onComplete: warm sim (redirected), no url");
+ }
+ break;
+ }
+ case ConnectivityManager.CMP_RESULT_CODE_NO_DNS:
+ case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: {
+ String url = getProvisioningUrl();
+ if (TextUtils.isEmpty(url) == false) {
+ log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url);
+ setNotificationVisible(true, ni, url);
+ } else {
+ log("CheckMp.onComplete: warm sim (no dns/tcp), no url");
+ }
+ break;
+ }
+ default: {
+ loge("CheckMp.onComplete: ignore unexpected result=" + result);
+ break;
+ }
+ }
+ }
+ };
+ CheckMp.Params params =
+ new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
+ log("checkMobileProvisioning: params=" + params);
+ setNotificationVisible(false, null, null);
+ checkMp.execute(params);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ log("checkMobileProvisioning: X");
+ }
+ return timeOutMs;
+ }
+
+ static class CheckMp extends
+ AsyncTask<CheckMp.Params, Void, Integer> {
+ private static final String CHECKMP_TAG = "CheckMp";
+ public static final int MAX_TIMEOUT_MS = 60000;
+ private static final int SOCKET_TIMEOUT_MS = 5000;
+ private Context mContext;
+ private ConnectivityService mCs;
+ private TelephonyManager mTm;
+ private Params mParams;
+
+ /**
+ * Parameters for AsyncTask.execute
+ */
+ static class Params {
+ private String mUrl;
+ private long mTimeOutMs;
+ private CallBack mCb;
+
+ Params(String url, long timeOutMs, CallBack cb) {
+ mUrl = url;
+ mTimeOutMs = timeOutMs;
+ mCb = cb;
+ }
+
+ @Override
+ public String toString() {
+ return "{" + " url=" + mUrl + " mTimeOutMs=" + mTimeOutMs + " mCb=" + mCb + "}";
+ }
+ }
+
+ /**
+ * The call back object passed in Params. onComplete will be called
+ * on the main thread.
+ */
+ abstract static class CallBack {
+ // Called on the main thread.
+ abstract void onComplete(Integer result);
+ }
+
+ public CheckMp(Context context, ConnectivityService cs) {
+ mContext = context;
+ mCs = cs;
+
+ // Setup access to TelephonyService we'll be using.
+ mTm = (TelephonyManager) mContext.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ }
+
+ /**
+ * Get the default url to use for the test.
+ */
+ public String getDefaultUrl() {
+ // See http://go/clientsdns for usage approval
+ String server = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.CAPTIVE_PORTAL_SERVER);
+ if (server == null) {
+ server = "clients3.google.com";
+ }
+ return "http://" + server + "/generate_204";
+ }
+
+ /**
+ * Detect if its possible to connect to the http url. DNS based detection techniques
+ * do not work at all hotspots. The best way to check is to perform a request to
+ * a known address that fetches the data we expect.
+ */
+ private synchronized Integer isMobileOk(Params params) {
+ Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+ Uri orgUri = Uri.parse(params.mUrl);
+ Random rand = new Random();
+ mParams = params;
+
+ try {
+ if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
+ log("isMobileOk: not mobile capable");
+ result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+ return result;
+ }
+
+ // Enable fail fast as we'll do retries here and use a
+ // hipri connection so the default connection stays active.
+ log("isMobileOk: start hipri url=" + params.mUrl);
+ mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
+ mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ Phone.FEATURE_ENABLE_HIPRI, new Binder());
+
+ // Continue trying to connect until time has run out
+ long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs;
+ while(SystemClock.elapsedRealtime() < endTime) {
+ try {
+ // Wait for hipri to connect.
+ // TODO: Don't poll and handle situation where hipri fails
+ // because default is retrying. See b/9569540
+ NetworkInfo.State state = mCs
+ .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
+ if (state != NetworkInfo.State.CONNECTED) {
+ log("isMobileOk: not connected ni=" +
+ mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
+ sleep(1);
+ result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+ continue;
+ }
+
+ // Get of the addresses associated with the url host. We need to use the
+ // address otherwise HttpURLConnection object will use the name to get
+ // the addresses and is will try every address but that will bypass the
+ // route to host we setup and the connection could succeed as the default
+ // interface might be connected to the internet via wifi or other interface.
+ InetAddress[] addresses;
+ try {
+ addresses = InetAddress.getAllByName(orgUri.getHost());
+ } catch (UnknownHostException e) {
+ log("isMobileOk: UnknownHostException");
+ result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS;
+ return result;
+ }
+ log("isMobileOk: addresses=" + inetAddressesToString(addresses));
+
+ // Get the type of addresses supported by this link
+ LinkProperties lp = mCs.getLinkProperties(
+ ConnectivityManager.TYPE_MOBILE_HIPRI);
+ boolean linkHasIpv4 = hasIPv4Address(lp);
+ boolean linkHasIpv6 = hasIPv6Address(lp);
+ log("isMobileOk: linkHasIpv4=" + linkHasIpv4
+ + " linkHasIpv6=" + linkHasIpv6);
+
+ // Loop through at most 3 valid addresses or all of the address or until
+ // we run out of time
+ int loops = Math.min(3, addresses.length);
+ for(int validAddr=0, addrTried=0;
+ (validAddr < loops) && (addrTried < addresses.length)
+ && (SystemClock.elapsedRealtime() < endTime);
+ addrTried ++) {
+
+ // Choose the address at random but make sure its type is supported
+ InetAddress hostAddr = addresses[rand.nextInt(addresses.length)];
+ if (((hostAddr instanceof Inet4Address) && linkHasIpv4)
+ || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) {
+ // Valid address, so use it
+ validAddr += 1;
+ } else {
+ // Invalid address so try next address
+ continue;
+ }
+
+ // Make a route to host so we check the specific interface.
+ if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI,
+ hostAddr.getAddress())) {
+ // Wait a short time to be sure the route is established ??
+ log("isMobileOk:"
+ + " wait to establish route to hostAddr=" + hostAddr);
+ sleep(3);
+ } else {
+ log("isMobileOk:"
+ + " could not establish route to hostAddr=" + hostAddr);
+ continue;
+ }
+
+ // Rewrite the url to have numeric address to use the specific route.
+ // I also set the "Connection" to "Close" as by default "Keep-Alive"
+ // is used which is useless in this case.
+ URL newUrl = new URL(orgUri.getScheme() + "://"
+ + hostAddr.getHostAddress() + orgUri.getPath());
+ log("isMobileOk: newUrl=" + newUrl);
+
+ HttpURLConnection urlConn = null;
+ try {
+ // Open the connection set the request header and get the response
+ urlConn = (HttpURLConnection) newUrl.openConnection(
+ java.net.Proxy.NO_PROXY);
+ urlConn.setInstanceFollowRedirects(false);
+ urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS);
+ urlConn.setReadTimeout(SOCKET_TIMEOUT_MS);
+ urlConn.setUseCaches(false);
+ urlConn.setAllowUserInteraction(false);
+ urlConn.setRequestProperty("Connection", "close");
+ int responseCode = urlConn.getResponseCode();
+ if (responseCode == 204) {
+ result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE;
+ } else {
+ result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED;
+ }
+ log("isMobileOk: connected responseCode=" + responseCode);
+ urlConn.disconnect();
+ urlConn = null;
+ return result;
+ } catch (Exception e) {
+ log("isMobileOk: HttpURLConnection Exception e=" + e);
+ if (urlConn != null) {
+ urlConn.disconnect();
+ urlConn = null;
+ }
+ }
+ }
+ result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION;
+ log("isMobileOk: loops|timed out");
+ return result;
+ } catch (Exception e) {
+ log("isMobileOk: Exception e=" + e);
+ continue;
+ }
+ }
+ log("isMobileOk: timed out");
+ } finally {
+ log("isMobileOk: F stop hipri");
+ mCs.setEnableFailFastMobileData(DctConstants.DISABLED);
+ mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ Phone.FEATURE_ENABLE_HIPRI);
+ log("isMobileOk: X result=" + result);
+ }
+ return result;
+ }
+
+ @Override
+ protected Integer doInBackground(Params... params) {
+ return isMobileOk(params[0]);
+ }
+
+ @Override
+ protected void onPostExecute(Integer result) {
+ log("onPostExecute: result=" + result);
+ if ((mParams != null) && (mParams.mCb != null)) {
+ mParams.mCb.onComplete(result);
+ }
+ }
+
+ private String inetAddressesToString(InetAddress[] addresses) {
+ StringBuffer sb = new StringBuffer();
+ boolean firstTime = true;
+ for(InetAddress addr : addresses) {
+ if (firstTime) {
+ firstTime = false;
+ } else {
+ sb.append(",");
+ }
+ sb.append(addr);
+ }
+ return sb.toString();
+ }
+
+ private void printNetworkInfo() {
+ boolean hasIccCard = mTm.hasIccCard();
+ int simState = mTm.getSimState();
+ log("hasIccCard=" + hasIccCard
+ + " simState=" + simState);
+ NetworkInfo[] ni = mCs.getAllNetworkInfo();
+ if (ni != null) {
+ log("ni.length=" + ni.length);
+ for (NetworkInfo netInfo: ni) {
+ log("netInfo=" + netInfo.toString());
+ }
+ } else {
+ log("no network info ni=null");
+ }
+ }
+
+ /**
+ * Sleep for a few seconds then return.
+ * @param seconds
+ */
+ private static void sleep(int seconds) {
+ try {
+ Thread.sleep(seconds * 1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean hasIPv4Address(LinkProperties lp) {
+ return lp.hasIPv4Address();
+ }
+
+ // Not implemented in LinkProperties, do it here.
+ public boolean hasIPv6Address(LinkProperties lp) {
+ for (LinkAddress address : lp.getLinkAddresses()) {
+ if (address.getAddress() instanceof Inet6Address) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void log(String s) {
+ Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
+ }
+ }
+
+ private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
+
+ private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) {
+ log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url);
+
+ Resources r = Resources.getSystem();
+ NotificationManager notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+
+ if (visible) {
+ CharSequence title;
+ CharSequence details;
+ int icon;
+ switch (networkInfo.getType()) {
+ case ConnectivityManager.TYPE_WIFI:
+ log("setNotificationVisible: TYPE_WIFI");
+ title = r.getString(R.string.wifi_available_sign_in, 0);
+ details = r.getString(R.string.network_available_sign_in_detailed,
+ networkInfo.getExtraInfo());
+ icon = R.drawable.stat_notify_wifi_in_range;
+ break;
+ case ConnectivityManager.TYPE_MOBILE:
+ case ConnectivityManager.TYPE_MOBILE_HIPRI:
+ log("setNotificationVisible: TYPE_MOBILE|HIPRI");
+ title = r.getString(R.string.network_available_sign_in, 0);
+ // TODO: Change this to pull from NetworkInfo once a printable
+ // name has been added to it
+ details = mTelephonyManager.getNetworkOperatorName();
+ icon = R.drawable.stat_notify_rssi_in_range;
+ break;
+ default:
+ log("setNotificationVisible: other type=" + networkInfo.getType());
+ title = r.getString(R.string.network_available_sign_in, 0);
+ details = r.getString(R.string.network_available_sign_in_detailed,
+ networkInfo.getExtraInfo());
+ icon = R.drawable.stat_notify_rssi_in_range;
+ break;
+ }
+
+ Notification notification = new Notification();
+ notification.when = 0;
+ notification.icon = icon;
+ notification.flags = Notification.FLAG_AUTO_CANCEL;
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+ Intent.FLAG_ACTIVITY_NEW_TASK);
+ notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+ notification.tickerText = title;
+ notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
+
+ log("setNotificaitionVisible: notify notificaiton=" + notification);
+ notificationManager.notify(NOTIFICATION_ID, 1, notification);
+ } else {
+ log("setNotificaitionVisible: cancel");
+ notificationManager.cancel(NOTIFICATION_ID, 1);
+ }
+ log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url);
+ }
+
+ private String getProvisioningUrl() {
+ String url = mContext.getResources().getString(R.string.mobile_provisioning_url);
+ log("getProvisioningUrl: resource url=" + url);
+
+ // populate the iccid and imei in the provisioning url.
+ if (!TextUtils.isEmpty(url)) {
+ url = String.format(url,
+ mTelephonyManager.getSimSerialNumber() /* ICCID */,
+ mTelephonyManager.getDeviceId() /* IMEI */,
+ mTelephonyManager.getLine1Number() /* Phone numer */);
+ }
+
+ log("getProvisioningUrl: url=" + url);
+ return url;
+ }
}
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
index faa72a2..e0f415b 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/java/com/android/server/NsdService.java
@@ -417,7 +417,15 @@
int keyId = clientInfo.mClientIds.indexOfValue(id);
if (keyId != -1) {
clientId = clientInfo.mClientIds.keyAt(keyId);
+ } else {
+ // This can happen because of race conditions. For example,
+ // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
+ // and we may get in this situation.
+ Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
+ handled = false;
+ return handled;
}
+
switch (code) {
case NativeResponseCode.SERVICE_FOUND:
/* NNN uniqueId serviceName regType domain */
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9c98848..72be39b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2007,7 +2007,6 @@
ps.addCpuTimeLocked(st.rel_utime-otherUTime,
st.rel_stime-otherSTime);
ps.addSpeedStepTimes(cpuSpeedTimes);
- pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
} else {
BatteryStatsImpl.Uid.Proc ps =
bstats.getProcessStatsLocked(st.name, st.pid);
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 92a1523..9afac2c 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -259,7 +259,9 @@
if (prev != null) {
prev.mLaunchHomeTaskNext = false;
}
- if (mHomeStack.topRunningActivityLocked(null) != null) {
+ ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
+ if (r != null) {
+ mService.setFocusedActivityLocked(r);
return resumeTopActivitiesLocked(mHomeStack, prev, null);
}
return mService.startHomeActivityLocked(mCurrentUser);
diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java
index 59403c5..a15d678 100644
--- a/services/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/java/com/android/server/connectivity/Nat464Xlat.java
@@ -147,17 +147,24 @@
" added, mIsRunning = " + mIsRunning + " -> true");
mIsRunning = true;
- // Get the network configuration of the clat interface, store it
- // in our link properties, and stack it on top of the interface
- // it's running on.
+ // Create the LinkProperties for the clat interface by fetching the
+ // IPv4 address for the interface and adding an IPv4 default route,
+ // then stack the LinkProperties on top of the link it's running on.
+ // Although the clat interface is a point-to-point tunnel, we don't
+ // point the route directly at the interface because some apps don't
+ // understand routes without gateways (see, e.g., http://b/9597256
+ // http://b/9597516). Instead, set the next hop of the route to the
+ // clat IPv4 address itself (for those apps, it doesn't matter what
+ // the IP of the gateway is, only that there is one).
try {
InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
+ LinkAddress clatAddress = config.getLinkAddress();
mLP.clear();
mLP.setInterfaceName(iface);
- RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), null,
- iface);
+ RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0),
+ clatAddress.getAddress(), iface);
mLP.addRoute(ipv4Default);
- mLP.addLinkAddress(config.getLinkAddress());
+ mLP.addLinkAddress(clatAddress);
mTracker.addStackedLink(mLP);
Slog.i(TAG, "Adding stacked link. tracker LP: " +
mTracker.getLinkProperties());
diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java
index 87b4394..4594fa67 100644
--- a/services/java/com/android/server/wifi/WifiController.java
+++ b/services/java/com/android/server/wifi/WifiController.java
@@ -379,6 +379,9 @@
@Override
public void enter() {
+
+ if (DBG) logd("Going to disabled without scan state");
+
mWifiStateMachine.setSupplicantRunning(false);
// Supplicant can't restart right away, so not the time we switched off
mDisabledTimestamp = SystemClock.elapsedRealtime();
@@ -496,6 +499,9 @@
@Override
public void enter() {
+
+ if (DBG) logd("Enabling disabled with scan state");
+
mWifiStateMachine.setSupplicantRunning(true);
mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE);
mWifiStateMachine.setDriverStart(true);
diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/java/com/android/server/wifi/WifiSettingsStore.java
index 3ff8061..f5c6ec3 100644
--- a/services/java/com/android/server/wifi/WifiSettingsStore.java
+++ b/services/java/com/android/server/wifi/WifiSettingsStore.java
@@ -51,7 +51,7 @@
mContext = context;
mAirplaneModeOn = getPersistedAirplaneModeOn();
mPersistWifiState = getPersistedWifiState();
- mScanAlwaysAvailable = getPersistedScanAlwaysAvailable();
+ mScanAlwaysAvailable = false; // getPersistedScanAlwaysAvailable();
}
synchronized boolean isWifiToggleEnabled() {
@@ -124,7 +124,8 @@
}
synchronized void handleWifiScanAlwaysAvailableToggled() {
- mScanAlwaysAvailable = getPersistedScanAlwaysAvailable();
+ // mScanAlwaysAvailable = getPersistedScanAlwaysAvailable();
+ mScanAlwaysAvailable = false;
}
void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index e416676..f332350 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -41,6 +41,7 @@
libutils \
libui \
libinput \
+ libinputservice \
libskia \
libgui \
libusbhost \
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 9d556c0..4d8342c 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -93,6 +93,7 @@
public static final int EVENT_ICC_CHANGED = BASE + 33;
public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35;
+ public static final int CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA = BASE + 36;
/***** Constants *****/
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 3b49819..452c60a 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -83,20 +83,19 @@
LOCAL_C_INCLUDES += external/libpng
LOCAL_C_INCLUDES += external/zlib
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_SHARED_LIBRARIES := \
+ libandroidfw \
+ libutils \
+ libcutils \
libpng \
+ liblog \
libz
LOCAL_STATIC_LIBRARIES := \
libstlport_static \
- libandroidfw \
- libutils \
- libcutils \
- libexpat_static \
- liblog
+ libexpat_static
include $(BUILD_EXECUTABLE)
endif
diff --git a/tools/validatekeymaps/Android.mk b/tools/validatekeymaps/Android.mk
index 90fbc08..9af721d 100644
--- a/tools/validatekeymaps/Android.mk
+++ b/tools/validatekeymaps/Android.mk
@@ -15,10 +15,8 @@
LOCAL_CFLAGS := -Wall -Werror
-#LOCAL_C_INCLUDES +=
-
LOCAL_STATIC_LIBRARIES := \
- libandroidfw \
+ libinput \
libutils \
libcutils \
liblog
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 91e4fda..5b45c55 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include <androidfw/KeyCharacterMap.h>
-#include <androidfw/KeyLayoutMap.h>
-#include <androidfw/VirtualKeyMap.h>
+#include <input/KeyCharacterMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/VirtualKeyMap.h>
#include <utils/PropertyMap.h>
#include <utils/String8.h>