diff options
193 files changed, 6214 insertions, 1204 deletions
diff --git a/api/current.xml b/api/current.xml index 22a105a..e3fcfcf 100644 --- a/api/current.xml +++ b/api/current.xml @@ -1773,7 +1773,7 @@ type="int" transient="false" volatile="false" - value="16843511" + value="16843513" static="true" final="true" deprecated="not deprecated" @@ -1784,7 +1784,7 @@ type="int" transient="false" volatile="false" - value="16843480" + value="16843482" static="true" final="true" deprecated="not deprecated" @@ -1795,7 +1795,7 @@ type="int" transient="false" volatile="false" - value="16843520" + value="16843522" static="true" final="true" deprecated="not deprecated" @@ -1806,7 +1806,7 @@ type="int" transient="false" volatile="false" - value="16843519" + value="16843521" static="true" final="true" deprecated="not deprecated" @@ -1817,7 +1817,7 @@ type="int" transient="false" volatile="false" - value="16843521" + value="16843523" static="true" final="true" deprecated="not deprecated" @@ -1828,7 +1828,7 @@ type="int" transient="false" volatile="false" - value="16843490" + value="16843492" static="true" final="true" deprecated="not deprecated" @@ -1839,7 +1839,7 @@ type="int" transient="false" volatile="false" - value="16843489" + value="16843491" static="true" final="true" deprecated="not deprecated" @@ -1850,7 +1850,7 @@ type="int" transient="false" volatile="false" - value="16843527" + value="16843529" static="true" final="true" deprecated="not deprecated" @@ -1861,7 +1861,7 @@ type="int" transient="false" volatile="false" - value="16843493" + value="16843495" static="true" final="true" deprecated="not deprecated" @@ -1872,7 +1872,7 @@ type="int" transient="false" volatile="false" - value="16843523" + value="16843525" static="true" final="true" deprecated="not deprecated" @@ -1883,7 +1883,7 @@ type="int" transient="false" volatile="false" - value="16843494" + value="16843496" static="true" final="true" deprecated="not deprecated" @@ -1894,7 +1894,7 @@ type="int" transient="false" volatile="false" - value="16843547" + value="16843549" static="true" final="true" deprecated="not deprecated" @@ -1905,7 +1905,7 @@ type="int" transient="false" volatile="false" - value="16843546" + value="16843548" static="true" final="true" deprecated="not deprecated" @@ -1916,7 +1916,7 @@ type="int" transient="false" volatile="false" - value="16843548" + value="16843550" static="true" final="true" deprecated="not deprecated" @@ -1927,7 +1927,7 @@ type="int" transient="false" volatile="false" - value="16843522" + value="16843524" static="true" final="true" deprecated="not deprecated" @@ -1938,7 +1938,7 @@ type="int" transient="false" volatile="false" - value="16843528" + value="16843530" static="true" final="true" deprecated="not deprecated" @@ -1949,7 +1949,7 @@ type="int" transient="false" volatile="false" - value="16843529" + value="16843531" static="true" final="true" deprecated="not deprecated" @@ -2004,7 +2004,7 @@ type="int" transient="false" volatile="false" - value="16843466" + value="16843468" static="true" final="true" deprecated="not deprecated" @@ -2037,7 +2037,7 @@ type="int" transient="false" volatile="false" - value="16843545" + value="16843547" static="true" final="true" deprecated="not deprecated" @@ -2059,7 +2059,7 @@ type="int" transient="false" volatile="false" - value="16843541" + value="16843543" static="true" final="true" deprecated="not deprecated" @@ -2070,7 +2070,7 @@ type="int" transient="false" volatile="false" - value="16843478" + value="16843480" static="true" final="true" deprecated="not deprecated" @@ -2169,7 +2169,7 @@ type="int" transient="false" volatile="false" - value="16843487" + value="16843489" static="true" final="true" deprecated="not deprecated" @@ -2180,7 +2180,7 @@ type="int" transient="false" volatile="false" - value="16843518" + value="16843520" static="true" final="true" deprecated="not deprecated" @@ -2279,7 +2279,7 @@ type="int" transient="false" volatile="false" - value="16843472" + value="16843474" static="true" final="true" deprecated="not deprecated" @@ -2521,7 +2521,7 @@ type="int" transient="false" volatile="false" - value="16843536" + value="16843538" static="true" final="true" deprecated="not deprecated" @@ -2532,7 +2532,7 @@ type="int" transient="false" volatile="false" - value="16843535" + value="16843537" static="true" final="true" deprecated="not deprecated" @@ -2565,7 +2565,7 @@ type="int" transient="false" volatile="false" - value="16843544" + value="16843546" static="true" final="true" deprecated="not deprecated" @@ -2983,7 +2983,7 @@ type="int" transient="false" volatile="false" - value="16843475" + value="16843477" static="true" final="true" deprecated="not deprecated" @@ -3137,7 +3137,7 @@ type="int" transient="false" volatile="false" - value="16843484" + value="16843486" static="true" final="true" deprecated="not deprecated" @@ -3346,7 +3346,7 @@ type="int" transient="false" volatile="false" - value="16843540" + value="16843542" static="true" final="true" deprecated="not deprecated" @@ -3423,7 +3423,7 @@ type="int" transient="false" volatile="false" - value="16843482" + value="16843484" static="true" final="true" deprecated="not deprecated" @@ -3467,7 +3467,7 @@ type="int" transient="false" volatile="false" - value="16843543" + value="16843545" static="true" final="true" deprecated="not deprecated" @@ -3643,7 +3643,7 @@ type="int" transient="false" volatile="false" - value="16843488" + value="16843490" static="true" final="true" deprecated="not deprecated" @@ -4215,7 +4215,7 @@ type="int" transient="false" volatile="false" - value="16843501" + value="16843503" static="true" final="true" deprecated="not deprecated" @@ -4226,7 +4226,7 @@ type="int" transient="false" volatile="false" - value="16843505" + value="16843507" static="true" final="true" deprecated="not deprecated" @@ -4237,7 +4237,7 @@ type="int" transient="false" volatile="false" - value="16843506" + value="16843508" static="true" final="true" deprecated="not deprecated" @@ -4248,7 +4248,7 @@ type="int" transient="false" volatile="false" - value="16843507" + value="16843509" static="true" final="true" deprecated="not deprecated" @@ -4259,7 +4259,7 @@ type="int" transient="false" volatile="false" - value="16843508" + value="16843510" static="true" final="true" deprecated="not deprecated" @@ -4270,7 +4270,7 @@ type="int" transient="false" volatile="false" - value="16843503" + value="16843505" static="true" final="true" deprecated="not deprecated" @@ -4281,7 +4281,7 @@ type="int" transient="false" volatile="false" - value="16843504" + value="16843506" static="true" final="true" deprecated="not deprecated" @@ -4292,7 +4292,7 @@ type="int" transient="false" volatile="false" - value="16843509" + value="16843511" static="true" final="true" deprecated="not deprecated" @@ -4303,7 +4303,7 @@ type="int" transient="false" volatile="false" - value="16843510" + value="16843512" static="true" final="true" deprecated="not deprecated" @@ -4325,7 +4325,7 @@ type="int" transient="false" volatile="false" - value="16843470" + value="16843472" static="true" final="true" deprecated="not deprecated" @@ -4358,7 +4358,7 @@ type="int" transient="false" volatile="false" - value="16843473" + value="16843475" static="true" final="true" deprecated="not deprecated" @@ -4655,7 +4655,7 @@ type="int" transient="false" volatile="false" - value="16843485" + value="16843487" static="true" final="true" deprecated="not deprecated" @@ -4787,7 +4787,7 @@ type="int" transient="false" volatile="false" - value="16843526" + value="16843528" static="true" final="true" deprecated="not deprecated" @@ -4908,7 +4908,7 @@ type="int" transient="false" volatile="false" - value="16843514" + value="16843516" static="true" final="true" deprecated="not deprecated" @@ -4919,7 +4919,7 @@ type="int" transient="false" volatile="false" - value="16843512" + value="16843514" static="true" final="true" deprecated="not deprecated" @@ -4930,7 +4930,7 @@ type="int" transient="false" volatile="false" - value="16843513" + value="16843515" static="true" final="true" deprecated="not deprecated" @@ -5953,7 +5953,7 @@ type="int" transient="false" volatile="false" - value="16843516" + value="16843518" static="true" final="true" deprecated="not deprecated" @@ -5997,7 +5997,7 @@ type="int" transient="false" volatile="false" - value="16843537" + value="16843539" static="true" final="true" deprecated="not deprecated" @@ -6008,7 +6008,7 @@ type="int" transient="false" volatile="false" - value="16843531" + value="16843533" static="true" final="true" deprecated="not deprecated" @@ -6096,7 +6096,7 @@ type="int" transient="false" volatile="false" - value="16843539" + value="16843541" static="true" final="true" deprecated="not deprecated" @@ -6261,7 +6261,7 @@ type="int" transient="false" volatile="false" - value="16843486" + value="16843488" static="true" final="true" deprecated="not deprecated" @@ -6404,7 +6404,7 @@ type="int" transient="false" volatile="false" - value="16843481" + value="16843483" static="true" final="true" deprecated="not deprecated" @@ -6580,7 +6580,7 @@ type="int" transient="false" volatile="false" - value="16843500" + value="16843502" static="true" final="true" deprecated="not deprecated" @@ -6910,7 +6910,7 @@ type="int" transient="false" volatile="false" - value="16843532" + value="16843534" static="true" final="true" deprecated="not deprecated" @@ -7009,7 +7009,7 @@ type="int" transient="false" volatile="false" - value="16843492" + value="16843494" static="true" final="true" deprecated="not deprecated" @@ -7174,7 +7174,7 @@ type="int" transient="false" volatile="false" - value="16843499" + value="16843501" static="true" final="true" deprecated="not deprecated" @@ -7621,6 +7621,17 @@ visibility="public" > </field> +<field name="screenDensity" + type="int" + transient="false" + volatile="false" + value="16843467" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="screenOrientation" type="int" transient="false" @@ -7632,6 +7643,17 @@ visibility="public" > </field> +<field name="screenSize" + type="int" + transient="false" + volatile="false" + value="16843466" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="scrollHorizontally" type="int" transient="false" @@ -7955,7 +7977,7 @@ type="int" transient="false" volatile="false" - value="16843467" + value="16843469" static="true" final="true" deprecated="not deprecated" @@ -8076,7 +8098,7 @@ type="int" transient="false" volatile="false" - value="16843491" + value="16843493" static="true" final="true" deprecated="not deprecated" @@ -8164,7 +8186,7 @@ type="int" transient="false" volatile="false" - value="16843468" + value="16843470" static="true" final="true" deprecated="not deprecated" @@ -8219,7 +8241,7 @@ type="int" transient="false" volatile="false" - value="16843517" + value="16843519" static="true" final="true" deprecated="not deprecated" @@ -8241,7 +8263,7 @@ type="int" transient="false" volatile="false" - value="16843515" + value="16843517" static="true" final="true" deprecated="not deprecated" @@ -8340,7 +8362,7 @@ type="int" transient="false" volatile="false" - value="16843530" + value="16843532" static="true" final="true" deprecated="not deprecated" @@ -8560,7 +8582,7 @@ type="int" transient="false" volatile="false" - value="16843483" + value="16843485" static="true" final="true" deprecated="not deprecated" @@ -8571,7 +8593,7 @@ type="int" transient="false" volatile="false" - value="16843525" + value="16843527" static="true" final="true" deprecated="not deprecated" @@ -8956,7 +8978,7 @@ type="int" transient="false" volatile="false" - value="16843533" + value="16843535" static="true" final="true" deprecated="not deprecated" @@ -9033,7 +9055,7 @@ type="int" transient="false" volatile="false" - value="16843534" + value="16843536" static="true" final="true" deprecated="not deprecated" @@ -9077,7 +9099,7 @@ type="int" transient="false" volatile="false" - value="16843538" + value="16843540" static="true" final="true" deprecated="not deprecated" @@ -9275,7 +9297,7 @@ type="int" transient="false" volatile="false" - value="16843542" + value="16843544" static="true" final="true" deprecated="not deprecated" @@ -9506,7 +9528,7 @@ type="int" transient="false" volatile="false" - value="16843524" + value="16843526" static="true" final="true" deprecated="not deprecated" @@ -9517,7 +9539,7 @@ type="int" transient="false" volatile="false" - value="16843471" + value="16843473" static="true" final="true" deprecated="not deprecated" @@ -9550,7 +9572,7 @@ type="int" transient="false" volatile="false" - value="16843474" + value="16843476" static="true" final="true" deprecated="not deprecated" @@ -9737,7 +9759,7 @@ type="int" transient="false" volatile="false" - value="16843469" + value="16843471" static="true" final="true" deprecated="not deprecated" @@ -9781,7 +9803,7 @@ type="int" transient="false" volatile="false" - value="16843496" + value="16843498" static="true" final="true" deprecated="not deprecated" @@ -9792,7 +9814,7 @@ type="int" transient="false" volatile="false" - value="16843497" + value="16843499" static="true" final="true" deprecated="not deprecated" @@ -9803,7 +9825,7 @@ type="int" transient="false" volatile="false" - value="16843498" + value="16843500" static="true" final="true" deprecated="not deprecated" @@ -10122,7 +10144,7 @@ type="int" transient="false" volatile="false" - value="16843479" + value="16843481" static="true" final="true" deprecated="not deprecated" @@ -10133,7 +10155,7 @@ type="int" transient="false" volatile="false" - value="16843502" + value="16843504" static="true" final="true" deprecated="not deprecated" @@ -10144,7 +10166,7 @@ type="int" transient="false" volatile="false" - value="16843495" + value="16843497" static="true" final="true" deprecated="not deprecated" @@ -10364,7 +10386,7 @@ type="int" transient="false" volatile="false" - value="16843477" + value="16843479" static="true" final="true" deprecated="not deprecated" @@ -10375,7 +10397,7 @@ type="int" transient="false" volatile="false" - value="16843476" + value="16843478" static="true" final="true" deprecated="not deprecated" @@ -22935,17 +22957,6 @@ visibility="public" > </field> -<field name="IMPORTANCE_HEAVY_WEIGHT" - type="int" - transient="false" - volatile="false" - value="170" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="IMPORTANCE_PERCEPTIBLE" type="int" transient="false" @@ -30357,11 +30368,11 @@ <parameter name="holder" type="android.view.SurfaceHolder"> </parameter> </method> -<field name="KEY_NATIVE_SAVED_STATE" +<field name="META_DATA_FUNC_NAME" type="java.lang.String" transient="false" volatile="false" - value=""android:native_state"" + value=""android.app.func_name"" static="true" final="true" deprecated="not deprecated" @@ -36131,7 +36142,7 @@ <implements name="android.bluetooth.BluetoothProfile"> </implements> <method name="getConnectedDevices" - return="java.util.Set<android.bluetooth.BluetoothDevice>" + return="java.util.List<android.bluetooth.BluetoothDevice>" abstract="false" native="false" synchronized="false" @@ -36155,7 +36166,7 @@ </parameter> </method> <method name="getDevicesMatchingConnectionStates" - return="java.util.Set<android.bluetooth.BluetoothDevice>" + return="java.util.List<android.bluetooth.BluetoothDevice>" abstract="false" native="false" synchronized="false" @@ -37969,7 +37980,7 @@ <implements name="android.bluetooth.BluetoothProfile"> </implements> <method name="getConnectedDevices" - return="java.util.Set<android.bluetooth.BluetoothDevice>" + return="java.util.List<android.bluetooth.BluetoothDevice>" abstract="false" native="false" synchronized="false" @@ -37993,7 +38004,7 @@ </parameter> </method> <method name="getDevicesMatchingConnectionStates" - return="java.util.Set<android.bluetooth.BluetoothDevice>" + return="java.util.List<android.bluetooth.BluetoothDevice>" abstract="false" native="false" synchronized="false" @@ -38097,7 +38108,7 @@ visibility="public" > <method name="getConnectedDevices" - return="java.util.Set<android.bluetooth.BluetoothDevice>" + return="java.util.List<android.bluetooth.BluetoothDevice>" abstract="true" native="false" synchronized="false" @@ -38121,7 +38132,7 @@ </parameter> </method> <method name="getDevicesMatchingConnectionStates" - return="java.util.Set<android.bluetooth.BluetoothDevice>" + return="java.util.List<android.bluetooth.BluetoothDevice>" abstract="true" native="false" synchronized="false" @@ -111981,6 +111992,18 @@ deprecated="not deprecated" visibility="public" > +<parameter name="data" type="byte[]"> +</parameter> +<exception name="FormatException" type="android.nfc.FormatException"> +</exception> +</constructor> +<constructor name="NdefMessage" + type="android.nfc.NdefMessage" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> <parameter name="records" type="android.nfc.NdefRecord[]"> </parameter> </constructor> @@ -112006,6 +112029,17 @@ visibility="public" > </method> +<method name="toByteArray" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="writeToParcel" return="void" abstract="false" @@ -112125,6 +112159,17 @@ visibility="public" > </method> +<method name="toByteArray" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="writeToParcel" return="void" abstract="false" @@ -112315,6 +112360,29 @@ > <implements name="android.os.Parcelable"> </implements> +<method name="createMockNdefTag" + return="android.nfc.NdefTag" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="id" type="byte[]"> +</parameter> +<parameter name="rawTargets" type="java.lang.String[]"> +</parameter> +<parameter name="pollBytes" type="byte[]"> +</parameter> +<parameter name="activationBytes" type="byte[]"> +</parameter> +<parameter name="ndefTargets" type="java.lang.String[]"> +</parameter> +<parameter name="messages" type="android.nfc.NdefMessage[][]"> +</parameter> +</method> <method name="getNdefMessages" return="android.nfc.NdefMessage[]" abstract="false" @@ -112784,6 +112852,25 @@ > <implements name="android.os.Parcelable"> </implements> +<method name="createMockTag" + return="android.nfc.Tag" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="id" type="byte[]"> +</parameter> +<parameter name="rawTargets" type="java.lang.String[]"> +</parameter> +<parameter name="pollBytes" type="byte[]"> +</parameter> +<parameter name="activationBytes" type="byte[]"> +</parameter> +</method> <method name="describeContents" return="int" abstract="false" @@ -112795,6 +112882,17 @@ visibility="public" > </method> +<method name="getActivationBytes" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getId" return="byte[]" abstract="false" @@ -112806,6 +112904,17 @@ visibility="public" > </method> +<method name="getPollBytes" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getRawTargets" return="java.lang.String[]" abstract="false" @@ -112864,17 +112973,6 @@ visibility="public" > </field> -<field name="TARGET_ISO_14443_3B_PRIME" - type="java.lang.String" - transient="false" - volatile="false" - value=""iso14443_3b"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="TARGET_ISO_14443_4" type="java.lang.String" transient="false" @@ -112919,17 +113017,6 @@ visibility="public" > </field> -<field name="TARGET_TOPAZ" - type="java.lang.String" - transient="false" - volatile="false" - value=""topaz"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> </class> </package> <package name="android.opengl" @@ -186728,6 +186815,17 @@ visibility="public" > </field> +<field name="DENSITY_XHIGH" + type="int" + transient="false" + volatile="false" + value="320" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="density" type="float" transient="false" diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 35f0249..d309ef9 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -84,7 +84,7 @@ static void dumpstate() { LOGI("wrote screenshot: %s\n", screenshot_path); } - run_command("SYSTEM LOG", 20, "logcat", "-v", "time", "-d", "*:v", NULL); + run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL); /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { @@ -104,8 +104,8 @@ static void dumpstate() { } // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); - run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "time", "-d", "*:v", NULL); - run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "time", "-d", "*:v", NULL); + run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL); + run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL); run_command("NETWORK INTERFACES", 10, "netcfg", NULL); dump_file("NETWORK ROUTES", "/proc/net/route"); @@ -174,6 +174,14 @@ static void dumpstate() { to increase its timeout. we really need to do the timeouts in dumpsys itself... */ run_command("DUMPSYS", 60, "dumpsys", NULL); + + printf("========================================================\n"); + printf("== Application Services\n"); + printf("========================================================\n"); + + /* Instead of a 60s timeout, we should give each service a 5 second timeout */ + run_command("APP SERVICES", 60, "dumpsys", "activity", "service", NULL); + } static void usage() { diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index a5b3e0e..2f03c7a 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -946,14 +946,12 @@ int linklib(const char* dataDir, const char* asecLibDir) const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX); if (libdirLen >= PKG_PATH_MAX) { LOGE("library dir len too large"); - rc = -1; - goto out; + return -1; } if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) { LOGE("library dir not written successfully: %s\n", strerror(errno)); - rc = -1; - goto out; + return -1; } if (stat(dataDir, &s) < 0) return -1; diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index d60a598..e269c31 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1215,4 +1215,16 @@ public class ValueAnimator extends Animator { void onAnimationUpdate(ValueAnimator animation); } -}
\ No newline at end of file + + /** + * Return the number of animations currently running. + * + * Used by StrictMode internally to annotate violations. Only + * called on the main thread. + * + * @hide + */ + public static int getCurrentAnimationsCount() { + return sAnimations.size(); + } +} diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 5ae8a1f..fe1e7d7 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -797,10 +797,12 @@ public class ActivityManager { public static final int IMPORTANCE_PERCEPTIBLE = 130; /** - * Constant for {@link #importance}: this process is running a - * heavy-weight application and thus should not be killed. + * Constant for {@link #importance}: this process is running an + * application that can not save its state, and thus can't be killed + * while in the background. + * @hide */ - public static final int IMPORTANCE_HEAVY_WEIGHT = 170; + public static final int IMPORTANCE_CANT_SAVE_STATE = 170; /** * Constant for {@link #importance}: this process is contains services diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java index c98128c..de36f27 100644 --- a/core/java/android/app/NativeActivity.java +++ b/core/java/android/app/NativeActivity.java @@ -5,7 +5,6 @@ import com.android.internal.view.IInputMethodSession; import android.content.Context; import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Configuration; @@ -48,9 +47,22 @@ import java.lang.ref.WeakReference; */ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, InputQueue.Callback, OnGlobalLayoutListener { + /** + * Optional meta-that can be in the manifest for this component, specifying + * the name of the native shared library to load. If not specified, + * "main" is used. + */ public static final String META_DATA_LIB_NAME = "android.app.lib_name"; - public static final String KEY_NATIVE_SAVED_STATE = "android:native_state"; + /** + * Optional meta-that can be in the manifest for this component, specifying + * the name of the main entry point for this native activity in the + * {@link #META_DATA_LIB_NAME} native code. If not specified, + * "ANativeActivity_onCreate" is used. + */ + public static final String META_DATA_FUNC_NAME = "android.app.func_name"; + + private static final String KEY_NATIVE_SAVED_STATE = "android:native_state"; private NativeContentView mNativeContentView; private InputMethodManager mIMM; @@ -71,7 +83,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, private boolean mDestroyed; - private native int loadNativeCode(String path, MessageQueue queue, + private native int loadNativeCode(String path, String funcname, MessageQueue queue, String internalDataPath, String externalDataPath, int sdkVersion, AssetManager assetMgr, byte[] savedState); private native void unloadNativeCode(int handle); @@ -131,6 +143,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, @Override protected void onCreate(Bundle savedInstanceState) { String libname = "main"; + String funcname = "ANativeActivity_onCreate"; ActivityInfo ai; mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); @@ -155,6 +168,8 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, if (ai.metaData != null) { String ln = ai.metaData.getString(META_DATA_LIB_NAME); if (ln != null) libname = ln; + ln = ai.metaData.getString(META_DATA_FUNC_NAME); + if (ln != null) funcname = ln; } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("Error getting activity info", e); @@ -175,7 +190,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, byte[] nativeSavedState = savedInstanceState != null ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null; - mNativeHandle = loadNativeCode(path, Looper.myQueue(), + mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(), getFilesDir().toString(), Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(), Build.VERSION.SDK_INT, getAssets(), nativeSavedState); diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 920ef89..61b4303 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -26,11 +26,8 @@ import android.os.ServiceManager; import android.server.BluetoothA2dpService; import android.util.Log; -import java.util.Collections; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; /** @@ -167,35 +164,35 @@ public final class BluetoothA2dp implements BluetoothProfile { /** * {@inheritDoc} */ - public Set<BluetoothDevice> getConnectedDevices() { + public List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices()"); if (mService != null && isEnabled()) { try { - return toDeviceSet(mService.getConnectedDevices()); + return mService.getConnectedDevices(); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } } if (mService == null) Log.w(TAG, "Proxy not attached to service"); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } /** * {@inheritDoc} */ - public Set<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) log("getDevicesMatchingStates()"); if (mService != null && isEnabled()) { try { - return toDeviceSet(mService.getDevicesMatchingConnectionStates(states)); + return mService.getDevicesMatchingConnectionStates(states); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } } if (mService == null) Log.w(TAG, "Proxy not attached to service"); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } /** @@ -396,11 +393,6 @@ public final class BluetoothA2dp implements BluetoothProfile { return false; } - private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) { - return Collections.unmodifiableSet( - new HashSet<BluetoothDevice>(Arrays.asList(devices))); - } - private static void log(String msg) { Log.d(TAG, msg); } diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java index b33ab21..fd8f930 100644 --- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java +++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java @@ -321,7 +321,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine mA2dpService.getDevicesMatchingConnectionStates( new int[] {BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING, - BluetoothProfile.STATE_DISCONNECTING}).length == 0) { + BluetoothProfile.STATE_DISCONNECTING}).size() == 0) { mA2dpService.connect(mDevice); } if (mService.getInputDevicePriority(mDevice) == diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 0496b1f..c64fdbe 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -18,20 +18,16 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.os.RemoteException; import android.os.IBinder; +import android.os.RemoteException; import android.util.Log; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; /** * Public API for controlling the Bluetooth Headset Service. This includes both @@ -218,35 +214,35 @@ public final class BluetoothHeadset implements BluetoothProfile { /** * {@inheritDoc} */ - public Set<BluetoothDevice> getConnectedDevices() { + public List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices()"); if (mService != null && isEnabled()) { try { - return toDeviceSet(mService.getConnectedDevices()); + return mService.getConnectedDevices(); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } } if (mService == null) Log.w(TAG, "Proxy not attached to service"); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } /** * {@inheritDoc} */ - public Set<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) log("getDevicesMatchingStates()"); if (mService != null && isEnabled()) { try { - return toDeviceSet(mService.getDevicesMatchingConnectionStates(states)); + return mService.getDevicesMatchingConnectionStates(states); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } } if (mService == null) Log.w(TAG, "Proxy not attached to service"); - return toDeviceSet(new BluetoothDevice[0]); + return new ArrayList<BluetoothDevice>(); } /** @@ -569,11 +565,6 @@ public final class BluetoothHeadset implements BluetoothProfile { return false; } - private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) { - return Collections.unmodifiableSet( - new HashSet<BluetoothDevice>(Arrays.asList(devices))); - } - private static void log(String msg) { Log.d(TAG, msg); } diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java index 1793838..bc8a836 100644 --- a/core/java/android/bluetooth/BluetoothInputDevice.java +++ b/core/java/android/bluetooth/BluetoothInputDevice.java @@ -24,10 +24,8 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; /** * Public API for controlling the Bluetooth HID (Input Device) Profile @@ -167,18 +165,16 @@ public final class BluetoothInputDevice { /** Check if any Input Device is connected. * - * @return a unmodifiable set of connected Input Devices, or null on error. + * @return List of devices, empty List on error. * @hide */ - public Set<BluetoothDevice> getConnectedInputDevices() { + public List<BluetoothDevice> getConnectedInputDevices() { if (DBG) log("getConnectedInputDevices()"); try { - return Collections.unmodifiableSet( - new HashSet<BluetoothDevice>( - Arrays.asList(mService.getConnectedInputDevices()))); + return mService.getConnectedInputDevices(); } catch (RemoteException e) { Log.e(TAG, "", e); - return null; + return new ArrayList<BluetoothDevice>(); } } diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index 9d0b3f2..f55e96a 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -19,15 +19,13 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; -import android.os.ServiceManager; -import android.os.RemoteException; import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; /** * @hide @@ -154,18 +152,16 @@ public final class BluetoothPan { * * Does not include devices that are currently connecting or disconnecting * - * @return a unmodifiable set of connected PAN Devices, or null on error. + * @return List of PAN devices or empty on Error * @hide */ - public Set<BluetoothDevice> getConnectedDevices() { + public List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices"); try { - return Collections.unmodifiableSet( - new HashSet<BluetoothDevice>( - Arrays.asList(mService.getConnectedPanDevices()))); + return mService.getConnectedPanDevices(); } catch (RemoteException e) { Log.e(TAG, "", e); - return null; + return new ArrayList<BluetoothDevice>(); } } diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 3b4c84c..3949b26 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -17,10 +17,7 @@ package android.bluetooth; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; - -import java.util.Set; +import java.util.List; /** * Public APIs for the Bluetooth Profiles. @@ -150,9 +147,9 @@ public interface BluetoothProfile { * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * - * @return An unmodifiable set of devices. The set will be empty on error. + * @return List of devices. The list will be empty on error. */ - public Set<BluetoothDevice> getConnectedDevices(); + public List<BluetoothDevice> getConnectedDevices(); /** * Get a set of devices that match any of the given connection @@ -166,9 +163,9 @@ public interface BluetoothProfile { * @param states Array of states. States can be one of * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING}, * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}, - * @return An unmodifiable set of devices. The set will be empty on error. + * @return List of devices. The list will be empty on error. */ - public Set<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states); + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states); /** * Get the current connection state of the profile diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index cc23146..f0252b7 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -81,7 +81,7 @@ interface IBluetooth // HID profile APIs boolean connectInputDevice(in BluetoothDevice device); boolean disconnectInputDevice(in BluetoothDevice device); - BluetoothDevice[] getConnectedInputDevices(); // change to Set<> once AIDL supports + List<BluetoothDevice> getConnectedInputDevices(); int getInputDeviceState(in BluetoothDevice device); boolean setInputDevicePriority(in BluetoothDevice device, int priority); int getInputDevicePriority(in BluetoothDevice device); @@ -89,7 +89,7 @@ interface IBluetooth boolean isTetheringOn(); void setBluetoothTethering(boolean value); int getPanDeviceState(in BluetoothDevice device); - BluetoothDevice[] getConnectedPanDevices(); + List<BluetoothDevice> getConnectedPanDevices(); boolean connectPanDevice(in BluetoothDevice device); boolean disconnectPanDevice(in BluetoothDevice device); } diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl index c5044c2..b4fc366 100644 --- a/core/java/android/bluetooth/IBluetoothA2dp.aidl +++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl @@ -27,9 +27,8 @@ interface IBluetoothA2dp { // Public API boolean connect(in BluetoothDevice device); boolean disconnect(in BluetoothDevice device); - // change to Set<> once AIDL supports - BluetoothDevice[] getConnectedDevices(); - BluetoothDevice[] getDevicesMatchingConnectionStates(in int[] states); + List<BluetoothDevice> getConnectedDevices(); + List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); int getConnectionState(in BluetoothDevice device); boolean setPriority(in BluetoothDevice device, int priority); int getPriority(in BluetoothDevice device); diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl index 8bcf103..3e4c7b4 100644 --- a/core/java/android/bluetooth/IBluetoothHeadset.aidl +++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl @@ -27,9 +27,8 @@ interface IBluetoothHeadset { // Public API boolean connect(in BluetoothDevice device); boolean disconnect(in BluetoothDevice device); - // Change to Set<> when AIDL supports - BluetoothDevice[] getConnectedDevices(); - BluetoothDevice[] getDevicesMatchingConnectionStates(in int[] states); + List<BluetoothDevice> getConnectedDevices(); + List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); int getConnectionState(in BluetoothDevice device); boolean setPriority(in BluetoothDevice device, int priority); int getPriority(in BluetoothDevice device); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 89c9d25..54dbe37 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1076,6 +1076,16 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("uses-gl-texture")) { + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + continue; + + } else if (tagName.equals("compatible-screens")) { + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + continue; + } else if (tagName.equals("eat-comment")) { // Just skip this tag XmlUtils.skipCurrentTag(parser); diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 6ff5a40..275e2eb 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -779,9 +779,9 @@ public class Camera { * Set the clockwise rotation of preview display in degrees. This affects * the preview frames and the picture displayed after snapshot. This method * is useful for portrait mode applications. Note that preview display of - * front-facing cameras is flipped horizontally, that is, the image is - * reflected along the central vertical axis of the camera sensor. So the - * users can see themselves as looking into a mirror. + * front-facing cameras is flipped horizontally before the rotation, that + * is, the image is reflected along the central vertical axis of the camera + * sensor. So the users can see themselves as looking into a mirror. * * This does not affect the order of byte array passed in {@link * PreviewCallback#onPreviewFrame}, JPEG pictures, or recorded videos. This diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java index 503c470..218df75 100644 --- a/core/java/android/net/http/CertificateChainValidator.java +++ b/core/java/android/net/http/CertificateChainValidator.java @@ -129,57 +129,6 @@ class CertificateChainValidator { } } - // Clean up the certificates chain and build a new one. - // Theoretically, we shouldn't have to do this, but various web servers - // in practice are mis-configured to have out-of-order certificates or - // expired self-issued root certificate. - int chainLength = serverCertificates.length; - if (serverCertificates.length > 1) { - // 1. we clean the received certificates chain. - // We start from the end-entity certificate, tracing down by matching - // the "issuer" field and "subject" field until we can't continue. - // This helps when the certificates are out of order or - // some certificates are not related to the site. - int currIndex; - for (currIndex = 0; currIndex < serverCertificates.length; ++currIndex) { - boolean foundNext = false; - for (int nextIndex = currIndex + 1; - nextIndex < serverCertificates.length; - ++nextIndex) { - if (serverCertificates[currIndex].getIssuerDN().equals( - serverCertificates[nextIndex].getSubjectDN())) { - foundNext = true; - // Exchange certificates so that 0 through currIndex + 1 are in proper order - if (nextIndex != currIndex + 1) { - X509Certificate tempCertificate = serverCertificates[nextIndex]; - serverCertificates[nextIndex] = serverCertificates[currIndex + 1]; - serverCertificates[currIndex + 1] = tempCertificate; - } - break; - } - } - if (!foundNext) break; - } - - // 2. we exam if the last traced certificate is self issued and it is expired. - // If so, we drop it and pass the rest to checkServerTrusted(), hoping we might - // have a similar but unexpired trusted root. - chainLength = currIndex + 1; - X509Certificate lastCertificate = serverCertificates[chainLength - 1]; - Date now = new Date(); - if (lastCertificate.getSubjectDN().equals(lastCertificate.getIssuerDN()) - && now.after(lastCertificate.getNotAfter())) { - --chainLength; - } - } - - // 3. Now we copy the newly built chain into an appropriately sized array. - X509Certificate[] newServerCertificates = null; - newServerCertificates = new X509Certificate[chainLength]; - for (int i = 0; i < chainLength; ++i) { - newServerCertificates[i] = serverCertificates[i]; - } - // first, we validate the new chain using the standard validation // solution; if we do not find any errors, we are done; if we // fail the standard validation, we re-validate again below, @@ -188,7 +137,7 @@ class CertificateChainValidator { // try { SSLParametersImpl.getDefaultTrustManager().checkServerTrusted( - newServerCertificates, "RSA"); + serverCertificates, "RSA"); // no errors!!! return null; diff --git a/core/java/android/nfc/NdefMessage.java b/core/java/android/nfc/NdefMessage.java index 378304e..feca94e 100644 --- a/core/java/android/nfc/NdefMessage.java +++ b/core/java/android/nfc/NdefMessage.java @@ -34,15 +34,12 @@ public class NdefMessage implements Parcelable { private final NdefRecord[] mRecords; - //TODO(npelly) FormatException /** * Create an NDEF message from raw bytes. * <p> * Validation is performed to make sure the Record format headers are valid, * and the ID + TYPE + PAYLOAD fields are of the correct size. * @throws FormatException - * - * @hide */ public NdefMessage(byte[] data) throws FormatException { mRecords = null; // stop compiler complaints about final field @@ -69,10 +66,7 @@ public class NdefMessage implements Parcelable { } /** - * Get a byte array representation of this NDEF message. - * - * @return byte array - * @hide + * Returns a byte array representation of this entire NDEF message. */ public byte[] toByteArray() { //TODO(nxp): do not return null diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java index edc5ab9..557e44d 100644 --- a/core/java/android/nfc/NdefRecord.java +++ b/core/java/android/nfc/NdefRecord.java @@ -247,8 +247,7 @@ public class NdefRecord implements Parcelable { } /** - * Return this NDEF Record as a byte array. - * @hide + * Returns this entire NDEF Record as a byte array. */ public byte[] toByteArray() { return generate(mFlags, mTnf, mType, mId, mPayload); diff --git a/core/java/android/nfc/NdefTag.java b/core/java/android/nfc/NdefTag.java index 45cdc31..d8681dc 100644 --- a/core/java/android/nfc/NdefTag.java +++ b/core/java/android/nfc/NdefTag.java @@ -16,8 +16,6 @@ package android.nfc; -import java.util.HashMap; - import android.os.Parcel; import android.os.Parcelable; @@ -33,19 +31,92 @@ import android.os.Parcelable; * is possible for {@link NdefTag}s to contain multiple {@link NdefMessage}s. * <p>{@link NfcAdapter#createNdefTagConnection createNdefTagConnection()} can be used to modify the * contents of some tags. - * <p>This is an immutable data class. + * <p>This is an immutable data class. All properties are set at Tag discovery + * time and calls on this class will retrieve those read-only properties, and + * not cause any further RF activity or block. Note however that arrays passed to and + * returned by this class are *not* cloned, so be careful not to modify them. */ public class NdefTag extends Tag implements Parcelable { - private final NdefMessage[] mMessages; + /** + * Target for NFC Forum Type 1 compliant tag. + * <p>This is based on Jewel/Topaz technology + */ + public static final String TARGET_TYPE_1 = "type_1"; + + /** + * Target for NFC Forum Type 2 compliant tag. + * <p>This is based on Mifare Ultralight technology. + */ + public static final String TARGET_TYPE_2 = "type_2"; /** - * Hidden constructor to be used by NFC service when a - * tag is discovered and by Parcelable methods. + * Target for NFC Forum Type 3 compliant tag. + * <p>This is based on Felica technology. + */ + public static final String TARGET_TYPE_3 = "type_3"; + + /** + * Target for NFC Forum Type 4 compliant tag. + * <p>This is based on Mifare Desfire technology. + */ + public static final String TARGET_TYPE_4 = "type_4"; + + /** + * Target for NFC Forum Enabled: Mifare Classic tag. + * <p>This is not strictly a NFC Forum tag type, but is a common + * NDEF message container. + */ + public static final String TARGET_MIFARE_CLASSIC = "type_mifare_classic"; + + /** + * Any other target. + */ + public static final String TARGET_OTHER = "other"; + + private final String[] mNdefTargets; + private final NdefMessage[][] mMessages; // one NdefMessage[] per NDEF target + private NdefMessage[] mFlatMessages; // collapsed mMessages, built lazily, protected by (this) + + /** + * Hidden constructor to be used by NFC service only. * @hide */ - public NdefTag(String typeName, byte[] uid, int nativeHandle, NdefMessage[] messages) { - super(typeName, true, uid, nativeHandle); - mMessages = messages.clone(); + public NdefTag(byte[] id, String[] rawTargets, byte[] pollBytes, byte[] activationBytes, + int serviceHandle, String[] ndefTargets, NdefMessage[][] messages) { + super(id, true, rawTargets, pollBytes, activationBytes, serviceHandle); + if (ndefTargets == null || messages == null) { + throw new IllegalArgumentException("ndefTargets or messages cannot be null"); + } + if (ndefTargets.length != messages.length){ + throw new IllegalArgumentException("ndefTargets and messages arrays must match"); + } + for (NdefMessage[] ms : messages) { + if (ms == null) { + throw new IllegalArgumentException("messages elements cannot be null"); + } + } + mNdefTargets = ndefTargets; + mMessages = messages; + } + + /** + * Construct a mock NdefTag. + * <p>This is an application constructed tag, so NfcAdapter methods on this + * Tag such as {@link NfcAdapter#createRawTagConnection} will fail with + * {@link IllegalArgumentException} since it does not represent a physical Tag. + * <p>This constructor might be useful for mock testing. + * @param id The tag identifier, can be null + * @param rawTargets must not be null + * @param pollBytes can be null + * @param activationBytes can be null + * @param ndefTargets NDEF target array, such as {TARGET_TYPE_2}, cannot be null + * @param messages messages, one array per NDEF target, cannot be null + * @return freshly constructed NdefTag + */ + public static NdefTag createMockNdefTag(byte[] id, String[] rawTargets, byte[] pollBytes, + byte[] activationBytes, String[] ndefTargets, NdefMessage[][] messages) { + // set serviceHandle to 0 to indicate mock tag + return new NdefTag(id, rawTargets, pollBytes, activationBytes, 0, ndefTargets, messages); } /** @@ -59,7 +130,29 @@ public class NdefTag extends Tag implements Parcelable { * @return NDEF Messages found at Tag discovery */ public NdefMessage[] getNdefMessages() { - return mMessages.clone(); + // common-case optimization + if (mMessages.length == 1) { + return mMessages[0]; + } + + // return cached flat array + synchronized(this) { + if (mFlatMessages != null) { + return mFlatMessages; + } + // not cached - build a flat array + int sz = 0; + for (NdefMessage[] ms : mMessages) { + sz += ms.length; + } + mFlatMessages = new NdefMessage[sz]; + int i = 0; + for (NdefMessage[] ms : mMessages) { + System.arraycopy(ms, 0, mFlatMessages, i, ms.length); + i += ms.length; + } + return mFlatMessages; + } } /** @@ -70,58 +163,25 @@ public class NdefTag extends Tag implements Parcelable { * <p> * Most tags only contain a single NDEF message. * - * @param target One of targets strings provided by getNdefTargets() + * @param target one of targets strings provided by getNdefTargets() * @return NDEF Messages found at Tag discovery */ public NdefMessage[] getNdefMessages(String target) { - // TODO: handle multiprotocol - String[] localTypes = convertToNdefType(mTypeName); - if (!target.equals(localTypes[0])) { - throw new IllegalArgumentException(); - } - return getNdefMessages(); - } - - /** TODO(npelly): - * - check that any single tag can only have one of each NDEF type - * - ok to include mifare_classic? - */ - public static final String TARGET_TYPE_1 = "type_1"; - public static final String TARGET_TYPE_2 = "type_2"; - public static final String TARGET_TYPE_3 = "type_3"; - public static final String TARGET_TYPE_4 = "type_4"; - public static final String TARGET_MIFARE_CLASSIC = "type_mifare_classic"; - public static final String TARGET_OTHER = "other"; - - private static final HashMap<String, String[]> NDEF_TYPES_CONVERTION_TABLE = new HashMap<String, String[]>() { - { - // TODO: handle multiprotocol - // TODO: move INTERNAL_TARGET_Type to TARGET_TYPE mapping to NFC service - put(Tag.INTERNAL_TARGET_TYPE_JEWEL, new String[] { NdefTag.TARGET_TYPE_1 }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UL, new String[] { NdefTag.TARGET_TYPE_2 }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_1K, new String[] { NdefTag.TARGET_MIFARE_CLASSIC }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_4K, new String[] { NdefTag.TARGET_MIFARE_CLASSIC }); - put(Tag.INTERNAL_TARGET_TYPE_FELICA, new String[] { NdefTag.TARGET_TYPE_3 }); - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_4, new String[] { NdefTag.TARGET_TYPE_4 }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_DESFIRE, new String[] { NdefTag.TARGET_TYPE_4 }); + for (int i=0; i<mNdefTargets.length; i++) { + if (target.equals(mNdefTargets[i])) { + return mMessages[i]; + } } - }; - - private String[] convertToNdefType(String internalTypeName) { - String[] result = NDEF_TYPES_CONVERTION_TABLE.get(internalTypeName); - if (result == null) { - return new String[] { NdefTag.TARGET_OTHER }; - } - return result; + throw new IllegalArgumentException("target (" + target + ") not found"); } /** - * Return the + * Return the NDEF targets on this Tag that support NDEF messages. * * @return */ public String[] getNdefTargets() { - return convertToNdefType(mTypeName); + return mNdefTargets; } @Override @@ -131,19 +191,50 @@ public class NdefTag extends Tag implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); + // Tag fields + dest.writeInt(mIsNdef ? 1 : 0); + writeBytesWithNull(dest, mId); + dest.writeInt(mRawTargets.length); + dest.writeStringArray(mRawTargets); + writeBytesWithNull(dest, mPollBytes); + writeBytesWithNull(dest, mActivationBytes); + dest.writeInt(mServiceHandle); + + // NdefTag fields + dest.writeInt(mNdefTargets.length); + dest.writeStringArray(mNdefTargets); dest.writeInt(mMessages.length); - dest.writeTypedArray(mMessages, flags); + for (NdefMessage[] ms : mMessages) { + dest.writeTypedArray(ms, flags); + } } public static final Parcelable.Creator<NdefTag> CREATOR = new Parcelable.Creator<NdefTag>() { public NdefTag createFromParcel(Parcel in) { - Tag tag = Tag.CREATOR.createFromParcel(in); - int messagesLength = in.readInt(); - NdefMessage[] messages = new NdefMessage[messagesLength]; - in.readTypedArray(messages, NdefMessage.CREATOR); - return new NdefTag(tag.mTypeName, tag.mUid, tag.mNativeHandle, messages); + boolean isNdef = (in.readInt() == 1); + if (!isNdef) { + throw new IllegalArgumentException("Creating NdefTag from Tag parcel"); + } + + // Tag fields + byte[] id = readBytesWithNull(in); + String[] rawTargets = new String[in.readInt()]; + in.readStringArray(rawTargets); + byte[] pollBytes = readBytesWithNull(in); + byte[] activationBytes = readBytesWithNull(in); + int serviceHandle = in.readInt(); + + // NdefTag fields + String[] ndefTargets = new String[in.readInt()]; + in.readStringArray(ndefTargets); + NdefMessage[][] messages = new NdefMessage[in.readInt()][]; + for (int i=0; i<messages.length; i++) { + messages[i] = new NdefMessage[in.readInt()]; + in.readTypedArray(messages[i], NdefMessage.CREATOR); + } + return new NdefTag(id, rawTargets, pollBytes, activationBytes, serviceHandle, + ndefTargets, messages); } public NdefTag[] newArray(int size) { return new NdefTag[size]; diff --git a/core/java/android/nfc/NdefTagConnection.java b/core/java/android/nfc/NdefTagConnection.java index 4795fa7..321b0ec 100644 --- a/core/java/android/nfc/NdefTagConnection.java +++ b/core/java/android/nfc/NdefTagConnection.java @@ -81,9 +81,9 @@ public class NdefTagConnection extends RawTagConnection { //TODO(nxp): do not use getLastError(), it is racy try { NdefMessage[] msgArray = new NdefMessage[1]; - NdefMessage msg = mTagService.read(mTag.mNativeHandle); + NdefMessage msg = mTagService.read(mTag.mServiceHandle); if (msg == null) { - int errorCode = mTagService.getLastError(mTag.mNativeHandle); + int errorCode = mTagService.getLastError(mTag.mServiceHandle); switch (errorCode) { case ErrorCodes.ERROR_IO: throw new IOException(); @@ -121,7 +121,7 @@ public class NdefTagConnection extends RawTagConnection { */ public void writeNdefMessage(NdefMessage message) throws IOException, FormatException { try { - int errorCode = mTagService.write(mTag.mNativeHandle, message); + int errorCode = mTagService.write(mTag.mServiceHandle, message); switch (errorCode) { case ErrorCodes.SUCCESS: break; @@ -148,7 +148,7 @@ public class NdefTagConnection extends RawTagConnection { */ public boolean makeReadOnly() throws IOException { try { - int errorCode = mTagService.makeReadOnly(mTag.mNativeHandle); + int errorCode = mTagService.makeReadOnly(mTag.mServiceHandle); switch (errorCode) { case ErrorCodes.SUCCESS: return true; @@ -175,7 +175,7 @@ public class NdefTagConnection extends RawTagConnection { */ public int getModeHint() throws IOException { try { - int result = mTagService.getModeHint(mTag.mNativeHandle); + int result = mTagService.getModeHint(mTag.mServiceHandle); if (ErrorCodes.isError(result)) { switch (result) { case ErrorCodes.ERROR_IO: diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 6884abb..7f4b4a2 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -327,6 +327,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public RawTagConnection createRawTagConnection(Tag tag) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new RawTagConnection(mService, tag); } catch (RemoteException e) { @@ -340,6 +343,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public RawTagConnection createRawTagConnection(Tag tag, String target) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new RawTagConnection(mService, tag, target); } catch (RemoteException e) { @@ -353,6 +359,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public NdefTagConnection createNdefTagConnection(NdefTag tag) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new NdefTagConnection(mService, tag); } catch (RemoteException e) { @@ -366,6 +375,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public NdefTagConnection createNdefTagConnection(NdefTag tag, String target) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new NdefTagConnection(mService, tag, target); } catch (RemoteException e) { diff --git a/core/java/android/nfc/RawTagConnection.java b/core/java/android/nfc/RawTagConnection.java index 1261db1..cf8283b 100644 --- a/core/java/android/nfc/RawTagConnection.java +++ b/core/java/android/nfc/RawTagConnection.java @@ -100,7 +100,7 @@ public class RawTagConnection { } try { - return mTagService.isPresent(mTag.mNativeHandle); + return mTagService.isPresent(mTag.mServiceHandle); } catch (RemoteException e) { Log.e(TAG, "NFC service died", e); return false; @@ -135,7 +135,7 @@ public class RawTagConnection { public void close() { mIsConnected = false; try { - mTagService.close(mTag.mNativeHandle); + mTagService.close(mTag.mServiceHandle); } catch (RemoteException e) { Log.e(TAG, "NFC service died", e); } @@ -154,7 +154,7 @@ public class RawTagConnection { */ public byte[] transceive(byte[] data) throws IOException { try { - byte[] response = mTagService.transceive(mTag.mNativeHandle, data); + byte[] response = mTagService.transceive(mTag.mServiceHandle, data); if (response == null) { throw new IOException("transcieve failed"); } diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index abf02b5..f9205a6 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -16,8 +16,6 @@ package android.nfc; -import java.util.HashMap; - import android.os.Parcel; import android.os.Parcelable; @@ -39,202 +37,180 @@ import android.os.Parcelable; * range. If it is removed and then returned to range, then the most recent * {@link Tag} object (in {@link NfcAdapter#ACTION_TAG_DISCOVERED}) should be used to create a * {@link RawTagConnection}. - * <p>This is an immutable data class. + * <p>This is an immutable data class. All properties are set at Tag discovery + * time and calls on this class will retrieve those read-only properties, and + * not cause any further RF activity or block. Note however that arrays passed to and + * returned by this class are *not* cloned, so be careful not to modify them. */ public class Tag implements Parcelable { - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_A = 1; /* phNfc_eISO14443_A_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_4A = 2; /* phNfc_eISO14443_4A_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_3A = 3; /* phNfc_eISO14443_3A_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_MIFARE = 4; /* phNfc_eMifare_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_B = 5; /* phNfc_eISO14443_B_PICC */ - /** - * @hide + * ISO 14443-3A technology. + * <p> + * Includes Topaz (which is -3A compatible) */ - public static final int NFC_TAG_ISO14443_4B = 6; /* phNfc_eISO14443_4B_PICC */ + public static final String TARGET_ISO_14443_3A = "iso14443_3a"; /** - * @hide + * ISO 14443-3B technology. */ - public static final int NFC_TAG_ISO14443_B_PRIME = 7; /* phNfc_eISO14443_BPrime_PICC */ + public static final String TARGET_ISO_14443_3B = "iso14443_3b"; /** - * @hide + * ISO 14443-4 technology. */ - public static final int NFC_TAG_FELICA = 8; /* phNfc_eFelica_PICC */ + public static final String TARGET_ISO_14443_4 = "iso14443_4"; /** - * @hide + * ISO 15693 technology, commonly known as RFID. */ - public static final int NFC_TAG_JEWEL = 9; /* phNfc_eJewel_PICC */ + public static final String TARGET_ISO_15693 = "iso15693"; /** - * @hide + * JIS X-6319-4 technology, commonly known as Felica. */ - public static final int NFC_TAG_ISO15693 = 10; /* phNfc_eISO15693_PICC */ + public static final String TARGET_JIS_X_6319_4 = "jis_x_6319_4"; /** - * @hide + * Any other technology. */ - public static final int NFC_TAG_OTHER = 11; /* phNfc_ePICC_DevType */ - - - public static final String TARGET_ISO_14443_3A = "iso14443_3a"; - - public static final String TARGET_ISO_14443_3B = "iso14443_3b"; - - public static final String TARGET_ISO_14443_3B_PRIME = "iso14443_3b"; - - public static final String TARGET_ISO_14443_4 = "iso14443_4"; - - public static final String TARGET_ISO_15693 = "iso15693"; - - public static final String TARGET_JIS_X_6319_4 = "jis_x_6319_4"; - - public static final String TARGET_TOPAZ = "topaz"; - public static final String TARGET_OTHER = "other"; - /*package*/ final String mTypeName; /*package*/ final boolean mIsNdef; - /*package*/ final byte[] mUid; - /*package*/ final int mNativeHandle; - - /*package*/ static final String INTERNAL_TARGET_TYPE_ISO14443_3A = "Iso14443-3A"; - /*package*/ static final String INTERNAL_TARGET_TYPE_ISO14443_3B = "Iso14443-3B"; - /*package*/ static final String INTERNAL_TARGET_TYPE_ISO14443_4 = "Iso14443-4"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_UL = "MifareUL"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_1K = "Mifare1K"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_4K = "Mifare4K"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_DESFIRE = "MifareDESFIRE"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_UNKNOWN = "Unknown Mifare"; - /*package*/ static final String INTERNAL_TARGET_TYPE_FELICA = "Felica"; - /*package*/ static final String INTERNAL_TARGET_TYPE_JEWEL = "Jewel"; - /*package*/ static final String INTERNAL_TARGET_TYPE_UNKNOWN = "Unknown Type"; - - private static final HashMap<String, Integer> INT_TYPES_CONVERTION_TABLE = new HashMap<String, Integer>() { - { - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3A, Tag.NFC_TAG_ISO14443_A ); - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3B, Tag.NFC_TAG_ISO14443_B ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UL, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_1K, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_4K, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_DESFIRE, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_FELICA, Tag.NFC_TAG_FELICA ); - put(Tag.INTERNAL_TARGET_TYPE_JEWEL, Tag.NFC_TAG_JEWEL ); - } - }; - - private int convertToInt(String internalTypeName) { - Integer result = INT_TYPES_CONVERTION_TABLE.get(internalTypeName); - if (result == null) { - return Tag.NFC_TAG_OTHER; - } - return result; - } - - private static final HashMap<String, String[]> RAW_TYPES_CONVERTION_TABLE = new HashMap<String, String[]>() { - { - /* TODO: handle multiprotocol */ - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3A, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3B, new String[] { Tag.TARGET_ISO_14443_3B }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UL, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_1K, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_4K, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_DESFIRE, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UNKNOWN, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_FELICA, new String[] { Tag.TARGET_JIS_X_6319_4 }); - put(Tag.INTERNAL_TARGET_TYPE_JEWEL, new String[] { Tag.TARGET_TOPAZ }); - } - }; - - private String[] convertToRaw(String internalTypeName) { - String[] result = RAW_TYPES_CONVERTION_TABLE.get(internalTypeName); - if (result == null) { - return new String[] { Tag.TARGET_OTHER }; - } - return result; - } + /*package*/ final byte[] mId; + /*package*/ final String[] mRawTargets; + /*package*/ final byte[] mPollBytes; + /*package*/ final byte[] mActivationBytes; + /*package*/ final int mServiceHandle; // for use by NFC service, 0 indicates a mock /** - * Hidden constructor to be used by NFC service only. + * Hidden constructor to be used by NFC service and internal classes. * @hide */ - public Tag(String typeName, boolean isNdef, byte[] uid, int nativeHandle) { - mTypeName = typeName; + public Tag(byte[] id, boolean isNdef, String[] rawTargets, byte[] pollBytes, + byte[] activationBytes, int serviceHandle) { + if (rawTargets == null) { + throw new IllegalArgumentException("rawTargets cannot be null"); + } mIsNdef = isNdef; - mUid = uid.clone(); - mNativeHandle = nativeHandle; + mId = id; + mRawTargets = rawTargets; + mPollBytes = pollBytes; + mActivationBytes = activationBytes; + mServiceHandle = serviceHandle; + } + + /** + * Construct a mock Tag. + * <p>This is an application constructed tag, so NfcAdapter methods on this + * Tag such as {@link NfcAdapter#createRawTagConnection} will fail with + * {@link IllegalArgumentException} since it does not represent a physical Tag. + * <p>This constructor might be useful for mock testing. + * @param id The tag identifier, can be null + * @param rawTargets must not be null + * @param pollBytes can be null + * @param activationBytes can be null + * @return freshly constructed tag + */ + public static Tag createMockTag(byte[] id, String[] rawTargets, byte[] pollBytes, + byte[] activationBytes) { + // set serviceHandle to 0 to indicate mock tag + return new Tag(id, false, rawTargets, pollBytes, activationBytes, 0); } /** * For use by NfcService only. * @hide */ - public int getHandle() { - return mNativeHandle; + public int getServiceHandle() { + return mServiceHandle; } /** * Return the available targets that this NFC adapter can use to create * a RawTagConnection. * - * @return + * @return raw targets, will not be null */ public String[] getRawTargets() { - return convertToRaw(mTypeName); + return mRawTargets; } /** - * Get the Tag type. - * <p> - * The Tag type is one of the NFC_TAG constants. It is read at discovery - * time and this method does not cause any further RF activity and does not - * block. + * Get the Tag Identifier (if it has one). + * <p>Tag ID is usually a serial number for the tag. * - * @return a NFC_TAG constant - * @hide + * @return ID, or null if it does not exist */ - public int getType() { - return convertToInt(mTypeName); + public byte[] getId() { + return mId; } /** - * Get the Tag Identifier (if it has one). - * <p> - * Tag ID is usually a serial number for the tag. - * <p> - * The Tag ID is read at discovery time and this method does not cause any - * further RF activity and does not block. + * Get the low-level bytes returned by this Tag at poll-time. + * <p>These can be used to help with advanced identification of a Tag. + * <p>The meaning of these bytes depends on the Tag technology. + * <p>ISO14443-3A: ATQA/SENS_RES + * <p>ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES + * <p>JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) + * <p>ISO15693: response flags (1 byte), DSFID (1 byte) + * from SENSF_RES * - * @return ID, or null if it does not exist + * @return poll bytes, or null if they do not exist for this Tag technology */ - public byte[] getId() { - if (mUid.length > 0) { - return mUid.clone(); - } else { - return null; + public byte[] getPollBytes() { + return mPollBytes; + } + + /** + * Get the low-level bytes returned by this Tag at activation-time. + * <p>These can be used to help with advanced identification of a Tag. + * <p>The meaning of these bytes depends on the Tag technology. + * <p>ISO14443-3A: SAK/SEL_RES + * <p>ISO14443-3B: null + * <p>ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS <TODO: confirm> + * <p>ISO14443-3B & ISO14443-4: ATTRIB response + * <p>JIS_X_6319_4: null + * <p>ISO15693: response flags (1 byte), DSFID (1 byte): null + * @return activation bytes, or null if they do not exist for this Tag technology + */ + public byte[] getActivationBytes() { + return mActivationBytes; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("TAG ") + .append("uid = ") + .append(mId) + .append(" poll ") + .append(mPollBytes) + .append(" activation ") + .append(mActivationBytes) + .append(" Raw ["); + for (String s : mRawTargets) { + sb.append(s) + .append(", "); + } + return sb.toString(); + } + + /*package*/ static byte[] readBytesWithNull(Parcel in) { + int len = in.readInt(); + byte[] result = null; + if (len > 0) { + result = new byte[len]; + in.readByteArray(result); } + return result; + } + + /*package*/ static void writeBytesWithNull(Parcel out, byte[] b) { + if (b == null) { + out.writeInt(-1); + return; + } + out.writeInt(b.length); + out.writeByteArray(b); } @Override @@ -242,29 +218,34 @@ public class Tag implements Parcelable { return 0; } + @Override public void writeToParcel(Parcel dest, int flags) { - boolean[] booleans = new boolean[] {mIsNdef}; - dest.writeString(mTypeName); - dest.writeBooleanArray(booleans); - dest.writeInt(mUid.length); - dest.writeByteArray(mUid); - dest.writeInt(mNativeHandle); + dest.writeInt(mIsNdef ? 1 : 0); + writeBytesWithNull(dest, mId); + dest.writeInt(mRawTargets.length); + dest.writeStringArray(mRawTargets); + writeBytesWithNull(dest, mPollBytes); + writeBytesWithNull(dest, mActivationBytes); + dest.writeInt(mServiceHandle); } public static final Parcelable.Creator<Tag> CREATOR = new Parcelable.Creator<Tag>() { public Tag createFromParcel(Parcel in) { - boolean[] booleans = new boolean[1]; - String type = in.readString(); - in.readBooleanArray(booleans); - boolean isNdef = booleans[0]; - int uidLength = in.readInt(); - byte[] uid = new byte[uidLength]; - in.readByteArray(uid); - int nativeHandle = in.readInt(); - - return new Tag(type, isNdef, uid, nativeHandle); + boolean isNdef = (in.readInt() == 1); + if (isNdef) { + throw new IllegalArgumentException("Creating Tag from NdefTag parcel"); + } + // Tag fields + byte[] id = Tag.readBytesWithNull(in); + String[] rawTargets = new String[in.readInt()]; + in.readStringArray(rawTargets); + byte[] pollBytes = Tag.readBytesWithNull(in); + byte[] activationBytes = Tag.readBytesWithNull(in); + int serviceHandle = in.readInt(); + + return new Tag(id, isNdef, rawTargets, pollBytes, activationBytes, serviceHandle); } public Tag[] newArray(int size) { return new Tag[size]; diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 9767786..b4c6a2923 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -188,15 +188,7 @@ public class Build { public static final int FROYO = 8; /** - * Next version of Android. - * - * <p>Applications targeting this or a later release will get these - * new changes in behavior:</p> - * <ul> - * <li> The status bar is now dark. Targeting this version allows - * the platform to perform performing compatibility on status bar - * graphics to ensure they look okay on a dark background. - * </ul> + * Newest version of Android, version 2.3. */ public static final int GINGERBREAD = 9; diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index e912089..9786959 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -15,6 +15,7 @@ */ package android.os; +import android.animation.ValueAnimator; import android.app.ActivityManagerNative; import android.app.ApplicationErrorReport; import android.util.Log; @@ -1110,6 +1111,11 @@ public final class StrictMode { public int durationMillis = -1; /** + * The number of animations currently running. + */ + public int numAnimationsRunning = 0; + + /** * Which violation number this was (1-based) since the last Looper loop, * from the perspective of the root caller (if it crossed any processes * via Binder calls). The value is 0 if the root caller wasn't on a Looper @@ -1138,6 +1144,7 @@ public final class StrictMode { crashInfo = new ApplicationErrorReport.CrashInfo(tr); violationUptimeMillis = SystemClock.uptimeMillis(); this.policy = policy; + this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount(); } /** @@ -1163,6 +1170,7 @@ public final class StrictMode { } durationMillis = in.readInt(); violationNumThisLoop = in.readInt(); + numAnimationsRunning = in.readInt(); violationUptimeMillis = in.readLong(); } @@ -1174,6 +1182,7 @@ public final class StrictMode { dest.writeInt(policy); dest.writeInt(durationMillis); dest.writeInt(violationNumThisLoop); + dest.writeInt(numAnimationsRunning); dest.writeLong(violationUptimeMillis); } @@ -1190,6 +1199,9 @@ public final class StrictMode { if (violationNumThisLoop != 0) { pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); } + if (numAnimationsRunning != 0) { + pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning); + } pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); } diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 7b2022b..61e2305 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -41,6 +41,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; public class BluetoothA2dpService extends IBluetoothA2dp.Stub { @@ -107,10 +108,10 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); if (streamType == AudioManager.STREAM_MUSIC) { - BluetoothDevice sinks[] = getConnectedDevices(); + List<BluetoothDevice> sinks = getConnectedDevices(); - if (sinks.length != 0 && isPhoneDocked(sinks[0])) { - String address = sinks[0].getAddress(); + if (sinks.size() != 0 && isPhoneDocked(sinks.get(0))) { + String address = sinks.get(0).getAddress(); int newVolLevel = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); int oldVolLevel = @@ -319,7 +320,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (getDevicesMatchingConnectionStates(new int[] { BluetoothA2dp.STATE_CONNECTING, BluetoothA2dp.STATE_CONNECTED, - BluetoothA2dp.STATE_DISCONNECTING}).length != 0) { + BluetoothA2dp.STATE_DISCONNECTING}).size() != 0) { return false; } @@ -430,19 +431,16 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return state; } - public synchronized BluetoothDevice[] getConnectedDevices() { + public synchronized List<BluetoothDevice> getConnectedDevices() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - BluetoothDevice[] sinks = getDevicesMatchingConnectionStates( + List<BluetoothDevice> sinks = getDevicesMatchingConnectionStates( new int[] {BluetoothA2dp.STATE_CONNECTED}); return sinks; } - public synchronized BluetoothDevice[] getDevicesMatchingConnectionStates(int[] states) { + public synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - ArrayList<BluetoothDevice> sinks = new ArrayList(); - if (mAudioDevices.isEmpty()) { - return sinks.toArray(new BluetoothDevice[sinks.size()]); - } + ArrayList<BluetoothDevice> sinks = new ArrayList<BluetoothDevice>(); for (BluetoothDevice device: mAudioDevices.keySet()) { int sinkState = getConnectionState(device); for (int state : states) { @@ -452,7 +450,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } } } - return sinks.toArray(new BluetoothDevice[sinks.size()]); + return sinks; } public synchronized int getPriority(BluetoothDevice device) { diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 239c3ac..f47c553 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -29,11 +29,12 @@ import android.content.Intent; import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; +import android.os.PowerManager; import android.util.Log; import java.util.HashMap; +import java.util.List; import java.util.Set; -import android.os.PowerManager; /** @@ -629,7 +630,7 @@ class BluetoothEventLoop { } private boolean isOtherInputDeviceConnected(String address) { - Set<BluetoothDevice> devices = + List<BluetoothDevice> devices = mBluetoothService.lookupInputDevicesMatchingStates(new int[] { BluetoothInputDevice.STATE_CONNECTING, BluetoothInputDevice.STATE_CONNECTED}); @@ -654,13 +655,13 @@ class BluetoothEventLoop { } private boolean isOtherSinkInNonDisconnectedState(String address) { - Set<BluetoothDevice> devices = + List<BluetoothDevice> devices = mA2dp.getDevicesMatchingConnectionStates(new int[] {BluetoothA2dp.STATE_CONNECTED, BluetoothA2dp.STATE_CONNECTING, BluetoothA2dp.STATE_DISCONNECTING}); if (devices.size() == 0) return false; - for(BluetoothDevice dev: devices) { + for (BluetoothDevice dev: devices) { if (!dev.getAddress().equals(address)) return true; } return false; diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index 7abb98e..660f9ab 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -27,12 +27,12 @@ package android.server; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothDeviceProfileState; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothInputDevice; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfileState; -import android.bluetooth.BluetoothInputDevice; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; import android.bluetooth.IBluetooth; @@ -80,6 +80,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; @@ -1415,7 +1416,7 @@ public class BluetoothService extends IBluetooth.Stub { } /*package*/ synchronized boolean allowIncomingTethering() { - if (isTetheringOn() && getConnectedPanDevices().length < mMaxPanDevices) + if (isTetheringOn() && getConnectedPanDevices().size() < mMaxPanDevices) return true; return false; } @@ -1503,16 +1504,17 @@ public class BluetoothService extends IBluetooth.Stub { return true; } - public synchronized BluetoothDevice[] getConnectedPanDevices() { + public synchronized List<BluetoothDevice> getConnectedPanDevices() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(); + List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); + for (BluetoothDevice device: mPanDevices.keySet()) { if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) { devices.add(device); } } - return devices.toArray(new BluetoothDevice[devices.size()]); + return devices; } public synchronized boolean disconnectPanDevice(BluetoothDevice device) { @@ -1569,7 +1571,7 @@ public class BluetoothService extends IBluetooth.Stub { } private String createNewTetheringAddressLocked() { - if (getConnectedPanDevices().length == mMaxPanDevices) { + if (getConnectedPanDevices().size() == mMaxPanDevices) { log("Max PAN device connections reached"); return null; } @@ -1688,7 +1690,7 @@ public class BluetoothService extends IBluetooth.Stub { "Need BLUETOOTH_ADMIN permission"); String objectPath = getObjectPathFromAddress(device.getAddress()); - if (objectPath == null || getConnectedInputDevices().length == 0) { + if (objectPath == null || getConnectedInputDevices().size() == 0) { return false; } BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress()); @@ -1721,11 +1723,11 @@ public class BluetoothService extends IBluetooth.Stub { return mInputDevices.get(device); } - public synchronized BluetoothDevice[] getConnectedInputDevices() { + public synchronized List<BluetoothDevice> getConnectedInputDevices() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - Set<BluetoothDevice> devices = lookupInputDevicesMatchingStates( + List<BluetoothDevice> devices = lookupInputDevicesMatchingStates( new int[] {BluetoothInputDevice.STATE_CONNECTED}); - return devices.toArray(new BluetoothDevice[devices.size()]); + return devices; } public synchronized int getInputDevicePriority(BluetoothDevice device) { @@ -1746,11 +1748,9 @@ public class BluetoothService extends IBluetooth.Stub { priority); } - /*package*/synchronized Set<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) { - Set<BluetoothDevice> inputDevices = new HashSet<BluetoothDevice>(); - if (mInputDevices.isEmpty()) { - return inputDevices; - } + /*package*/synchronized List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) { + List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>(); + for (BluetoothDevice device: mInputDevices.keySet()) { int inputDeviceState = getInputDeviceState(device); for (int state : states) { @@ -2487,11 +2487,11 @@ public class BluetoothService extends IBluetooth.Stub { // dump pw.println("\n--Headset Service--"); if (mBluetoothHeadset != null) { - Set<BluetoothDevice> deviceSet = mBluetoothHeadset.getConnectedDevices(); - if (deviceSet.size() == 0) { + List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); + if (deviceList.size() == 0) { pw.println("\n--No headsets connected--"); } - BluetoothDevice device = (BluetoothDevice) deviceSet.toArray()[0]; + BluetoothDevice device = deviceList.get(0); switch (mBluetoothHeadset.getConnectionState(device)) { case BluetoothHeadset.STATE_DISCONNECTED: @@ -2511,11 +2511,11 @@ public class BluetoothService extends IBluetooth.Stub { break; } - deviceSet.clear(); - deviceSet = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] { + deviceList.clear(); + deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] { BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); pw.println("\n--Connected and Disconnected Headsets"); - for (BluetoothDevice dev: deviceSet) { + for (BluetoothDevice dev: deviceList) { pw.println(device); if (mBluetoothHeadset.isAudioConnected(device)) { pw.println("SCO audio connected to device:" + device); diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 76d8106..63baf14 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -45,6 +45,11 @@ public class DisplayMetrics { public static final int DENSITY_HIGH = 240; /** + * Standard quantized DPI for extra-high-density screens. + */ + public static final int DENSITY_XHIGH = 320; + + /** * The reference density used throughout the system. */ public static final int DENSITY_DEFAULT = DENSITY_MEDIUM; diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index 61a8cda..3010178 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -98,6 +98,10 @@ public final class CookieManager { private boolean mAcceptCookie = true; + // TODO: Remove this if/when we permanently switch to the Chromium HTTP stack + // http:/b/3118772 + private static Boolean sUseChromiumHttpStack; + /** * This contains a list of 2nd-level domains that aren't allowed to have * wildcards when combined with country-codes. For example: [.co.uk]. @@ -257,6 +261,13 @@ public final class CookieManager { return sRef; } + private static boolean useChromiumHttpStack() { + if (sUseChromiumHttpStack == null) { + sUseChromiumHttpStack = nativeUseChromiumHttpStack(); + } + return sUseChromiumHttpStack; + } + /** * Control whether cookie is enabled or disabled * @param accept TRUE if accept cookie @@ -524,11 +535,11 @@ public final class CookieManager { * Remove all cookies */ public void removeAllCookie() { - // Clear cookies for the Chromium HTTP stack - nativeRemoveAllCookie(); - // Clear cookies for the Android HTTP stack - // TODO: Remove this if/when we permanently switch to the Chromium HTTP stack - // http:/b/3118772 + if (useChromiumHttpStack()) { + nativeRemoveAllCookie(); + return; + } + final Runnable clearCache = new Runnable() { public void run() { synchronized(CookieManager.this) { @@ -1023,5 +1034,6 @@ public final class CookieManager { } // Native functions + private static native boolean nativeUseChromiumHttpStack(); private static native void nativeRemoveAllCookie(); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index be1af65..c095199 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2388,7 +2388,7 @@ public class WebView extends AbsoluteLayout if (!rect.equals(mLastVisibleRectSent)) { Point pos = new Point(rect.left, rect.top); mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET, - nativeMoveGeneration(), 0, pos); + nativeMoveGeneration(), mUserScroll ? 1 : 0, pos); mLastVisibleRectSent = rect; } Rect globalRect = new Rect(); @@ -3966,7 +3966,9 @@ public class WebView extends AbsoluteLayout imm.restartInput(mWebTextView); } } - mWebTextView.requestFocus(); + if (isFocused()) { + mWebTextView.requestFocus(); + } } /** @@ -6442,6 +6444,7 @@ public class WebView extends AbsoluteLayout } case NEW_PICTURE_MSG_ID: { // called for new content + mUserScroll = false; final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj; setBaseLayer(draw.mBaseLayer, draw.mInvalRegion.getBounds()); final Point viewSize = draw.mViewPoint; diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 8cd9f68..1c8e2cd 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1074,7 +1074,7 @@ final class WebViewCore { // note: these are in document coordinates // (inv-zoom) Point pt = (Point) msg.obj; - nativeSetScrollOffset(msg.arg1, pt.x, pt.y); + nativeSetScrollOffset(msg.arg1, msg.arg2, pt.x, pt.y); break; case SET_GLOBAL_BOUNDS: @@ -2203,7 +2203,8 @@ final class WebViewCore { if (mViewportInitialScale > 0) { mInitialViewState.mViewScale = mInitialViewState.mTextWrapScale = mViewportInitialScale / 100.0f; - } else if (mViewportWidth > 0 && mViewportWidth < webViewWidth) { + } else if (mViewportWidth > 0 && mViewportWidth < webViewWidth && + !mWebView.getSettings().getUseFixedViewport()) { mInitialViewState.mViewScale = mInitialViewState.mTextWrapScale = (float) webViewWidth / mViewportWidth; } else { @@ -2347,7 +2348,7 @@ final class WebViewCore { private native void nativeScrollFocusedTextInput(float xPercent, int y); // these must be in document space (i.e. not scaled/zoomed). - private native void nativeSetScrollOffset(int gen, int dx, int dy); + private native void nativeSetScrollOffset(int gen, int userScrolled, int dx, int dy); private native void nativeSetGlobalBounds(int x, int y, int w, int h); diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 0a91ac4..91c0fb2 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -554,9 +554,7 @@ class ZoomManager { } if (settings.getLayoutAlgorithm() == WebSettings.LayoutAlgorithm.NARROW_COLUMNS - && willScaleTriggerZoom(mTextWrapScale) - // For tablet, not much need to reflow text w/o double tapping. - && !settings.getUseFixedViewport()) { + && willScaleTriggerZoom(mTextWrapScale)) { refreshZoomScale(true); } else if (!mInZoomOverview) { zoomToOverview(); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 9e7cc44..728c2a7 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -856,6 +856,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public boolean performItemClick(View view, int position, long id) { boolean handled = false; + boolean dispatchItemClick = true; if (mChoiceMode != CHOICE_MODE_NONE) { handled = true; @@ -879,6 +880,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mChoiceActionMode != null) { mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode, position, id, newValue); + dispatchItemClick = false; } } else if (mChoiceMode == CHOICE_MODE_SINGLE) { boolean newValue = !mCheckStates.get(position, false); @@ -900,7 +902,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te requestLayout(); } - handled |= super.performItemClick(view, position, id); + if (dispatchItemClick) { + handled |= super.performItemClick(view, position, id); + } return handled; } @@ -1984,6 +1988,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mAdapter != null && mDataSetObserver == null) { mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); + + // Data may have changed while we were detached. Refresh. + mDataChanged = true; + mOldItemCount = mItemCount; + mItemCount = mAdapter.getCount(); } } diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java index 87453ae..bb2e26c3 100644 --- a/core/java/android/widget/AdapterViewAnimator.java +++ b/core/java/android/widget/AdapterViewAnimator.java @@ -69,12 +69,12 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> * The number of views that the {@link AdapterViewAnimator} keeps as children at any * given time (not counting views that are pending removal, see {@link #mPreviousViews}). */ - int mNumActiveViews = 1; + int mMaxNumActiveViews = 1; /** * Map of the children of the {@link AdapterViewAnimator}. */ - private HashMap<Integer, ViewAndIndex> mViewsMap = new HashMap<Integer, ViewAndIndex>(); + HashMap<Integer, ViewAndIndex> mViewsMap = new HashMap<Integer, ViewAndIndex>(); /** * List of views pending removal from the {@link AdapterViewAnimator} @@ -141,8 +141,6 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> ObjectAnimator mInAnimation; ObjectAnimator mOutAnimation; - private ArrayList<View> mViewsToBringToFront; - private static final int DEFAULT_ANIMATION_DURATION = 200; public AdapterViewAnimator(Context context) { @@ -188,10 +186,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> private void initViewAnimator() { mMainQueue = new Handler(Looper.myLooper()); mPreviousViews = new ArrayList<Integer>(); - mViewsToBringToFront = new ArrayList<View>(); } - private class ViewAndIndex { + class ViewAndIndex { ViewAndIndex(View v, int i) { view = v; index = i; @@ -217,7 +214,7 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> if (activeOffset > numVisibleViews - 1) { // Throw an exception here. } - mNumActiveViews = numVisibleViews; + mMaxNumActiveViews = numVisibleViews; mActiveOffset = activeOffset; mPreviousViews.clear(); mViewsMap.clear(); @@ -266,10 +263,10 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> public void setDisplayedChild(int whichChild) { if (mAdapter != null) { mWhichChild = whichChild; - if (whichChild >= mAdapter.getCount()) { - mWhichChild = mLoopViews ? 0 : mAdapter.getCount() - 1; + if (whichChild >= getWindowSize()) { + mWhichChild = mLoopViews ? 0 : getWindowSize() - 1; } else if (whichChild < 0) { - mWhichChild = mLoopViews ? mAdapter.getCount() - 1 : 0; + mWhichChild = mLoopViews ? getWindowSize() - 1 : 0; } boolean hasFocus = getFocusedChild() != null; @@ -327,7 +324,7 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> showOnly(childIndex, animate, false); } - private int modulo(int pos, int size) { + int modulo(int pos, int size) { if (size > 0) { return (size + (pos % size)) % size; } else { @@ -342,9 +339,8 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> * @return View at this index, null if the index is outside the bounds */ View getViewAtRelativeIndex(int relativeIndex) { - if (relativeIndex >= 0 && relativeIndex <= mNumActiveViews - 1 && mAdapter != null) { - int adapterCount = mAdapter.getCount(); - int i = modulo(mCurrentWindowStartUnbounded + relativeIndex, adapterCount); + if (relativeIndex >= 0 && relativeIndex <= getNumActiveViews() - 1 && mAdapter != null) { + int i = modulo(mCurrentWindowStartUnbounded + relativeIndex, getWindowSize()); if (mViewsMap.get(i) != null) { return mViewsMap.get(i).view; } @@ -352,6 +348,27 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> return null; } + int getNumActiveViews() { + if (mAdapter != null) { + return Math.min(mAdapter.getCount() + 1, mMaxNumActiveViews); + } else { + return mMaxNumActiveViews; + } + } + + int getWindowSize() { + if (mAdapter != null) { + int adapterCount = mAdapter.getCount(); + if (adapterCount <= getNumActiveViews() && mLoopViews) { + return adapterCount*mMaxNumActiveViews; + } else { + return adapterCount; + } + } else { + return 0; + } + } + LayoutParams createOrReuseLayoutParams(View v) { final ViewGroup.LayoutParams currentLp = v.getLayoutParams(); if (currentLp instanceof ViewGroup.LayoutParams) { @@ -363,7 +380,7 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> void refreshChildren() { for (int i = mCurrentWindowStart; i <= mCurrentWindowEnd; i++) { - int index = modulo(i, mNumActiveViews); + int index = modulo(i, mMaxNumActiveViews); // get the fresh child from the adapter View updatedChild = mAdapter.getView(i, null, this); @@ -412,7 +429,7 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> } mPreviousViews.clear(); int newWindowStartUnbounded = childIndex - mActiveOffset; - int newWindowEndUnbounded = newWindowStartUnbounded + mNumActiveViews - 1; + int newWindowEndUnbounded = newWindowStartUnbounded + getNumActiveViews() - 1; int newWindowStart = Math.max(0, newWindowStartUnbounded); int newWindowEnd = Math.min(adapterCount - 1, newWindowEndUnbounded); @@ -420,8 +437,8 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> newWindowStart = newWindowStartUnbounded; newWindowEnd = newWindowEndUnbounded; } - int rangeStart = modulo(newWindowStart, adapterCount); - int rangeEnd = modulo(newWindowEnd, adapterCount); + int rangeStart = modulo(newWindowStart, getWindowSize()); + int rangeEnd = modulo(newWindowEnd, getWindowSize()); boolean wrap = false; if (rangeStart > rangeEnd) { @@ -450,11 +467,12 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> } // If the window has changed - if (!(newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd)) { + if (!(newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd && + newWindowStartUnbounded == mCurrentWindowStartUnbounded)) { // Run through the indices in the new range for (int i = newWindowStart; i <= newWindowEnd; i++) { - int index = modulo(i, adapterCount); + int index = modulo(i, getWindowSize()); int oldRelativeIndex; if (mViewsMap.containsKey(index)) { oldRelativeIndex = mViewsMap.get(index).index; @@ -494,13 +512,6 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> } mViewsMap.get(index).view.bringToFront(); } - - for (int i = 0; i < mViewsToBringToFront.size(); i++) { - View v = mViewsToBringToFront.get(i); - v.bringToFront(); - } - mViewsToBringToFront.clear(); - mCurrentWindowStart = newWindowStart; mCurrentWindowEnd = newWindowEnd; mCurrentWindowStartUnbounded = newWindowStartUnbounded; diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 1d36b49..029aebf 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -306,6 +306,10 @@ public class SearchView extends LinearLayout { */ public void setQuery(CharSequence query, boolean submit) { mQueryTextView.setText(query); + if (query != null) { + mQueryTextView.setSelection(query.length()); + } + // If the query is not empty and submit is requested, submit the query if (submit && !TextUtils.isEmpty(query)) { onSubmitQuery(); diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index 4c3927b..c05da03 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -129,7 +129,7 @@ public class StackView extends AdapterViewAnimator { } private void initStackView() { - configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2); + configureViewAnimator(NUM_ACTIVE_VIEWS, 1); setStaticTransformationsEnabled(true); final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); @@ -165,7 +165,7 @@ public class StackView extends AdapterViewAnimator { * Animate the views between different relative indexes within the {@link AdapterViewAnimator} */ void animateViewForTransition(int fromIndex, int toIndex, View view) { - if (fromIndex == -1 && toIndex == 0) { + if (fromIndex == -1 && toIndex != 0) { // Fade item in if (view.getAlpha() == 1) { view.setAlpha(0); @@ -175,7 +175,7 @@ public class StackView extends AdapterViewAnimator { ObjectAnimator fadeIn = ObjectAnimator.ofFloat(view, "alpha", view.getAlpha(), 1.0f); fadeIn.setDuration(DEFAULT_ANIMATION_DURATION); fadeIn.start(); - } else if (fromIndex == mNumActiveViews - 1 && toIndex == mNumActiveViews - 2) { + } else if (fromIndex == 0 && toIndex == 1) { // Slide item in view.setVisibility(VISIBLE); @@ -189,7 +189,7 @@ public class StackView extends AdapterViewAnimator { pa.setDuration(duration); pa.setInterpolator(new LinearInterpolator()); pa.start(); - } else if (fromIndex == mNumActiveViews - 2 && toIndex == mNumActiveViews - 1) { + } else if (fromIndex == 1 && toIndex == 0) { // Slide item out int duration = Math.round(mStackSlider.getDurationForOffscreenPosition(mYVelocity)); @@ -201,7 +201,7 @@ public class StackView extends AdapterViewAnimator { pa.setDuration(duration); pa.setInterpolator(new LinearInterpolator()); pa.start(); - } else if (fromIndex == -1 && toIndex == mNumActiveViews - 1) { + } else if (fromIndex == -1 && toIndex == 0) { // Make sure this view that is "waiting in the wings" is invisible view.setAlpha(0.0f); view.setVisibility(INVISIBLE); @@ -223,9 +223,10 @@ public class StackView extends AdapterViewAnimator { private void transformViewAtIndex(int index, View view) { float maxPerpectiveShift = mMeasuredHeight * PERSPECTIVE_SHIFT_FACTOR; - if (index == mNumActiveViews -1) index--; + index = mMaxNumActiveViews - index - 1; + if (index == mMaxNumActiveViews - 1) index--; - float r = (index * 1.0f) / (mNumActiveViews - 2); + float r = (index * 1.0f) / (mMaxNumActiveViews - 2); float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", scale); @@ -245,8 +246,20 @@ public class StackView extends AdapterViewAnimator { pa.start(); } + @Override + void showOnly(int childIndex, boolean animate, boolean onLayout) { + super.showOnly(childIndex, animate, onLayout); + + // Here we need to make sure that the z-order of the children is correct + for (int i = mCurrentWindowEnd; i >= mCurrentWindowStart; i--) { + int index = modulo(i, getWindowSize()); + View v = mViewsMap.get(index).view; + if (v != null) v.bringToFront(); + } + } + private void updateChildTransforms() { - for (int i = 0; i < mNumActiveViews - 1; i++) { + for (int i = 0; i < getNumActiveViews(); i++) { View v = getViewAtRelativeIndex(i); if (v != null) { transformViewAtIndex(i, v); @@ -341,19 +354,17 @@ public class StackView extends AdapterViewAnimator { int activeIndex; if (mStackMode == ITEMS_SLIDE_UP) { - activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? - mNumActiveViews - 1 : mNumActiveViews - 2; + activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? 0 : 1; } else { - activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? - mNumActiveViews - 2 : mNumActiveViews - 1; + activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? 1 : 0; } if (mLoopViews) { mStackSlider.setMode(StackSlider.NORMAL_MODE); - } else if (mCurrentWindowStartUnbounded + activeIndex == 0) { + } else if (mCurrentWindowStartUnbounded + activeIndex == -1) { + activeIndex++; mStackSlider.setMode(StackSlider.BEGINNING_OF_STACK_MODE); - } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount()) { - activeIndex--; + } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount() - 1) { mStackSlider.setMode(StackSlider.END_OF_STACK_MODE); } else { mStackSlider.setMode(StackSlider.NORMAL_MODE); @@ -439,8 +450,7 @@ public class StackView extends AdapterViewAnimator { final int pointerId = ev.getPointerId(activePointerIndex); if (pointerId == mActivePointerId) { - int activeViewIndex = (mSwipeGestureType == GESTURE_SLIDE_DOWN) ? mNumActiveViews - 1 - : mNumActiveViews - 2; + int activeViewIndex = (mSwipeGestureType == GESTURE_SLIDE_DOWN) ? 0 : 1; View v = getViewAtRelativeIndex(activeViewIndex); if (v == null) return; @@ -498,18 +508,18 @@ public class StackView extends AdapterViewAnimator { && mStackSlider.mMode == StackSlider.NORMAL_MODE) { // Swipe threshold exceeded, swipe down if (mStackMode == ITEMS_SLIDE_UP) { - showNext(); - } else { showPrevious(); + } else { + showNext(); } mHighlight.bringToFront(); } else if (deltaY < -mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_UP && mStackSlider.mMode == StackSlider.NORMAL_MODE) { // Swipe threshold exceeded, swipe up if (mStackMode == ITEMS_SLIDE_UP) { - showPrevious(); - } else { showNext(); + } else { + showPrevious(); } mHighlight.bringToFront(); @@ -643,13 +653,13 @@ public class StackView extends AdapterViewAnimator { mView.setRotationX(stackDirection * 90.0f * rotationInterpolator(r)); mHighlight.setRotationX(stackDirection * 90.0f * rotationInterpolator(r)); break; - case BEGINNING_OF_STACK_MODE: + case END_OF_STACK_MODE: r = r * 0.2f; viewLp.setVerticalOffset(Math.round(-stackDirection * r * mSlideAmount)); highlightLp.setVerticalOffset(Math.round(-stackDirection * r * mSlideAmount)); mHighlight.setAlpha(highlightAlphaInterpolator(r)); break; - case END_OF_STACK_MODE: + case BEGINNING_OF_STACK_MODE: r = (1-r) * 0.2f; viewLp.setVerticalOffset(Math.round(stackDirection * r * mSlideAmount)); highlightLp.setVerticalOffset(Math.round(stackDirection * r * mSlideAmount)); @@ -735,12 +745,10 @@ public class StackView extends AdapterViewAnimator { public void onRemoteAdapterConnected() { super.onRemoteAdapterConnected(); // On first run, we want to set the stack to the end. - if (mAdapter != null && mWhichChild == -1) { - mWhichChild = mAdapter.getCount() - 1; - } - if (mWhichChild >= 0) { - setDisplayedChild(mWhichChild); + if (mWhichChild == -1) { + mWhichChild = 0; } + setDisplayedChild(mWhichChild); } LayoutParams createOrReuseLayoutParams(View v) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index be056da..09563fc 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5018,6 +5018,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } mLayout = mHintLayout = null; + + // Since it depends on the value of mLayout + prepareCursorControllers(); } /** diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 224f9a5..0f482b7 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -51,8 +51,8 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; @@ -65,16 +65,16 @@ public final class BatteryStatsImpl extends BatteryStats { private static final String TAG = "BatteryStatsImpl"; private static final boolean DEBUG = false; private static final boolean DEBUG_HISTORY = false; - + // In-memory Parcel magic number, used to detect attempts to unmarshall bad data - private static final int MAGIC = 0xBA757475; // 'BATSTATS' + private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 52; // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; - + // No, really, THIS is the maximum number of items we will record in the history. private static final int MAX_MAX_HISTORY_ITEMS = 3000; @@ -82,9 +82,9 @@ public final class BatteryStatsImpl extends BatteryStats { // per uid; once the limit is reached, we batch the remaining wakelocks // in to one common name. private static final int MAX_WAKELOCKS_PER_UID = 30; - + private static final String BATCHED_WAKELOCK_NAME = "*overflow*"; - + private static int sNumSpeedSteps; private final JournaledFile mFile; @@ -147,9 +147,9 @@ public final class BatteryStatsImpl extends BatteryStats { // These are the objects that will want to do something when the device // is unplugged from power. final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>(); - + boolean mShuttingDown; - + long mHistoryBaseTime; boolean mHaveBatteryLevel = false; boolean mRecordingHistory = true; @@ -159,7 +159,7 @@ public final class BatteryStatsImpl extends BatteryStats { HistoryItem mHistoryLastEnd; HistoryItem mHistoryCache; final HistoryItem mHistoryCur = new HistoryItem(); - + int mStartCount; long mBatteryUptime; @@ -173,41 +173,41 @@ public final class BatteryStatsImpl extends BatteryStats { long mRealtime; long mRealtimeStart; long mLastRealtime; - + boolean mScreenOn; StopwatchTimer mScreenOnTimer; int mScreenBrightnessBin = -1; final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; - + Counter mInputEventCounter; - + boolean mPhoneOn; StopwatchTimer mPhoneOnTimer; - + boolean mAudioOn; StopwatchTimer mAudioOnTimer; - + boolean mVideoOn; StopwatchTimer mVideoOnTimer; - + int mPhoneSignalStrengthBin = -1; - final StopwatchTimer[] mPhoneSignalStrengthsTimer = + final StopwatchTimer[] mPhoneSignalStrengthsTimer = new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS]; StopwatchTimer mPhoneSignalScanningTimer; int mPhoneDataConnectionType = -1; - final StopwatchTimer[] mPhoneDataConnectionsTimer = + final StopwatchTimer[] mPhoneDataConnectionsTimer = new StopwatchTimer[NUM_DATA_CONNECTION_TYPES]; - + boolean mWifiOn; StopwatchTimer mWifiOnTimer; int mWifiOnUid = -1; boolean mGlobalWifiRunning; StopwatchTimer mGlobalWifiRunningTimer; - + boolean mBluetoothOn; StopwatchTimer mBluetoothOnTimer; @@ -256,15 +256,15 @@ public final class BatteryStatsImpl extends BatteryStats { /* * Holds a SamplingTimer associated with each kernel wakelock name being tracked. */ - private final HashMap<String, SamplingTimer> mKernelWakelockStats = + private final HashMap<String, SamplingTimer> mKernelWakelockStats = new HashMap<String, SamplingTimer>(); - + public Map<String, ? extends SamplingTimer> getKernelWakelockStats() { return mKernelWakelockStats; } - + private static int sKernelWakelockUpdateVersion = 0; - + private static final int[] PROC_WAKELOCKS_FORMAT = new int[] { Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count @@ -273,19 +273,19 @@ public final class BatteryStatsImpl extends BatteryStats { Process.PROC_TAB_TERM, Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime }; - + private final String[] mProcWakelocksName = new String[3]; private final long[] mProcWakelocksData = new long[3]; - + /* * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added * to mKernelWakelockStats. */ - private final Map<String, KernelWakelockStats> mProcWakelockFileStats = + private final Map<String, KernelWakelockStats> mProcWakelockFileStats = new HashMap<String, KernelWakelockStats>(); private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>(); - + // For debugging public BatteryStatsImpl() { mFile = null; @@ -296,7 +296,7 @@ public final class BatteryStatsImpl extends BatteryStats { void unplug(long batteryUptime, long batteryRealtime); void plug(long batteryUptime, long batteryRealtime); } - + /** * State for keeping track of counting information. */ @@ -307,7 +307,7 @@ public final class BatteryStatsImpl extends BatteryStats { int mLastCount; int mUnpluggedCount; int mPluggedCount; - + Counter(ArrayList<Unpluggable> unpluggables, Parcel in) { mUnpluggables = unpluggables; mPluggedCount = in.readInt(); @@ -322,7 +322,7 @@ public final class BatteryStatsImpl extends BatteryStats { mUnpluggables = unpluggables; unpluggables.add(this); } - + public void writeToParcel(Parcel out) { out.writeInt(mCount.get()); out.writeInt(mLoadedCount); @@ -337,7 +337,7 @@ public final class BatteryStatsImpl extends BatteryStats { public void plug(long batteryUptime, long batteryRealtime) { mPluggedCount = mCount.get(); } - + /** * Writes a possibly null Counter to a Parcel. * @@ -377,7 +377,7 @@ public final class BatteryStatsImpl extends BatteryStats { + " mUnpluggedCount=" + mUnpluggedCount + " mPluggedCount=" + mPluggedCount); } - + void stepAtomic() { mCount.incrementAndGet(); } @@ -392,11 +392,11 @@ public final class BatteryStatsImpl extends BatteryStats { detach(); } } - + void detach() { mUnpluggables.remove(this); } - + void writeSummaryFromParcelLocked(Parcel out) { int count = mCount.get(); out.writeInt(count); @@ -431,41 +431,41 @@ public final class BatteryStatsImpl extends BatteryStats { public static abstract class Timer extends BatteryStats.Timer implements Unpluggable { final int mType; final ArrayList<Unpluggable> mUnpluggables; - + int mCount; int mLoadedCount; int mLastCount; int mUnpluggedCount; - + // Times are in microseconds for better accuracy when dividing by the // lock count, and are in "battery realtime" units. - + /** * The total time we have accumulated since the start of the original * boot, to the last time something interesting happened in the * current run. */ long mTotalTime; - + /** * The total time we loaded for the previous runs. Subtract this from * mTotalTime to find the time for the current run of the system. */ long mLoadedTime; - + /** * The run time of the last run of the system, as loaded from the * saved data. */ long mLastTime; - + /** * The value of mTotalTime when unplug() was last called. Subtract * this from mTotalTime to find the time since the last unplug from * power. */ long mUnpluggedTime; - + /** * Constructs from a parcel. * @param type @@ -476,7 +476,7 @@ public final class BatteryStatsImpl extends BatteryStats { Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) { mType = type; mUnpluggables = unpluggables; - + mCount = in.readInt(); mLoadedCount = in.readInt(); mLastCount = 0; @@ -495,9 +495,9 @@ public final class BatteryStatsImpl extends BatteryStats { } protected abstract long computeRunTimeLocked(long curBatteryRealtime); - + protected abstract int computeCurrentCountLocked(); - + /** * Clear state of this timer. Returns true if the timer is inactive * so can be completely dropped. @@ -510,11 +510,11 @@ public final class BatteryStatsImpl extends BatteryStats { } return true; } - + void detach() { mUnpluggables.remove(this); } - + public void writeToParcel(Parcel out, long batteryRealtime) { out.writeInt(mCount); out.writeInt(mLoadedCount); @@ -551,7 +551,7 @@ public final class BatteryStatsImpl extends BatteryStats { + ": new mTotalTime=" + mTotalTime); } } - + /** * Writes a possibly null Timer to a Parcel. * @@ -612,8 +612,8 @@ public final class BatteryStatsImpl extends BatteryStats { pw.println(prefix + "mLastTime=" + mLastTime + " mUnpluggedTime=" + mUnpluggedTime); } - - + + void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { long runTime = computeRunTimeLocked(batteryRealtime); // Divide by 1000 for backwards compatibility @@ -631,9 +631,9 @@ public final class BatteryStatsImpl extends BatteryStats { mUnpluggedCount = mCount; } } - + public static final class SamplingTimer extends Timer { - + /** * The most recent reported count from /proc/wakelocks. */ @@ -647,7 +647,7 @@ public final class BatteryStatsImpl extends BatteryStats { /** * The most recent reported total_time from /proc/wakelocks. - */ + */ long mCurrentReportedTotalTime; @@ -666,12 +666,12 @@ public final class BatteryStatsImpl extends BatteryStats { * Whether we are currently recording reported values. */ boolean mTrackingReportedValues; - + /* * A sequnce counter, incremented once for each update of the stats. */ int mUpdateVersion; - + SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) { super(0, unpluggables, in); mCurrentReportedCount = in.readInt(); @@ -681,28 +681,28 @@ public final class BatteryStatsImpl extends BatteryStats { mTrackingReportedValues = in.readInt() == 1; mInDischarge = inDischarge; } - - SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, + + SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, boolean trackReportedValues) { super(0, unpluggables); mTrackingReportedValues = trackReportedValues; mInDischarge = inDischarge; } - + public void setStale() { mTrackingReportedValues = false; mUnpluggedReportedTotalTime = 0; mUnpluggedReportedCount = 0; } - + public void setUpdateVersion(int version) { mUpdateVersion = version; } - + public int getUpdateVersion() { return mUpdateVersion; } - + public void updateCurrentReportedCount(int count) { if (mInDischarge && mUnpluggedReportedCount == 0) { // Updating the reported value for the first time. @@ -712,7 +712,7 @@ public final class BatteryStatsImpl extends BatteryStats { } mCurrentReportedCount = count; } - + public void updateCurrentReportedTotalTime(long totalTime) { if (mInDischarge && mUnpluggedReportedTotalTime == 0) { // Updating the reported value for the first time. @@ -722,7 +722,7 @@ public final class BatteryStatsImpl extends BatteryStats { } mCurrentReportedTotalTime = totalTime; } - + public void unplug(long batteryUptime, long batteryRealtime) { super.unplug(batteryUptime, batteryRealtime); if (mTrackingReportedValues) { @@ -736,25 +736,25 @@ public final class BatteryStatsImpl extends BatteryStats { super.plug(batteryUptime, batteryRealtime); mInDischarge = false; } - + public void logState(Printer pw, String prefix) { super.logState(pw, prefix); - pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount + pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount + " mUnpluggedReportedCount=" + mUnpluggedReportedCount + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime); } - + protected long computeRunTimeLocked(long curBatteryRealtime) { - return mTotalTime + (mInDischarge && mTrackingReportedValues + return mTotalTime + (mInDischarge && mTrackingReportedValues ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0); } - + protected int computeCurrentCountLocked() { return mCount + (mInDischarge && mTrackingReportedValues ? mCurrentReportedCount - mUnpluggedReportedCount : 0); } - + public void writeToParcel(Parcel out, long batteryRealtime) { super.writeToParcel(out, batteryRealtime); out.writeInt(mCurrentReportedCount); @@ -763,13 +763,13 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(mUnpluggedReportedTotalTime); out.writeInt(mTrackingReportedValues ? 1 : 0); } - + boolean reset(BatteryStatsImpl stats, boolean detachIfReset) { super.reset(stats, detachIfReset); setStale(); return true; } - + void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { super.writeSummaryFromParcelLocked(out, batteryRealtime); out.writeLong(mCurrentReportedTotalTime); @@ -784,7 +784,7 @@ public final class BatteryStatsImpl extends BatteryStats { mTrackingReportedValues = in.readInt() == 1; } } - + /** * State for keeping track of timing information. */ @@ -800,7 +800,7 @@ public final class BatteryStatsImpl extends BatteryStats { * time we have been running since we last computed an update. */ long mUpdateTime; - + /** * The total time at which the timer was acquired, to determine if it * was actually held for an interesting duration. @@ -829,7 +829,7 @@ public final class BatteryStatsImpl extends BatteryStats { mUid = uid; mTimerPool = timerPool; } - + void setTimeout(long timeout) { mTimeout = timeout; } @@ -857,7 +857,7 @@ public final class BatteryStatsImpl extends BatteryStats { pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime + " mAcquireTime=" + mAcquireTime); } - + void startRunningLocked(BatteryStatsImpl stats) { if (mNesting++ == 0) { mUpdateTime = stats.getBatteryRealtimeLocked( @@ -897,19 +897,19 @@ public final class BatteryStatsImpl extends BatteryStats { // Remove this timer from the active pool mTimerPool.remove(this); } else { - final long realtime = SystemClock.elapsedRealtime() * 1000; + final long realtime = SystemClock.elapsedRealtime() * 1000; final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime); mNesting = 1; mTotalTime = computeRunTimeLocked(batteryRealtime); mNesting = 0; } - + if (DEBUG && mType < 0) { Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime + " mTotalTime=" + mTotalTime + " mCount=" + mCount + " mAcquireTime=" + mAcquireTime); } - + if (mTotalTime == mAcquireTime) { // If there was no change in the time, then discard this // count. A somewhat cheezy strategy, but hey. @@ -922,7 +922,7 @@ public final class BatteryStatsImpl extends BatteryStats { // due to a change in timer count private static void refreshTimersLocked(final BatteryStatsImpl stats, final ArrayList<StopwatchTimer> pool) { - final long realtime = SystemClock.elapsedRealtime() * 1000; + final long realtime = SystemClock.elapsedRealtime() * 1000; final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime); final int N = pool.size(); for (int i=N-1; i>= 0; i--) { @@ -961,25 +961,25 @@ public final class BatteryStatsImpl extends BatteryStats { mAcquireTime = mTotalTime; return canDetach; } - + void detach() { super.detach(); if (mTimerPool != null) { mTimerPool.remove(this); } } - + void readSummaryFromParcelLocked(Parcel in) { super.readSummaryFromParcelLocked(in); mNesting = 0; } } - + private final Map<String, KernelWakelockStats> readKernelWakelockStats() { - + byte[] buffer = new byte[8192]; int len; - + try { FileInputStream is = new FileInputStream("/proc/wakelocks"); len = is.read(buffer); @@ -999,10 +999,10 @@ public final class BatteryStatsImpl extends BatteryStats { } catch (java.io.IOException e) { return null; } - + return parseProcWakelocks(buffer, len); } - + private final Map<String, KernelWakelockStats> parseProcWakelocks( byte[] wlBuffer, int len) { String name; @@ -1018,11 +1018,11 @@ public final class BatteryStatsImpl extends BatteryStats { synchronized(this) { Map<String, KernelWakelockStats> m = mProcWakelockFileStats; - + sKernelWakelockUpdateVersion++; while (endIndex < len) { - for (endIndex=startIndex; - endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; + for (endIndex=startIndex; + endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; endIndex++); endIndex++; // endIndex is an exclusive upper bound. // Don't go over the end of the buffer, Process.parseProcLine might @@ -1049,7 +1049,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (parsed && name.length() > 0) { if (!m.containsKey(name)) { - m.put(name, new KernelWakelockStats(count, totalTime, + m.put(name, new KernelWakelockStats(count, totalTime, sKernelWakelockUpdateVersion)); numUpdatedWlNames++; } else { @@ -1080,27 +1080,27 @@ public final class BatteryStatsImpl extends BatteryStats { return m; } } - + private class KernelWakelockStats { public int mCount; public long mTotalTime; public int mVersion; - + KernelWakelockStats(int count, long totalTime, int version) { mCount = count; mTotalTime = totalTime; mVersion = version; } } - + /* - * Get the KernelWakelockTimer associated with name, and create a new one if one + * Get the KernelWakelockTimer associated with name, and create a new one if one * doesn't already exist. */ public SamplingTimer getKernelWakelockTimerLocked(String name) { SamplingTimer kwlt = mKernelWakelockStats.get(name); if (kwlt == null) { - kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, + kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, true /* track reported values */); mKernelWakelockStats.put(name, kwlt); } @@ -1144,7 +1144,7 @@ public final class BatteryStatsImpl extends BatteryStats { } /** - * Returns the duration that the cell radio was up for data transfers. + * Returns the duration that the cell radio was up for data transfers. */ public long getRadioDataUptime() { if (mRadioDataStart == -1) { @@ -1156,10 +1156,9 @@ public final class BatteryStatsImpl extends BatteryStats { private int getCurrentBluetoothPingCount() { if (mBtHeadset != null) { - Set<BluetoothDevice> deviceSet = mBtHeadset.getConnectedDevices(); - BluetoothDevice[] devices = deviceSet.toArray(new BluetoothDevice[deviceSet.size()]); - if (devices.length > 0) { - return mBtHeadset.getBatteryUsageHint(devices[0]); + List<BluetoothDevice> deviceList = mBtHeadset.getConnectedDevices(); + if (deviceList.size() > 0) { + return mBtHeadset.getBatteryUsageHint(deviceList.get(0)); } } return -1; @@ -1234,7 +1233,7 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE); } - + void addHistoryRecordLocked(long curTime, byte cmd) { HistoryItem rec = mHistoryCache; if (rec != null) { @@ -1243,10 +1242,10 @@ public final class BatteryStatsImpl extends BatteryStats { rec = new HistoryItem(); } rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur); - + addHistoryRecordLocked(rec); } - + void addHistoryRecordLocked(HistoryItem rec) { mNumHistoryItems++; rec.next = null; @@ -1258,7 +1257,7 @@ public final class BatteryStatsImpl extends BatteryStats { mHistory = mHistoryEnd = rec; } } - + void clearHistoryLocked() { if (mHistory != null) { mHistoryEnd.next = mHistoryCache; @@ -1268,7 +1267,7 @@ public final class BatteryStatsImpl extends BatteryStats { mNumHistoryItems = 0; mHistoryBaseTime = 0; } - + public void doUnplugLocked(long batteryUptime, long batteryRealtime) { for (int iu = mUidStats.size() - 1; iu >= 0; iu--) { Uid u = mUidStats.valueAt(iu); @@ -1532,7 +1531,7 @@ public final class BatteryStatsImpl extends BatteryStats { } int mGpsNesting; - + public void noteStartGpsLocked(int uid) { if (mGpsNesting == 0) { mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG; @@ -1543,7 +1542,7 @@ public final class BatteryStatsImpl extends BatteryStats { mGpsNesting++; getUidStatsLocked(uid).noteStartGps(); } - + public void noteStopGpsLocked(int uid) { mGpsNesting--; if (mGpsNesting == 0) { @@ -1572,7 +1571,7 @@ public final class BatteryStatsImpl extends BatteryStats { noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL); } } - + public void noteScreenOffLocked() { if (mScreenOn) { mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG; @@ -1588,7 +1587,7 @@ public final class BatteryStatsImpl extends BatteryStats { noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL); } } - + public void noteScreenBrightnessLocked(int brightness) { // Bin the brightness. int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS); @@ -1609,15 +1608,15 @@ public final class BatteryStatsImpl extends BatteryStats { mScreenBrightnessBin = bin; } } - + public void noteInputEventAtomic() { mInputEventCounter.stepAtomic(); } - + public void noteUserActivityLocked(int uid, int event) { getUidStatsLocked(uid).noteUserActivityLocked(event); } - + public void notePhoneOnLocked() { if (!mPhoneOn) { mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG; @@ -1628,7 +1627,7 @@ public final class BatteryStatsImpl extends BatteryStats { mPhoneOnTimer.startRunningLocked(this); } } - + public void notePhoneOffLocked() { if (mPhoneOn) { mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG; @@ -1688,7 +1687,7 @@ public final class BatteryStatsImpl extends BatteryStats { mPhoneSignalScanningTimer.startRunningLocked(this); } } - + if (!scanning) { // If we are no longer scanning, then stop the scanning timer. if (mPhoneSignalScanningTimer.isRunningLocked()) { @@ -1746,7 +1745,7 @@ public final class BatteryStatsImpl extends BatteryStats { mPhoneSignalStrengthsTimer[bin].startRunningLocked(this); } } - + public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) { int bin = DATA_CONNECTION_NONE; if (hasData) { @@ -1806,7 +1805,7 @@ public final class BatteryStatsImpl extends BatteryStats { mPhoneDataConnectionsTimer[bin].startRunningLocked(this); } } - + public void noteWifiOnLocked() { if (!mWifiOn) { mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG; @@ -1817,7 +1816,7 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiOnTimer.startRunningLocked(this); } } - + public void noteWifiOffLocked() { if (mWifiOn) { mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG; @@ -1844,7 +1843,7 @@ public final class BatteryStatsImpl extends BatteryStats { } getUidStatsLocked(uid).noteAudioTurnedOnLocked(); } - + public void noteAudioOffLocked(int uid) { if (mAudioOn) { mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG; @@ -1868,7 +1867,7 @@ public final class BatteryStatsImpl extends BatteryStats { } getUidStatsLocked(uid).noteVideoTurnedOnLocked(); } - + public void noteVideoOffLocked(int uid) { if (mVideoOn) { mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG; @@ -1940,7 +1939,7 @@ public final class BatteryStatsImpl extends BatteryStats { mBluetoothOnTimer.startRunningLocked(this); } } - + public void noteBluetoothOffLocked() { if (mBluetoothOn) { mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG; @@ -1951,9 +1950,9 @@ public final class BatteryStatsImpl extends BatteryStats { mBluetoothOnTimer.stopRunningLocked(this); } } - + int mWifiFullLockNesting = 0; - + public void noteFullWifiLockAcquiredLocked(int uid) { if (mWifiFullLockNesting == 0) { mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG; @@ -1977,7 +1976,7 @@ public final class BatteryStatsImpl extends BatteryStats { } int mWifiScanLockNesting = 0; - + public void noteScanWifiLockAcquiredLocked(int uid) { if (mWifiScanLockNesting == 0) { mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_LOCK_FLAG; @@ -2001,7 +2000,7 @@ public final class BatteryStatsImpl extends BatteryStats { } int mWifiMulticastNesting = 0; - + public void noteWifiMulticastEnabledLocked(int uid) { if (mWifiMulticastNesting == 0) { mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG; @@ -2069,7 +2068,7 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public long getScreenOnTime(long batteryRealtime, int which) { return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which); } - + @Override public long getScreenBrightnessTime(int brightnessBin, long batteryRealtime, int which) { return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked( @@ -2079,7 +2078,7 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public int getInputEventCount(int which) { return mInputEventCounter.getCountLocked(which); } - + @Override public long getPhoneOnTime(long batteryRealtime, int which) { return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which); } @@ -2099,21 +2098,21 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public int getPhoneSignalStrengthCount(int dataType, int which) { return mPhoneDataConnectionsTimer[dataType].getCountLocked(which); } - + @Override public long getPhoneDataConnectionTime(int dataType, long batteryRealtime, int which) { return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked( batteryRealtime, which); } - + @Override public int getPhoneDataConnectionCount(int dataType, int which) { return mPhoneDataConnectionsTimer[dataType].getCountLocked(which); } - + @Override public long getWifiOnTime(long batteryRealtime, int which) { return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which); } - + @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) { return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which); } @@ -2121,11 +2120,11 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public long getBluetoothOnTime(long batteryRealtime, int which) { return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which); } - + @Override public boolean getIsOnBattery() { return mOnBattery; } - + @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() { return mUidStats; } @@ -2134,7 +2133,7 @@ public final class BatteryStatsImpl extends BatteryStats { * The statistics associated with a particular uid. */ public final class Uid extends BatteryStats.Uid { - + final int mUid; long mLoadedTcpBytesReceived; long mLoadedTcpBytesSent; @@ -2142,32 +2141,32 @@ public final class BatteryStatsImpl extends BatteryStats { long mCurrentTcpBytesSent; long mTcpBytesReceivedAtLastUnplug; long mTcpBytesSentAtLastUnplug; - + // These are not saved/restored when parcelling, since we want // to return from the parcel with a snapshot of the state. long mStartedTcpBytesReceived = -1; long mStartedTcpBytesSent = -1; - + boolean mWifiRunning; StopwatchTimer mWifiRunningTimer; - + boolean mFullWifiLockOut; StopwatchTimer mFullWifiLockTimer; - + boolean mScanWifiLockOut; StopwatchTimer mScanWifiLockTimer; - + boolean mWifiMulticastEnabled; StopwatchTimer mWifiMulticastTimer; - + boolean mAudioTurnedOn; StopwatchTimer mAudioTurnedOnTimer; - + boolean mVideoTurnedOn; StopwatchTimer mVideoTurnedOnTimer; Counter[] mUserActivityCounters; - + /** * The statistics we have collected for this uid's wake locks. */ @@ -2187,7 +2186,7 @@ public final class BatteryStatsImpl extends BatteryStats { * The statistics we have collected for this uid's processes. */ final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>(); - + /** * The transient wake stats we have collected for this uid's pids. */ @@ -2248,7 +2247,7 @@ public final class BatteryStatsImpl extends BatteryStats { return current; } } - + public long computeCurrentTcpBytesReceived() { return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0 ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0); @@ -2268,7 +2267,7 @@ public final class BatteryStatsImpl extends BatteryStats { return current; } } - + @Override public void noteWifiRunningLocked() { if (!mWifiRunning) { @@ -2280,7 +2279,7 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this); } } - + @Override public void noteWifiStoppedLocked() { if (mWifiRunning) { @@ -2288,7 +2287,7 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this); } } - + @Override public void noteFullWifiLockAcquiredLocked() { if (!mFullWifiLockOut) { @@ -2300,7 +2299,7 @@ public final class BatteryStatsImpl extends BatteryStats { mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this); } } - + @Override public void noteFullWifiLockReleasedLocked() { if (mFullWifiLockOut) { @@ -2308,7 +2307,7 @@ public final class BatteryStatsImpl extends BatteryStats { mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this); } } - + @Override public void noteScanWifiLockAcquiredLocked() { if (!mScanWifiLockOut) { @@ -2320,7 +2319,7 @@ public final class BatteryStatsImpl extends BatteryStats { mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this); } } - + @Override public void noteScanWifiLockReleasedLocked() { if (mScanWifiLockOut) { @@ -2389,7 +2388,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - @Override + @Override public long getWifiRunningTime(long batteryRealtime, int which) { if (mWifiRunningTimer == null) { return 0; @@ -2397,15 +2396,15 @@ public final class BatteryStatsImpl extends BatteryStats { return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which); } - @Override + @Override public long getFullWifiLockTime(long batteryRealtime, int which) { if (mFullWifiLockTimer == null) { return 0; } return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which); } - - @Override + + @Override public long getScanWifiLockTime(long batteryRealtime, int which) { if (mScanWifiLockTimer == null) { return 0; @@ -2422,7 +2421,7 @@ public final class BatteryStatsImpl extends BatteryStats { which); } - @Override + @Override public long getAudioTurnedOnTime(long batteryRealtime, int which) { if (mAudioTurnedOnTimer == null) { return 0; @@ -2430,7 +2429,7 @@ public final class BatteryStatsImpl extends BatteryStats { return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which); } - @Override + @Override public long getVideoTurnedOnTime(long batteryRealtime, int which) { if (mVideoTurnedOnTimer == null) { return 0; @@ -2447,12 +2446,12 @@ public final class BatteryStatsImpl extends BatteryStats { else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1; mUserActivityCounters[type].stepAtomic(); } - + @Override public boolean hasUserActivity() { return mUserActivityCounters != null; } - + @Override public int getUserActivityCount(int type, int which) { if (mUserActivityCounters == null) { @@ -2460,14 +2459,14 @@ public final class BatteryStatsImpl extends BatteryStats { } return mUserActivityCounters[type].getCountLocked(which); } - + void initUserActivityLocked() { mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES]; for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) { mUserActivityCounters[i] = new Counter(mUnpluggables); } } - + public long computeCurrentTcpBytesSent() { return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0 ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0); @@ -2479,7 +2478,7 @@ public final class BatteryStatsImpl extends BatteryStats { */ boolean reset() { boolean active = false; - + if (mWifiRunningTimer != null) { active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false); active |= mWifiRunning; @@ -2504,10 +2503,10 @@ public final class BatteryStatsImpl extends BatteryStats { active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false); active |= mVideoTurnedOn; } - + mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0; mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0; - + if (mUserActivityCounters != null) { for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) { mUserActivityCounters[i].reset(false); @@ -2571,7 +2570,7 @@ public final class BatteryStatsImpl extends BatteryStats { } mPackageStats.clear(); } - + mPids.clear(); if (!active) { @@ -2599,10 +2598,10 @@ public final class BatteryStatsImpl extends BatteryStats { } } } - + return !active; } - + void writeToParcelLocked(Parcel out, long batteryRealtime) { out.writeInt(mWakelockStats.size()); for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) { @@ -2631,7 +2630,7 @@ public final class BatteryStatsImpl extends BatteryStats { Uid.Pkg pkg = pkgEntry.getValue(); pkg.writeToParcelLocked(out); } - + out.writeLong(mLoadedTcpBytesReceived); out.writeLong(mLoadedTcpBytesSent); out.writeLong(computeCurrentTcpBytesReceived()); @@ -2725,7 +2724,7 @@ public final class BatteryStatsImpl extends BatteryStats { pkg.readFromParcelLocked(in); mPackageStats.put(packageName, pkg); } - + mLoadedTcpBytesReceived = in.readLong(); mLoadedTcpBytesSent = in.readLong(); mCurrentTcpBytesReceived = in.readLong(); @@ -2846,7 +2845,7 @@ public final class BatteryStatsImpl extends BatteryStats { } return !wlactive; } - + void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) { mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL, mPartialTimers, unpluggables, in); @@ -2876,7 +2875,7 @@ public final class BatteryStatsImpl extends BatteryStats { public final class Sensor extends BatteryStats.Uid.Sensor { final int mHandle; StopwatchTimer mTimer; - + public Sensor(int handle) { mHandle = handle; } @@ -2902,7 +2901,7 @@ public final class BatteryStatsImpl extends BatteryStats { } return false; } - + void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) { mTimer = readTimerFromParcel(unpluggables, in); } @@ -3024,7 +3023,7 @@ public final class BatteryStatsImpl extends BatteryStats { public void plug(long batteryUptime, long batteryRealtime) { } - + void detach() { mUnpluggables.remove(this); for (int i = 0; i < mSpeedBins.length; i++) { @@ -3035,7 +3034,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } } - + public int countExcessivePowers() { return mExcessivePower != null ? mExcessivePower.size() : 0; } @@ -3302,18 +3301,18 @@ public final class BatteryStatsImpl extends BatteryStats { Pkg() { mUnpluggables.add(this); } - + public void unplug(long batteryUptime, long batteryRealtime) { mUnpluggedWakeups = mWakeups; } public void plug(long batteryUptime, long batteryRealtime) { } - + void detach() { mUnpluggables.remove(this); } - + void readFromParcelLocked(Parcel in) { mWakeups = in.readInt(); mLoadedWakeups = in.readInt(); @@ -3464,7 +3463,7 @@ public final class BatteryStatsImpl extends BatteryStats { Serv() { mUnpluggables.add(this); } - + public void unplug(long batteryUptime, long batteryRealtime) { mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime); mUnpluggedStarts = mStarts; @@ -3473,11 +3472,11 @@ public final class BatteryStatsImpl extends BatteryStats { public void plug(long batteryUptime, long batteryRealtime) { } - + void detach() { mUnpluggables.remove(this); } - + void readFromParcelLocked(Parcel in) { mStartTime = in.readLong(); mRunningSince = in.readLong(); @@ -3652,7 +3651,7 @@ public final class BatteryStatsImpl extends BatteryStats { public SparseArray<? extends Pid> getPidStats() { return mPids; } - + public Pid getPidStatsLocked(int pid) { Pid p = mPids.get(pid); if (p == null) { @@ -3790,7 +3789,7 @@ public final class BatteryStatsImpl extends BatteryStats { p.addExcessiveWake(overTime, usedTime); } } - + public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) { Proc p = getProcessStatsLocked(proc); if (p != null) { @@ -3802,7 +3801,7 @@ public final class BatteryStatsImpl extends BatteryStats { StopwatchTimer t = getSensorTimerLocked(sensor, true); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); - } + } } public void noteStopSensor(int sensor) { @@ -3810,16 +3809,16 @@ public final class BatteryStatsImpl extends BatteryStats { StopwatchTimer t = getSensorTimerLocked(sensor, false); if (t != null) { t.stopRunningLocked(BatteryStatsImpl.this); - } + } } - + public void noteStartGps() { StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); - } + } } - + public void noteStopGps() { StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false); if (t != null) { @@ -3909,12 +3908,12 @@ public final class BatteryStatsImpl extends BatteryStats { public HistoryItem getHistory() { return mHistory; } - + @Override public long getHistoryBaseTime() { return mHistoryBaseTime; } - + @Override public int getStartCount() { return mStartCount; @@ -3936,7 +3935,7 @@ public final class BatteryStatsImpl extends BatteryStats { mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart); mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart); } - + public void resetAllStatsLocked() { mStartCount = 0; initTimes(); @@ -3958,24 +3957,24 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiOnTimer.reset(this, false); mGlobalWifiRunningTimer.reset(this, false); mBluetoothOnTimer.reset(this, false); - + for (int i=0; i<mUidStats.size(); i++) { if (mUidStats.valueAt(i).reset()) { mUidStats.remove(mUidStats.keyAt(i)); i--; } } - + if (mKernelWakelockStats.size() > 0) { for (SamplingTimer timer : mKernelWakelockStats.values()) { mUnpluggables.remove(timer); } mKernelWakelockStats.clear(); } - + clearHistoryLocked(); } - + void setOnBattery(boolean onBattery, int oldStatus, int level) { synchronized(this) { boolean doWrite = false; @@ -3983,7 +3982,7 @@ public final class BatteryStatsImpl extends BatteryStats { m.arg1 = onBattery ? 1 : 0; mHandler.sendMessage(m); mOnBattery = mOnBatteryInternal = onBattery; - + long uptime = SystemClock.uptimeMillis() * 1000; long mSecRealtime = SystemClock.elapsedRealtime(); long realtime = mSecRealtime * 1000; @@ -4036,10 +4035,10 @@ public final class BatteryStatsImpl extends BatteryStats { } } } - + // This should probably be exposed in the API, though it's not critical private static final int BATTERY_PLUGGED_NONE = 0; - + public void setBatteryState(int status, int health, int plugType, int level, int temp, int volt) { boolean onBattery = plugType == BATTERY_PLUGGED_NONE; @@ -4107,10 +4106,10 @@ public final class BatteryStatsImpl extends BatteryStats { mRecordingHistory = false; } } - + public void updateKernelWakelocksLocked() { Map<String, KernelWakelockStats> m = readKernelWakelockStats(); - + if (m == null) { // Not crashing might make board bringup easier. Slog.w(TAG, "Couldn't get kernel wake lock stats"); @@ -4120,10 +4119,10 @@ public final class BatteryStatsImpl extends BatteryStats { for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) { String name = ent.getKey(); KernelWakelockStats kws = ent.getValue(); - + SamplingTimer kwlt = mKernelWakelockStats.get(name); if (kwlt == null) { - kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, + kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, true /* track reported values */); mKernelWakelockStats.put(name, kwlt); } @@ -4131,7 +4130,7 @@ public final class BatteryStatsImpl extends BatteryStats { kwlt.updateCurrentReportedTotalTime(kws.mTotalTime); kwlt.setUpdateVersion(sKernelWakelockUpdateVersion); } - + if (m.size() != mKernelWakelockStats.size()) { // Set timers to stale if they didn't appear in /proc/wakelocks this time. for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) { @@ -4276,18 +4275,18 @@ public final class BatteryStatsImpl extends BatteryStats { return getDischargeStartLevelLocked(); } } - + public int getDischargeStartLevelLocked() { return mDischargeUnplugLevel; } - + @Override public int getDischargeCurrentLevel() { synchronized(this) { return getDischargeCurrentLevelLocked(); } } - + public int getDischargeCurrentLevelLocked() { return mDischargeCurrentLevel; } @@ -4430,7 +4429,7 @@ public final class BatteryStatsImpl extends BatteryStats { writeSyncLocked(); mShuttingDown = true; } - + Parcel mPendingWrite = null; final ReentrantLock mWriteLock = new ReentrantLock(); @@ -4451,7 +4450,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (mShuttingDown) { return; } - + Parcel out = Parcel.obtain(); writeSummaryToParcel(out); mLastWriteTime = SystemClock.elapsedRealtime(); @@ -4551,7 +4550,7 @@ public final class BatteryStatsImpl extends BatteryStats { } catch(java.io.IOException e) { Slog.e("BatteryStats", "Error reading battery statistics", e); } - + addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START); } @@ -4570,7 +4569,7 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryBaseTime = rec.time; } } - + long oldnow = SystemClock.elapsedRealtime() - (5*60*100); if (oldnow > 0) { // If the system process has restarted, but not the entire @@ -4582,7 +4581,7 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryBaseTime -= oldnow; } } - + void writeHistory(Parcel out) { HistoryItem rec = mHistory; while (rec != null) { @@ -4591,7 +4590,7 @@ public final class BatteryStatsImpl extends BatteryStats { } out.writeLong(-1); } - + private void readSummaryFromParcel(Parcel in) { final int version = in.readInt(); if (version != VERSION) { @@ -4601,7 +4600,7 @@ public final class BatteryStatsImpl extends BatteryStats { } readHistory(in); - + mStartCount = in.readInt(); mBatteryUptime = in.readLong(); mBatteryRealtime = in.readLong(); @@ -4611,9 +4610,9 @@ public final class BatteryStatsImpl extends BatteryStats { mDischargeCurrentLevel = in.readInt(); mLowDischargeAmountSinceCharge = in.readInt(); mHighDischargeAmountSinceCharge = in.readInt(); - + mStartCount++; - + mScreenOn = false; mScreenOnTimer.readSummaryFromParcelLocked(in); for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { @@ -4693,7 +4692,7 @@ public final class BatteryStatsImpl extends BatteryStats { u.mUserActivityCounters[i].readSummaryFromParcelLocked(in); } } - + int NW = in.readInt(); if (NW > 10000) { Slog.w(TAG, "File corrupt: too many wake locks " + NW); @@ -4786,7 +4785,7 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(VERSION); writeHistory(out); - + out.writeInt(mStartCount); out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED)); out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED)); @@ -4796,7 +4795,7 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(mDischargeCurrentLevel); out.writeInt(mLowDischargeAmountSinceCharge); out.writeInt(mHighDischargeAmountSinceCharge); - + mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL); @@ -4825,14 +4824,14 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } } - + out.writeInt(sNumSpeedSteps); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { out.writeInt(mUidStats.keyAt(iu)); Uid u = mUidStats.valueAt(iu); - + if (u.mWifiRunningTimer != null) { out.writeInt(1); u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL); @@ -4878,7 +4877,7 @@ public final class BatteryStatsImpl extends BatteryStats { u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out); } } - + int NW = u.mWakelockStats.size(); out.writeInt(NW); if (NW > 0) { @@ -4970,7 +4969,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } } - + out.writeLong(u.getTcpBytesReceived(STATS_SINCE_CHARGED)); out.writeLong(u.getTcpBytesSent(STATS_SINCE_CHARGED)); } @@ -4979,7 +4978,7 @@ public final class BatteryStatsImpl extends BatteryStats { public void readFromParcel(Parcel in) { readFromParcelLocked(in); } - + void readFromParcelLocked(Parcel in) { int magic = in.readInt(); if (magic != MAGIC) { @@ -4987,7 +4986,7 @@ public final class BatteryStatsImpl extends BatteryStats { } readHistory(in); - + mStartCount = in.readInt(); mBatteryUptime = in.readLong(); mBatteryLastUptime = 0; @@ -5062,7 +5061,7 @@ public final class BatteryStatsImpl extends BatteryStats { mKernelWakelockStats.put(wakelockName, kwlt); } } - + mPartialTimers.clear(); mFullTimers.clear(); mWindowTimers.clear(); @@ -5090,18 +5089,18 @@ public final class BatteryStatsImpl extends BatteryStats { public void writeToParcelWithoutUids(Parcel out, int flags) { writeToParcelLocked(out, false, flags); } - - @SuppressWarnings("unused") + + @SuppressWarnings("unused") void writeToParcelLocked(Parcel out, boolean inclUids, int flags) { final long uSecUptime = SystemClock.uptimeMillis() * 1000; final long uSecRealtime = SystemClock.elapsedRealtime() * 1000; final long batteryUptime = getBatteryUptimeLocked(uSecUptime); final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime); - + out.writeInt(MAGIC); - + writeHistory(out); - + out.writeInt(mStartCount); out.writeLong(mBatteryUptime); out.writeLong(mBatteryRealtime); @@ -5190,7 +5189,7 @@ public final class BatteryStatsImpl extends BatteryStats { return new BatteryStatsImpl[size]; } }; - + public void dumpLocked(PrintWriter pw) { if (DEBUG) { Printer pr = new PrintWriterPrinter(pw); diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java index d381901..b54daba 100644 --- a/core/java/com/android/internal/view/StandaloneActionMode.java +++ b/core/java/com/android/internal/view/StandaloneActionMode.java @@ -87,7 +87,6 @@ public class StandaloneActionMode extends ActionMode implements MenuBuilder.Call mFinished = true; mCallback.onDestroyActionMode(this); - mContextView.setVisibility(View.GONE); } @Override diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java index 5d66372..38f76d3 100644 --- a/core/java/com/android/internal/widget/ActionBarContextView.java +++ b/core/java/com/android/internal/widget/ActionBarContextView.java @@ -213,7 +213,7 @@ public class ActionBarContextView extends ViewGroup { } final int heightMode = MeasureSpec.getMode(heightMeasureSpec); - if (heightMode != MeasureSpec.AT_MOST) { + if (heightMode == MeasureSpec.UNSPECIFIED) { throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + "with android:layout_height=\"wrap_content\""); } diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index f8a80b0..8956e39 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -256,20 +256,20 @@ static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) { #ifdef USE_OPENGL_RENDERER
if (android::uirenderer::Caches::hasInstance()) {
android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
+ return;
}
-#else // !USE_OPENGL_RENDERER
+#endif // USE_OPENGL_RENDERER
delete bitmap;
-#endif
}
static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
#ifdef USE_OPENGL_RENDERER
if (android::uirenderer::Caches::hasInstance()) {
android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
+ return;
}
-#else // !USE_OPENGL_RENDERER
- bitmap->setPixels(NULL, NULL);
#endif // USE_OPENGL_RENDERER
+ bitmap->setPixels(NULL, NULL);
}
// These must match the int values in Bitmap.java
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index f700791..bf18d55 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -65,6 +65,7 @@ static SkMemoryStream* buildSkMemoryStream(SkStream *stream) { } } data = (char*)sk_realloc_throw(data, streamLen); + SkMemoryStream* streamMem = new SkMemoryStream(); streamMem->setMemoryOwned(data, streamLen); return streamMem; @@ -133,6 +134,12 @@ static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz, } stream = fdStream; } else { + /* Restore our offset when we leave, so we can be called more than once + with the same descriptor. This is only required if we didn't dup the + file descriptor, but it is OK to do it all the time. + */ + AutoFDSeek as(descriptor); + SkFDStream* fdStream = new SkFDStream(descriptor, false); if (!fdStream->isValid()) { fdStream->unref(); @@ -142,12 +149,6 @@ static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz, fdStream->unref(); } - /* Restore our offset when we leave, so we can be called more than once - with the same descriptor. This is only required if we didn't dup the - file descriptor, but it is OK to do it all the time. - */ - AutoFDSeek as(descriptor); - return doBuildTileIndex(env, stream); } diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp index 6667756..b305506 100644 --- a/core/jni/android/graphics/Matrix.cpp +++ b/core/jni/android/graphics/Matrix.cpp @@ -35,10 +35,10 @@ public: #ifdef USE_OPENGL_RENDERER if (android::uirenderer::Caches::hasInstance()) { android::uirenderer::Caches::getInstance().resourceCache.destructor(obj); + return; } -#else // !USE_OPENGL_RENDERER +#endif // USE_OPENGL_RENDERER delete obj; -#endif } static SkMatrix* create(JNIEnv* env, jobject clazz, const SkMatrix* src) { diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 339c1a4..79a02f1 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -66,10 +66,10 @@ public: #ifdef USE_OPENGL_RENDERER if (android::uirenderer::Caches::hasInstance()) { android::uirenderer::Caches::getInstance().resourceCache.destructor(obj); + return; } -#else // !USE_OPENGL_RENDERER +#endif // USE_OPENGL_RENDERER delete obj; -#endif } static SkPaint* init(JNIEnv* env, jobject clazz) { diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index 63d3578..45fd5a0 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -626,7 +626,8 @@ static int mainWorkCallback(int fd, int events, void* data) { // ------------------------------------------------------------------------ static jint -loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue, +loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName, + jobject messageQueue, jstring internalDataDir, jstring externalDataDir, int sdkVersion, jobject jAssetMgr, jbyteArray savedState) { @@ -640,8 +641,11 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ env->ReleaseStringUTFChars(path, pathStr); if (handle != NULL) { + const char* funcStr = env->GetStringUTFChars(funcName, NULL); code = new NativeCode(handle, (ANativeActivity_createFunc*) - dlsym(handle, "ANativeActivity_onCreate")); + dlsym(handle, funcStr)); + env->ReleaseStringUTFChars(funcName, funcStr); + if (code->createActivityFunc == NULL) { LOGW("ANativeActivity_onCreate not found"); delete code; @@ -999,7 +1003,7 @@ finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, } static const JNINativeMethod g_methods[] = { - { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I", + { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I", (void*)loadNativeCode_native }, { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, { "onStartNative", "(I)V", (void*)onStart_native }, diff --git a/core/jni/android_nfc_NdefMessage.cpp b/core/jni/android_nfc_NdefMessage.cpp index 99295f4..eaf989d 100644 --- a/core/jni/android_nfc_NdefMessage.cpp +++ b/core/jni/android_nfc_NdefMessage.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "NdefMessage" +#include <stdlib.h> + #include "jni.h" #include "JNIHelp.h" diff --git a/core/jni/android_nfc_NdefRecord.cpp b/core/jni/android_nfc_NdefRecord.cpp index 9d20d6d..0a3a519 100644 --- a/core/jni/android_nfc_NdefRecord.cpp +++ b/core/jni/android_nfc_NdefRecord.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "NdefRecord" +#include <stdlib.h> + #include "jni.h" #include "JNIHelp.h" diff --git a/core/res/res/color/primary_text_holo_dark.xml b/core/res/res/color/primary_text_holo_dark.xml index 69ee309..6418664 100644 --- a/core/res/res/color/primary_text_holo_dark.xml +++ b/core/res/res/color/primary_text_holo_dark.xml @@ -15,10 +15,10 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" android:color="@android:color/bright_foreground_dark_disabled"/> - <item android:state_window_focused="false" android:color="@android:color/bright_foreground_dark"/> - <item android:state_pressed="true" android:color="@android:color/bright_foreground_dark"/> - <item android:state_selected="true" android:color="@android:color/bright_foreground_dark"/> - <item android:state_activated="true" android:color="@android:color/bright_foreground_dark"/> - <item android:color="@android:color/bright_foreground_dark"/> <!-- not selected --> + <item android:state_enabled="false" android:color="@android:color/bright_foreground_disabled_holo_dark"/> + <item android:state_window_focused="false" android:color="@android:color/bright_foreground_holo_dark"/> + <item android:state_pressed="true" android:color="@android:color/bright_foreground_holo_dark"/> + <item android:state_selected="true" android:color="@android:color/bright_foreground_holo_dark"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_dark"/> + <item android:color="@android:color/bright_foreground_holo_dark"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/primary_text_holo_light.xml b/core/res/res/color/primary_text_holo_light.xml index a8d31ce..86f8f86 100644 --- a/core/res/res/color/primary_text_holo_light.xml +++ b/core/res/res/color/primary_text_holo_light.xml @@ -15,12 +15,12 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" android:color="@android:color/bright_foreground_light_disabled"/> - <item android:state_window_focused="false" android:color="@android:color/bright_foreground_light"/> - <item android:state_pressed="true" android:color="@android:color/bright_foreground_light"/> - <item android:state_selected="true" android:color="@android:color/bright_foreground_light"/> - <item android:state_activated="true" android:color="@android:color/bright_foreground_light"/> - <item android:color="@android:color/bright_foreground_light"/> <!-- not selected --> + <item android:state_enabled="false" android:color="@android:color/bright_foreground_disabled_holo_light"/> + <item android:state_window_focused="false" android:color="@android:color/bright_foreground_holo_light"/> + <item android:state_pressed="true" android:color="@android:color/bright_foreground_holo_light"/> + <item android:state_selected="true" android:color="@android:color/bright_foreground_holo_light"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_light"/> + <item android:color="@android:color/bright_foreground_holo_light"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/secondary_text_holo_dark.xml b/core/res/res/color/secondary_text_holo_dark.xml index 376156e..881a1de 100644 --- a/core/res/res/color/secondary_text_holo_dark.xml +++ b/core/res/res/color/secondary_text_holo_dark.xml @@ -15,13 +15,13 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_disabled"/> - <item android:state_window_focused="false" android:color="@android:color/dim_foreground_dark"/> - <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/> - <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/> - <item android:state_selected="true" android:color="@android:color/dim_foreground_dark_inverse"/> - <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/> - <item android:state_pressed="true" android:color="@android:color/dim_foreground_dark_inverse"/> - <item android:state_enabled="false" android:color="@android:color/dim_foreground_dark_disabled"/> - <item android:color="@android:color/dim_foreground_dark"/> <!-- not selected --> + <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/> + <item android:state_window_focused="false" android:color="@android:color/dim_foreground_holo_dark"/> + <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_inverse_disabled_holo_dark"/> + <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_inverse_disabled_holo_dark"/> + <item android:state_selected="true" android:color="@android:color/dim_foreground_inverse_holo_dark"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_inverse_holo_dark"/> + <item android:state_pressed="true" android:color="@android:color/dim_foreground_inverse_holo_dark"/> + <item android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/> + <item android:color="@android:color/dim_foreground_holo_dark"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/secondary_text_holo_light.xml b/core/res/res/color/secondary_text_holo_light.xml index b791aeb..05721b2 100644 --- a/core/res/res/color/secondary_text_holo_light.xml +++ b/core/res/res/color/secondary_text_holo_light.xml @@ -15,14 +15,14 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/> - <item android:state_window_focused="false" android:color="@android:color/dim_foreground_light"/> + <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/> + <item android:state_window_focused="false" android:color="@android:color/dim_foreground_holo_light"/> <!-- Since there is only one selector (for both light and dark), the light's selected state shouldn't be inversed like the dark's. --> - <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/> - <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/> - <item android:state_pressed="true" android:color="@android:color/dim_foreground_light"/> - <item android:state_selected="true" android:color="@android:color/dim_foreground_light"/> - <item android:state_activated="true" android:color="@android:color/bright_foreground_light"/> - <item android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/> - <item android:color="@android:color/dim_foreground_light"/> <!-- not selected --> + <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/> + <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/> + <item android:state_pressed="true" android:color="@android:color/dim_foreground_holo_light"/> + <item android:state_selected="true" android:color="@android:color/dim_foreground_holo_light"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_light"/> + <item android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/> + <item android:color="@android:color/dim_foreground_holo_light"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/tertiary_text_holo_dark.xml b/core/res/res/color/tertiary_text_holo_dark.xml index 269ff71..0718d7d 100644 --- a/core/res/res/color/tertiary_text_holo_dark.xml +++ b/core/res/res/color/tertiary_text_holo_dark.xml @@ -18,7 +18,7 @@ <item android:state_enabled="false" android:color="#808080"/> <item android:state_window_focused="false" android:color="#808080"/> <item android:state_pressed="true" android:color="#808080"/> - <item android:state_selected="true" android:color="@android:color/dim_foreground_light"/> + <item android:state_selected="true" android:color="@android:color/dim_foreground_holo_light"/> <item android:color="#808080"/> <!-- not selected --> </selector> diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png Binary files differindex 05d1668..19ad5c9 100644 --- a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png Binary files differindex 6f7eb42..180cdf5 100644 --- a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png Binary files differindex 2c814f0..c66bb07 100644 --- a/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png Binary files differindex a88bdf6..c0d3dd7 100644 --- a/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png Binary files differindex 9a61d82..b440e15 100644 --- a/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png Binary files differindex 56ca528..8769d0a 100644 --- a/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png Binary files differindex 6600035..7b8e9e8 100644 --- a/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png Binary files differindex 11d31bb..37c8028 100644 --- a/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png Binary files differindex 8c58c37..aa08f45 100644 --- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png Binary files differindex d543c66..3e99cb6 100644 --- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/list_activated_holo.9.png b/core/res/res/drawable-hdpi/list_activated_holo.9.png Binary files differnew file mode 100644 index 0000000..cd9a08e --- /dev/null +++ b/core/res/res/drawable-hdpi/list_activated_holo.9.png diff --git a/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..7b18202 --- /dev/null +++ b/core/res/res/drawable-hdpi/list_divider_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/list_divider_holo_light.9.png b/core/res/res/drawable-hdpi/list_divider_holo_light.9.png Binary files differnew file mode 100644 index 0000000..17bcbb4 --- /dev/null +++ b/core/res/res/drawable-hdpi/list_divider_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/list_focused_holo.9.png b/core/res/res/drawable-hdpi/list_focused_holo.9.png Binary files differnew file mode 100644 index 0000000..b91e9f2 --- /dev/null +++ b/core/res/res/drawable-hdpi/list_focused_holo.9.png diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo.9.png Binary files differnew file mode 100644 index 0000000..db4831d --- /dev/null +++ b/core/res/res/drawable-hdpi/list_longpressed_holo.9.png diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..1ce1601 --- /dev/null +++ b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png Binary files differnew file mode 100644 index 0000000..b36aa2c --- /dev/null +++ b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/list_section_divider_holo_dark.9.png b/core/res/res/drawable-hdpi/list_section_divider_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..2dabb5f --- /dev/null +++ b/core/res/res/drawable-hdpi/list_section_divider_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/list_section_divider_holo_light.9.png b/core/res/res/drawable-hdpi/list_section_divider_holo_light.9.png Binary files differnew file mode 100644 index 0000000..763f4f6 --- /dev/null +++ b/core/res/res/drawable-hdpi/list_section_divider_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..c054e14 --- /dev/null +++ b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png Binary files differnew file mode 100644 index 0000000..77c4032 --- /dev/null +++ b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png Binary files differindex 15003be..ca2271a 100644 --- a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png Binary files differindex 573f197..0d498e3 100644 --- a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png Binary files differindex 953a553..ae922ce 100644 --- a/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png Binary files differindex d79a61e..89aef31 100644 --- a/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png Binary files differindex 897676e..1f4be44 100644 --- a/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png Binary files differindex b485925..e4d0ba0 100644 --- a/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png Binary files differindex 1cdbf66..050fb19 100644 --- a/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png Binary files differindex ab7eb54..75651fc 100644 --- a/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png Binary files differindex d95ef6d..c7d02cf 100644 --- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png Binary files differindex 60ed4fc..40c9f64 100644 --- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/list_activated_holo.9.png b/core/res/res/drawable-mdpi/list_activated_holo.9.png Binary files differnew file mode 100644 index 0000000..01ec674 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_activated_holo.9.png diff --git a/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png b/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..7b18202 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_divider_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/list_divider_holo_light.9.png b/core/res/res/drawable-mdpi/list_divider_holo_light.9.png Binary files differnew file mode 100644 index 0000000..17bcbb4 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_divider_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/list_focused_holo.9.png b/core/res/res/drawable-mdpi/list_focused_holo.9.png Binary files differnew file mode 100644 index 0000000..23385df --- /dev/null +++ b/core/res/res/drawable-mdpi/list_focused_holo.9.png diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo.9.png Binary files differnew file mode 100644 index 0000000..3312a51 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_longpressed_holo.9.png diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..bbb14d8 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png Binary files differnew file mode 100644 index 0000000..72380d4 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/list_section_divider_holo_dark.9.png b/core/res/res/drawable-mdpi/list_section_divider_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..953d7bf --- /dev/null +++ b/core/res/res/drawable-mdpi/list_section_divider_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/list_section_divider_holo_light.9.png b/core/res/res/drawable-mdpi/list_section_divider_holo_light.9.png Binary files differnew file mode 100644 index 0000000..e5fe664 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_section_divider_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png Binary files differnew file mode 100644 index 0000000..c453506 --- /dev/null +++ b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png Binary files differnew file mode 100644 index 0000000..58b6b3c --- /dev/null +++ b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png diff --git a/core/res/res/drawable/activated_background_holo_dark.xml b/core/res/res/drawable/activated_background_holo_dark.xml index f71235e..febf2c4 100644 --- a/core/res/res/drawable/activated_background_holo_dark.xml +++ b/core/res/res/drawable/activated_background_holo_dark.xml @@ -15,6 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_activated="true" android:drawable="@android:drawable/list_selector_activated_holo_dark" /> + <item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" /> <item android:drawable="@color/transparent" /> </selector> diff --git a/core/res/res/drawable/activated_background_holo_light.xml b/core/res/res/drawable/activated_background_holo_light.xml index 615033d..febf2c4 100644 --- a/core/res/res/drawable/activated_background_holo_light.xml +++ b/core/res/res/drawable/activated_background_holo_light.xml @@ -15,6 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_activated="true" android:drawable="@android:drawable/list_selector_activated_holo_light" /> + <item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" /> <item android:drawable="@color/transparent" /> </selector> diff --git a/core/res/res/drawable/btn_default_holo_light.xml b/core/res/res/drawable/btn_default_holo_light.xml new file mode 100644 index 0000000..61bb1bd --- /dev/null +++ b/core/res/res/drawable/btn_default_holo_light.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_window_focused="false" android:state_enabled="true" + android:drawable="@drawable/btn_default_normal_holo_light" /> + <item android:state_window_focused="false" android:state_enabled="false" + android:drawable="@drawable/btn_default_disabled_holo_light" /> + <item android:state_pressed="true" + android:drawable="@drawable/btn_default_pressed_holo_light" /> + <item android:state_focused="true" android:state_enabled="true" + android:drawable="@drawable/btn_default_focused_holo_light" /> + <item android:state_enabled="true" + android:drawable="@drawable/btn_default_normal_holo_light" /> + <item android:state_focused="true" + android:drawable="@drawable/btn_default_disabled_focused_holo_light" /> + <item + android:drawable="@drawable/btn_default_disabled_holo_light" /> +</selector> diff --git a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml new file mode 100644 index 0000000..7c68426 --- /dev/null +++ b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<transition xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@android:drawable/list_pressed_holo_dark" /> + <item android:drawable="@android:drawable/list_longpressed_holo" /> +</transition> diff --git a/core/res/res/drawable/list_selector_background_transition_holo_light.xml b/core/res/res/drawable/list_selector_background_transition_holo_light.xml new file mode 100644 index 0000000..fc08a84 --- /dev/null +++ b/core/res/res/drawable/list_selector_background_transition_holo_light.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<transition xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@android:drawable/list_pressed_holo_light" /> + <item android:drawable="@android:drawable/list_longpressed_holo" /> +</transition> diff --git a/core/res/res/drawable/list_selector_holo_dark.xml b/core/res/res/drawable/list_selector_holo_dark.xml index 9cc993a..e4c5c52 100644 --- a/core/res/res/drawable/list_selector_holo_dark.xml +++ b/core/res/res/drawable/list_selector_holo_dark.xml @@ -21,7 +21,7 @@ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. --> <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_dark" /> <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/list_selector_disabled_holo_dark" /> - <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" /> - <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" /> - <item android:state_focused="true" android:drawable="@drawable/list_selector_focused_holo_dark" /> + <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_dark" /> + <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_dark" /> + <item android:state_focused="true" android:drawable="@drawable/list_focused_holo" /> </selector> diff --git a/core/res/res/drawable/list_selector_holo_light.xml b/core/res/res/drawable/list_selector_holo_light.xml index f2def40..17631bd 100644 --- a/core/res/res/drawable/list_selector_holo_light.xml +++ b/core/res/res/drawable/list_selector_holo_light.xml @@ -21,8 +21,8 @@ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. --> <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" /> <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/list_selector_disabled_holo_light" /> - <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" /> - <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" /> - <item android:state_focused="true" android:drawable="@drawable/list_selector_focused_holo_light" /> + <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" /> + <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" /> + <item android:state_focused="true" android:drawable="@drawable/list_focused_holo" /> </selector> diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml index bbf7df5..ec9d8c0 100644 --- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml +++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml @@ -144,6 +144,6 @@ <string name="same_month_mdy1_mdy2">%9$s 年 %2$s %3$s - %8$s 日</string> <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s 年 %2$s %3$s 日%1$s - %7$s %8$s 日%6$s</string> <string name="short_format_month">%b</string> - <string name="full_wday_month_day_no_year">M 月 d 日E</string> - <string name="abbrev_wday_month_day_year">yyyy 年 M 月 d 日EEE</string> + <string name="full_wday_month_day_no_year">M 月 d 日 E</string> + <string name="abbrev_wday_month_day_year">yyyy 年 M 月 d 日 EEE</string> </resources> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 949d960..065c10d 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1441,6 +1441,38 @@ <attr name="functionalTest" /> </declare-styleable> + <!-- Attributes that can be supplied in an AndroidManifest.xml + <code>screen</code> tag, a child of <code>compatible-screens</code>, + which is itseld a child of the root + {@link #AndroidManifest manifest} tag. --> + <declare-styleable name="AndroidManifestCompatibleScreensScreen"> + <!-- Specifies a compatible screen size, as per the device + configuration screen size bins. --> + <attr name="screenSize"> + <!-- A small screen configuration, at least 240x320db. --> + <enum name="small" value="200" /> + <!-- A normal screen configuration, at least 320x480db. --> + <enum name="normal" value="300" /> + <!-- A large screen configuration, at least 400x530db. --> + <enum name="large" value="400" /> + <!-- An extra large screen configuration, at least 600x800db. --> + <enum name="xlarge" value="500" /> + </attr> + <!-- Specifies a compatible screen density, as per the device + configuration screen density bins. --> + <attr name="screenDensity" format="integer"> + <!-- A low density screen, approximately 120dpi. --> + <enum name="ldpi" value="120" /> + <!-- A medium density screen, approximately 160dpi. --> + <enum name="mdpi" value="160" /> + <!-- A high density screen, approximately 240dpi. --> + <enum name="hdpi" value="240" /> + <!-- An extra high density screen, approximately 320dpi. --> + <enum name="xhdpi" value="320" /> + </attr> + </declare-styleable> + + <!-- Declaration of an {@link android.content.Intent} object in XML. May also include zero or more {@link #IntentCategory <category> and {@link #Extra <extra>} tags. --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 5add8d6..47bb5f8 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1257,6 +1257,8 @@ <public type="attr" name="textSelectHandle" id="0x010102c7" /> <public type="attr" name="textSelectHandleWindowStyle" id="0x010102c8" /> <public type="attr" name="popupAnimationStyle" id="0x010102c9" /> + <public type="attr" name="screenSize" id="0x010102ca" /> + <public type="attr" name="screenDensity" id="0x010102cb" /> <!-- presence drawables for videochat or audiochat capable contacts --> <public type="drawable" name="presence_video_away" id="0x010800ac" /> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 5e77ee1..6f6f1db 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1289,7 +1289,7 @@ </style> <style name="Widget.Holo.TextView.ListSeparator" parent="Widget.TextView.ListSeparator"> - <item name="android:background">@android:drawable/list_section_header_holo_dark</item> + <item name="android:background">@android:drawable/list_section_divider_holo_dark</item> </style> <style name="Widget.Holo.TextSelectHandle" parent="Widget.TextSelectHandle"> @@ -1332,6 +1332,8 @@ </style> <style name="Widget.Holo.ListView" parent="Widget.ListView"> + <item name="android:divider">?android:attr/listDivider</item> + <item name="android:listSelector">?android:attr/listChoiceBackgroundIndicator</item> </style> <style name="Widget.Holo.ListView.White"> @@ -1521,6 +1523,12 @@ </style> <style name="Widget.Holo.Light.Button" parent="Widget.Button"> + <item name="android:background">@android:drawable/btn_default_holo_light</item> + <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> + <item name="android:textColor">@android:color/primary_text_holo_light</item> + <item name="android:minHeight">48dip</item> + <item name="android:paddingLeft">32dip</item> + <item name="android:paddingRight">32dip</item> </style> <style name="Widget.Holo.Light.Button.Small"> @@ -1556,7 +1564,7 @@ </style> <style name="Widget.Holo.Light.TextView.ListSeparator" parent="Widget.TextView.ListSeparator"> - <item name="android:background">@android:drawable/list_section_header_holo_light</item> + <item name="android:background">@android:drawable/list_section_divider_holo_light</item> </style> <style name="Widget.Holo.Light.TextSelectHandle" parent="Widget.TextSelectHandle"> @@ -1598,7 +1606,7 @@ <style name="Widget.Holo.Light.ImageWell" parent="Widget.ImageWell"> </style> - <style name="Widget.Holo.Light.ListView" parent="Widget.ListView"> + <style name="Widget.Holo.Light.ListView" parent="Widget.Holo.ListView"> </style> <style name="Widget.Holo.Light.ListView.White"> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index b226aa0..7f6da2a 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -703,7 +703,7 @@ <item name="listPreferredItemHeight">64dip</item> <!-- @hide --> <item name="searchResultListItemHeight">58dip</item> - <item name="listDivider">@drawable/divider_horizontal_holo_dark</item> + <item name="listDivider">@drawable/list_divider_holo_dark</item> <item name="listSeparatorTextViewStyle">@android:style/Widget.Holo.TextView.ListSeparator</item> <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_dark</item> @@ -713,7 +713,7 @@ <item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_dark</item> - <item name="listDividerAlertDialog">@android:drawable/divider_horizontal_holo_dark</item> + <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_dark</item> <item name="expandableListPreferredItemPaddingLeft">40dip</item> <item name="expandableListPreferredChildPaddingLeft"> @@ -936,7 +936,7 @@ <item name="listPreferredItemHeight">64dip</item> <!-- @hide --> <item name="searchResultListItemHeight">58dip</item> - <item name="listDivider">@drawable/divider_horizontal_holo_light</item> + <item name="listDivider">@drawable/list_divider_holo_light</item> <item name="listSeparatorTextViewStyle">@android:style/Widget.Holo.Light.TextView.ListSeparator</item> <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_light</item> @@ -957,7 +957,7 @@ <item name="expandableListPreferredChildIndicatorRight"> ?android:attr/expandableListPreferredItemIndicatorRight</item> - <item name="listDividerAlertDialog">@android:drawable/divider_horizontal_holo_light</item> + <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_light</item> <!-- Gallery attributes --> <item name="galleryItemBackground">@android:drawable/gallery_item_background</item> @@ -1143,6 +1143,7 @@ <item name="android:windowAnimationStyle">@android:style/Animation.Holo.Dialog</item> <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item> <item name="android:windowActionBar">false</item> + <item name="android:windowActionModeOverlay">true</item> <item name="android:colorBackgroundCacheHint">@null</item> diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java index 82de509..cddf63d 100644 --- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java +++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java @@ -35,7 +35,7 @@ public class BluetoothTestUtils extends Assert { /** * Timeout for {@link BluetoothAdapter#disable()} in ms. */ - private static final int DISABLE_TIMEOUT = 5000; + private static final int DISABLE_TIMEOUT = 20000; /** * Timeout for {@link BluetoothAdapter#enable()} in ms. diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk new file mode 100644 index 0000000..4e7a403 --- /dev/null +++ b/data/sounds/AllAudio.mk @@ -0,0 +1,20 @@ +# +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +$(call inherit-product, frameworks/base/data/sounds/OriginalAudio.mk) +$(call inherit-product, frameworks/base/data/sounds/AudioPackage2.mk) +$(call inherit-product, frameworks/base/data/sounds/AudioPackage3.mk) +$(call inherit-product, frameworks/base/data/sounds/AudioPackage4.mk) diff --git a/include/camera/Camera.h b/include/camera/Camera.h index 171a3b6..8d8edd6 100644 --- a/include/camera/Camera.h +++ b/include/camera/Camera.h @@ -81,6 +81,18 @@ enum { enum { CAMERA_CMD_START_SMOOTH_ZOOM = 1, CAMERA_CMD_STOP_SMOOTH_ZOOM = 2, + // Set the clockwise rotation of preview display (setPreviewDisplay) in + // degrees. This affects the preview frames and the picture displayed after + // snapshot. This method is useful for portrait mode applications. Note that + // preview display of front-facing cameras is flipped horizontally before + // the rotation, that is, the image is reflected along the central vertical + // axis of the camera sensor. So the users can see themselves as looking + // into a mirror. + // + // This does not affect the order of byte array of CAMERA_MSG_PREVIEW_FRAME, + // CAMERA_MSG_VIDEO_FRAME, CAMERA_MSG_POSTVIEW_FRAME, CAMERA_MSG_RAW_IMAGE, + // or CAMERA_MSG_COMPRESSED_IMAGE. This is not allowed to be set during + // preview. CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3, // cmdType to disable/enable shutter sound. diff --git a/include/media/IOMX.h b/include/media/IOMX.h index 1f8ce71..fa775e7 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -79,6 +79,9 @@ public: node_id node, OMX_INDEXTYPE index, const void *params, size_t size) = 0; + virtual status_t storeMetaDataInBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0; + virtual status_t enableGraphicBuffers( node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0; diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h index 4ded5e8..b009e1b 100644 --- a/include/media/stagefright/HardwareAPI.h +++ b/include/media/stagefright/HardwareAPI.h @@ -49,6 +49,32 @@ struct EnableAndroidNativeBuffersParams { OMX_BOOL enable; }; +// A pointer to this struct is passed to OMX_SetParameter() when the extension +// index "OMX.google.android.index.storeMetaDataInBuffers" +// is given. +// +// When meta data is stored in the video buffers passed between OMX clients +// and OMX components, interpretation of the buffer data is up to the +// buffer receiver, and the data may or may not be the actual video data, but +// some information helpful for the receiver to locate the actual data. +// The buffer receiver thus needs to know how to interpret what is stored +// in these buffers, with mechanisms pre-determined externally. How to +// interpret the meta data is outside of the scope of this method. +// +// Currently, this is specifically used to pass meta data from video source +// (camera component, for instance) to video encoder to avoid memcpying of +// input video frame data. To do this, bStoreMetaDta is set to OMX_TRUE. +// If bStoreMetaData is set to false, real YUV frame data will be stored +// in the buffers. In addition, if no OMX_SetParameter() call is made +// with the corresponding extension index, real YUV data is stored +// in the buffers. +struct StoreMetaDataInBuffersParams { + OMX_U32 nSize; + OMX_VERSIONTYPE nVersion; + OMX_U32 nPortIndex; + OMX_BOOL bStoreMetaData; +}; + // Color formats in the range [OMX_COLOR_FormatAndroidPrivateStart, // OMX_COLOR_FormatAndroidPrivateEnd) will be converted to a gralloc pixel // format when used to allocate Android native buffers via gralloc. The diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index 2d4bf8b..f3a2dd2 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -170,11 +170,10 @@ public: * and parameters maintained by the input reader. */ class InputReaderContext { -protected: +public: InputReaderContext() { } virtual ~InputReaderContext() { } -public: virtual void updateGlobalMetaState() = 0; virtual int32_t getGlobalMetaState() = 0; @@ -193,7 +192,7 @@ public: * the input reader, the input reader never calls into other components while holding * an exclusive internal lock whenever re-entrance can happen. */ -class InputReader : public InputReaderInterface, private InputReaderContext { +class InputReader : public InputReaderInterface, protected InputReaderContext { public: InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, @@ -219,6 +218,11 @@ public: virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); +protected: + // These methods are protected virtual so they can be overridden and instrumented + // by test cases. + virtual InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); + private: sp<EventHubInterface> mEventHub; sp<InputReaderPolicyInterface> mPolicy; @@ -244,12 +248,11 @@ private: void addDevice(int32_t deviceId); void removeDevice(int32_t deviceId); - InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); void configureExcludedDevices(); void consumeEvent(const RawEvent* rawEvent); - void handleConfigurationChanged(); + void handleConfigurationChanged(nsecs_t when); // state management for all devices Mutex mStateLock; @@ -546,6 +549,21 @@ protected: int32_t toolMajor; int32_t toolMinor; int32_t orientation; + + inline bool operator== (const PointerData& other) const { + return id == other.id + && x == other.x + && y == other.y + && pressure == other.pressure + && touchMajor == other.touchMajor + && touchMinor == other.touchMinor + && toolMajor == other.toolMajor + && toolMinor == other.toolMinor + && orientation == other.orientation; + } + inline bool operator!= (const PointerData& other) const { + return !(*this == other); + } }; // Raw data for a collection of pointers including a pointer id mapping table. diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index f314b09..d661f7b 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -8,6 +8,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) utils/SortedListImpl.cpp \ FontRenderer.cpp \ GammaFontRenderer.cpp \ + Caches.cpp \ DisplayListRenderer.cpp \ FboCache.cpp \ GradientCache.cpp \ diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp new file mode 100644 index 0000000..a4def0b --- /dev/null +++ b/libs/hwui/Caches.cpp @@ -0,0 +1,77 @@ +/* + * 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 "OpenGLRenderer" + +#include "Caches.h" + +namespace android { + +#ifdef USE_OPENGL_RENDERER +using namespace uirenderer; +ANDROID_SINGLETON_STATIC_INSTANCE(Caches); +#endif + +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO), + lastDstMode(GL_ZERO), currentProgram(NULL) { + GLint maxTextureUnits; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { + LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); + } + + glGenBuffers(1, &meshBuffer); + glBindBuffer(GL_ARRAY_BUFFER, meshBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW); + + currentBuffer = meshBuffer; +} + +/** + * Binds the VBO used to render simple textured quads. + */ +void Caches::bindMeshBuffer() { + bindMeshBuffer(meshBuffer); +} + +/** + * Binds the specified VBO. + */ +void Caches::bindMeshBuffer(const GLuint buffer) { + if (currentBuffer != buffer) { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + currentBuffer = buffer; + } +} + +/** + * Unbinds the VBO used to render simple textured quads. + */ +void Caches::unbindMeshBuffer() { + if (currentBuffer) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + currentBuffer = 0; + } +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 0c704da..79644a5 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -75,52 +75,16 @@ struct CacheLogger { /////////////////////////////////////////////////////////////////////////////// class Caches: public Singleton<Caches> { - Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO), - lastDstMode(GL_ZERO), currentProgram(NULL) { - GLint maxTextureUnits; - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { - LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); - } - - glGenBuffers(1, &meshBuffer); - glBindBuffer(GL_ARRAY_BUFFER, meshBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW); - - currentBuffer = meshBuffer; - } + Caches(); friend class Singleton<Caches>; CacheLogger logger; public: - /** - * Binds the VBO used to render simple textured quads. - */ - inline void bindMeshBuffer() { - bindMeshBuffer(meshBuffer); - } - - /** - * Binds the specified VBO. - */ - inline void bindMeshBuffer(const GLuint buffer) { - if (currentBuffer != buffer) { - glBindBuffer(GL_ARRAY_BUFFER, buffer); - currentBuffer = buffer; - } - } - - /** - * Unbinds the VBO used to render simple textured quads. - */ - inline void unbindMeshBuffer() { - if (currentBuffer) { - glBindBuffer(GL_ARRAY_BUFFER, 0); - currentBuffer = 0; - } - } + void bindMeshBuffer(); + void bindMeshBuffer(const GLuint buffer); + void unbindMeshBuffer(); bool blend; GLenum lastSrcMode; @@ -146,11 +110,6 @@ public: }; // namespace uirenderer -#ifdef USE_OPENGL_RENDERER -using namespace uirenderer; -ANDROID_SINGLETON_STATIC_INSTANCE(Caches); -#endif - }; // namespace android #endif // ANDROID_UI_CACHES_H diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 17ef598..7495a06 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -353,11 +353,22 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, // Window coordinates of the layer Rect bounds(left, top, right, bottom); - if (!fboLayer) { + if (fboLayer) { + // Clear the previous layer regions before we change the viewport + clearLayerRegions(); + } else { mSnapshot->transform->mapRect(bounds); + // Layers only make sense if they are in the framebuffer's bounds - bounds.intersect(*mSnapshot->clipRect); + bounds.intersect(*snapshot->clipRect); + + // We cannot work with sub-pixels in this case bounds.snapToPixelBoundaries(); + + // When the layer is not an FBO, we may use glCopyTexImage so we + // need to make sure the layer does not extend outside the bounds + // of the framebuffer + bounds.intersect(snapshot->previous->viewport); } if (bounds.isEmpty() || bounds.getWidth() > mMaxTextureSize || @@ -446,14 +457,14 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, // Copy the framebuffer into the layer glBindTexture(GL_TEXTURE_2D, layer->texture); - if (layer->empty) { - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom, - layer->width, layer->height, 0); - layer->empty = false; - } else { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom, - bounds.getWidth(), bounds.getHeight()); - } + if (layer->empty) { + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, + snapshot->height - bounds.bottom, layer->width, layer->height, 0); + layer->empty = false; + } else { + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, + snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); + } // Enqueue the buffer coordinates to clear the corresponding region later mLayers.push(new Rect(bounds)); @@ -479,7 +490,8 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { } // Restore the clip from the previous snapshot - const Rect& clip = *previous->clipRect; + Rect& clip(*previous->clipRect); + clip.snapToPixelBoundaries(); glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight()); Layer* layer = current->layer; @@ -787,7 +799,8 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { - const Rect& clip = *mSnapshot->clipRect; + Rect& clip(*mSnapshot->clipRect); + clip.snapToPixelBoundaries(); drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); } @@ -855,6 +868,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, paint->getTextSize()); Rect clipRect(*mSnapshot->clipRect); + clipRect.snapToPixelBoundaries(); glScissor(clipRect.left, mSnapshot->height - clipRect.bottom, clipRect.getWidth(), clipRect.getHeight()); diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index c571ea1..8f3655c 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -149,10 +149,10 @@ struct Rect { } void snapToPixelBoundaries() { - left = floorf(left); - top = floorf(top); - right = ceilf(right); - bottom = ceilf(bottom); + left = floorf(left + 0.5f); + top = floorf(top + 0.5f); + right = floorf(right + 0.5f); + bottom = floorf(bottom + 0.5f); } void dump() const { diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 05c1a48..2ec003f 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -23,7 +23,13 @@ include $(BUILD_HOST_EXECUTABLE) # TODO: This should go into build/core/config.mk RSG_GENERATOR:=$(LOCAL_BUILT_MODULE) - +include $(CLEAR_VARS) +input_data_file := $(LOCAL_PATH)/rslib.bc +slangdata_output_var_name := rs_runtime_lib_bc +LOCAL_MODULE := librslib_rt +LOCAL_MODULE_TAGS := optional +include frameworks/compile/slang/SlangData.mk +include $(BUILD_STATIC_LIBRARY) # Build render script lib ==================== @@ -109,7 +115,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc -LOCAL_STATIC_LIBRARIES := libft2 +LOCAL_STATIC_LIBRARIES := libft2 librslib_rt LOCAL_C_INCLUDES += external/freetype/include diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index 165fa71..9dce158 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -390,6 +390,9 @@ static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name) return NULL; } +extern const char rs_runtime_lib_bc[]; +extern unsigned rs_runtime_lib_bc_size; + void ScriptCState::runCompiler(Context *rsc, ScriptC *s) { LOGV("%p ScriptCState::runCompiler ", rsc); @@ -398,6 +401,7 @@ void ScriptCState::runCompiler(Context *rsc, ScriptC *s) s->mBccScript = bccCreateScript(); s->mEnviroment.mIsThreadable = true; bccScriptBitcode(s->mBccScript, s->mEnviroment.mScriptText, s->mEnviroment.mScriptTextLength); + //bccLinkBitcode(s->mBccScript, rs_runtime_lib_bc, rs_runtime_lib_bc_size); bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s); bccCompileScript(s->mBccScript); bccGetScriptLabel(s->mBccScript, "root", (BCCvoid**) &s->mProgram.mRoot); @@ -533,5 +537,3 @@ RsScript rsi_ScriptCCreate(Context * rsc) } } - - diff --git a/libs/rs/rslib.bc b/libs/rs/rslib.bc Binary files differnew file mode 100644 index 0000000..1897c3b --- /dev/null +++ b/libs/rs/rslib.bc diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index bc08e0a..9c7e7f4 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -403,6 +403,7 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->deviceId = device->id; } outEvent->type = DEVICE_REMOVED; + outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); delete device; mNeedToSendFinishedDeviceScan = true; return true; @@ -419,6 +420,7 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->deviceId = device->id; } outEvent->type = DEVICE_ADDED; + outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); mNeedToSendFinishedDeviceScan = true; return true; } @@ -426,6 +428,7 @@ bool EventHub::getEvent(RawEvent* outEvent) if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; outEvent->type = FINISHED_DEVICE_SCAN; + outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); return true; } diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index d679ea2..629234b 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -124,12 +124,19 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, pointerCount, MAX_POINTERS); return false; } + BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { - if (pointerIds[i] < 0 || pointerIds[i] > MAX_POINTER_ID) { + int32_t id = pointerIds[i]; + if (id < 0 || id > MAX_POINTER_ID) { LOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", - pointerIds[i], MAX_POINTER_ID); + id, MAX_POINTER_ID); return false; } + if (pointerIdBits.hasBit(id)) { + LOGE("Motion event has duplicate pointer id %d", id); + return false; + } + pointerIdBits.markBit(id); } return true; } diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 88b91e0..120222c 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -266,7 +266,7 @@ void InputReader::process(const RawEvent* rawEvent) { break; case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChanged(); + handleConfigurationChanged(rawEvent->when); break; default: @@ -404,7 +404,7 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) { } // release device registry reader lock } -void InputReader::handleConfigurationChanged() { +void InputReader::handleConfigurationChanged(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaState(); @@ -412,7 +412,6 @@ void InputReader::handleConfigurationChanged() { updateInputConfiguration(); // Enqueue configuration changed. - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mDispatcher->notifyConfigurationChanged(when); } @@ -2189,7 +2188,7 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); + mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_UP; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; @@ -2214,13 +2213,22 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); + mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_UP; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED; - touchResult = DROP_STROKE; - goto DispatchVirtualKey; + + // Check whether the pointer moved inside the display area where we should + // start a new stroke. + int32_t x = mCurrentTouch.pointers[0].x; + int32_t y = mCurrentTouch.pointers[0].y; + if (isPointInsideSurfaceLocked(x, y)) { + mLastTouch.clear(); + touchResult = DISPATCH_TOUCH; + } else { + touchResult = DROP_STROKE; + } } else { if (mCurrentTouch.pointerCount >= 1 && mLastTouch.pointerCount == 0) { // Pointer just went down. Handle off-screen touches, if needed. @@ -2238,7 +2246,8 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.scanCode = virtualKey->scanCode; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); + mLocked.currentVirtualKey.keyCode, + mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_DOWN; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM @@ -2285,14 +2294,35 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchTouch(when, policyFlags, & mCurrentTouch, currentIdBits, -1, currentPointerCount, motionEventAction); } else { - // There may be pointers going up and pointers going down at the same time when pointer - // ids are reported by the device driver. + // There may be pointers going up and pointers going down and pointers moving + // all at the same time. BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value); BitSet32 activeIdBits(lastIdBits.value); uint32_t pointerCount = lastPointerCount; - while (! upIdBits.isEmpty()) { + // Produce an intermediate representation of the touch data that consists of the + // old location of pointers that have just gone up and the new location of pointers that + // have just moved but omits the location of pointers that have just gone down. + TouchData interimTouch; + interimTouch.copyFrom(mLastTouch); + + BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); + bool moveNeeded = false; + while (!moveIdBits.isEmpty()) { + uint32_t moveId = moveIdBits.firstMarkedBit(); + moveIdBits.clearBit(moveId); + + int32_t oldIndex = mLastTouch.idToIndex[moveId]; + int32_t newIndex = mCurrentTouch.idToIndex[moveId]; + if (mLastTouch.pointers[oldIndex] != mCurrentTouch.pointers[newIndex]) { + interimTouch.pointers[oldIndex] = mCurrentTouch.pointers[newIndex]; + moveNeeded = true; + } + } + + // Dispatch pointer up events using the interim pointer locations. + while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.firstMarkedBit(); upIdBits.clearBit(upId); BitSet32 oldActiveIdBits = activeIdBits; @@ -2305,12 +2335,21 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP; } - dispatchTouch(when, policyFlags, & mLastTouch, + dispatchTouch(when, policyFlags, &interimTouch, oldActiveIdBits, upId, pointerCount, motionEventAction); pointerCount -= 1; } - while (! downIdBits.isEmpty()) { + // Dispatch move events if any of the remaining pointers moved from their old locations. + // Although applications receive new locations as part of individual pointer up + // events, they do not generally handle them except when presented in a move event. + if (moveNeeded) { + dispatchTouch(when, policyFlags, &mCurrentTouch, + activeIdBits, -1, pointerCount, AMOTION_EVENT_ACTION_MOVE); + } + + // Dispatch pointer down events using the new pointer locations. + while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.firstMarkedBit(); downIdBits.clearBit(downId); BitSet32 oldActiveIdBits = activeIdBits; @@ -2325,7 +2364,7 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { } pointerCount += 1; - dispatchTouch(when, policyFlags, & mCurrentTouch, + dispatchTouch(when, policyFlags, &mCurrentTouch, activeIdBits, downId, pointerCount, motionEventAction); } } @@ -3434,8 +3473,8 @@ void MultiTouchInputMapper::sync(nsecs_t when) { if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { if (inPointer.absMTPressure <= 0) { - // Some devices send sync packets with X / Y but with a 0 presure to indicate - // a pointer up. Drop this finger. + // Some devices send sync packets with X / Y but with a 0 pressure to indicate + // a pointer going up. Drop this finger. continue; } outPointer.pressure = inPointer.absMTPressure; diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk index 62f824f..aa017b9 100644 --- a/libs/ui/tests/Android.mk +++ b/libs/ui/tests/Android.mk @@ -7,6 +7,7 @@ ifneq ($(TARGET_SIMULATOR),true) # Build the unit tests. test_src_files := \ InputChannel_test.cpp \ + InputReader_test.cpp \ InputDispatcher_test.cpp \ InputPublisherAndConsumer_test.cpp diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp index 1dc6e46..8874dfe 100644 --- a/libs/ui/tests/InputDispatcher_test.cpp +++ b/libs/ui/tests/InputDispatcher_test.cpp @@ -4,15 +4,223 @@ #include <ui/InputDispatcher.h> #include <gtest/gtest.h> +#include <linux/input.h> namespace android { -class InputDispatcherTest : public testing::Test { +// An arbitrary time value. +static const nsecs_t ARBITRARY_TIME = 1234; + +// An arbitrary device id. +static const int32_t DEVICE_ID = 1; + +// An arbitrary injector pid / uid pair that has permission to inject events. +static const int32_t INJECTOR_PID = 999; +static const int32_t INJECTOR_UID = 1001; + + +// --- FakeInputDispatcherPolicy --- + +class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { +protected: + virtual ~FakeInputDispatcherPolicy() { + } + public: + FakeInputDispatcherPolicy() { + } + +private: + virtual void notifyConfigurationChanged(nsecs_t when) { + } + + virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, + const sp<InputChannel>& inputChannel) { + return 0; + } + + virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) { + } + + virtual nsecs_t getKeyRepeatTimeout() { + return 500 * 1000000LL; + } + + virtual nsecs_t getKeyRepeatDelay() { + return 50 * 1000000LL; + } + + virtual int32_t getMaxEventsPerSecond() { + return 60; + } + + virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, + int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode, + uint32_t& policyFlags) { + } + + virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { + } + + virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + const KeyEvent* keyEvent, uint32_t policyFlags) { + return false; + } + + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { + } + + virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) { + } + + virtual bool checkInjectEventsPermissionNonReentrant( + int32_t injectorPid, int32_t injectorUid) { + return false; + } }; -TEST_F(InputDispatcherTest, Dummy) { - // TODO + +// --- InputDispatcherTest --- + +class InputDispatcherTest : public testing::Test { +protected: + sp<FakeInputDispatcherPolicy> mFakePolicy; + sp<InputDispatcher> mDispatcher; + + virtual void SetUp() { + mFakePolicy = new FakeInputDispatcherPolicy(); + mDispatcher = new InputDispatcher(mFakePolicy); + } + + virtual void TearDown() { + mFakePolicy.clear(); + mDispatcher.clear(); + } +}; + + +TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { + KeyEvent event; + + // Rejects undefined key actions. + event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, + /*action*/ -1, 0, + AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject key events with undefined action."; + + // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. + event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, + AKEY_EVENT_ACTION_MULTIPLE, 0, + AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject key events with ACTION_MULTIPLE."; +} + +TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { + MotionEvent event; + int32_t pointerIds[MAX_POINTERS + 1]; + PointerCoords pointerCoords[MAX_POINTERS + 1]; + for (int i = 0; i <= MAX_POINTERS; i++) { + pointerIds[i] = i; + } + + // Rejects undefined motion actions. + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with undefined action."; + + // Rejects pointer down with invalid index. + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with pointer down index too large."; + + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with pointer down index too small."; + + // Rejects pointer up with invalid index. + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with pointer up index too large."; + + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with pointer up index too small."; + + // Rejects motion events with invalid number of pointers. + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 0, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with 0 pointers."; + + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ MAX_POINTERS + 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with more than MAX_POINTERS pointers."; + + // Rejects motion events with invalid pointer ids. + pointerIds[0] = -1; + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with pointer ids less than 0."; + + pointerIds[0] = MAX_POINTER_ID + 1; + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; + + // Rejects motion events with duplicate pointer ids. + pointerIds[0] = 1; + pointerIds[1] = 1; + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 2, pointerIds, pointerCoords); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0)) + << "Should reject motion events with duplicate pointer ids."; } } // namespace android diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp new file mode 100644 index 0000000..c19147f --- /dev/null +++ b/libs/ui/tests/InputReader_test.cpp @@ -0,0 +1,3381 @@ +// +// Copyright 2010 The Android Open Source Project +// + +#include <ui/InputReader.h> +#include <utils/List.h> +#include <gtest/gtest.h> +#include <math.h> + +namespace android { + +// An arbitrary time value. +static const nsecs_t ARBITRARY_TIME = 1234; + +// Arbitrary display properties. +static const int32_t DISPLAY_ID = 0; +static const int32_t DISPLAY_WIDTH = 480; +static const int32_t DISPLAY_HEIGHT = 800; + +// Error tolerance for floating point assertions. +static const float EPSILON = 0.001f; + +template<typename T> +static inline T min(T a, T b) { + return a < b ? a : b; +} + +static inline float avg(float x, float y) { + return (x + y) / 2; +} + + +// --- FakeInputReaderPolicy --- + +class FakeInputReaderPolicy : public InputReaderPolicyInterface { + struct DisplayInfo { + int32_t width; + int32_t height; + int32_t orientation; + }; + + KeyedVector<int32_t, DisplayInfo> mDisplayInfos; + bool mFilterTouchEvents; + bool mFilterJumpyTouchEvents; + KeyedVector<String8, Vector<VirtualKeyDefinition> > mVirtualKeyDefinitions; + KeyedVector<String8, InputDeviceCalibration> mInputDeviceCalibrations; + Vector<String8> mExcludedDeviceNames; + +protected: + virtual ~FakeInputReaderPolicy() { } + +public: + FakeInputReaderPolicy() : + mFilterTouchEvents(false), mFilterJumpyTouchEvents(false) { + } + + void removeDisplayInfo(int32_t displayId) { + mDisplayInfos.removeItem(displayId); + } + + void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { + removeDisplayInfo(displayId); + + DisplayInfo info; + info.width = width; + info.height = height; + info.orientation = orientation; + mDisplayInfos.add(displayId, info); + } + + void setFilterTouchEvents(bool enabled) { + mFilterTouchEvents = enabled; + } + + void setFilterJumpyTouchEvents(bool enabled) { + mFilterJumpyTouchEvents = enabled; + } + + void addInputDeviceCalibration(const String8& deviceName, + const InputDeviceCalibration& calibration) { + mInputDeviceCalibrations.add(deviceName, calibration); + } + + void addInputDeviceCalibrationProperty(const String8& deviceName, + const String8& key, const String8& value) { + ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName); + if (index < 0) { + index = mInputDeviceCalibrations.add(deviceName, InputDeviceCalibration()); + } + mInputDeviceCalibrations.editValueAt(index).addProperty(key, value); + } + + void addVirtualKeyDefinition(const String8& deviceName, + const VirtualKeyDefinition& definition) { + if (mVirtualKeyDefinitions.indexOfKey(deviceName) < 0) { + mVirtualKeyDefinitions.add(deviceName, Vector<VirtualKeyDefinition>()); + } + + mVirtualKeyDefinitions.editValueFor(deviceName).push(definition); + } + + void addExcludedDeviceName(const String8& deviceName) { + mExcludedDeviceNames.push(deviceName); + } + +private: + virtual bool getDisplayInfo(int32_t displayId, + int32_t* width, int32_t* height, int32_t* orientation) { + ssize_t index = mDisplayInfos.indexOfKey(displayId); + if (index >= 0) { + const DisplayInfo& info = mDisplayInfos.valueAt(index); + if (width) { + *width = info.width; + } + if (height) { + *height = info.height; + } + if (orientation) { + *orientation = info.orientation; + } + return true; + } + return false; + } + + virtual bool filterTouchEvents() { + return mFilterTouchEvents; + } + + virtual bool filterJumpyTouchEvents() { + return mFilterJumpyTouchEvents; + } + + virtual void getVirtualKeyDefinitions(const String8& deviceName, + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) { + ssize_t index = mVirtualKeyDefinitions.indexOfKey(deviceName); + if (index >= 0) { + outVirtualKeyDefinitions.appendVector(mVirtualKeyDefinitions.valueAt(index)); + } + } + + virtual void getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration) { + ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName); + if (index >= 0) { + outCalibration = mInputDeviceCalibrations.valueAt(index); + } + } + + virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { + outExcludedDeviceNames.appendVector(mExcludedDeviceNames); + } +}; + + +// --- FakeInputDispatcher --- + +class FakeInputDispatcher : public InputDispatcherInterface { +public: + struct NotifyConfigurationChangedArgs { + nsecs_t eventTime; + }; + + struct NotifyKeyArgs { + nsecs_t eventTime; + int32_t deviceId; + int32_t source; + uint32_t policyFlags; + int32_t action; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + nsecs_t downTime; + }; + + struct NotifyMotionArgs { + nsecs_t eventTime; + int32_t deviceId; + int32_t source; + uint32_t policyFlags; + int32_t action; + int32_t flags; + int32_t metaState; + int32_t edgeFlags; + uint32_t pointerCount; + Vector<int32_t> pointerIds; + Vector<PointerCoords> pointerCoords; + float xPrecision; + float yPrecision; + nsecs_t downTime; + }; + + struct NotifySwitchArgs { + nsecs_t when; + int32_t switchCode; + int32_t switchValue; + uint32_t policyFlags; + }; + +private: + List<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgs; + List<NotifyKeyArgs> mNotifyKeyArgs; + List<NotifyMotionArgs> mNotifyMotionArgs; + List<NotifySwitchArgs> mNotifySwitchArgs; + +protected: + virtual ~FakeInputDispatcher() { } + +public: + FakeInputDispatcher() { + } + + void assertNotifyConfigurationChangedWasCalled(NotifyConfigurationChangedArgs* outArgs = NULL) { + ASSERT_FALSE(mNotifyConfigurationChangedArgs.empty()) + << "Expected notifyConfigurationChanged() to have been called."; + if (outArgs) { + *outArgs = *mNotifyConfigurationChangedArgs.begin(); + } + mNotifyConfigurationChangedArgs.erase(mNotifyConfigurationChangedArgs.begin()); + } + + void assertNotifyKeyWasCalled(NotifyKeyArgs* outArgs = NULL) { + ASSERT_FALSE(mNotifyKeyArgs.empty()) + << "Expected notifyKey() to have been called."; + if (outArgs) { + *outArgs = *mNotifyKeyArgs.begin(); + } + mNotifyKeyArgs.erase(mNotifyKeyArgs.begin()); + } + + void assertNotifyKeyWasNotCalled() { + ASSERT_TRUE(mNotifyKeyArgs.empty()) + << "Expected notifyKey() to not have been called."; + } + + void assertNotifyMotionWasCalled(NotifyMotionArgs* outArgs = NULL) { + ASSERT_FALSE(mNotifyMotionArgs.empty()) + << "Expected notifyMotion() to have been called."; + if (outArgs) { + *outArgs = *mNotifyMotionArgs.begin(); + } + mNotifyMotionArgs.erase(mNotifyMotionArgs.begin()); + } + + void assertNotifyMotionWasNotCalled() { + ASSERT_TRUE(mNotifyMotionArgs.empty()) + << "Expected notifyMotion() to not have been called."; + } + + void assertNotifySwitchWasCalled(NotifySwitchArgs* outArgs = NULL) { + ASSERT_FALSE(mNotifySwitchArgs.empty()) + << "Expected notifySwitch() to have been called."; + if (outArgs) { + *outArgs = *mNotifySwitchArgs.begin(); + } + mNotifySwitchArgs.erase(mNotifySwitchArgs.begin()); + } + +private: + virtual void notifyConfigurationChanged(nsecs_t eventTime) { + NotifyConfigurationChangedArgs args; + args.eventTime = eventTime; + mNotifyConfigurationChangedArgs.push_back(args); + } + + virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source, + uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime) { + NotifyKeyArgs args; + args.eventTime = eventTime; + args.deviceId = deviceId; + args.source = source; + args.policyFlags = policyFlags; + args.action = action; + args.flags = flags; + args.keyCode = keyCode; + args.scanCode = scanCode; + args.metaState = metaState; + args.downTime = downTime; + mNotifyKeyArgs.push_back(args); + } + + virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source, + uint32_t policyFlags, int32_t action, int32_t flags, + int32_t metaState, int32_t edgeFlags, + uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, nsecs_t downTime) { + NotifyMotionArgs args; + args.eventTime = eventTime; + args.deviceId = deviceId; + args.source = source; + args.policyFlags = policyFlags; + args.action = action; + args.flags = flags; + args.metaState = metaState; + args.edgeFlags = edgeFlags; + args.pointerCount = pointerCount; + args.pointerIds.clear(); + args.pointerIds.appendArray(pointerIds, pointerCount); + args.pointerCoords.clear(); + args.pointerCoords.appendArray(pointerCoords, pointerCount); + args.xPrecision = xPrecision; + args.yPrecision = yPrecision; + args.downTime = downTime; + mNotifyMotionArgs.push_back(args); + } + + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { + NotifySwitchArgs args; + args.when = when; + args.switchCode = switchCode; + args.switchValue = switchValue; + args.policyFlags = policyFlags; + mNotifySwitchArgs.push_back(args); + } + + virtual void dump(String8& dump) { + ADD_FAILURE() << "Should never be called by input reader."; + } + + virtual void dispatchOnce() { + ADD_FAILURE() << "Should never be called by input reader."; + } + + virtual int32_t injectInputEvent(const InputEvent* event, + int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) { + ADD_FAILURE() << "Should never be called by input reader."; + return INPUT_EVENT_INJECTION_FAILED; + } + + virtual void setInputWindows(const Vector<InputWindow>& inputWindows) { + ADD_FAILURE() << "Should never be called by input reader."; + } + + virtual void setFocusedApplication(const InputApplication* inputApplication) { + ADD_FAILURE() << "Should never be called by input reader."; + } + + virtual void setInputDispatchMode(bool enabled, bool frozen) { + ADD_FAILURE() << "Should never be called by input reader."; + } + + virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, + const sp<InputChannel>& toChannel) { + ADD_FAILURE() << "Should never be called by input reader."; + return 0; + } + + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) { + ADD_FAILURE() << "Should never be called by input reader."; + return 0; + } + + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) { + ADD_FAILURE() << "Should never be called by input reader."; + return 0; + } +}; + + +// --- FakeEventHub --- + +class FakeEventHub : public EventHubInterface { + struct KeyInfo { + int32_t keyCode; + uint32_t flags; + }; + + struct Device { + String8 name; + uint32_t classes; + KeyedVector<int, RawAbsoluteAxisInfo> axes; + KeyedVector<int32_t, int32_t> keyCodeStates; + KeyedVector<int32_t, int32_t> scanCodeStates; + KeyedVector<int32_t, int32_t> switchStates; + KeyedVector<int32_t, KeyInfo> keys; + + Device(const String8& name, uint32_t classes) : + name(name), classes(classes) { + } + }; + + KeyedVector<int32_t, Device*> mDevices; + Vector<String8> mExcludedDevices; + List<RawEvent> mEvents; + +protected: + virtual ~FakeEventHub() { + for (size_t i = 0; i < mDevices.size(); i++) { + delete mDevices.valueAt(i); + } + } + +public: + FakeEventHub() { } + + void addDevice(int32_t deviceId, const String8& name, uint32_t classes) { + Device* device = new Device(name, classes); + mDevices.add(deviceId, device); + + enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0, 0, 0); + } + + void removeDevice(int32_t deviceId) { + delete mDevices.valueFor(deviceId); + mDevices.removeItem(deviceId); + + enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0, 0, 0); + } + + void finishDeviceScan() { + enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0, 0, 0); + } + + void addAxis(int32_t deviceId, int axis, + int32_t minValue, int32_t maxValue, int flat, int fuzz) { + Device* device = getDevice(deviceId); + + RawAbsoluteAxisInfo info; + info.valid = true; + info.minValue = minValue; + info.maxValue = maxValue; + info.flat = flat; + info.fuzz = fuzz; + device->axes.add(axis, info); + } + + void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { + Device* device = getDevice(deviceId); + device->keyCodeStates.replaceValueFor(keyCode, state); + } + + void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { + Device* device = getDevice(deviceId); + device->scanCodeStates.replaceValueFor(scanCode, state); + } + + void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { + Device* device = getDevice(deviceId); + device->switchStates.replaceValueFor(switchCode, state); + } + + void addKey(int32_t deviceId, int32_t scanCode, int32_t keyCode, uint32_t flags) { + Device* device = getDevice(deviceId); + KeyInfo info; + info.keyCode = keyCode; + info.flags = flags; + device->keys.add(scanCode, info); + } + + Vector<String8>& getExcludedDevices() { + return mExcludedDevices; + } + + void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type, + int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) { + RawEvent event; + event.when = when; + event.deviceId = deviceId; + event.type = type; + event.scanCode = scanCode; + event.keyCode = keyCode; + event.value = value; + event.flags = flags; + mEvents.push_back(event); + } + + void assertQueueIsEmpty() { + ASSERT_EQ(size_t(0), mEvents.size()) + << "Expected the event queue to be empty (fully consumed)."; + } + +private: + Device* getDevice(int32_t deviceId) const { + ssize_t index = mDevices.indexOfKey(deviceId); + return index >= 0 ? mDevices.valueAt(index) : NULL; + } + + virtual uint32_t getDeviceClasses(int32_t deviceId) const { + Device* device = getDevice(deviceId); + return device ? device->classes : 0; + } + + virtual String8 getDeviceName(int32_t deviceId) const { + Device* device = getDevice(deviceId); + return device ? device->name : String8("unknown"); + } + + virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, + RawAbsoluteAxisInfo* outAxisInfo) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->axes.indexOfKey(axis); + if (index >= 0) { + *outAxisInfo = device->axes.valueAt(index); + return OK; + } + } + return -1; + } + + virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, + int32_t* outKeycode, uint32_t* outFlags) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->keys.indexOfKey(scancode); + if (index >= 0) { + if (outKeycode) { + *outKeycode = device->keys.valueAt(index).keyCode; + } + if (outFlags) { + *outFlags = device->keys.valueAt(index).flags; + } + return OK; + } + } + return NAME_NOT_FOUND; + } + + virtual void addExcludedDevice(const char* deviceName) { + mExcludedDevices.add(String8(deviceName)); + } + + virtual bool getEvent(RawEvent* outEvent) { + if (mEvents.empty()) { + return false; + } + + *outEvent = *mEvents.begin(); + mEvents.erase(mEvents.begin()); + return true; + } + + virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->scanCodeStates.indexOfKey(scanCode); + if (index >= 0) { + return device->scanCodeStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; + } + + virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->keyCodeStates.indexOfKey(keyCode); + if (index >= 0) { + return device->keyCodeStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; + } + + virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->switchStates.indexOfKey(sw); + if (index >= 0) { + return device->switchStates.valueAt(index); + } + } + return AKEY_STATE_UNKNOWN; + } + + virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) const { + bool result = false; + Device* device = getDevice(deviceId); + if (device) { + for (size_t i = 0; i < numCodes; i++) { + for (size_t j = 0; j < device->keys.size(); j++) { + if (keyCodes[i] == device->keys.valueAt(j).keyCode) { + outFlags[i] = 1; + result = true; + } + } + } + } + return result; + } + + virtual bool hasLed(int32_t deviceId, int32_t led) const { + return false; + } + + virtual void setLedState(int32_t deviceId, int32_t led, bool on) { + } + + virtual void dump(String8& dump) { + } +}; + + +// --- FakeInputReaderContext --- + +class FakeInputReaderContext : public InputReaderContext { + sp<EventHubInterface> mEventHub; + sp<InputReaderPolicyInterface> mPolicy; + sp<InputDispatcherInterface> mDispatcher; + int32_t mGlobalMetaState; + bool mUpdateGlobalMetaStateWasCalled; + +public: + FakeInputReaderContext(const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputDispatcherInterface>& dispatcher) : + mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher), + mGlobalMetaState(0) { + } + + virtual ~FakeInputReaderContext() { } + + void assertUpdateGlobalMetaStateWasCalled() { + ASSERT_TRUE(mUpdateGlobalMetaStateWasCalled) + << "Expected updateGlobalMetaState() to have been called."; + mUpdateGlobalMetaStateWasCalled = false; + } + + void setGlobalMetaState(int32_t state) { + mGlobalMetaState = state; + } + +private: + virtual void updateGlobalMetaState() { + mUpdateGlobalMetaStateWasCalled = true; + } + + virtual int32_t getGlobalMetaState() { + return mGlobalMetaState; + } + + virtual EventHubInterface* getEventHub() { + return mEventHub.get(); + } + + virtual InputReaderPolicyInterface* getPolicy() { + return mPolicy.get(); + } + + virtual InputDispatcherInterface* getDispatcher() { + return mDispatcher.get(); + } +}; + + +// --- FakeInputMapper --- + +class FakeInputMapper : public InputMapper { + uint32_t mSources; + int32_t mKeyboardType; + int32_t mMetaState; + KeyedVector<int32_t, int32_t> mKeyCodeStates; + KeyedVector<int32_t, int32_t> mScanCodeStates; + KeyedVector<int32_t, int32_t> mSwitchStates; + Vector<int32_t> mSupportedKeyCodes; + RawEvent mLastEvent; + + bool mConfigureWasCalled; + bool mResetWasCalled; + bool mProcessWasCalled; + +public: + FakeInputMapper(InputDevice* device, uint32_t sources) : + InputMapper(device), + mSources(sources), mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), + mMetaState(0), + mConfigureWasCalled(false), mResetWasCalled(false), mProcessWasCalled(false) { + } + + virtual ~FakeInputMapper() { } + + void setKeyboardType(int32_t keyboardType) { + mKeyboardType = keyboardType; + } + + void setMetaState(int32_t metaState) { + mMetaState = metaState; + } + + void assertConfigureWasCalled() { + ASSERT_TRUE(mConfigureWasCalled) + << "Expected configure() to have been called."; + mConfigureWasCalled = false; + } + + void assertResetWasCalled() { + ASSERT_TRUE(mResetWasCalled) + << "Expected reset() to have been called."; + mResetWasCalled = false; + } + + void assertProcessWasCalled(RawEvent* outLastEvent = NULL) { + ASSERT_TRUE(mProcessWasCalled) + << "Expected process() to have been called."; + if (outLastEvent) { + *outLastEvent = mLastEvent; + } + mProcessWasCalled = false; + } + + void setKeyCodeState(int32_t keyCode, int32_t state) { + mKeyCodeStates.replaceValueFor(keyCode, state); + } + + void setScanCodeState(int32_t scanCode, int32_t state) { + mScanCodeStates.replaceValueFor(scanCode, state); + } + + void setSwitchState(int32_t switchCode, int32_t state) { + mSwitchStates.replaceValueFor(switchCode, state); + } + + void addSupportedKeyCode(int32_t keyCode) { + mSupportedKeyCodes.add(keyCode); + } + +private: + virtual uint32_t getSources() { + return mSources; + } + + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) { + InputMapper::populateDeviceInfo(deviceInfo); + + if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) { + deviceInfo->setKeyboardType(mKeyboardType); + } + } + + virtual void configure() { + mConfigureWasCalled = true; + } + + virtual void reset() { + mResetWasCalled = true; + } + + virtual void process(const RawEvent* rawEvent) { + mLastEvent = *rawEvent; + mProcessWasCalled = true; + } + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + ssize_t index = mKeyCodeStates.indexOfKey(keyCode); + return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; + } + + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + ssize_t index = mScanCodeStates.indexOfKey(scanCode); + return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; + } + + virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) { + ssize_t index = mSwitchStates.indexOfKey(switchCode); + return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN; + } + + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + bool result = false; + for (size_t i = 0; i < numCodes; i++) { + for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { + if (keyCodes[i] == mSupportedKeyCodes[j]) { + outFlags[i] = 1; + result = true; + } + } + } + return result; + } + + virtual int32_t getMetaState() { + return mMetaState; + } +}; + + +// --- InstrumentedInputReader --- + +class InstrumentedInputReader : public InputReader { + InputDevice* mNextDevice; + +public: + InstrumentedInputReader(const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputDispatcherInterface>& dispatcher) : + InputReader(eventHub, policy, dispatcher) { + } + + virtual ~InstrumentedInputReader() { + if (mNextDevice) { + delete mNextDevice; + } + } + + void setNextDevice(InputDevice* device) { + mNextDevice = device; + } + +protected: + virtual InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes) { + if (mNextDevice) { + InputDevice* device = mNextDevice; + mNextDevice = NULL; + return device; + } + return InputReader::createDevice(deviceId, name, classes); + } + + friend class InputReaderTest; +}; + + +// --- InputReaderTest --- + +class InputReaderTest : public testing::Test { +protected: + sp<FakeInputDispatcher> mFakeDispatcher; + sp<FakeInputReaderPolicy> mFakePolicy; + sp<FakeEventHub> mFakeEventHub; + sp<InstrumentedInputReader> mReader; + + virtual void SetUp() { + mFakeEventHub = new FakeEventHub(); + mFakePolicy = new FakeInputReaderPolicy(); + mFakeDispatcher = new FakeInputDispatcher(); + + mReader = new InstrumentedInputReader(mFakeEventHub, mFakePolicy, mFakeDispatcher); + } + + virtual void TearDown() { + mReader.clear(); + + mFakeDispatcher.clear(); + mFakePolicy.clear(); + mFakeEventHub.clear(); + } + + void addDevice(int32_t deviceId, const String8& name, uint32_t classes) { + mFakeEventHub->addDevice(deviceId, name, classes); + mFakeEventHub->finishDeviceScan(); + mReader->loopOnce(); + mReader->loopOnce(); + mFakeEventHub->assertQueueIsEmpty(); + } + + FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, + const String8& name, uint32_t classes, uint32_t sources) { + InputDevice* device = new InputDevice(mReader.get(), deviceId, name); + FakeInputMapper* mapper = new FakeInputMapper(device, sources); + device->addMapper(mapper); + mReader->setNextDevice(device); + addDevice(deviceId, name, classes); + return mapper; + } +}; + +TEST_F(InputReaderTest, GetInputConfiguration_WhenNoDevices_ReturnsDefaults) { + InputConfiguration config; + mReader->getInputConfiguration(&config); + + ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); + ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation); + ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); +} + +TEST_F(InputReaderTest, GetInputConfiguration_WhenAlphabeticKeyboardPresent_ReturnsQwertyKeyboard) { + ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("keyboard"), + INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY)); + + InputConfiguration config; + mReader->getInputConfiguration(&config); + + ASSERT_EQ(InputConfiguration::KEYBOARD_QWERTY, config.keyboard); + ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation); + ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); +} + +TEST_F(InputReaderTest, GetInputConfiguration_WhenTouchScreenPresent_ReturnsFingerTouchScreen) { + ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("touchscreen"), + INPUT_DEVICE_CLASS_TOUCHSCREEN)); + + InputConfiguration config; + mReader->getInputConfiguration(&config); + + ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); + ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation); + ASSERT_EQ(InputConfiguration::TOUCHSCREEN_FINGER, config.touchScreen); +} + +TEST_F(InputReaderTest, GetInputConfiguration_WhenTrackballPresent_ReturnsTrackballNavigation) { + ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("trackball"), + INPUT_DEVICE_CLASS_TRACKBALL)); + + InputConfiguration config; + mReader->getInputConfiguration(&config); + + ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); + ASSERT_EQ(InputConfiguration::NAVIGATION_TRACKBALL, config.navigation); + ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); +} + +TEST_F(InputReaderTest, GetInputConfiguration_WhenDPadPresent_ReturnsDPadNavigation) { + ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("dpad"), + INPUT_DEVICE_CLASS_DPAD)); + + InputConfiguration config; + mReader->getInputConfiguration(&config); + + ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); + ASSERT_EQ(InputConfiguration::NAVIGATION_DPAD, config.navigation); + ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); +} + +TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsValid) { + ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), + INPUT_DEVICE_CLASS_KEYBOARD)); + + InputDeviceInfo info; + status_t result = mReader->getInputDeviceInfo(1, &info); + + ASSERT_EQ(OK, result); + ASSERT_EQ(1, info.getId()); + ASSERT_STREQ("keyboard", info.getName().string()); + ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, info.getKeyboardType()); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, info.getSources()); + ASSERT_EQ(size_t(0), info.getMotionRanges().size()); +} + +TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsInvalid) { + InputDeviceInfo info; + status_t result = mReader->getInputDeviceInfo(-1, &info); + + ASSERT_EQ(NAME_NOT_FOUND, result); +} + +TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsIgnored) { + addDevice(1, String8("ignored"), 0); // no classes so device will be ignored + + InputDeviceInfo info; + status_t result = mReader->getInputDeviceInfo(1, &info); + + ASSERT_EQ(NAME_NOT_FOUND, result); +} + +TEST_F(InputReaderTest, GetInputDeviceIds) { + ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), + INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY)); + ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("trackball"), + INPUT_DEVICE_CLASS_TRACKBALL)); + + Vector<int32_t> ids; + mReader->getInputDeviceIds(ids); + + ASSERT_EQ(size_t(2), ids.size()); + ASSERT_EQ(1, ids[0]); + ASSERT_EQ(2, ids[1]); +} + +TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { + FakeInputMapper* mapper = NULL; + ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0, + AINPUT_SOURCE_ANY, AKEYCODE_A)) + << "Should return unknown when the device id is >= 0 but unknown."; + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1, + AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return unknown when the device id is valid but the sources are not supported by the device."; + + ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1, + AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1, + AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; + + ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(-1, + AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; +} + +TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { + FakeInputMapper* mapper = NULL; + ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN); + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0, + AINPUT_SOURCE_ANY, KEY_A)) + << "Should return unknown when the device id is >= 0 but unknown."; + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1, + AINPUT_SOURCE_TRACKBALL, KEY_A)) + << "Should return unknown when the device id is valid but the sources are not supported by the device."; + + ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1, + AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) + << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1, + AINPUT_SOURCE_TRACKBALL, KEY_A)) + << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; + + ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(-1, + AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) + << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; +} + +TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { + FakeInputMapper* mapper = NULL; + ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN); + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0, + AINPUT_SOURCE_ANY, SW_LID)) + << "Should return unknown when the device id is >= 0 but unknown."; + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1, + AINPUT_SOURCE_TRACKBALL, SW_LID)) + << "Should return unknown when the device id is valid but the sources are not supported by the device."; + + ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1, + AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) + << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1, + AINPUT_SOURCE_TRACKBALL, SW_LID)) + << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; + + ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(-1, + AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) + << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; +} + +TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { + FakeInputMapper* mapper = NULL; + ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + mapper->addSupportedKeyCode(AKEYCODE_A); + mapper->addSupportedKeyCode(AKEYCODE_B); + + const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; + uint8_t flags[4] = { 0, 0, 0, 1 }; + + ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags)) + << "Should return false when device id is >= 0 but unknown."; + ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); + + flags[3] = 1; + ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + << "Should return false when device id is valid but the sources are not supported by the device."; + ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); + + flags[3] = 1; + ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); + + flags[3] = 1; + ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + << "Should return false when the device id is < 0 but the sources are not supported by any device."; + ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); + + flags[3] = 1; + ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; + ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); +} + +TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) { + addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD); + + FakeInputDispatcher::NotifyConfigurationChangedArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyConfigurationChangedWasCalled(&args)); + ASSERT_EQ(ARBITRARY_TIME, args.eventTime); +} + +TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { + FakeInputMapper* mapper = NULL; + ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + + mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, AKEYCODE_A, 1, POLICY_FLAG_WAKE); + mReader->loopOnce(); + ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty()); + + RawEvent event; + ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event)); + ASSERT_EQ(0, event.when); + ASSERT_EQ(1, event.deviceId); + ASSERT_EQ(EV_KEY, event.type); + ASSERT_EQ(KEY_A, event.scanCode); + ASSERT_EQ(AKEYCODE_A, event.keyCode); + ASSERT_EQ(1, event.value); + ASSERT_EQ(POLICY_FLAG_WAKE, event.flags); +} + + +// --- InputDeviceTest --- + +class InputDeviceTest : public testing::Test { +protected: + static const char* DEVICE_NAME; + static const int32_t DEVICE_ID; + + sp<FakeEventHub> mFakeEventHub; + sp<FakeInputReaderPolicy> mFakePolicy; + sp<FakeInputDispatcher> mFakeDispatcher; + FakeInputReaderContext* mFakeContext; + + InputDevice* mDevice; + + virtual void SetUp() { + mFakeEventHub = new FakeEventHub(); + mFakePolicy = new FakeInputReaderPolicy(); + mFakeDispatcher = new FakeInputDispatcher(); + mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeDispatcher); + + mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME)); + } + + virtual void TearDown() { + delete mDevice; + + delete mFakeContext; + mFakeDispatcher.clear(); + mFakePolicy.clear(); + mFakeEventHub.clear(); + } +}; + +const char* InputDeviceTest::DEVICE_NAME = "device"; +const int32_t InputDeviceTest::DEVICE_ID = 1; + +TEST_F(InputDeviceTest, ImmutableProperties) { + ASSERT_EQ(DEVICE_ID, mDevice->getId()); + ASSERT_STREQ(DEVICE_NAME, mDevice->getName()); +} + +TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { + // Configuration. + mDevice->configure(); + + // Metadata. + ASSERT_TRUE(mDevice->isIgnored()); + ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mDevice->getSources()); + + InputDeviceInfo info; + mDevice->getDeviceInfo(&info); + ASSERT_EQ(DEVICE_ID, info.getId()); + ASSERT_STREQ(DEVICE_NAME, info.getName().string()); + ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType()); + ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources()); + + // State queries. + ASSERT_EQ(0, mDevice->getMetaState()); + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, 0)) + << "Ignored device should return unknown key code state."; + ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 0)) + << "Ignored device should return unknown scan code state."; + ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0)) + << "Ignored device should return unknown switch state."; + + const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; + uint8_t flags[2] = { 0, 1 }; + ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags)) + << "Ignored device should never mark any key codes."; + ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; + ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; + + // Reset. + mDevice->reset(); +} + +TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { + // Configuration. + InputDeviceCalibration calibration; + calibration.addProperty(String8("key"), String8("value")); + mFakePolicy->addInputDeviceCalibration(String8(DEVICE_NAME), calibration); + + FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD); + mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); + mapper1->setMetaState(AMETA_ALT_ON); + mapper1->addSupportedKeyCode(AKEYCODE_A); + mapper1->addSupportedKeyCode(AKEYCODE_B); + mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); + mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP); + mapper1->setScanCodeState(2, AKEY_STATE_DOWN); + mapper1->setScanCodeState(3, AKEY_STATE_UP); + mapper1->setSwitchState(4, AKEY_STATE_DOWN); + mDevice->addMapper(mapper1); + + FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); + mapper2->setMetaState(AMETA_SHIFT_ON); + mDevice->addMapper(mapper2); + + mDevice->configure(); + + String8 propertyValue; + ASSERT_TRUE(mDevice->getCalibration().tryGetProperty(String8("key"), propertyValue)) + << "Device should have read calibration during configuration phase."; + ASSERT_STREQ("value", propertyValue.string()); + + ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled()); + + // Metadata. + ASSERT_FALSE(mDevice->isIgnored()); + ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), mDevice->getSources()); + + InputDeviceInfo info; + mDevice->getDeviceInfo(&info); + ASSERT_EQ(DEVICE_ID, info.getId()); + ASSERT_STREQ(DEVICE_NAME, info.getName().string()); + ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType()); + ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources()); + + // State queries. + ASSERT_EQ(AMETA_ALT_ON | AMETA_SHIFT_ON, mDevice->getMetaState()) + << "Should query mappers and combine meta states."; + + ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return unknown key code state when source not supported."; + ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return unknown scan code state when source not supported."; + ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return unknown switch state when source not supported."; + + ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, AKEYCODE_A)) + << "Should query mapper when source is supported."; + ASSERT_EQ(AKEY_STATE_UP, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 3)) + << "Should query mapper when source is supported."; + ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4)) + << "Should query mapper when source is supported."; + + const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; + uint8_t flags[4] = { 0, 0, 0, 1 }; + ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + << "Should do nothing when source is unsupported."; + ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported."; + ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported."; + ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported."; + ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported."; + + ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags)) + << "Should query mapper when source is supported."; + ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set."; + ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set."; + ASSERT_EQ(0, flags[2]) << "Flag for unsupported key should be unchanged."; + ASSERT_EQ(1, flags[3]) << "Flag for unsupported key should be unchanged."; + + // Event handling. + RawEvent event; + mDevice->process(&event); + + ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); + + // Reset. + mDevice->reset(); + + ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); +} + + +// --- InputMapperTest --- + +class InputMapperTest : public testing::Test { +protected: + static const char* DEVICE_NAME; + static const int32_t DEVICE_ID; + + sp<FakeEventHub> mFakeEventHub; + sp<FakeInputReaderPolicy> mFakePolicy; + sp<FakeInputDispatcher> mFakeDispatcher; + FakeInputReaderContext* mFakeContext; + InputDevice* mDevice; + + virtual void SetUp() { + mFakeEventHub = new FakeEventHub(); + mFakePolicy = new FakeInputReaderPolicy(); + mFakeDispatcher = new FakeInputDispatcher(); + mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeDispatcher); + mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME)); + + mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); + } + + virtual void TearDown() { + delete mDevice; + delete mFakeContext; + mFakeDispatcher.clear(); + mFakePolicy.clear(); + mFakeEventHub.clear(); + } + + void prepareCalibration(const char* key, const char* value) { + mFakePolicy->addInputDeviceCalibrationProperty(String8(DEVICE_NAME), + String8(key), String8(value)); + } + + void addMapperAndConfigure(InputMapper* mapper) { + mDevice->addMapper(mapper); + mDevice->configure(); + } + + static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type, + int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) { + RawEvent event; + event.when = when; + event.deviceId = deviceId; + event.type = type; + event.scanCode = scanCode; + event.keyCode = keyCode; + event.value = value; + event.flags = flags; + mapper->process(&event); + } + + static void assertMotionRange(const InputDeviceInfo& info, + int32_t rangeType, float min, float max, float flat, float fuzz) { + const InputDeviceInfo::MotionRange* range = info.getMotionRange(rangeType); + ASSERT_TRUE(range != NULL) << "Range: " << rangeType; + ASSERT_NEAR(min, range->min, EPSILON) << "Range: " << rangeType; + ASSERT_NEAR(max, range->max, EPSILON) << "Range: " << rangeType; + ASSERT_NEAR(flat, range->flat, EPSILON) << "Range: " << rangeType; + ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Range: " << rangeType; + } + + static void assertPointerCoords(const PointerCoords& coords, + float x, float y, float pressure, float size, + float touchMajor, float touchMinor, float toolMajor, float toolMinor, + float orientation) { + ASSERT_NEAR(x, coords.x, 1); + ASSERT_NEAR(y, coords.y, 1); + ASSERT_NEAR(pressure, coords.pressure, EPSILON); + ASSERT_NEAR(size, coords.size, EPSILON); + ASSERT_NEAR(touchMajor, coords.touchMajor, 1); + ASSERT_NEAR(touchMinor, coords.touchMinor, 1); + ASSERT_NEAR(toolMajor, coords.toolMajor, 1); + ASSERT_NEAR(toolMinor, coords.toolMinor, 1); + ASSERT_NEAR(orientation, coords.orientation, EPSILON); + } +}; + +const char* InputMapperTest::DEVICE_NAME = "device"; +const int32_t InputMapperTest::DEVICE_ID = 1; + + +// --- SwitchInputMapperTest --- + +class SwitchInputMapperTest : public InputMapperTest { +protected: +}; + +TEST_F(SwitchInputMapperTest, GetSources) { + SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); + addMapperAndConfigure(mapper); + + ASSERT_EQ(uint32_t(0), mapper->getSources()); +} + +TEST_F(SwitchInputMapperTest, GetSwitchState) { + SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); + addMapperAndConfigure(mapper); + + mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1); + ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); + + mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0); + ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); +} + +TEST_F(SwitchInputMapperTest, Process) { + SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); + addMapperAndConfigure(mapper); + + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_LID, 0, 1, 0); + + FakeInputDispatcher::NotifySwitchArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifySwitchWasCalled(&args)); + ASSERT_EQ(ARBITRARY_TIME, args.when); + ASSERT_EQ(SW_LID, args.switchCode); + ASSERT_EQ(1, args.switchValue); + ASSERT_EQ(uint32_t(0), args.policyFlags); +} + + +// --- KeyboardInputMapperTest --- + +class KeyboardInputMapperTest : public InputMapperTest { +protected: + void testDPadKeyRotation(KeyboardInputMapper* mapper, + int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode); +}; + +void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, + int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) { + FakeInputDispatcher::NotifyKeyArgs args; + + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, originalKeyCode, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); + ASSERT_EQ(originalScanCode, args.scanCode); + ASSERT_EQ(rotatedKeyCode, args.keyCode); + + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, originalKeyCode, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(originalScanCode, args.scanCode); + ASSERT_EQ(rotatedKeyCode, args.keyCode); +} + + +TEST_F(KeyboardInputMapperTest, GetSources) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources()); +} + +TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + // Key down. + process(mapper, ARBITRARY_TIME, DEVICE_ID, + EV_KEY, KEY_HOME, AKEYCODE_HOME, 1, POLICY_FLAG_WAKE); + FakeInputDispatcher::NotifyKeyArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(ARBITRARY_TIME, args.eventTime); + ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); + ASSERT_EQ(AKEYCODE_HOME, args.keyCode); + ASSERT_EQ(KEY_HOME, args.scanCode); + ASSERT_EQ(AMETA_NONE, args.metaState); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); + ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); + ASSERT_EQ(ARBITRARY_TIME, args.downTime); + + // Key up. + process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, + EV_KEY, KEY_HOME, AKEYCODE_HOME, 0, POLICY_FLAG_WAKE); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(AKEYCODE_HOME, args.keyCode); + ASSERT_EQ(KEY_HOME, args.scanCode); + ASSERT_EQ(AMETA_NONE, args.metaState); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); + ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); + ASSERT_EQ(ARBITRARY_TIME, args.downTime); +} + +TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + // Key down. + process(mapper, ARBITRARY_TIME, DEVICE_ID, + EV_KEY, KEY_HOME, AKEYCODE_HOME, 1, POLICY_FLAG_WAKE); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + // Key up. + process(mapper, ARBITRARY_TIME, DEVICE_ID, + EV_KEY, KEY_HOME, AKEYCODE_HOME, 0, POLICY_FLAG_WAKE); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + // Reset. Since no keys still down, should not synthesize any key ups. + mapper->reset(); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); +} + +TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + // Metakey down. + process(mapper, ARBITRARY_TIME, DEVICE_ID, + EV_KEY, KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + // Key down. + process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, + EV_KEY, KEY_A, AKEYCODE_A, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + // Reset. Since two keys are still down, should synthesize two key ups in reverse order. + mapper->reset(); + + FakeInputDispatcher::NotifyKeyArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(AKEYCODE_A, args.keyCode); + ASSERT_EQ(KEY_A, args.scanCode); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); + ASSERT_EQ(uint32_t(0), args.policyFlags); + ASSERT_EQ(ARBITRARY_TIME + 1, args.downTime); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(AKEYCODE_SHIFT_LEFT, args.keyCode); + ASSERT_EQ(KEY_LEFTSHIFT, args.scanCode); + ASSERT_EQ(AMETA_NONE, args.metaState); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); + ASSERT_EQ(uint32_t(0), args.policyFlags); + ASSERT_EQ(ARBITRARY_TIME + 1, args.downTime); + + // And that's it. + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); +} + +TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + // Initial metastate. + ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); + + // Metakey down. + process(mapper, ARBITRARY_TIME, DEVICE_ID, + EV_KEY, KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT, 1, 0); + FakeInputDispatcher::NotifyKeyArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); + ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); + + // Key down. + process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, + EV_KEY, KEY_A, AKEYCODE_A, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); + + // Key up. + process(mapper, ARBITRARY_TIME + 2, DEVICE_ID, + EV_KEY, KEY_A, AKEYCODE_A, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); + + // Metakey up. + process(mapper, ARBITRARY_TIME + 3, DEVICE_ID, + EV_KEY, KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AMETA_NONE, args.metaState); + ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); + ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); +} + +TEST_F(KeyboardInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateDPad) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); +} + +TEST_F(KeyboardInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateDPad) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, DISPLAY_ID, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_0); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_90); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN)); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_180); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT)); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_270); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, + KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP)); + + // Special case: if orientation changes while key is down, we still emit the same keycode + // in the key up as we did in the key down. + FakeInputDispatcher::NotifyKeyArgs args; + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_270); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); + ASSERT_EQ(KEY_UP, args.scanCode); + ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_180); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(KEY_UP, args.scanCode); + ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); +} + +TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1); + ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); + + mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0); + ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); +} + +TEST_F(KeyboardInputMapperTest, GetScanCodeState) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1); + ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); + + mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0); + ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); +} + +TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + mFakeEventHub->addKey(DEVICE_ID, KEY_A, AKEYCODE_A, 0); + + const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; + uint8_t flags[2] = { 0, 0 }; + ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); + ASSERT_TRUE(flags[0]); + ASSERT_FALSE(flags[1]); +} + + +// --- TrackballInputMapperTest --- + +class TrackballInputMapperTest : public InputMapperTest { +protected: + static const int32_t TRACKBALL_MOVEMENT_THRESHOLD; + + void testMotionRotation(TrackballInputMapper* mapper, + int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); +}; + +const int32_t TrackballInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; + +void TrackballInputMapperTest::testMotionRotation(TrackballInputMapper* mapper, + int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) { + FakeInputDispatcher::NotifyMotionArgs args; + + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, originalX, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, originalY, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, + float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); +} + +TEST_F(TrackballInputMapperTest, GetSources) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); +} + +TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + InputDeviceInfo info; + mapper->populateDeviceInfo(&info); + + ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X, + -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); + ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y, + -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); +} + +TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Button press. + // Mostly testing non x/y behavior here so we don't need to check again elsewhere. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(ARBITRARY_TIME, args.eventTime); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); + ASSERT_EQ(uint32_t(0), args.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + ASSERT_EQ(0, args.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(0, args.edgeFlags); + ASSERT_EQ(uint32_t(1), args.pointerCount); + ASSERT_EQ(0, args.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); + ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); + ASSERT_EQ(ARBITRARY_TIME, args.downTime); + + // Button release. Should have same down time. + process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); + ASSERT_EQ(uint32_t(0), args.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); + ASSERT_EQ(0, args.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(0, args.edgeFlags); + ASSERT_EQ(uint32_t(1), args.pointerCount); + ASSERT_EQ(0, args.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); + ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); + ASSERT_EQ(ARBITRARY_TIME, args.downTime); +} + +TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Motion in X but not Y. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, 1, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + + // Motion in Y but not X. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, -2, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + ASSERT_NEAR(0.0f, args.pointerCoords[0].x, EPSILON); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); +} + +TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Button press without following sync. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + + // Button release without following sync. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); +} + +TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Combined X, Y and Button. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, 1, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, -2, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + + // Move X, Y a bit while pressed. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 0, 2, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 0, 1, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + + // Release Button. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); +} + +TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Button press. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + + // Button release. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + + // Reset. Should not synthesize button up since button is not pressed. + mapper->reset(); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); +} + +TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Button press. + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + + // Reset. Should synthesize button up. + mapper->reset(); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); +} + +TEST_F(TrackballInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateMotions) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + addMapperAndConfigure(mapper); + + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); +} + +TEST_F(TrackballInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateMotions) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, DISPLAY_ID); + addMapperAndConfigure(mapper); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_0); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_90); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_180); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); + + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_270); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); + ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); +} + + +// --- TouchInputMapperTest --- + +class TouchInputMapperTest : public InputMapperTest { +protected: + static const int32_t RAW_X_MIN; + static const int32_t RAW_X_MAX; + static const int32_t RAW_Y_MIN; + static const int32_t RAW_Y_MAX; + static const int32_t RAW_TOUCH_MIN; + static const int32_t RAW_TOUCH_MAX; + static const int32_t RAW_TOOL_MIN; + static const int32_t RAW_TOOL_MAX; + static const int32_t RAW_PRESSURE_MIN; + static const int32_t RAW_PRESSURE_MAX; + static const int32_t RAW_ORIENTATION_MIN; + static const int32_t RAW_ORIENTATION_MAX; + static const int32_t RAW_ID_MIN; + static const int32_t RAW_ID_MAX; + static const float X_PRECISION; + static const float Y_PRECISION; + + static const VirtualKeyDefinition VIRTUAL_KEYS[2]; + + enum Axes { + POSITION = 1 << 0, + TOUCH = 1 << 1, + TOOL = 1 << 2, + PRESSURE = 1 << 3, + ORIENTATION = 1 << 4, + MINOR = 1 << 5, + ID = 1 << 6, + }; + + void prepareDisplay(int32_t orientation); + void prepareVirtualKeys(); + int32_t toRawX(float displayX); + int32_t toRawY(float displayY); + float toDisplayX(int32_t rawX); + float toDisplayY(int32_t rawY); +}; + +const int32_t TouchInputMapperTest::RAW_X_MIN = 25; +const int32_t TouchInputMapperTest::RAW_X_MAX = 1020; +const int32_t TouchInputMapperTest::RAW_Y_MIN = 30; +const int32_t TouchInputMapperTest::RAW_Y_MAX = 1010; +const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0; +const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31; +const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0; +const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15; +const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN; +const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX; +const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; +const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; +const int32_t TouchInputMapperTest::RAW_ID_MIN = 0; +const int32_t TouchInputMapperTest::RAW_ID_MAX = 9; +const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH; +const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT; + +const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { + { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 }, + { KEY_MENU, DISPLAY_HEIGHT - 60, DISPLAY_WIDTH + 15, 20, 20 }, +}; + +void TouchInputMapperTest::prepareDisplay(int32_t orientation) { + mFakePolicy->setDisplayInfo(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation); +} + +void TouchInputMapperTest::prepareVirtualKeys() { + mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[0]); + mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[1]); + mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, AKEYCODE_HOME, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, AKEYCODE_MENU, POLICY_FLAG_WAKE); +} + +int32_t TouchInputMapperTest::toRawX(float displayX) { + return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH + RAW_X_MIN); +} + +int32_t TouchInputMapperTest::toRawY(float displayY) { + return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT + RAW_Y_MIN); +} + +float TouchInputMapperTest::toDisplayX(int32_t rawX) { + return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN); +} + +float TouchInputMapperTest::toDisplayY(int32_t rawY) { + return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN); +} + + +// --- SingleTouchInputMapperTest --- + +class SingleTouchInputMapperTest : public TouchInputMapperTest { +protected: + void prepareAxes(int axes); + + void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y); + void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y); + void processUp(SingleTouchInputMapper* mappery); + void processPressure(SingleTouchInputMapper* mapper, int32_t pressure); + void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor); + void processSync(SingleTouchInputMapper* mapper); +}; + +void SingleTouchInputMapperTest::prepareAxes(int axes) { + if (axes & POSITION) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0); + mFakeEventHub->addAxis(DEVICE_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); + } + if (axes & PRESSURE) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); + } + if (axes & TOOL) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); + } +} + +void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0, 1, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, 0, x, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, 0, y, 0); +} + +void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, 0, x, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, 0, y, 0); +} + +void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0, 0, 0); +} + +void SingleTouchInputMapperTest::processPressure( + SingleTouchInputMapper* mapper, int32_t pressure) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_PRESSURE, 0, pressure, 0); +} + +void SingleTouchInputMapperTest::processToolMajor( + SingleTouchInputMapper* mapper, int32_t toolMajor) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TOOL_WIDTH, 0, toolMajor, 0); +} + +void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); +} + + +TEST_F(SingleTouchInputMapperTest, GetSources_WhenNotAttachedToADisplay_ReturnsTouchPad) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, -1); + prepareAxes(POSITION); + addMapperAndConfigure(mapper); + + ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); +} + +TEST_F(SingleTouchInputMapperTest, GetSources_WhenAttachedToADisplay_ReturnsTouchScreen) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareAxes(POSITION); + addMapperAndConfigure(mapper); + + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); +} + +TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + // Unknown key. + ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); + + // Virtual key is down. + int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); + int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); + processDown(mapper, x, y); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); + + // Virtual key is up. + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); +} + +TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + // Unknown key. + ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); + + // Virtual key is down. + int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); + int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); + processDown(mapper, x, y); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); + + // Virtual key is up. + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); +} + +TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; + uint8_t flags[2] = { 0, 0 }; + ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); + ASSERT_TRUE(flags[0]); + ASSERT_FALSE(flags[1]); +} + +TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) { + // Note: Ideally we should send cancels but the implementation is more straightforward + // with up and this will only happen if a device is forcibly removed. + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + // Press virtual key. + int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); + int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); + processDown(mapper, x, y); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + // Reset. Since key is down, synthesize key up. + mapper->reset(); + + FakeInputDispatcher::NotifyKeyArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + //ASSERT_EQ(ARBITRARY_TIME, args.eventTime); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); + ASSERT_EQ(AKEYCODE_HOME, args.keyCode); + ASSERT_EQ(KEY_HOME, args.scanCode); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(ARBITRARY_TIME, args.downTime); +} + +TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + // Press virtual key. + int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); + int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); + processDown(mapper, x, y); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + // Release virtual key. + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled()); + + // Reset. Since no key is down, nothing happens. + mapper->reset(); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + FakeInputDispatcher::NotifyKeyArgs args; + + // Press virtual key. + int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); + int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); + processDown(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(ARBITRARY_TIME, args.eventTime); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); + ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); + ASSERT_EQ(AKEYCODE_HOME, args.keyCode); + ASSERT_EQ(KEY_HOME, args.scanCode); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(ARBITRARY_TIME, args.downTime); + + // Release virtual key. + processUp(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(ARBITRARY_TIME, args.eventTime); + ASSERT_EQ(DEVICE_ID, args.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); + ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); + ASSERT_EQ(AKEYCODE_HOME, args.keyCode); + ASSERT_EQ(KEY_HOME, args.scanCode); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(ARBITRARY_TIME, args.downTime); + + // Should not have sent any motions. + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + FakeInputDispatcher::NotifyKeyArgs keyArgs; + + // Press virtual key. + int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); + int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); + processDown(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&keyArgs)); + ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); + ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); + ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); + ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, keyArgs.flags); + ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); + ASSERT_EQ(KEY_HOME, keyArgs.scanCode); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); + ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); + + // Move out of bounds. This should generate a cancel and a pointer down since we moved + // into the display area. + y -= 100; + processMove(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&keyArgs)); + ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); + ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); + ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); + ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY + | AKEY_EVENT_FLAG_CANCELED, keyArgs.flags); + ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); + ASSERT_EQ(KEY_HOME, keyArgs.scanCode); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); + ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); + + FakeInputDispatcher::NotifyMotionArgs motionArgs; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Keep moving out of bounds. Should generate a pointer move. + y -= 50; + processMove(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Release out of bounds. Should generate a pointer up. + processUp(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Should not have sent any more keys or motions. + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + FakeInputDispatcher::NotifyMotionArgs motionArgs; + + // Initially go down out of bounds. + int32_t x = -10; + int32_t y = -10; + processDown(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); + + // Move into the display area. Should generate a pointer down. + x = 50; + y = 75; + processMove(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Release. Should generate a pointer up. + processUp(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Should not have sent any more keys or motions. + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + FakeInputDispatcher::NotifyMotionArgs motionArgs; + + // Down. + int32_t x = 100; + int32_t y = 125; + processDown(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Move. + x += 50; + y += 75; + processMove(mapper, x, y); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Up. + processUp(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Should not have sent any more keys or motions. + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_Rotation) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareAxes(POSITION); + addMapperAndConfigure(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Rotation 0. + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + processDown(mapper, toRawX(50), toRawY(75)); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NEAR(50, args.pointerCoords[0].x, 1); + ASSERT_NEAR(75, args.pointerCoords[0].y, 1); + + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); + + // Rotation 90. + prepareDisplay(InputReaderPolicyInterface::ROTATION_90); + processDown(mapper, toRawX(50), toRawY(75)); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NEAR(75, args.pointerCoords[0].x, 1); + ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].y, 1); + + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); + + // Rotation 180. + prepareDisplay(InputReaderPolicyInterface::ROTATION_180); + processDown(mapper, toRawX(50), toRawY(75)); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].x, 1); + ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].y, 1); + + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); + + // Rotation 270. + prepareDisplay(InputReaderPolicyInterface::ROTATION_270); + processDown(mapper, toRawX(50), toRawY(75)); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].x, 1); + ASSERT_NEAR(50, args.pointerCoords[0].y, 1); + + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION | PRESSURE | TOOL); + addMapperAndConfigure(mapper); + + // These calculations are based on the input device calibration documentation. + int32_t rawX = 100; + int32_t rawY = 200; + int32_t rawPressure = 10; + int32_t rawToolMajor = 12; + + float x = toDisplayX(rawX); + float y = toDisplayY(rawY); + float pressure = float(rawPressure) / RAW_PRESSURE_MAX; + float size = float(rawToolMajor) / RAW_TOOL_MAX; + float tool = min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * size; + float touch = min(tool * pressure, tool); + + processDown(mapper, rawX, rawY); + processPressure(mapper, rawPressure); + processToolMajor(mapper, rawToolMajor); + processSync(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + x, y, pressure, size, touch, touch, tool, tool, 0)); +} + + +// --- MultiTouchInputMapperTest --- + +class MultiTouchInputMapperTest : public TouchInputMapperTest { +protected: + void prepareAxes(int axes); + + void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y); + void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor); + void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor); + void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor); + void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor); + void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation); + void processPressure(MultiTouchInputMapper* mapper, int32_t pressure); + void processId(MultiTouchInputMapper* mapper, int32_t id); + void processMTSync(MultiTouchInputMapper* mapper); + void processSync(MultiTouchInputMapper* mapper); +}; + +void MultiTouchInputMapperTest::prepareAxes(int axes) { + if (axes & POSITION) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0); + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); + } + if (axes & TOUCH) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); + if (axes & MINOR) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, + RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); + } + } + if (axes & TOOL) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); + if (axes & MINOR) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR, + RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0); + } + } + if (axes & ORIENTATION) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_ORIENTATION, + RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0); + } + if (axes & PRESSURE) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_PRESSURE, + RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); + } + if (axes & ID) { + mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TRACKING_ID, + RAW_ID_MIN, RAW_ID_MAX, 0, 0); + } +} + +void MultiTouchInputMapperTest::processPosition( + MultiTouchInputMapper* mapper, int32_t x, int32_t y) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, 0, x, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, 0, y, 0); +} + +void MultiTouchInputMapperTest::processTouchMajor( + MultiTouchInputMapper* mapper, int32_t touchMajor) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, 0, touchMajor, 0); +} + +void MultiTouchInputMapperTest::processTouchMinor( + MultiTouchInputMapper* mapper, int32_t touchMinor) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, 0, touchMinor, 0); +} + +void MultiTouchInputMapperTest::processToolMajor( + MultiTouchInputMapper* mapper, int32_t toolMajor) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MAJOR, 0, toolMajor, 0); +} + +void MultiTouchInputMapperTest::processToolMinor( + MultiTouchInputMapper* mapper, int32_t toolMinor) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MINOR, 0, toolMinor, 0); +} + +void MultiTouchInputMapperTest::processOrientation( + MultiTouchInputMapper* mapper, int32_t orientation) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, 0, orientation, 0); +} + +void MultiTouchInputMapperTest::processPressure( + MultiTouchInputMapper* mapper, int32_t pressure) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_PRESSURE, 0, pressure, 0); +} + +void MultiTouchInputMapperTest::processId( + MultiTouchInputMapper* mapper, int32_t id) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TRACKING_ID, 0, id, 0); +} + +void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0, 0, 0); +} + +void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); +} + + +TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) { + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + FakeInputDispatcher::NotifyMotionArgs motionArgs; + + // Two fingers down at once. + int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; + processPosition(mapper, x1, y1); + processMTSync(mapper); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Move. + x1 += 10; y1 += 15; x2 += 5; y2 -= 10; + processPosition(mapper, x1, y1); + processMTSync(mapper); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // First finger up. + x2 += 15; y2 -= 20; + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Move. + x2 += 20; y2 -= 25; + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // New finger down. + int32_t x3 = 700, y3 = 300; + processPosition(mapper, x2, y2); + processMTSync(mapper); + processPosition(mapper, x3, y3); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Second finger up. + x3 += 30; y3 -= 20; + processPosition(mapper, x3, y3); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Last finger up. + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); + ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); + ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_EQ(0, motionArgs.flags); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.edgeFlags); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); + ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); + ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); + + // Should not have sent any more keys or motions. + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); +} + +TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION | ID); + prepareVirtualKeys(); + addMapperAndConfigure(mapper); + + mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); + + FakeInputDispatcher::NotifyMotionArgs motionArgs; + + // Two fingers down at once. + int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; + processPosition(mapper, x1, y1); + processId(mapper, 1); + processMTSync(mapper); + processPosition(mapper, x2, y2); + processId(mapper, 2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_EQ(2, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + + // Move. + x1 += 10; y1 += 15; x2 += 5; y2 -= 10; + processPosition(mapper, x1, y1); + processId(mapper, 1); + processMTSync(mapper); + processPosition(mapper, x2, y2); + processId(mapper, 2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_EQ(2, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + + // First finger up. + x2 += 15; y2 -= 20; + processPosition(mapper, x2, y2); + processId(mapper, 2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_EQ(2, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(2, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + + // Move. + x2 += 20; y2 -= 25; + processPosition(mapper, x2, y2); + processId(mapper, 2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(2, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + + // New finger down. + int32_t x3 = 700, y3 = 300; + processPosition(mapper, x2, y2); + processId(mapper, 2); + processMTSync(mapper); + processPosition(mapper, x3, y3); + processId(mapper, 3); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(2, motionArgs.pointerIds[0]); + ASSERT_EQ(3, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + + // Second finger up. + x3 += 30; y3 -= 20; + processPosition(mapper, x3, y3); + processId(mapper, 3); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(size_t(2), motionArgs.pointerCount); + ASSERT_EQ(2, motionArgs.pointerIds[0]); + ASSERT_EQ(3, motionArgs.pointerIds[1]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(3, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + + // Last finger up. + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_EQ(size_t(1), motionArgs.pointerCount); + ASSERT_EQ(3, motionArgs.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], + toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); + + // Should not have sent any more keys or motions. + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); +} + +TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR); + addMapperAndConfigure(mapper); + + // These calculations are based on the input device calibration documentation. + int32_t rawX = 100; + int32_t rawY = 200; + int32_t rawTouchMajor = 7; + int32_t rawTouchMinor = 6; + int32_t rawToolMajor = 9; + int32_t rawToolMinor = 8; + int32_t rawPressure = 11; + int32_t rawOrientation = 3; + int32_t id = 5; + + float x = toDisplayX(rawX); + float y = toDisplayY(rawY); + float pressure = float(rawPressure) / RAW_PRESSURE_MAX; + float size = avg(rawToolMajor, rawToolMinor) / RAW_TOOL_MAX; + float toolMajor = float(min(DISPLAY_WIDTH, DISPLAY_HEIGHT)) * rawToolMajor / RAW_TOOL_MAX; + float toolMinor = float(min(DISPLAY_WIDTH, DISPLAY_HEIGHT)) * rawToolMinor / RAW_TOOL_MAX; + float touchMajor = min(toolMajor * pressure, toolMajor); + float touchMinor = min(toolMinor * pressure, toolMinor); + float orientation = float(rawOrientation) / RAW_ORIENTATION_MAX * M_PI_2; + + processPosition(mapper, rawX, rawY); + processTouchMajor(mapper, rawTouchMajor); + processTouchMinor(mapper, rawTouchMinor); + processToolMajor(mapper, rawToolMajor); + processToolMinor(mapper, rawToolMinor); + processPressure(mapper, rawPressure); + processOrientation(mapper, rawOrientation); + processId(mapper, id); + processMTSync(mapper); + processSync(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(id, args.pointerIds[0]); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, orientation)); +} + +TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION | TOUCH | TOOL | MINOR); + prepareCalibration("touch.touchSize.calibration", "geometric"); + prepareCalibration("touch.toolSize.calibration", "geometric"); + addMapperAndConfigure(mapper); + + // These calculations are based on the input device calibration documentation. + int32_t rawX = 100; + int32_t rawY = 200; + int32_t rawTouchMajor = 140; + int32_t rawTouchMinor = 120; + int32_t rawToolMajor = 180; + int32_t rawToolMinor = 160; + + float x = toDisplayX(rawX); + float y = toDisplayY(rawY); + float pressure = float(rawTouchMajor) / RAW_TOUCH_MAX; + float size = avg(rawToolMajor, rawToolMinor) / RAW_TOOL_MAX; + float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN), + float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN)); + float toolMajor = float(rawToolMajor) * scale; + float toolMinor = float(rawToolMinor) * scale; + float touchMajor = min(float(rawTouchMajor) * scale, toolMajor); + float touchMinor = min(float(rawTouchMinor) * scale, toolMinor); + + processPosition(mapper, rawX, rawY); + processTouchMajor(mapper, rawTouchMajor); + processTouchMinor(mapper, rawTouchMinor); + processToolMajor(mapper, rawToolMajor); + processToolMinor(mapper, rawToolMinor); + processMTSync(mapper); + processSync(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, 0)); +} + +TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinearCalibration) { + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION | TOUCH | TOOL); + prepareCalibration("touch.touchSize.calibration", "pressure"); + prepareCalibration("touch.toolSize.calibration", "linear"); + prepareCalibration("touch.toolSize.linearScale", "10"); + prepareCalibration("touch.toolSize.linearBias", "160"); + prepareCalibration("touch.toolSize.isSummed", "1"); + prepareCalibration("touch.pressure.calibration", "amplitude"); + prepareCalibration("touch.pressure.source", "touch"); + prepareCalibration("touch.pressure.scale", "0.01"); + addMapperAndConfigure(mapper); + + // These calculations are based on the input device calibration documentation. + // Note: We only provide a single common touch/tool value because the device is assumed + // not to emit separate values for each pointer (isSummed = 1). + int32_t rawX = 100; + int32_t rawY = 200; + int32_t rawX2 = 150; + int32_t rawY2 = 250; + int32_t rawTouchMajor = 60; + int32_t rawToolMajor = 5; + + float x = toDisplayX(rawX); + float y = toDisplayY(rawY); + float x2 = toDisplayX(rawX2); + float y2 = toDisplayY(rawY2); + float pressure = float(rawTouchMajor) * 0.01f; + float size = float(rawToolMajor) / RAW_TOOL_MAX; + float tool = (float(rawToolMajor) * 10.0f + 160.0f) / 2; + float touch = min(tool * pressure, tool); + + processPosition(mapper, rawX, rawY); + processTouchMajor(mapper, rawTouchMajor); + processToolMajor(mapper, rawToolMajor); + processMTSync(mapper); + processPosition(mapper, rawX2, rawY2); + processTouchMajor(mapper, rawTouchMajor); + processToolMajor(mapper, rawToolMajor); + processMTSync(mapper); + processSync(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + ASSERT_EQ(size_t(2), args.pointerCount); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + x, y, pressure, size, touch, touch, tool, tool, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[1], + x2, y2, pressure, size, touch, touch, tool, tool, 0)); +} + +TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_AreaCalibration) { + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + prepareDisplay(InputReaderPolicyInterface::ROTATION_0); + prepareAxes(POSITION | TOUCH | TOOL); + prepareCalibration("touch.touchSize.calibration", "pressure"); + prepareCalibration("touch.toolSize.calibration", "area"); + prepareCalibration("touch.toolSize.areaScale", "22"); + prepareCalibration("touch.toolSize.areaBias", "1"); + prepareCalibration("touch.toolSize.linearScale", "9.2"); + prepareCalibration("touch.toolSize.linearBias", "3"); + prepareCalibration("touch.pressure.calibration", "amplitude"); + prepareCalibration("touch.pressure.source", "touch"); + prepareCalibration("touch.pressure.scale", "0.01"); + addMapperAndConfigure(mapper); + + // These calculations are based on the input device calibration documentation. + int32_t rawX = 100; + int32_t rawY = 200; + int32_t rawTouchMajor = 60; + int32_t rawToolMajor = 5; + + float x = toDisplayX(rawX); + float y = toDisplayY(rawY); + float pressure = float(rawTouchMajor) * 0.01f; + float size = float(rawToolMajor) / RAW_TOOL_MAX; + float tool = sqrtf(float(rawToolMajor) * 22.0f + 1.0f) * 9.2f + 3.0f; + float touch = min(tool * pressure, tool); + + processPosition(mapper, rawX, rawY); + processTouchMajor(mapper, rawTouchMajor); + processToolMajor(mapper, rawToolMajor); + processMTSync(mapper); + processSync(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], + x, y, pressure, size, touch, touch, tool, tool, 0)); +} + +} // namespace android diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index 5ff1f8f..4261196 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -412,10 +412,18 @@ void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash) /* * Find a matching entry. * - * Returns 0 if not found. + * Returns NULL if not found. */ ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const { + /* + * If the ZipFileRO instance is not initialized, the entry number will + * end up being garbage since mHashTableSize is -1. + */ + if (mHashTableSize <= 0) { + return NULL; + } + int nameLen = strlen(fileName); unsigned int hash = computeHash(fileName, nameLen); int ent = hash & (mHashTableSize-1); diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 6aa1ae6..23f34d2 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -58,6 +58,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; @@ -1112,18 +1113,16 @@ public class AudioService extends IAudioService.Stub { new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { mBluetoothHeadset = (BluetoothHeadset) proxy; - Set<BluetoothDevice> deviceSet = mBluetoothHeadset.getConnectedDevices(); - if (deviceSet.size() > 0) { - BluetoothDevice[] devices = - deviceSet.toArray(new BluetoothDevice[deviceSet.size()]); - mBluetoothHeadsetDevice = devices[0]; + List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); + if (deviceList.size() > 0) { + mBluetoothHeadsetDevice = deviceList.get(0); } else { mBluetoothHeadsetDevice = null; } } public void onServiceDisconnected(int profile) { if (mBluetoothHeadset != null) { - Set<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices(); + List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices(); if (devices.size() == 0) { mBluetoothHeadsetDevice = null; clearAllScoClients(); diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 57cafd4..27b28ee 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -131,6 +131,7 @@ static void captureCallback(void* user, samplingrate, 0, jArray); + env->DeleteLocalRef(jArray); } } diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index 40801a2..f975217 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -24,6 +24,7 @@ enum { ENABLE_GRAPHIC_BUFFERS, USE_BUFFER, USE_GRAPHIC_BUFFER, + STORE_META_DATA_IN_BUFFERS, ALLOC_BUFFER, ALLOC_BUFFER_WITH_BACKUP, FREE_BUFFER, @@ -276,6 +277,19 @@ public: return err; } + virtual status_t storeMetaDataInBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeInt32((uint32_t)enable); + remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply); + + status_t err = reply.readInt32(); + return err; + } + virtual status_t allocateBuffer( node_id node, OMX_U32 port_index, size_t size, buffer_id *buffer, void **buffer_data) { @@ -634,6 +648,20 @@ status_t BnOMX::onTransact( return NO_ERROR; } + case STORE_META_DATA_IN_BUFFERS: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + OMX_BOOL enable = (OMX_BOOL)data.readInt32(); + + status_t err = storeMetaDataInBuffers(node, port_index, enable); + reply->writeInt32(err); + + return NO_ERROR; + } + case ALLOC_BUFFER: { CHECK_INTERFACE(IOMX, data, reply); diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index 83b75ad..5a6c96f9 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -62,6 +62,9 @@ public: virtual status_t enableGraphicBuffers( node_id node, OMX_U32 port_index, OMX_BOOL enable); + virtual status_t storeMetaDataInBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable); + virtual status_t useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, buffer_id *buffer); diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index 8c7c562..86c102c 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -50,6 +50,7 @@ struct OMXNodeInstance { status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size); status_t enableGraphicBuffers(OMX_U32 portIndex, OMX_BOOL enable); + status_t storeMetaDataInBuffers(OMX_U32 portIndex, OMX_BOOL enable); status_t useBuffer( OMX_U32 portIndex, const sp<IMemory> ¶ms, diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index d89f54b..f9f638f 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -294,6 +294,11 @@ status_t OMX::enableGraphicBuffers( return findInstance(node)->enableGraphicBuffers(port_index, enable); } +status_t OMX::storeMetaDataInBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable) { + return findInstance(node)->storeMetaDataInBuffers(port_index, enable); +} + status_t OMX::useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, buffer_id *buffer) { diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index ba4d765..9b6d441 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -284,6 +284,37 @@ status_t OMXNodeInstance::enableGraphicBuffers( return OK; } +status_t OMXNodeInstance::storeMetaDataInBuffers( + OMX_U32 portIndex, + OMX_BOOL enable) { + Mutex::Autolock autolock(mLock); + + OMX_INDEXTYPE index; + OMX_STRING name = const_cast<OMX_STRING>( + "OMX.google.android.index.storeMetaDataInBuffers"); + + OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); + if (err != OMX_ErrorNone) { + LOGE("OMX_GetExtensionIndex %s failed", name); + return StatusFromOMXError(err); + } + + StoreMetaDataInBuffersParams params; + memset(¶ms, 0, sizeof(params)); + params.nSize = sizeof(params); + + // Version: 1.0.0.0 + params.nVersion.s.nVersionMajor = 1; + + params.nPortIndex = portIndex; + params.bStoreMetaData = enable; + if ((err = OMX_SetParameter(mHandle, index, ¶ms)) != OMX_ErrorNone) { + LOGE("OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x%08x", err); + return UNKNOWN_ERROR; + } + return err; +} + status_t OMXNodeInstance::useBuffer( OMX_U32 portIndex, const sp<IMemory> ¶ms, OMX::buffer_id *buffer) { diff --git a/native/copy-to-ndk.sh b/native/copy-to-ndk.sh index 4f5a16a..6470892 100644 --- a/native/copy-to-ndk.sh +++ b/native/copy-to-ndk.sh @@ -10,7 +10,7 @@ copyndkheaders() { local DST_HEADERS=$NDK_PLATFORMS/$CURR_PLATFORM local SRC_LIB_ANDROID=$ANDROID_PRODUCT_OUT/system/lib/libandroid.so - local DST_LIB_ANDROID=$NDK_PLATFORMS/$CURR_PLATFORM/arch-arm/usr/lib/libandroid.so + local DST_LIB_ANDROID=$NDK_PLATFORMS/$CURR_PLATFORM/arch-arm/lib/libandroid.so local didsomething="" @@ -20,9 +20,9 @@ copyndkheaders() { local src=$SRC_HEADERS/$i local changed="" for j in $ALL_PLATFORMS; do - local dst=$NDK_PLATFORMS/$j/arch-arm/usr/include/android/$i + local dst=$NDK_PLATFORMS/$j/include/android/$i if [ "$changed" == "" -a -e $dst ]; then - #echo "Exists: $dst" + echo "Exists: $dst" if diff $src $dst >/dev/null; then echo "$i: has not changed from $j" >/dev/null changed="false" @@ -34,13 +34,13 @@ copyndkheaders() { done if [ "$changed" == "true" -o "$changed" == "" ]; then echo "Updating: $i" - cp $src $NDK_PLATFORMS/$CURR_PLATFORM/arch-arm/usr/include/android/$i + cp $src $NDK_PLATFORMS/$CURR_PLATFORM/include/android/$i didsomething="true" fi done if diff $SRC_LIB_ANDROID $DST_LIB_ANDROID >/dev/null; then - echo "libandroid.so: has not changed" >/dev/null + echo "libandroid.so: has not changed" else echo "Updating: $DST_LIB_ANDROID" cp $SRC_LIB_ANDROID $DST_LIB_ANDROID diff --git a/native/include/android/input.h b/native/include/android/input.h index d190e49..729dd2e 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -336,6 +336,8 @@ enum { AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, + + AINPUT_SOURCE_ANY = 0xffffff00, }; /* diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h index a8f11c9..d89bc8b 100644 --- a/native/include/android/native_activity.h +++ b/native/include/android/native_activity.h @@ -223,18 +223,34 @@ typedef void ANativeActivity_createFunc(ANativeActivity* activity, /** * The name of the function that NativeInstance looks for when launching its - * native code. + * native code. This is the default function that is used, you can specify + * "android.app.func_name" string meta-data in your manifest to use a different + * function. */ extern ANativeActivity_createFunc ANativeActivity_onCreate; /** * Finish the given activity. Its finish() method will be called, causing it - * to be stopped and destroyed. + * to be stopped and destroyed. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. */ void ANativeActivity_finish(ANativeActivity* activity); +/** + * Change the window format of the given activity. Calls getWindow().setFormat() + * of the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. + */ void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); +/** + * Change the window flags of the given activity. Calls getWindow().setFlags() + * of the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. See window.h for flag constants. + */ void ANativeActivity_setWindowFlags(ANativeActivity* activity, uint32_t addFlags, uint32_t removeFlags); @@ -247,6 +263,12 @@ enum { ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002, }; +/** + * Show the IME while in the given activity. Calls InputMethodManager.showSoftInput() + * for the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. + */ void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags); /** @@ -258,6 +280,12 @@ enum { ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002, }; +/** + * Hide the IME while in the given activity. Calls InputMethodManager.hideSoftInput() + * for the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. + */ void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags); #ifdef __cplusplus diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/packages/SystemUI/res/anim/notification_dnd_off.xml new file mode 100644 index 0000000..4e88855 --- /dev/null +++ b/packages/SystemUI/res/anim/notification_dnd_off.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + > + <translate android:fromXDelta="100%p" android:toXDelta="0" + android:duration="@android:integer/config_longAnimTime" + android:interpolator="@anim/hydraulic_brake_interpolator" + /> +</set> diff --git a/packages/SystemUI/res/anim/notification_dnd_on.xml b/packages/SystemUI/res/anim/notification_dnd_on.xml new file mode 100644 index 0000000..309943b --- /dev/null +++ b/packages/SystemUI/res/anim/notification_dnd_on.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + > + <translate android:toXDelta="100%p" android:fromXDelta="0" + android:duration="@android:integer/config_longAnimTime" + android:interpolator="@anim/hydraulic_brake_interpolator" + /> +</set> diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png Binary files differdeleted file mode 100644 index 6c5a79b..0000000 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_avail.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_avail.png Binary files differnew file mode 100644 index 0000000..9123fef --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_avail.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_avail_open.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_avail_open.png Binary files differnew file mode 100644 index 0000000..8e56f2a --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_avail_open.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_dnd.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_dnd.png Binary files differnew file mode 100644 index 0000000..80cf99c --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_dnd.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_none.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_none.png Binary files differnew file mode 100644 index 0000000..e0d018b --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_none.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_none_open.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_none_open.png Binary files differnew file mode 100644 index 0000000..5db8c9c --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_noti_none_open.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png Binary files differindex 5c57802..f99a66d 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png Binary files differindex a2527b3..94a0649 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png Binary files differindex f219ded..7e8ade5 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png Binary files differindex 9e64fe8..7e8ade5 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_recent_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_default.png Binary files differindex 4dd8dc7..7de67b0 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_recent_default.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_default.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_recent_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_pressed.png Binary files differindex 350a3e9..7de67b0 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_recent_pressed.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_pressed.png diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml index 8824028..429fdf2 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml @@ -28,26 +28,27 @@ > <ImageView - android:id="@+id/expand" + android:id="@+id/notificationTrigger" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/ic_sysbar_open" + android:layout_height="match_parent" + android:layout_alignParentRight="true" + android:layout_marginLeft="6dip" + android:src="@drawable/ic_sysbar_noti_none" android:background="@drawable/ic_sysbar_icon_bg" - android:paddingLeft="6dip" + android:gravity="center" /> <LinearLayout android:id="@+id/notificationButtons" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_toRightOf="@+id/expand" - android:layout_toLeftOf="@+id/systemInfo" + android:layout_toLeftOf="@+id/notificationTrigger" android:gravity="center_vertical" android:orientation="horizontal" android:visibility="gone" > - <TextView android:id="@+id/do_not_disturb" + <TextView android:id="@+id/clear_all_button" style="?android:attr/textAppearance" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -57,10 +58,10 @@ android:layout_marginRight="10dip" android:padding="6dip" android:textSize="14sp" - android:text="@string/status_bar_do_not_disturb_button" + android:text="@string/status_bar_clear_all_button" /> - <TextView android:id="@+id/clear_all_button" + <TextView android:id="@+id/do_not_disturb" style="?android:attr/textAppearance" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -70,7 +71,7 @@ android:layout_marginRight="10dip" android:padding="6dip" android:textSize="14sp" - android:text="@string/status_bar_clear_all_button" + android:text="@string/status_bar_do_not_disturb_button" /> </LinearLayout> @@ -79,26 +80,10 @@ android:id="@+id/notificationIcons" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_toRightOf="@+id/expand" - android:layout_toLeftOf="@+id/systemInfo" + android:layout_toLeftOf="@+id/notificationTrigger" android:gravity="center_vertical" android:orientation="horizontal" > - <view - class="com.android.systemui.statusbar.tablet.NotificationIconArea$IconLayout" - android:id="@+id/icons" - android:layout_width="wrap_content" - android:layout_height="@*android:dimen/status_bar_icon_size" - android:layout_marginLeft="8dip" - /> - <view - class="com.android.systemui.statusbar.tablet.NotificationIconArea$DraggerView" - android:id="@+id/handle" - android:layout_width="32dip" - android:layout_height="match_parent" - android:background="@drawable/sysbar_hidenotification_handle" - android:layout_marginLeft="8dip" - /> <com.android.systemui.statusbar.tablet.InputMethodButton android:id="@+id/imeButton" android:layout_width="wrap_content" @@ -106,7 +91,14 @@ android:layout_marginLeft="8dip" android:src="@drawable/ic_sysbar_ime_default" android:background="@drawable/ic_sysbar_icon_bg" - android:visibility="visible" + android:visibility="invisible" + /> + <view + class="com.android.systemui.statusbar.tablet.NotificationIconArea$IconLayout" + android:id="@+id/icons" + android:layout_width="wrap_content" + android:layout_height="@*android:dimen/status_bar_icon_size" + android:layout_marginLeft="8dip" /> </com.android.systemui.statusbar.tablet.NotificationIconArea> @@ -115,8 +107,8 @@ android:id="@+id/ticker" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_alignParentLeft="true" - android:layout_toLeftOf="@+id/systemInfo" + android:layout_alignParentRight="true" + android:layout_toRightOf="@+id/systemInfo" android:paddingLeft="6dip" android:gravity="center_vertical" android:animateLayoutChanges="true" @@ -132,16 +124,53 @@ android:id="@+id/navigationArea" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_alignParentRight="true" + android:layout_alignParentLeft="true" android:orientation="horizontal" > + + <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:paddingLeft="15dip" + android:paddingRight="15dip" + android:src="@drawable/status_bar_back" + android:background="@drawable/ic_sysbar_icon_bg" + systemui:keyCode="4" + /> + <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:paddingLeft="15dip" + android:paddingRight="15dip" + android:src="@drawable/ic_sysbar_home" + android:background="@drawable/ic_sysbar_icon_bg" + systemui:keyCode="3" + /> + <ImageButton android:id="@+id/recent" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:src="@drawable/ic_sysbar_recent" + android:background="@drawable/ic_sysbar_icon_bg" + android:paddingLeft="15dip" + android:paddingRight="15dip" + /> + <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:paddingLeft="15dip" + android:paddingRight="15dip" + android:src="@drawable/ic_sysbar_menu" + android:background="@drawable/ic_sysbar_icon_bg" + systemui:keyCode="82" + android:visibility="invisible" + /> <com.android.systemui.statusbar.tablet.ShirtPocket android:id="@+id/pocket" android:layout_width="71dip" android:layout_height="match_parent" android:background="@drawable/ic_sysbar_icon_bg" - android:paddingLeft="4dip" - android:paddingRight="4dip" + android:paddingLeft="15dip" + android:paddingRight="15dip" android:animateLayoutChanges="true" android:clickable="true" android:descendantFocusability="blocksDescendants" @@ -156,42 +185,6 @@ android:gravity="center" /> </com.android.systemui.statusbar.tablet.ShirtPocket> - <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_menu" - android:background="@drawable/ic_sysbar_icon_bg" - android:paddingLeft="4dip" - android:paddingRight="4dip" - systemui:keyCode="82" - android:visibility="invisible" - /> - <ImageButton android:id="@+id/recent" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_recent" - android:background="@drawable/ic_sysbar_icon_bg" - android:paddingLeft="4dip" - android:paddingRight="4dip" - /> - <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:paddingLeft="4dip" - android:paddingRight="4dip" - android:src="@drawable/ic_sysbar_home" - android:background="@drawable/ic_sysbar_icon_bg" - systemui:keyCode="3" - /> - <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:paddingLeft="4dip" - android:paddingRight="4dip" - android:src="@drawable/ic_sysbar_back" - android:background="@drawable/ic_sysbar_icon_bg" - systemui:keyCode="4" - /> </LinearLayout> </RelativeLayout> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml new file mode 100644 index 0000000..ff59db0 --- /dev/null +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Vymazat"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žádná oznámení"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Probíhající"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Prosím připojte dobíjecí zařízení"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Baterie je vybitá:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g> nebo méně."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Využití baterie"</string> +</resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml new file mode 100644 index 0000000..9389617 --- /dev/null +++ b/packages/SystemUI/res/values-da/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ryd"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen meddelelser"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelelser"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Forbind oplader"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er ved at være fladt:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> eller mindre tilbage."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Batteriforbrug"</string> +</resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml new file mode 100644 index 0000000..3ea65d9 --- /dev/null +++ b/packages/SystemUI/res/values-de/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Löschen"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Keine Benachrichtigungen"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Ladegerät anschließen"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Akku ist fast leer."</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> oder weniger verbleiben."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Akkuverbrauch"</string> +</resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml new file mode 100644 index 0000000..cba1047 --- /dev/null +++ b/packages/SystemUI/res/values-el/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Εκκαθάριση"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Δεν υπάρχουν ειδοποιήσεις"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Συνδέστε τον φορτιστή"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Η στάθμη της μπαταρίας είναι χαμηλή:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g> ή λιγότερο."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Χρήση μπαταρίας"</string> +</resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml new file mode 100644 index 0000000..56dead5 --- /dev/null +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No hay notificaciones"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Hay poca batería:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"Restan <xliff:g id="NUMBER">%d%%</xliff:g> o menos."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string> +</resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml new file mode 100644 index 0000000..4ebe492 --- /dev/null +++ b/packages/SystemUI/res/values-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No tienes notificaciones"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Se está agotando la batería:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> o menos disponible"</string> + <string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string> +</resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml new file mode 100644 index 0000000..7aff506 --- /dev/null +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Effacer"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Branchez le chargeur"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Le niveau de la batterie est bas :"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"Maximum <xliff:g id="NUMBER">%d%%</xliff:g> restants."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string> +</resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml new file mode 100644 index 0000000..496a82e --- /dev/null +++ b/packages/SystemUI/res/values-it/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Cancella"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nessuna notifica"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"In corso"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Collegare il caricabatterie"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteria quasi scarica:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente o meno."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Utilizzo batteria"</string> +</resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml new file mode 100644 index 0000000..24c018b --- /dev/null +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"通知を消去"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"通知なし"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"実行中"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string> + <string name="battery_low_title" msgid="7923774589611311406">"充電してください"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"電池が残り少なくなっています:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"残り<xliff:g id="NUMBER">%d%%</xliff:g>未満です。"</string> + <string name="battery_low_why" msgid="7279169609518386372">"電池使用量"</string> +</resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml new file mode 100644 index 0000000..0b6649d --- /dev/null +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"지우기"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"알림 없음"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string> + <string name="battery_low_title" msgid="7923774589611311406">"충전기를 연결하세요."</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"배터리 전원이 부족합니다."</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"잔여 배터리가 <xliff:g id="NUMBER">%d%%</xliff:g> 이하입니다."</string> + <string name="battery_low_why" msgid="7279169609518386372">"배터리 사용량"</string> +</resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml new file mode 100644 index 0000000..5684e57 --- /dev/null +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Fjern"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen varslinger"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Koble til en lader"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er nesten tomt:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Batteribruk"</string> +</resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml new file mode 100644 index 0000000..cd10b29 --- /dev/null +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wissen"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen meldingen"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Sluit de oplader aan"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"De accu raakt op:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> of minder resterend."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Accugebruik"</string> +</resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml new file mode 100644 index 0000000..70f3ad2 --- /dev/null +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wyczyść"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Brak powiadomień"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Podłącz ładowarkę"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Bateria się rozładowuje:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g> lub mniej."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Użycie baterii"</string> +</resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml new file mode 100644 index 0000000..492063a --- /dev/null +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Limpar"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Ligue o carregador"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está a ficar fraca:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"Restam <xliff:g id="NUMBER">%d%%</xliff:g> ou menos."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Utilização da bateria"</string> +</resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml new file mode 100644 index 0000000..08effa7 --- /dev/null +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Limpar"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Conecte o carregador"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está ficando baixa:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> ou menos restante(s)."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Uso da bateria"</string> +</resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml new file mode 100644 index 0000000..7c5bcf7 --- /dev/null +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Очистить"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Нет уведомлений"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текущие"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Подключите зарядное устройство"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Батарея разряжена:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g> или меньше."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Расход заряда батареи"</string> +</resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml new file mode 100644 index 0000000..1127c9d --- /dev/null +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ta bort"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Inga aviseringar"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Anslut laddaren"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet håller på att ta slut:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> eller mindre kvar."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Batteriförbrukning"</string> +</resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml new file mode 100644 index 0000000..dd66d82 --- /dev/null +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Temizle"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirim yok"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string> + <string name="battery_low_title" msgid="7923774589611311406">"Lütfen şarj cihazını takın"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"Pil tükeniyor:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> veya daha az kaldı."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Pil kullanımı"</string> +</resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000..cda0317 --- /dev/null +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"无通知"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行的"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string> + <string name="battery_low_title" msgid="7923774589611311406">"请连接充电器"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"电量所剩不多:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"电量剩余 <xliff:g id="NUMBER">%d%%</xliff:g> 或更少。"</string> + <string name="battery_low_why" msgid="7279169609518386372">"电量使用情况"</string> +</resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..503087b --- /dev/null +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for app_label (4489004083283879149) --> + <skip /> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"沒有通知"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string> + <string name="battery_low_title" msgid="7923774589611311406">"請連接充電器"</string> + <string name="battery_low_subtitle" msgid="7388781709819722764">"電池電量即將不足:"</string> + <string name="battery_low_percent_format" msgid="696154104579022959">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g> 以下。"</string> + <string name="battery_low_why" msgid="7279169609518386372">"電池使用狀況"</string> +</resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java index 7c7d74c..2b4f9d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java @@ -32,13 +32,11 @@ public class NotificationIconArea extends LinearLayout { private static final String TAG = "NotificationIconArea"; IconLayout mIconLayout; - DraggerView mDraggerView; public NotificationIconArea(Context context, AttributeSet attrs) { super(context, attrs); mIconLayout = (IconLayout)findViewById(R.id.icons); - mDraggerView = (DraggerView) findViewById(R.id.handle); } static class IconLayout extends LinearLayout { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java index 6426e7e..d11aba6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java @@ -77,7 +77,7 @@ public class TabletStatusBarService extends StatusBarService { private NotificationData mNotns = new NotificationData(); TabletStatusBarView mStatusBarView; - View mNotificationTrigger; + ImageView mNotificationTrigger; NotificationIconArea mNotificationIconArea; View mNotificationButtons; View mSystemInfo; @@ -132,7 +132,7 @@ public class TabletStatusBarService extends StatusBarService { WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, PixelFormat.TRANSLUCENT); - lp.gravity = Gravity.BOTTOM | Gravity.LEFT; + lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; lp.setTitle("NotificationPanel"); lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard; @@ -192,7 +192,7 @@ public class TabletStatusBarService extends StatusBarService { mCurtains.setOnLongClickListener(on); // the button to open the notification area - mNotificationTrigger = sb.findViewById(R.id.expand); + mNotificationTrigger = (ImageView) sb.findViewById(R.id.notificationTrigger); mNotificationTrigger.setOnClickListener(mOnClickListener); // the more notifications icon @@ -222,6 +222,7 @@ public class TabletStatusBarService extends StatusBarService { // set the initial view visibility setAreThereNotifications(); + refreshNotificationTrigger(); // Add the windows addPanelWindows(); @@ -253,6 +254,7 @@ public class TabletStatusBarService extends StatusBarService { R.anim.notification_icons_out); setViewVisibility(mNotificationButtons, View.VISIBLE, R.anim.notification_buttons_in); + refreshNotificationTrigger(); } break; case MSG_CLOSE_NOTIFICATION_PANEL: @@ -263,6 +265,7 @@ public class TabletStatusBarService extends StatusBarService { R.anim.notification_icons_in); setViewVisibility(mNotificationButtons, View.GONE, R.anim.notification_buttons_out); + refreshNotificationTrigger(); } break; case MSG_OPEN_SYSTEM_PANEL: @@ -276,6 +279,22 @@ public class TabletStatusBarService extends StatusBarService { } } } + + public void refreshNotificationTrigger() { + if (mNotificationTrigger == null) return; + + int resId; + boolean panel = (mNotificationPanel != null + && mNotificationPanel.getVisibility() == View.VISIBLE); + if (!mNotificationsOn) { + resId = R.drawable.ic_sysbar_noti_dnd; + } else if (mNotns.size() > 0) { + resId = panel ? R.drawable.ic_sysbar_noti_avail_open : R.drawable.ic_sysbar_noti_avail; + } else { + resId = panel ? R.drawable.ic_sysbar_noti_none_open : R.drawable.ic_sysbar_noti_none; + } + mNotificationTrigger.setImageResource(resId); + } public void setBatteryMeter(int level, boolean plugged) { if (DEBUG) Slog.d(TAG, "battery=" + level + (plugged ? " - plugged" : " - unplugged")); @@ -598,21 +617,30 @@ public class TabletStatusBarService extends StatusBarService { // system process is dead if we're here. } animateCollapse(); + refreshNotificationTrigger(); } void onClickDoNotDisturb() { mNotificationsOn = !mNotificationsOn; + mIconLayout.setVisibility(mNotificationsOn ? View.VISIBLE : View.INVISIBLE); // TODO: animation animateCollapse(); + refreshNotificationTrigger(); } public void onClickNotificationTrigger() { if (DEBUG) Slog.d(TAG, "clicked notification icons"); if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) { - int msg = (mNotificationPanel.getVisibility() == View.GONE) - ? MSG_OPEN_NOTIFICATION_PANEL - : MSG_CLOSE_NOTIFICATION_PANEL; - mHandler.removeMessages(msg); - mHandler.sendEmptyMessage(msg); + if (!mNotificationsOn) { + mNotificationsOn = true; + mIconLayout.setVisibility(View.VISIBLE); // TODO: animation + refreshNotificationTrigger(); + } else { + int msg = (mNotificationPanel.getVisibility() == View.GONE) + ? MSG_OPEN_NOTIFICATION_PANEL + : MSG_CLOSE_NOTIFICATION_PANEL; + mHandler.removeMessages(msg); + mHandler.sendEmptyMessage(msg); + } } } @@ -757,6 +785,8 @@ public class TabletStatusBarService extends StatusBarService { for (int i=0; i<N; i++) { mPile.addView(mNotns.get(N-i-1).row); } + + refreshNotificationTrigger(); } private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index db5f6c1..39224ba 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -58,6 +58,7 @@ import android.util.Config; import android.util.EventLog; import android.util.Log; import android.util.SparseArray; +import android.util.TypedValue; import android.view.ActionMode; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -83,6 +84,7 @@ import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.PopupWindow; import android.widget.ProgressBar; import android.widget.TextView; @@ -1700,6 +1702,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ActionMode mActionMode; private ActionBarContextView mActionModeView; + private PopupWindow mActionModePopup; public DecorView(Context context, int featureId) { super(context); @@ -2019,9 +2022,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mActionModeView == null) { if (hasFeature(FEATURE_ACTION_MODE_OVERLAY)) { mActionModeView = new ActionBarContextView(mContext); - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( - MATCH_PARENT, WRAP_CONTENT); - addView(mActionModeView, params); + mActionModePopup = new PopupWindow(mContext); + mActionModePopup.setLayoutInScreenEnabled(true); + mActionModePopup.setClippingEnabled(false); + mActionModePopup.setContentView(mActionModeView); + mActionModePopup.setWidth(MATCH_PARENT); + + TypedValue heightValue = new TypedValue(); + mContext.getTheme().resolveAttribute( + com.android.internal.R.attr.actionBarSize, heightValue, false); + final int height = TypedValue.complexToDimensionPixelSize(heightValue.data, + mContext.getResources().getDisplayMetrics()); + mActionModePopup.setHeight(height); } else { ViewStub stub = (ViewStub) findViewById( com.android.internal.R.id.action_mode_bar_stub); @@ -2038,6 +2050,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mActionModeView.initForMode(mode); mActionModeView.setVisibility(View.VISIBLE); mActionMode = mode; + if (mActionModePopup != null) { + mActionModePopup.showAtLocation(this, + Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0); + } } else { mActionMode = null; } @@ -2250,6 +2266,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void onDestroyActionMode(ActionMode mode) { mWrapped.onDestroyActionMode(mode); + if (mActionModePopup != null) { + mActionModePopup.dismiss(); + } else if (mActionModeView != null) { + mActionModeView.setVisibility(GONE); + } if (mActionModeView != null) { mActionModeView.removeAllViews(); } diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 2bfdc29..535f07f 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -151,7 +151,10 @@ sp<ICamera> CameraService::connect( LOGE("Fail to open camera hardware (id=%d)", cameraId); return NULL; } - client = new Client(this, cameraClient, hardware, cameraId, callingPid); + CameraInfo info; + HAL_getCameraInfo(cameraId, &info); + client = new Client(this, cameraClient, hardware, cameraId, info.facing, + callingPid); mClient[cameraId] = client; LOG1("CameraService::connect X"); return client; @@ -293,7 +296,7 @@ void CameraService::playSound(sound_kind kind) { CameraService::Client::Client(const sp<CameraService>& cameraService, const sp<ICameraClient>& cameraClient, const sp<CameraHardwareInterface>& hardware, - int cameraId, int clientPid) { + int cameraId, int cameraFacing, int clientPid) { int callingPid = getCallingPid(); LOG1("Client::Client E (pid %d)", callingPid); @@ -301,6 +304,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, mCameraClient = cameraClient; mHardware = hardware; mCameraId = cameraId; + mCameraFacing = cameraFacing; mClientPid = clientPid; mUseOverlay = mHardware->useOverlay(); mMsgEnabled = 0; @@ -318,8 +322,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, // Callback is disabled by default mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; - mOrientation = 0; - mPreviewWindowFlag = 0; + mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT); mOrientationChanged = false; mPlayShutterSound = true; cameraService->setCameraBusy(cameraId); @@ -509,7 +512,7 @@ status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) { result = setOverlay(); } else if (mPreviewWindow != 0) { native_window_set_buffers_transform(mPreviewWindow.get(), - mPreviewWindowFlag); + mOrientation); result = mHardware->setPreviewWindow(mPreviewWindow); } } @@ -637,7 +640,7 @@ status_t CameraService::Client::startPreviewMode() { } else { if (mPreviewWindow != 0) { native_window_set_buffers_transform(mPreviewWindow.get(), - mPreviewWindowFlag); + mOrientation); } mHardware->setPreviewWindow(mPreviewWindow); result = mHardware->startPreview(); @@ -844,26 +847,10 @@ status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t a if (mHardware->previewEnabled()) { return INVALID_OPERATION; } - switch (arg1) { - case 0: - orientation = ISurface::BufferHeap::ROT_0; - mPreviewWindowFlag = 0; - break; - case 90: - orientation = ISurface::BufferHeap::ROT_90; - mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_90; - break; - case 180: - orientation = ISurface::BufferHeap::ROT_180; - mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_180; - break; - case 270: - orientation = ISurface::BufferHeap::ROT_270; - mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_270; - break; - default: - return BAD_VALUE; - } + // Mirror the preview if the camera is front-facing. + orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT); + if (orientation == -1) return BAD_VALUE; + if (mOrientation != orientation) { mOrientation = orientation; if (mOverlayRef != 0) mOrientationChanged = true; @@ -1226,6 +1213,28 @@ void CameraService::Client::copyFrameAndPostCopiedFrame( client->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame); } +int CameraService::Client::getOrientation(int degrees, bool mirror) { + if (!mirror) { + if (degrees == 0) return 0; + else if (degrees == 90) return HAL_TRANSFORM_ROT_90; + else if (degrees == 180) return HAL_TRANSFORM_ROT_180; + else if (degrees == 270) return HAL_TRANSFORM_ROT_270; + } else { // Do mirror (horizontal flip) + if (degrees == 0) { // FLIP_H and ROT_0 + return HAL_TRANSFORM_FLIP_H; + } else if (degrees == 90) { // FLIP_H and ROT_90 + return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90; + } else if (degrees == 180) { // FLIP_H and ROT_180 + return HAL_TRANSFORM_FLIP_V; + } else if (degrees == 270) { // FLIP_H and ROT_270 + return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90; + } + } + LOGE("Invalid setDisplayOrientation degrees=%d", degrees); + return -1; +} + + // ---------------------------------------------------------------------------- static const int kDumpLockRetries = 50; diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index b5b85bc..60e0d04 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -117,6 +117,7 @@ private: const sp<ICameraClient>& cameraClient, const sp<CameraHardwareInterface>& hardware, int cameraId, + int cameraFacing, int clientPid); ~Client(); @@ -165,6 +166,8 @@ private: const sp<IMemoryHeap>& heap, size_t offset, size_t size); + int getOrientation(int orientation, bool mirror); + // these are initialized in the constructor. sp<CameraService> mCameraService; // immutable after constructor sp<ICameraClient> mCameraClient; @@ -180,7 +183,6 @@ private: int mOrientation; // Current display orientation // True if display orientation has been changed. This is only used in overlay. int mOrientationChanged; - int mPreviewWindowFlag; bool mPlayShutterSound; // Ensures atomicity among the public methods diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index c50a01e..7c758a2 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -7166,7 +7166,9 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" resourcePath="); pw.println(ps.resourcePathString); pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); pw.print(" obbPath="); pw.println(ps.obbPathString); + pw.print(" versionCode="); pw.println(ps.versionCode); if (ps.pkg != null) { + pw.print(" versionName="); pw.println(ps.pkg.mVersionName); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion); if (ps.pkg.mOperationPending) { @@ -7224,8 +7226,6 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); pw.print(" installStatus="); pw.print(ps.installStatus); pw.print(" enabled="); pw.println(ps.enabled); - pw.print(" versionCode="); pw.print(ps.versionCode); - pw.print(" versionName="); pw.println(ps.pkg.mVersionName); if (ps.disabledComponents.size() > 0) { pw.println(" disabledComponents:"); for (String s : ps.disabledComponents) { diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 76588eb..b3e9f9d 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -1794,8 +1794,12 @@ class PowerManagerService extends IPowerManager.Stub private void updateLightsLocked(int newState, int forceState) { final int oldState = mPowerState; - newState = applyButtonState(newState); - newState = applyKeyboardState(newState); + if ((newState & SCREEN_ON_BIT) != 0) { + // Only turn on the buttons or keyboard if the screen is also on. + // We should never see the buttons on but not the screen. + newState = applyButtonState(newState); + newState = applyKeyboardState(newState); + } final int realDifference = (newState ^ oldState); final int difference = realDifference | forceState; if (difference == 0) { @@ -1898,6 +1902,16 @@ class PowerManagerService extends IPowerManager.Stub INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); } + if (mSpew) { + Slog.d(TAG, "offMask=0x" + Integer.toHexString(offMask) + + " dimMask=0x" + Integer.toHexString(dimMask) + + " onMask=0x" + Integer.toHexString(onMask) + + " difference=0x" + Integer.toHexString(difference) + + " realDifference=0x" + Integer.toHexString(realDifference) + + " forceState=0x" + Integer.toHexString(forceState) + ); + } + if (offMask != 0) { if (mSpew) Slog.i(TAG, "Setting brightess off: " + offMask); setLightBrightness(offMask, Power.BRIGHTNESS_OFF); diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index f5b7ca9..747af26 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -357,7 +357,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyDataActivity()" )) { return; } - handleRemoveListLocked(); synchronized (mRecords) { mDataActivity = state; for (Record r : mRecords) { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 7258729..9bc24d2 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -552,6 +552,7 @@ public class WindowManagerService extends IWindowManager.Stub mInputManager.unregisterInputChannel(mServerChannel); InputQueue.unregisterInputChannel(mClientChannel); mClientChannel.dispose(); + mServerChannel.dispose(); mClientChannel = null; mServerChannel = null; } @@ -624,7 +625,7 @@ public class WindowManagerService extends IWindowManager.Stub } } if (DEBUG_DRAG) { - Slog.d(TAG, "sending DRAG_STARTED to new window " + newWin); + Slog.d(TAG, "need to send DRAG_STARTED to new window " + newWin); } sendDragStartedLw(newWin, mCurrentX, mCurrentY, mDataDescription); } @@ -6242,8 +6243,14 @@ public class WindowManagerService extends IWindowManager.Stub mDragState.register(); mInputMonitor.updateInputWindowsLw(); - mInputManager.transferTouchFocus(callingWin.mInputChannel, - mDragState.mServerChannel); + if (!mInputManager.transferTouchFocus(callingWin.mInputChannel, + mDragState.mServerChannel)) { + Slog.e(TAG, "Unable to transfer touch focus"); + mDragState.unregister(); + mDragState = null; + mInputMonitor.updateInputWindowsLw(); + return false; + } mDragState.mData = data; mDragState.mCurrentX = touchX; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index b0ace2f..8d36e4f 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -6676,6 +6676,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (info.violationNumThisLoop != 0) { sb.append("Loop-Violation-Number: ").append(info.violationNumThisLoop).append("\n"); } + if (info.numAnimationsRunning != 0) { + sb.append("Animations-Running: ").append(info.numAnimationsRunning).append("\n"); + } if (info != null && info.durationMillis != -1) { sb.append("Duration-Millis: ").append(info.durationMillis).append("\n"); } @@ -7152,7 +7155,7 @@ public final class ActivityManagerService extends ActivityManagerNative } else if (adj >= SECONDARY_SERVER_ADJ) { currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; } else if (adj >= HEAVY_WEIGHT_APP_ADJ) { - currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_HEAVY_WEIGHT; + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE; } else if (adj >= PERCEPTIBLE_APP_ADJ) { currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE; } else if (adj >= VISIBLE_APP_ADJ) { @@ -7284,7 +7287,7 @@ public final class ActivityManagerService extends ActivityManagerNative } return; } else if ("service".equals(cmd)) { - dumpService(fd, pw, args, opti, dumpAll); + dumpService(fd, pw, args, opti); return; } else if ("services".equals(cmd) || "s".equals(cmd)) { synchronized (this) { @@ -7643,8 +7646,7 @@ public final class ActivityManagerService extends ActivityManagerNative * - the first arg isn't the flattened component name of an existing service: * dump all services whose component contains the first arg as a substring */ - protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args, - int opti, boolean dumpAll) { + protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args, int opti) { String[] newArgs; String componentNameString; ServiceRecord r; @@ -7664,7 +7666,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (r != null) { - dumpService(fd, pw, r, newArgs, dumpAll); + dumpService(fd, pw, r, newArgs); } else { ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); synchronized (this) { @@ -7676,7 +7678,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } for (int i=0; i<services.size(); i++) { - dumpService(fd, pw, services.get(i), newArgs, dumpAll); + dumpService(fd, pw, services.get(i), newArgs); } } } @@ -7685,16 +7687,10 @@ public final class ActivityManagerService extends ActivityManagerNative * Invokes IApplicationThread.dumpService() on the thread of the specified service if * there is a thread associated with the service. */ - private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args, - boolean dumpAll) { - pw.println(" Service " + r.name.flattenToString()); - if (dumpAll) { - synchronized (this) { - pw.print(" * "); pw.println(r); - r.dump(pw, " "); - } - pw.println(""); - } + private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) { + pw.println("------------------------------------------------------------" + + "-------------------"); + pw.println("APP SERVICE: " + r.name.flattenToString()); if (r.app != null && r.app.thread != null) { try { // flush anything that is already in the PrintWriter since the thread is going diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 4a6b5f4..755a228 100755 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -1451,23 +1451,30 @@ public class GpsLocationProvider implements LocationProviderInterface { mContext.getSystemService(Context.TELEPHONY_SERVICE); if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); - if ((gsm_cell != null) && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) - && (phone.getNetworkOperator().length() > 3)) { + if ((gsm_cell != null) && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) && + (phone.getNetworkOperator() != null) && + (phone.getNetworkOperator().length() > 3)) { int type; int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); - if (phone.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS) + int networkType = phone.getNetworkType(); + if (networkType == TelephonyManager.NETWORK_TYPE_UMTS + || networkType == TelephonyManager.NETWORK_TYPE_HSDPA + || networkType == TelephonyManager.NETWORK_TYPE_HSUPA + || networkType == TelephonyManager.NETWORK_TYPE_HSPA) { type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; - else + } else { type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; + } native_agps_set_ref_location_cellid(type, mcc, mnc, gsm_cell.getLac(), gsm_cell.getCid()); - } - else + } else { Log.e(TAG,"Error getting cell location info."); + } } - else + else { Log.e(TAG,"CDMA not supported."); + } } private void sendMessage(int message, int arg, Object obj) { diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml index 68ecc6e..a4d8c79 100644 --- a/tests/DpiTest/AndroidManifest.xml +++ b/tests/DpiTest/AndroidManifest.xml @@ -18,6 +18,12 @@ package="com.google.android.test.dpi"> <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="3" /> <supports-screens android:smallScreens="true" /> + <compatible-screens> + <screen android:screenSize="small" android:screenDensity="ldpi" /> + <screen android:screenSize="small" android:screenDensity="xhdpi" /> + <screen android:screenSize="large" android:screenDensity="hdpi" /> + <screen android:screenSize="xlarge" android:screenDensity="mdpi" /> + </compatible-screens> <application android:label="DpiTest"> <activity android:name="DpiTestActivity"> <intent-filter> diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 4469e68..e9833c9 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -334,13 +334,15 @@ enum { REQ_FIVE_WAY_NAV_ATTR = 0x01010232, TARGET_SDK_VERSION_ATTR = 0x01010270, TEST_ONLY_ATTR = 0x01010272, - DENSITY_ATTR = 0x0101026c, + ANY_DENSITY_ATTR = 0x0101026c, GL_ES_VERSION_ATTR = 0x01010281, SMALL_SCREEN_ATTR = 0x01010284, NORMAL_SCREEN_ATTR = 0x01010285, LARGE_SCREEN_ATTR = 0x01010286, XLARGE_SCREEN_ATTR = 0x010102bf, REQUIRED_ATTR = 0x0101028e, + SCREEN_SIZE_ATTR = 0x010102ca, + SCREEN_DENSITY_ATTR = 0x010102cb, }; const char *getComponentName(String8 &pkgName, String8 &componentName) { @@ -357,6 +359,42 @@ const char *getComponentName(String8 &pkgName, String8 &componentName) { return retStr.string(); } +static void printCompatibleScreens(ResXMLTree& tree) { + size_t len; + ResXMLTree::event_code_t code; + int depth = 0; + bool first = true; + printf("compatible-screens:"); + while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { + if (code == ResXMLTree::END_TAG) { + depth--; + if (depth < 0) { + break; + } + continue; + } + if (code != ResXMLTree::START_TAG) { + continue; + } + depth++; + String8 tag(tree.getElementName(&len)); + if (tag == "screen") { + int32_t screenSize = getIntegerAttribute(tree, + SCREEN_SIZE_ATTR, NULL, -1); + int32_t screenDensity = getIntegerAttribute(tree, + SCREEN_DENSITY_ATTR, NULL, -1); + if (screenSize > 0 && screenDensity > 0) { + if (!first) { + printf(","); + } + first = false; + printf("'%d/%d'", screenSize, screenDensity); + } + } + } + printf("\n"); +} + /* * Handle the "dump" command, to extract select data from an archive. */ @@ -575,6 +613,7 @@ int doDump(Bundle* bundle) int normalScreen = 1; int largeScreen = 1; int xlargeScreen = 1; + int anyDensity = 1; String8 pkg; String8 activityName; String8 activityLabel; @@ -742,14 +781,6 @@ int doDump(Bundle* bundle) printf(" reqFiveWayNav='%d'", reqFiveWayNav); } printf("\n"); - } else if (tag == "supports-density") { - int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error); - if (error != "") { - fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n", - error.string()); - goto bail; - } - printf("supports-density:'%d'\n", dens); } else if (tag == "supports-screens") { smallScreen = getIntegerAttribute(tree, SMALL_SCREEN_ATTR, NULL, 1); @@ -759,6 +790,8 @@ int doDump(Bundle* bundle) LARGE_SCREEN_ATTR, NULL, 1); xlargeScreen = getIntegerAttribute(tree, XLARGE_SCREEN_ATTR, NULL, 1); + anyDensity = getIntegerAttribute(tree, + ANY_DENSITY_ATTR, NULL, 1); } else if (tag == "uses-feature") { String8 name = getAttribute(tree, NAME_ATTR, &error); @@ -883,6 +916,9 @@ int doDump(Bundle* bundle) error.string()); goto bail; } + } else if (tag == "compatible-screens") { + printCompatibleScreens(tree); + depth--; } } else if (depth == 3 && withinApplication) { withinActivity = false; @@ -1109,6 +1145,9 @@ int doDump(Bundle* bundle) // Introduced in Honeycomb. xlargeScreen = targetSdk >= 10 ? -1 : 0; } + if (anyDensity > 0) { + anyDensity = targetSdk >= 4 ? -1 : 0; + } printf("supports-screens:"); if (smallScreen != 0) printf(" 'small'"); if (normalScreen != 0) printf(" 'normal'"); @@ -1116,6 +1155,8 @@ int doDump(Bundle* bundle) if (xlargeScreen != 0) printf(" 'xlarge'"); printf("\n"); + printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false"); + printf("locales:"); Vector<String8> locales; res.getLocales(&locales); diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath index 175a98b..70140d8 100644 --- a/tools/layoutlib/bridge/.classpath +++ b/tools/layoutlib/bridge/.classpath @@ -4,7 +4,7 @@ <classpathentry kind="src" path="tests"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/> - <classpathentry combineaccessrules="false" kind="src" path="/layoutlib_api"/> + <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/> <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_SRC/dalvik/libcore/xml/src/main/java"/> <classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/layoutlib.jar" sourcepath="/ANDROID_SRC/frameworks/base/core/java"/> <classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/ninepatch.jar" sourcepath="/ANDROID_SRC/development/tools/ninepatch/src"/> diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk index b2010d5..b7a602a 100644 --- a/tools/layoutlib/bridge/Android.mk +++ b/tools/layoutlib/bridge/Android.mk @@ -20,7 +20,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_JAVA_LIBRARIES := \ kxml2-2.3.0 \ - layoutlib_api \ + layoutlib_api-prebuilt \ ninepatch LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java index 590923f..a9ede26 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java @@ -96,6 +96,7 @@ public class AsmGenerator { methods.add(methodName); } for (String className : createInfo.getDelegateClassNatives()) { + className = binaryToInternalClassName(className); Set<String> methods = mDelegateMethods.get(className); if (methods == null) { methods = new HashSet<String>(); @@ -312,6 +313,11 @@ public class AsmGenerator { rv = new RenameClassAdapter(cw, className, newName); } + ClassVisitor cv = new TransformClassAdapter(mLog, mStubMethods, + mDeleteReturns.get(className), + newName, rv, + stubNativesOnly, stubNativesOnly || hasNativeMethods); + Set<String> delegateMethods = mDelegateMethods.get(className); if (delegateMethods != null && !delegateMethods.isEmpty()) { // If delegateMethods only contains one entry ALL_NATIVES and the class is @@ -319,14 +325,10 @@ public class AsmGenerator { if (hasNativeMethods || !(delegateMethods.size() == 1 && delegateMethods.contains(DelegateClassAdapter.ALL_NATIVES))) { - rv = new DelegateClassAdapter(mLog, rv, className, delegateMethods); + cv = new DelegateClassAdapter(mLog, cv, className, delegateMethods); } } - TransformClassAdapter cv = new TransformClassAdapter(mLog, mStubMethods, - mDeleteReturns.get(className), - newName, rv, - stubNativesOnly, stubNativesOnly || hasNativeMethods); cr.accept(cv, 0 /* flags */); return cw.toByteArray(); } diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java index 9ad2e6e..7d80796 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java @@ -28,11 +28,8 @@ import org.junit.Before; import org.junit.Test; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.util.TraceClassVisitor; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -178,24 +175,26 @@ public class DelegateClassAdapterTest { }; cl2.testModifiedInstance(); - } catch (Throwable t) { - // For debugging, dump the bytecode of the class in case of unexpected error. - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - TraceClassVisitor tcv = new TraceClassVisitor(pw); - - ClassReader cr2 = new ClassReader(bytes); - cr2.accept(tcv, 0 /* flags */); - - String msg = "\n" + t.getClass().getCanonicalName(); - if (t.getMessage() != null) { - msg += ": " + t.getMessage(); - } - msg = msg + "\nBytecode dump:\n" + sw.toString(); - - // Re-throw exception with new message - RuntimeException ex = new RuntimeException(msg, t); - throw ex; + // This code block is useful for debugging. However to make it work you need to + // pull in the org.objectweb.asm.util.TraceClassVisitor class and associated + // utilities which are found in the ASM source jar. + // + // } catch (Throwable t) { + // For debugging, dump the bytecode of the class in case of unexpected error. + // StringWriter sw = new StringWriter(); + // PrintWriter pw = new PrintWriter(sw); + // TraceClassVisitor tcv = new TraceClassVisitor(pw); + // ClassReader cr2 = new ClassReader(bytes); + // cr2.accept(tcv, 0 /* flags */); + // String msg = "\n" + t.getClass().getCanonicalName(); + // if (t.getMessage() != null) { + // msg += ": " + t.getMessage(); + // } + // msg = msg + "\nBytecode dump:\n" + sw.toString(); + // // Re-throw exception with new message + // RuntimeException ex = new RuntimeException(msg, t); + // throw ex; + } finally { } } diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 65b910b..e3deeb3 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -79,7 +79,6 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; @@ -1297,14 +1296,14 @@ public class WifiStateMachine extends HierarchicalStateMachine { */ private boolean shouldDisableCoexistenceMode() { if (mBluetoothHeadset == null) return true; - Set<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices(); + List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices(); return (devices.size() != 0 ? false : true); } private void checkIsBluetoothPlaying() { boolean isBluetoothPlaying = false; if (mBluetoothA2dp != null) { - Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedDevices(); + List<BluetoothDevice> connected = mBluetoothA2dp.getConnectedDevices(); for (BluetoothDevice device : connected) { if (mBluetoothA2dp.isA2dpPlaying(device)) { |
