diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 3478e2b8bd6..09427df3857 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -495,12 +495,15 @@ pref("app.update.incompatible.mode", 0); pref("app.update.service.enabled", true); // The URL hosting the update manifest. -//pref("app.update.url", "http://localhost/updates.xml"); +pref("app.update.url", "http://update.boot2gecko.org/m2.5/updates.xml"); // Interval at which update manifest is fetched. In units of seconds. -pref("app.update.interval", 86400); // 24 hours +pref("app.update.interval", 3600); // 1 hour // First interval to elapse before checking for update. In units of // milliseconds. Capped at 10 seconds. pref("app.update.timerFirstInterval", 30000); +pref("app.update.timerMinimumDelay", 30); // seconds +// Don't throttle background updates. +pref("app.update.download.backgroundInterval", 0); // Enable update logging for now, to diagnose growing pains in the // field. diff --git a/b2g/components/UpdatePrompt.js b/b2g/components/UpdatePrompt.js index 8331b03d634..904f7cc6680 100644 --- a/b2g/components/UpdatePrompt.js +++ b/b2g/components/UpdatePrompt.js @@ -24,6 +24,8 @@ UpdatePrompt.prototype = { classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt]), + _selfDestructTimer: null, + // nsIUpdatePrompt // FIXME/bug 737601: we should have users opt-in to downloading @@ -39,6 +41,10 @@ UpdatePrompt.prototype = { log("Update downloaded, restarting to apply it"); + // If not cleanly shut down within 5 seconds, this process will + // explode. + this._setSelfDestructTimer(5000); + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup); // NB: on Gonk, we rely on the system process manager to restart // us. Trying to restart here would conflict with the process @@ -51,6 +57,24 @@ UpdatePrompt.prototype = { ); }, + _setSelfDestructTimer: function UP__setSelfDestructTimer(timeoutMs) { +#ifdef ANDROID + Cu.import("resource://gre/modules/ctypes.jsm"); + let libc = ctypes.open("libc.so"); + let _exit = libc.declare("_exit", ctypes.default_abi, + ctypes.void_t, // [return] + ctypes.int); // status + this.notify = function UP_notify(_) { + log("Self-destruct timer fired; didn't cleanly shut down. BOOM"); + _exit(0); + } + + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.initWithCallback(this, timeoutMs, timer.TYPE_ONE_SHOT); + this._selfDestructTimer = timer; +#endif + }, + showUpdateInstalled: function UP_showUpdateInstalled() { }, showUpdateError: function UP_showUpdateError(aUpdate) { diff --git a/b2g/config/mozconfigs/linux32/debug b/b2g/config/mozconfigs/linux32/debug index b89fe59b7af..b53abb687d1 100644 --- a/b2g/config/mozconfigs/linux32/debug +++ b/b2g/config/mozconfigs/linux32/debug @@ -1,4 +1,5 @@ #GONK_TOOLCHAIN_VERSION=0 +#TOOLCHAIN_HOST=linux-x86 #export GONK_PRODUCT=generic #gonk="/home/cjones/mozilla/gonk-toolchain-$GONK_TOOLCHAIN_VERSION" @@ -10,6 +11,7 @@ ac_add_options --enable-application=b2g ac_add_options --target=arm-android-eabi ac_add_options --with-gonk="$gonk" +ac_add_options --with-gonk-toolchain-prefix="$gonk/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-eabi-4.4.3/bin/arm-eabi-" ac_add_options --with-endian=little ac_add_options --disable-elf-hack ac_add_options --enable-debug-symbols diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 7194295f55f..592b6086cf2 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -402,6 +402,8 @@ @BINPATH@/components/contentAreaDropListener.js @BINPATH@/components/messageWakeupService.js @BINPATH@/components/messageWakeupService.manifest +@BINPATH@/components/SettingsManager.js +@BINPATH@/components/SettingsManager.manifest @BINPATH@/components/nsFilePicker.js @BINPATH@/components/nsFilePicker.manifest #ifdef MOZ_B2G_RIL diff --git a/dom/system/gonk/AudioManager.cpp b/dom/system/gonk/AudioManager.cpp index d901614edee..9434a29f2e9 100644 --- a/dom/system/gonk/AudioManager.cpp +++ b/dom/system/gonk/AudioManager.cpp @@ -117,24 +117,47 @@ AudioManager::SetPhoneState(PRInt32 aState) return NS_OK; } +// +// Kids, don't try this at home. We want this to link and work on +// both GB and ICS. Problem is, the symbol exported by audioflinger +// is different on the two gonks. +// +// So what we do here is weakly link to both of them, and then call +// whichever symbol resolves at dynamic link time (if any). +// NS_IMETHODIMP AudioManager::SetForceForUse(PRInt32 aUsage, PRInt32 aForce) { - /* - * FIXME/bug XXXXXX: why do we need to disable forceUse in ICS? - if (AudioSystem::setForceUse((AudioSystem::force_use)aUsage, - (AudioSystem::forced_config)aForce)) { - return NS_ERROR_FAILURE; + status_t status = 0; + if (static_cast< + status_t (*)(AudioSystem::force_use, AudioSystem::forced_config) + >(AudioSystem::setForceUse)) { + // Dynamically resolved the GB signature. + status = AudioSystem::setForceUse((AudioSystem::force_use)aUsage, + (AudioSystem::forced_config)aForce); + } else if (static_cast< + status_t (*)(audio_policy_force_use_t, audio_policy_forced_cfg_t) + >(AudioSystem::setForceUse)) { + // Dynamically resolved the ICS signature. + status = AudioSystem::setForceUse((audio_policy_force_use_t)aUsage, + (audio_policy_forced_cfg_t)aForce); } - */ - return NS_OK; + + return status ? NS_ERROR_FAILURE : NS_OK; } NS_IMETHODIMP AudioManager::GetForceForUse(PRInt32 aUsage, PRInt32* aForce) { - /* - * FIXME/bug XXXXXX: why do we need to disable forceUse in ICS? - *aForce = AudioSystem::getForceUse((AudioSystem::force_use)aUsage); - */ + if (static_cast< + AudioSystem::forced_config (*)(AudioSystem::force_use) + >(AudioSystem::getForceUse)) { + // Dynamically resolved the GB signature. + *aForce = AudioSystem::getForceUse((AudioSystem::force_use)aUsage); + } else if (static_cast< + audio_policy_forced_cfg_t (*)(audio_policy_force_use_t) + >(AudioSystem::getForceUse)) { + // Dynamically resolved the ICS signature. + *aForce = AudioSystem::getForceUse((audio_policy_force_use_t)aUsage); + } return NS_OK; } diff --git a/dom/wifi/DOMWifiManager.js b/dom/wifi/DOMWifiManager.js index 555be0dacda..b6761292b2a 100644 --- a/dom/wifi/DOMWifiManager.js +++ b/dom/wifi/DOMWifiManager.js @@ -48,18 +48,21 @@ DOMWifiManager.prototype = { // Maintain this state for synchronous APIs. this._currentNetwork = null; this._enabled = true; + this._lastConnectionInfo = null; const messages = ["WifiManager:setEnabled:Return:OK", "WifiManager:setEnabled:Return:NO", "WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO", "WifiManager:associate:Return:OK", "WifiManager:associate:Return:NO", "WifiManager:onconnecting", "WifiManager:onassociate", - "WifiManager:onconnect", "WifiManager:ondisconnect"]; + "WifiManager:onconnect", "WifiManager:ondisconnect", + "WifiManager:connectionInfoUpdate"]; this.initHelper(aWindow, messages); this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender); - var state = this._mm.sendSyncMessage("WifiManager:getState"); - this._currentNetwork = state[0].network; - this._enabled = state[0].enabled; + var state = this._mm.sendSyncMessage("WifiManager:getState")[0]; + this._currentNetwork = state.network; + this._lastConnectionInfo = state.connectionInfo; + this._enabled = state.enabled; }, uninit: function() { @@ -67,6 +70,7 @@ DOMWifiManager.prototype = { this._onAssociate = null; this._onConnect = null; this._onDisconnect = null; + this._onConnectionInfoUpdate = null; }, _sendMessageForRequest: function(name, data, request) { @@ -132,6 +136,12 @@ DOMWifiManager.prototype = { case "WifiManager:ondisconnect": this._fireOnDisconnect(this._currentNetwork); this._currentNetwork = null; + this._lastConnectionInfo = null; + break; + + case "WifiManager:connectionInfoUpdate": + this._lastConnectionInfo = msg; + this._fireConnectionInfoUpdate(msg); break; } }, @@ -152,8 +162,17 @@ DOMWifiManager.prototype = { }, _fireOnDisconnect: function onDisconnect(network) { - if (this._onDisconnect) { + if (this._onDisconnect) this._onDisconnect.handleEvent(new WifiStateChangeEvent(network)); + }, + + _fireConnectionInfoUpdate: function connectionInfoUpdate(info) { + if (this._onConnectionInfoUpdate) { + var evt = new ConnectionInfoUpdate(this._currentNetwork, + info.signalStrength, + info.relSignalStrength, + info.linkSpeed); + this._onConnectionInfoUpdate.handleEvent(evt); } }, @@ -194,6 +213,12 @@ DOMWifiManager.prototype = { return this._currentNetwork; }, + get connectionInfo() { + if (!this._hasPrivileges) + throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE); + return this._lastConnectionInfo; + }, + set onconnecting(callback) { if (!this._hasPrivileges) throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE); @@ -216,6 +241,12 @@ DOMWifiManager.prototype = { if (!this._hasPrivileges) throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE); this._onDisconnect = callback; + }, + + set connectionInfoUpdate(callback) { + if (!this._hasPrivileges) + throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE); + this._onConnectionInfoUpdate = callback; } }; @@ -233,6 +264,23 @@ WifiStateChangeEvent.prototype = { classDescription: "Wifi State Change Event"}) }; +function ConnectionInfoUpdate(network, signalStrength, relSignalStrength, linkSpeed) { + this.network = network; + this.signalStrength = signalStrength; + this.relSignalStrength = relSignalStrength; + this.linkSpeed = linkSpeed; +} + +ConnectionInfoUpdate.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMWifiConnectionInfoEvent]), + + classInfo: XPCOMUtils.generateCI({classID: Components.ID("{aba4c481-7ea2-464a-b14c-7254a5c99454}"), + contractID: "@mozilla.org/wifi/connectioninfo-event;1", + interfaces: [Ci.nsIDOMWifiConnectionInfoEvent], + flags: Ci.nsIClassInfo.DOM_OBJECT, + classDescription: "Wifi Connection Info Event"}) +}; + const NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMWifiManager]); let debug; diff --git a/dom/wifi/WifiWorker.js b/dom/wifi/WifiWorker.js index 3086d9cf320..11643d2a994 100644 --- a/dom/wifi/WifiWorker.js +++ b/dom/wifi/WifiWorker.js @@ -59,6 +59,23 @@ const WIFIWORKER_WORKER = "resource://gre/modules/network_worker.js"; // command always succeeds and we do a string/boolean check for the // expected results). var WifiManager = (function() { + Cu.import("resource://gre/modules/ctypes.jsm"); + let cutils = ctypes.open("libcutils.so"); + let cbuf = ctypes.char.array(4096)(); + let c_property_get = cutils.declare("property_get", ctypes.default_abi, + ctypes.int, // return value: length + ctypes.char.ptr, // key + ctypes.char.ptr, // value + ctypes.char.ptr); // default + let property_get = function (key, defaultValue) { + if (defaultValue === undefined) { + defaultValue = null; + } + c_property_get(key, cbuf, defaultValue); + return cbuf.readString(); + } + let sdkVersion = parseInt(property_get("ro.build.version.sdk")); + var controlWorker = new ChromeWorker(WIFIWORKER_WORKER); var eventWorker = new ChromeWorker(WIFIWORKER_WORKER); @@ -283,7 +300,7 @@ var WifiManager = (function() { if (reply != "OK") { // Format is: rssi XX". SSID can contain spaces. var offset = reply.lastIndexOf("rssi "); - if (offset != -1) + if (offset !== -1) rssi = reply.substr(offset + 5) | 0; } } @@ -302,7 +319,7 @@ var WifiManager = (function() { function getLinkSpeedCommand(callback) { doStringCommand("DRIVER LINKSPEED", function(reply) { if (reply) - reply = reply.split()[1] | 0; // Format: LinkSpeed XX + reply = reply.split(" ")[1] | 0; // Format: LinkSpeed XX callback(reply); }); } @@ -583,6 +600,8 @@ var WifiManager = (function() { } manager.start = function() { + debug("detected SDK version " + sdkVersion); + // If we reconnected to an already-running supplicant, then manager.state // will have already been updated to the supplicant's state. Otherwise, we // started the supplicant ourselves and need to connect. @@ -647,9 +666,15 @@ var WifiManager = (function() { }); } - var supplicantStatesMap = ["DISCONNECTED", "INACTIVE", "SCANNING", "ASSOCIATING", - "ASSOCIATED", "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE", - "COMPLETED", "DORMANT", "UNINITIALIZED"]; + var supplicantStatesMap = (sdkVersion >= 15) ? + ["DISCONNECTED", "INTERFACE_DISABLED", "INACTIVE", "SCANNING", + "AUTHENTICATING", "ASSOCIATING", "ASSOCIATED", "FOUR_WAY_HANDSHAKE", + "GROUP_HANDSHAKE", "COMPLETED"] + : + ["DISCONNECTED", "INACTIVE", "SCANNING", "ASSOCIATING", + "ASSOCIATED", "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE", + "COMPLETED", "DORMANT", "UNINITIALIZED"]; + var driverEventMap = { STOPPED: "driverstopped", STARTED: "driverstarted", HANGED: "driverhung" }; // handle events sent to us by the event worker @@ -1010,6 +1035,8 @@ var WifiManager = (function() { setScanModeCommand(mode === "active", callback); } manager.scan = scanCommand; + manager.getRssiApprox = getRssiApproxCommand; + manager.getLinkSpeed = getLinkSpeedCommand; return manager; })(); @@ -1106,6 +1133,9 @@ function WifiWorker() { this.currentNetwork = null; + this._lastConnectionInfo = null; + this._connectionInfoTimer = null; + // Given a connection status network, takes a network from // self.configuredNetworks and prepares it for the DOM. netToDOM = function(net) { @@ -1209,6 +1239,12 @@ function WifiWorker() { WifiManager.onstatechange = function() { debug("State change: " + this.prevState + " -> " + this.state); + if (self._connectionInfoTimer && + this.state !== "CONNECTED" && + this.state !== "COMPLETED") { + self._stopConnectionInfoTimer(); + } + if (this.state === "DORMANT") { // The dormant state is a bad state to be in since we won't // automatically connect. Try to knock us out of it. We only @@ -1248,16 +1284,17 @@ function WifiWorker() { WifiManager.getNetworkConfiguration(self.currentNetwork, function(){}); } - self._fireEvent("onassociate", netToDOM(self.currentNetwork)); + self._startConnectionInfoTimer(); + self._fireEvent("onassociate", { network: netToDOM(self.currentNetwork) }); } else if (this.state === "DISCONNECTED") { - self._fireEvent("ondisconnect"); + self._fireEvent("ondisconnect", {}); self.currentNetwork = null; } }; WifiManager.ondhcpconnected = function() { if (this.info) - self._fireEvent("onconnect", netToDOM(self.currentNetwork)); + self._fireEvent("onconnect", { network: netToDOM(self.currentNetwork) }); else WifiManager.disconnect(function(){}); }; @@ -1362,10 +1399,66 @@ WifiWorker.prototype = { } }, + _startConnectionInfoTimer: function() { + if (this._connectionInfoTimer) + return; + + var self = this; + function getConnectionInformation() { + WifiManager.getRssiApprox(function(rssi) { + // See comments in calculateSignal for information about this. + if (rssi > 0) + rssi -= 256; + if (rssi <= MIN_RSSI) + rssi = MIN_RSSI; + else if (rssi >= MAX_RSSI) + rssi = MAX_RSSI; + + WifiManager.getLinkSpeed(function(linkspeed) { + let info = { signalStrength: rssi, + relSignalStrength: calculateSignal(rssi), + linkSpeed: linkspeed }; + let last = self._lastConnectionInfo; + + // Only fire the event if the link speed changed or the signal + // strength changed by more than 10%. + function tensPlace(percent) ((percent / 10) | 0) + + if (last && last.linkSpeed === info.linkSpeed && + tensPlace(last.relSignalStrength) === tensPlace(info.relSignalStrength)) { + return; + } + + self._lastConnectionInfo = info; + self._fireEvent("connectionInfoUpdate", info); + }); + }); + } + + // Prime our _lastConnectionInfo immediately and fire the event at the + // same time. + getConnectionInformation(); + + // Now, set up the timer for regular updates. + this._connectionInfoTimer = + Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + this._connectionInfoTimer.init(getConnectionInformation, 5000, + Ci.nsITimer.TYPE_REPEATING_SLACK); + }, + + _stopConnectionInfoTimer: function() { + if (!this._connectionInfoTimer) + return; + + this._connectionInfoTimer.cancel(); + this._connectionInfoTimer = null; + this._lastConnectionInfo = null; + }, + // nsIWifi _fireEvent: function(message, data) { - this._mm.sendAsyncMessage("WifiManager:" + message, { network: data }); + this._mm.sendAsyncMessage("WifiManager:" + message, data); }, _sendMessage: function(message, success, data, rid, mid) { @@ -1388,6 +1481,7 @@ WifiWorker.prototype = { case "WifiManager:getState": { let net = this.currentNetwork ? netToDOM(this.currentNetwork) : null; return { network: net, + connectionInfo: this._lastConnectionInfo, enabled: WifiManager.state !== "UNINITIALIZED", }; } } @@ -1475,6 +1569,7 @@ WifiWorker.prototype = { get worker() { throw "Not implemented"; }, shutdown: function() { + debug("shutting down ..."); this.setWifiEnabled(false); } }; diff --git a/dom/wifi/libnetutils.js b/dom/wifi/libnetutils.js index e6e0337481a..e55ed4aa18f 100644 --- a/dom/wifi/libnetutils.js +++ b/dom/wifi/libnetutils.js @@ -5,8 +5,25 @@ let libnetutils = (function () { let library = ctypes.open("libnetutils.so"); + let cutils = ctypes.open("libcutils.so"); - return { + let cbuf = ctypes.char.array(4096)(); + let c_property_get = cutils.declare("property_get", ctypes.default_abi, + ctypes.int, // return value: length + ctypes.char.ptr, // key + ctypes.char.ptr, // value + ctypes.char.ptr); // default + let property_get = function (key, defaultValue) { + if (defaultValue === undefined) { + defaultValue = null; + } + c_property_get(key, cbuf, defaultValue); + return cbuf.readString(); + } + + let sdkVersion = parseInt(property_get("ro.build.version.sdk")); + + let iface = { ifc_enable: library.declare("ifc_enable", ctypes.default_abi, ctypes.int, ctypes.char.ptr), ifc_disable: library.declare("ifc_disable", ctypes.default_abi, ctypes.int, ctypes.char.ptr), ifc_add_host_route: library.declare("ifc_add_host_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int), @@ -17,14 +34,113 @@ let libnetutils = (function () { ifc_reset_connections: library.declare("ifc_reset_connections", ctypes.default_abi, ctypes.int, ctypes.char.ptr), ifc_configure: library.declare("ifc_configure", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int, ctypes.int, ctypes.int, ctypes.int, ctypes.int), - dhcp_do_request: library.declare("dhcp_do_request", ctypes.default_abi, ctypes.int, - ctypes.char.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr, - ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr), dhcp_stop: library.declare("dhcp_stop", ctypes.default_abi, ctypes.int, ctypes.char.ptr), dhcp_release_lease: library.declare("dhcp_release_lease", ctypes.default_abi, ctypes.int, ctypes.char.ptr), dhcp_get_errmsg: library.declare("dhcp_get_errmsg", ctypes.default_abi, ctypes.char.ptr), - dhcp_do_request_renew: library.declare("dhcp_do_request_renew", ctypes.default_abi, ctypes.int, - ctypes.char.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr, - ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr) }; + + if (sdkVersion >= 15) { + let ipaddrbuf = ctypes.char.array(4096)(); + let gatewaybuf = ctypes.char.array(4096)(); + let prefixLen = ctypes.int(); + let dns1buf = ctypes.char.array(4096)(); + let dns2buf = ctypes.char.array(4096)(); + let serverbuf = ctypes.char.array(4096)(); + let lease = ctypes.int(); + let c_dhcp_do_request = + library.declare("dhcp_do_request", ctypes.default_abi, + ctypes.int, // [return] + ctypes.char.ptr, // ifname + ctypes.char.ptr, // ipaddr + ctypes.char.ptr, // gateway + ctypes.int.ptr, // prefixlen + ctypes.char.ptr, // dns1 + ctypes.char.ptr, // dns2 + ctypes.char.ptr, // server + ctypes.int.ptr); // lease + + let stringToIp = function (s) { + if (!s) return 0; + let comps = s.split("."); + return ((parseInt(comps[0]) & 0xff) << 0 | + (parseInt(comps[1]) & 0xff) << 8 | + (parseInt(comps[2]) & 0xff) << 16 | + (parseInt(comps[3]) & 0xff) << 24); + } + + let makeMask = function (len) { + let mask = 0; + for (let i = 0; i < len; ++i) + mask |= (1 << i); + return mask; + } + + iface.dhcp_do_request = function (ifname) { + let ret = c_dhcp_do_request(ifname, + ipaddrbuf, + gatewaybuf, + prefixLen.address(), + dns1buf, + dns2buf, + serverbuf, + lease.address()); + return { + ret: ret |0, + ipaddr: stringToIp(ipaddrbuf.readString()), + gateway: stringToIp(gatewaybuf.readString()), + mask: makeMask(prefixLen), + dns1: stringToIp(dns1buf.readString()), + dns2: stringToIp(dns2buf.readString()), + server: stringToIp(serverbuf.readString()), + lease: lease |0 + }; + }; + // dhcp_do_request_renew() went away in newer libnetutils. + iface.dhcp_do_request_renew = iface.dhcp_do_request; + } else { + let ints = ctypes.int.array(8)(); + let c_dhcp_do_request = + library.declare("dhcp_do_request", ctypes.default_abi, + ctypes.int, // [return] + ctypes.char.ptr, // ifname + ctypes.int.ptr, // ipaddr + ctypes.int.ptr, // gateway + ctypes.int.ptr, // mask + ctypes.int.ptr, // dns1 + ctypes.int.ptr, // dns2 + ctypes.int.ptr, // server + ctypes.int.ptr); // lease + let c_dhcp_do_request_renew = + library.declare("dhcp_do_request_renew", ctypes.default_abi, + ctypes.int, // [return] + ctypes.char.ptr, // ifname + ctypes.int.ptr, // ipaddr + ctypes.int.ptr, // gateway + ctypes.int.ptr, // mask + ctypes.int.ptr, // dns1 + ctypes.int.ptr, // dns2 + ctypes.int.ptr, // server + ctypes.int.ptr); // lease + + let makeRequestWrapper = function (c_fn) { + return function (ifname) { + let ret = c_fn(ifname, + ints.addressOfElement(0), + ints.addressOfElement(1), + ints.addressOfElement(2), + ints.addressOfElement(3), + ints.addressOfElement(4), + ints.addressOfElement(5), + ints.addressOfElement(6)); + return { ret: ret |0, ipaddr: ints[0] |0, gateway: ints[1] |0, + mask: ints[2] |0, dns1: ints[3] |0, dns2: ints[4] |0, + server: ints[5] |0, lease: ints[6] |0 }; + }; + } + + iface.dhcp_do_request = makeRequestWrapper(c_dhcp_do_request); + iface.dhcp_do_request_renew = makeRequestWrapper(c_dhcp_do_request_renew); + } + + return iface; })(); diff --git a/dom/wifi/network_worker.js b/dom/wifi/network_worker.js index b04cf14e3fb..246938fa791 100644 --- a/dom/wifi/network_worker.js +++ b/dom/wifi/network_worker.js @@ -64,16 +64,11 @@ self.onmessage = function(e) { break; case "dhcp_do_request": case "dhcp_do_request_renew": - var ret = libnetutils[cmd](data.ifname, - ints.addressOfElement(0), - ints.addressOfElement(1), - ints.addressOfElement(2), - ints.addressOfElement(3), - ints.addressOfElement(4), - ints.addressOfElement(5), - ints.addressOfElement(6)); - postMessage({ id: id, status: ret, ipaddr: ints[0], gateway: ints[1], mask: ints[2], - dns1: ints[3], dns2: ints[4], server: ints[5], lease: ints[6]}); + var out = libnetutils[cmd](data.ifname); + postMessage({ id: id, status: out.ret, ipaddr: out.ipaddr, + gateway: out.gateway, mask: out.mask, + dns1: out.dns1, dns2: out.dns2, server: out.server, + lease: out.lease }); break; case "property_get": var ret = libcutils.property_get(data.key, cbuf, data.defaultValue); diff --git a/dom/wifi/nsIWifi.idl b/dom/wifi/nsIWifi.idl index 458fdf74413..7cf0dfab19f 100644 --- a/dom/wifi/nsIWifi.idl +++ b/dom/wifi/nsIWifi.idl @@ -47,7 +47,7 @@ interface nsIWifi : nsISupports { void shutdown(); }; -[scriptable, uuid(1509221f-470e-4445-b476-88e74fd5c617)] +[scriptable, uuid(7df14510-f58b-4c9a-9e35-a39a94255941)] interface nsIDOMWifiManager : nsISupports { /** * TODO Remove in favor of a settings API. @@ -91,6 +91,13 @@ interface nsIDOMWifiManager : nsISupports { */ readonly attribute jsval connectedNetwork; + /** + * A connectionInformation object with the same information found in an + * nsIDOMWifiConnectionInfoEvent (but without the network). + * If we are not currently connected to a network, this will be null. + */ + readonly attribute jsval connectionInformation; + /** * These four functions serve as state notification listeners. * onconnecting: Fires when we start the process of connecting to a @@ -108,6 +115,12 @@ interface nsIDOMWifiManager : nsISupports { attribute nsIDOMEventListener onassociate; attribute nsIDOMEventListener onconnect; attribute nsIDOMEventListener ondisconnect; + + /** + * An event listener that is called with information about the signal + * strength and link speed every 5 seconds. + */ + attribute nsIDOMEventListener connectionInfoUpdate; }; [scriptable, uuid(4674c6f1-ea64-44db-ac2f-e7bd6514dfd6)] @@ -118,3 +131,26 @@ interface nsIDOMWifiStateChangeEvent : nsIDOMEvent { */ readonly attribute jsval network; }; + +[scriptable, uuid(5c9ee332-dd98-4227-b7fc-768418fd50e3)] +interface nsIDOMWifiConnectionInfoEvent : nsIDOMEvent { + /** + * Network object with an SSID field. + */ + readonly attribute jsval network; + + /** + * Strength of the signal to network, in dBm between -55 and -100 dBm. + */ + readonly attribute short signalStrength; + + /** + * Relative signal strength between 0 and 100. + */ + readonly attribute short relSignalStrength; + + /** + * Link spead in Mb/s. + */ + readonly attribute long linkSpeed; +}; diff --git a/media/libsydneyaudio/src/gonk/AudioSystem.h b/media/libsydneyaudio/src/gonk/AudioSystem.h index dc6bc6c85eb..28b2819fd13 100644 --- a/media/libsydneyaudio/src/gonk/AudioSystem.h +++ b/media/libsydneyaudio/src/gonk/AudioSystem.h @@ -21,6 +21,41 @@ #include #include "IAudioFlinger.h" +#ifndef VANILLA_ANDROID +/* device categories used for audio_policy->set_force_use() */ +typedef enum { + AUDIO_POLICY_FORCE_NONE, + AUDIO_POLICY_FORCE_SPEAKER, + AUDIO_POLICY_FORCE_HEADPHONES, + AUDIO_POLICY_FORCE_BT_SCO, + AUDIO_POLICY_FORCE_BT_A2DP, + AUDIO_POLICY_FORCE_WIRED_ACCESSORY, + AUDIO_POLICY_FORCE_BT_CAR_DOCK, + AUDIO_POLICY_FORCE_BT_DESK_DOCK, + +#ifdef VANILLA_ANDROID + AUDIO_POLICY_FORCE_ANALOG_DOCK, + AUDIO_POLICY_FORCE_DIGITAL_DOCK, +#endif + + AUDIO_POLICY_FORCE_CFG_CNT, + AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1, + + AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE, +} audio_policy_forced_cfg_t; + +/* usages used for audio_policy->set_force_use() */ +typedef enum { + AUDIO_POLICY_FORCE_FOR_COMMUNICATION, + AUDIO_POLICY_FORCE_FOR_MEDIA, + AUDIO_POLICY_FORCE_FOR_RECORD, + AUDIO_POLICY_FORCE_FOR_DOCK, + + AUDIO_POLICY_FORCE_USE_CNT, + AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1, +} audio_policy_force_use_t; +#endif + namespace android { typedef void (*audio_error_callback)(status_t err); @@ -359,8 +394,16 @@ public: static device_connection_state getDeviceConnectionState(audio_devices device, const char *device_address); static status_t setPhoneState(int state); static status_t setRingerMode(uint32_t mode, uint32_t mask); +#ifdef VANILLA_ANDROID static status_t setForceUse(force_use usage, forced_config config); static forced_config getForceUse(force_use usage); +#else + static status_t setForceUse(force_use usage, forced_config config) __attribute__((weak)); + static forced_config getForceUse(force_use usage) __attribute__((weak)); + + static status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) __attribute__((weak)); + static audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) __attribute__((weak)); +#endif static audio_io_handle_t getOutput(stream_type stream, uint32_t samplingRate = 0, uint32_t format = FORMAT_DEFAULT, diff --git a/media/libsydneyaudio/src/gonk/AudioTrack.h b/media/libsydneyaudio/src/gonk/AudioTrack.h index ae561988b3c..6f8c6bb28ce 100644 --- a/media/libsydneyaudio/src/gonk/AudioTrack.h +++ b/media/libsydneyaudio/src/gonk/AudioTrack.h @@ -480,6 +480,7 @@ private: uint32_t mFlags; int mSessionId; int mAuxEffectId; + uint32_t mPadding[8]; }; diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html index c6457a20fd7..624e8ccc969 100644 --- a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html +++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html @@ -76,41 +76,35 @@ var testsleftinround = 0; var currentround = ""; - var _PBSvc = null; - var _PrefSvc = null; + var gPBSvc = null; + var gPrefSvc = null; - function _getPBService() { - if (_PBSvc) - return _PBSvc; + function _getServices() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); // not all apps will have the private browsing service. try { - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - _PBSvc = Components.classes["@mozilla.org/privatebrowsing;1"] - .getService(Components.interfaces.nsIPrivateBrowsingService); - return _PBSvc; - } catch (e) {} - return null; - } - function _getPrefService() { - if (_PrefSvc) - return _PrefSvc; + gPBSvc = Components.classes["@mozilla.org/privatebrowsing;1"] + .getService(Components.interfaces.nsIPrivateBrowsingService); + } catch (ex) { + SimpleTest.todo(false, "PB service is not available, will skip dependent tests"); + } - // not all apps will have the private browsing service. + // Not all apps will have the preference service. try { - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - _PrefSvc = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefService) - .QueryInterface(Components.interfaces.nsIPrefBranch); - return _PrefSvc; - } catch (e) {} - return null; + gPrefSvc = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefService) + .QueryInterface(Components.interfaces.nsIPrefBranch); + } catch (ex) { + SimpleTest.todo(false, "Pref service is not available, won't be able to manage preferences"); + } } + _getServices(); function startRound(round) { currentround = round; testsleftinround = NUM_TEST_FRAMES; - dump("TESTS LEFT IN ROUND: " + testsleftinround + "\n"); + SimpleTest.info("TESTS LEFT IN ROUND " + currentround + ": " + testsleftinround); var frame = document.createElement("iframe"); frame.setAttribute('id', 'ifr_bootstrap'); frame.setAttribute('src', "https://example.com" + STSPATH + @@ -149,9 +143,6 @@ // check if the result (SECURE/INSECURE) is expected for this round/test // combo dump_STSState(); - dump( "*** in ROUND " + currentround + - ", test " + result[1] + - " is " + result[0] + "\n"); SimpleTest.is(result[0], testframes[result[1]].expected[currentround], "in ROUND " + currentround + ", test " + result[1]); @@ -159,7 +150,7 @@ // if this round is complete... if (testsleftinround < 1) { - dump("DONE WITH ROUND " + currentround + "\n"); + SimpleTest.info("DONE WITH ROUND " + currentround); // remove all the iframes in the document document.body.removeChild(document.getElementById('ifr_bootstrap')); for (var test in testframes) @@ -174,36 +165,37 @@ function test_sts_before_private_mode() { dump_STSState(); - dump("*** not in private browsing mode\n"); + SimpleTest.info("Not in private browsing mode"); startRound('plain'); } function test_sts_in_private_mode() { dump_STSState(); - dump("*** Entering private browsing mode\n"); + SimpleTest.info("Entering private browsing mode ..."); netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - _getPrefService().setBoolPref("browser.privatebrowsing.keep_current_session", - true); - _getPBService().privateBrowsingEnabled = true; - dump("*** ... done\n"); + if (gPrefSvc) + gPrefSvc.setBoolPref("browser.privatebrowsing.keep_current_session", true); + gPBSvc.privateBrowsingEnabled = true; + SimpleTest.info("... done"); dump_STSState(); startRound('subdom'); } function test_sts_after_exiting_private_mode() { dump_STSState(); - dump("*** Exiting private browsing mode\n"); + SimpleTest.info("Exiting private browsing mode ..."); netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - _getPBService().privateBrowsingEnabled = false; - _getPrefService().clearUserPref("browser.privatebrowsing.keep_current_session"); - dump("*** ... done\n"); + gPBSvc.privateBrowsingEnabled = false; + if (gPrefSvc) + gPrefSvc.clearUserPref("browser.privatebrowsing.keep_current_session"); + SimpleTest.info("... done"); dump_STSState(); startRound('nosts'); } function clean_up_sts_state() { // erase all signs that this test ran. - dump("*** Cleaning up STS data.\n"); + SimpleTest.info("Cleaning up STS data"); netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); const Cc = Components.classes; const Ci = Components.interfaces; @@ -221,43 +213,39 @@ function dump_STSState() { netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); var stss = Components.classes["@mozilla.org/stsservice;1"] .getService(Components.interfaces.nsIStrictTransportSecurityService); - dump("*** State of example.com: " + stss.isStsHost("example.com") + "\n"); + SimpleTest.info("State of example.com: " + stss.isStsHost("example.com")); } // these are executed in the order presented. // 0. test that STS works before entering private browsing mode. // (load sts-bootstrapped "plain" tests) // ... clear any STS data ... + var tests = [ + test_sts_before_private_mode, + clean_up_sts_state + ]; // 1. test that STS works in private browsing mode // (load sts-bootstrapped "subdomain" tests) // 2. test that after exiting private browsing, STS data is forgotten // (verified with non-sts-bootstrapped pages) - var tests = []; - { // skip these tests if there's no private mode support - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - if ("@mozilla.org/privatebrowsing;1" in Components.classes) { - tests = [ - test_sts_before_private_mode, - clean_up_sts_state, - test_sts_in_private_mode, - test_sts_after_exiting_private_mode, - clean_up_sts_state, - ]; - } + // ... clear any STS data ... + // Skip these tests if there is no private mode support. + if (gPBSvc) { + tests = tests.concat( + test_sts_in_private_mode, + test_sts_after_exiting_private_mode, + clean_up_sts_state + ); } function nextTest() { - if (tests.length) - SimpleTest.executeSoon(tests.shift()); - else - SimpleTest.executeSoon(SimpleTest.finish); + SimpleTest.executeSoon(tests.length ? tests.shift() : SimpleTest.finish); } // listen for calls back from the sts-setting iframe and then // the verification frames. window.addEventListener("message", onMessageReceived, false); window.addEventListener('load', nextTest, false); - diff --git a/widget/gonk/Makefile.in b/widget/gonk/Makefile.in index f5209767c17..3acf3ea3b09 100644 --- a/widget/gonk/Makefile.in +++ b/widget/gonk/Makefile.in @@ -62,6 +62,7 @@ CPPSRCS = \ nsLookAndFeel.cpp \ nsIdleServiceGonk.cpp \ EventHub.cpp \ + Input.cpp \ InputApplication.cpp \ InputDispatcher.cpp \ InputListener.cpp \ @@ -73,6 +74,12 @@ CPPSRCS = \ KeyLayoutMap.cpp \ PixelFormat.cpp \ VirtualKeyMap.cpp \ + PropertyMap.cpp \ + Unicode.cpp \ + Timers.cpp \ + Tokenizer.cpp \ + String8.cpp \ + Static.cpp \ $(NULL) SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a diff --git a/widget/gonk/libui/BitSet.h b/widget/gonk/libui/BitSet.h new file mode 100644 index 00000000000..9452e86d617 --- /dev/null +++ b/widget/gonk/libui/BitSet.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UTILS_BITSET_H +#define UTILS_BITSET_H + +#include + +/* + * Contains some bit manipulation helpers. + */ + +namespace android { + +// A simple set of 32 bits that can be individually marked or cleared. +struct BitSet32 { + uint32_t value; + + inline BitSet32() : value(0) { } + explicit inline BitSet32(uint32_t value) : value(value) { } + + // Gets the value associated with a particular bit index. + static inline uint32_t valueForBit(uint32_t n) { return 0x80000000 >> n; } + + // Clears the bit set. + inline void clear() { value = 0; } + + // Returns the number of marked bits in the set. + inline uint32_t count() const { return __builtin_popcount(value); } + + // Returns true if the bit set does not contain any marked bits. + inline bool isEmpty() const { return ! value; } + + // Returns true if the bit set does not contain any unmarked bits. + inline bool isFull() const { return value == 0xffffffff; } + + // Returns true if the specified bit is marked. + inline bool hasBit(uint32_t n) const { return value & valueForBit(n); } + + // Marks the specified bit. + inline void markBit(uint32_t n) { value |= valueForBit(n); } + + // Clears the specified bit. + inline void clearBit(uint32_t n) { value &= ~ valueForBit(n); } + + // Finds the first marked bit in the set. + // Result is undefined if all bits are unmarked. + inline uint32_t firstMarkedBit() const { return __builtin_clz(value); } + + // Finds the first unmarked bit in the set. + // Result is undefined if all bits are marked. + inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); } + + // Finds the last marked bit in the set. + // Result is undefined if all bits are unmarked. + inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); } + + // Finds the first marked bit in the set and clears it. Returns the bit index. + // Result is undefined if all bits are unmarked. + inline uint32_t clearFirstMarkedBit() { + uint32_t n = firstMarkedBit(); + clearBit(n); + return n; + } + + // Finds the first unmarked bit in the set and marks it. Returns the bit index. + // Result is undefined if all bits are marked. + inline uint32_t markFirstUnmarkedBit() { + uint32_t n = firstUnmarkedBit(); + markBit(n); + return n; + } + + // Finds the last marked bit in the set and clears it. Returns the bit index. + // Result is undefined if all bits are unmarked. + inline uint32_t clearLastMarkedBit() { + uint32_t n = lastMarkedBit(); + clearBit(n); + return n; + } + + // Gets the index of the specified bit in the set, which is the number of + // marked bits that appear before the specified bit. + inline uint32_t getIndexOfBit(uint32_t n) const { + return __builtin_popcount(value & ~(0xffffffffUL >> n)); + } + + inline bool operator== (const BitSet32& other) const { return value == other.value; } + inline bool operator!= (const BitSet32& other) const { return value != other.value; } +}; + +} // namespace android + +#endif // UTILS_BITSET_H diff --git a/widget/gonk/libui/EventHub.cpp b/widget/gonk/libui/EventHub.cpp index 1212d7656f3..448de29e6bf 100644 --- a/widget/gonk/libui/EventHub.cpp +++ b/widget/gonk/libui/EventHub.cpp @@ -18,13 +18,13 @@ // #define LOG_NDEBUG 0 +#include "utils_Log.h" #include "EventHub.h" #include #include -#include -#include +#include "Timers.h" #include #include diff --git a/widget/gonk/libui/EventHub.h b/widget/gonk/libui/EventHub.h index 0b1b110343b..7881855684d 100644 --- a/widget/gonk/libui/EventHub.h +++ b/widget/gonk/libui/EventHub.h @@ -18,22 +18,22 @@ #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H +#include "utils_Log.h" #include "Input.h" #include "Keyboard.h" #include "KeyLayoutMap.h" #include "KeyCharacterMap.h" #include "VirtualKeyMap.h" -#include +#include "String8.h" #include -#include #include #include #include -#include +#include "PropertyMap.h" #include #include -#include +#include "linux_input.h" #include /* Convenience constants. */ diff --git a/widget/gonk/libui/Input.cpp b/widget/gonk/libui/Input.cpp new file mode 100644 index 00000000000..264836e432e --- /dev/null +++ b/widget/gonk/libui/Input.cpp @@ -0,0 +1,1224 @@ +// +// Copyright 2010 The Android Open Source Project +// +// Provides a pipe-based transport for native events in the NDK. +// +#define LOG_TAG "Input" + +//#define LOG_NDEBUG 0 + +// Log debug messages about keymap probing. +#define DEBUG_PROBE 0 + +// Log debug messages about velocity tracking. +#define DEBUG_VELOCITY 0 + +// Log debug messages about least squares fitting. +#define DEBUG_LEAST_SQUARES 0 + +// Log debug messages about acceleration. +#define DEBUG_ACCELERATION 0 + + +#include +#include +#include + +#include "utils_Log.h" +#include "Input.h" + +#include +#include + +#ifdef HAVE_ANDROID_OS +#include + +#include "SkPoint.h" +#include "SkMatrix.h" +#include "SkScalar.h" +#endif + +namespace android { + +static const char* CONFIGURATION_FILE_DIR[] = { + "idc/", + "keylayout/", + "keychars/", +}; + +static const char* CONFIGURATION_FILE_EXTENSION[] = { + ".idc", + ".kl", + ".kcm", +}; + +static bool isValidNameChar(char ch) { + return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); +} + +static void appendInputDeviceConfigurationFileRelativePath(String8& path, + const String8& name, InputDeviceConfigurationFileType type) { + path.append(CONFIGURATION_FILE_DIR[type]); + for (size_t i = 0; i < name.length(); i++) { + char ch = name[i]; + if (!isValidNameChar(ch)) { + ch = '_'; + } + path.append(&ch, 1); + } + path.append(CONFIGURATION_FILE_EXTENSION[type]); +} + +String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( + const InputDeviceIdentifier& deviceIdentifier, + InputDeviceConfigurationFileType type) { + if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { + if (deviceIdentifier.version != 0) { + // Try vendor product version. + String8 versionPath(getInputDeviceConfigurationFilePathByName( + String8::format("Vendor_%04x_Product_%04x_Version_%04x", + deviceIdentifier.vendor, deviceIdentifier.product, + deviceIdentifier.version), + type)); + if (!versionPath.isEmpty()) { + return versionPath; + } + } + + // Try vendor product. + String8 productPath(getInputDeviceConfigurationFilePathByName( + String8::format("Vendor_%04x_Product_%04x", + deviceIdentifier.vendor, deviceIdentifier.product), + type)); + if (!productPath.isEmpty()) { + return productPath; + } + } + + // Try device name. + return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); +} + +String8 getInputDeviceConfigurationFilePathByName( + const String8& name, InputDeviceConfigurationFileType type) { + // Search system repository. + String8 path; + path.setTo(getenv("ANDROID_ROOT")); + path.append("/usr/"); + appendInputDeviceConfigurationFileRelativePath(path, name, type); +#if DEBUG_PROBE + ALOGD("Probing for system provided input device configuration file: path='%s'", path.string()); +#endif + if (!access(path.string(), R_OK)) { +#if DEBUG_PROBE + ALOGD("Found"); +#endif + return path; + } + + // Search user repository. + // TODO Should only look here if not in safe mode. + path.setTo(getenv("ANDROID_DATA")); + path.append("/system/devices/"); + appendInputDeviceConfigurationFileRelativePath(path, name, type); +#if DEBUG_PROBE + ALOGD("Probing for system user input device configuration file: path='%s'", path.string()); +#endif + if (!access(path.string(), R_OK)) { +#if DEBUG_PROBE + ALOGD("Found"); +#endif + return path; + } + + // Not found. +#if DEBUG_PROBE + ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", + name.string(), type); +#endif + return String8(); +} + + +// --- InputEvent --- + +void InputEvent::initialize(int32_t deviceId, int32_t source) { + mDeviceId = deviceId; + mSource = source; +} + +void InputEvent::initialize(const InputEvent& from) { + mDeviceId = from.mDeviceId; + mSource = from.mSource; +} + +// --- KeyEvent --- + +bool KeyEvent::hasDefaultAction(int32_t keyCode) { + switch (keyCode) { + case AKEYCODE_HOME: + case AKEYCODE_BACK: + case AKEYCODE_CALL: + case AKEYCODE_ENDCALL: + case AKEYCODE_VOLUME_UP: + case AKEYCODE_VOLUME_DOWN: + case AKEYCODE_VOLUME_MUTE: + case AKEYCODE_POWER: + case AKEYCODE_CAMERA: + case AKEYCODE_HEADSETHOOK: + case AKEYCODE_MENU: + case AKEYCODE_NOTIFICATION: + case AKEYCODE_FOCUS: + case AKEYCODE_SEARCH: + case AKEYCODE_MEDIA_PLAY: + case AKEYCODE_MEDIA_PAUSE: + case AKEYCODE_MEDIA_PLAY_PAUSE: + case AKEYCODE_MEDIA_STOP: + case AKEYCODE_MEDIA_NEXT: + case AKEYCODE_MEDIA_PREVIOUS: + case AKEYCODE_MEDIA_REWIND: + case AKEYCODE_MEDIA_RECORD: + case AKEYCODE_MEDIA_FAST_FORWARD: + case AKEYCODE_MUTE: + return true; + } + + return false; +} + +bool KeyEvent::hasDefaultAction() const { + return hasDefaultAction(getKeyCode()); +} + +bool KeyEvent::isSystemKey(int32_t keyCode) { + switch (keyCode) { + case AKEYCODE_MENU: + case AKEYCODE_SOFT_RIGHT: + case AKEYCODE_HOME: + case AKEYCODE_BACK: + case AKEYCODE_CALL: + case AKEYCODE_ENDCALL: + case AKEYCODE_VOLUME_UP: + case AKEYCODE_VOLUME_DOWN: + case AKEYCODE_VOLUME_MUTE: + case AKEYCODE_MUTE: + case AKEYCODE_POWER: + case AKEYCODE_HEADSETHOOK: + case AKEYCODE_MEDIA_PLAY: + case AKEYCODE_MEDIA_PAUSE: + case AKEYCODE_MEDIA_PLAY_PAUSE: + case AKEYCODE_MEDIA_STOP: + case AKEYCODE_MEDIA_NEXT: + case AKEYCODE_MEDIA_PREVIOUS: + case AKEYCODE_MEDIA_REWIND: + case AKEYCODE_MEDIA_RECORD: + case AKEYCODE_MEDIA_FAST_FORWARD: + case AKEYCODE_CAMERA: + case AKEYCODE_FOCUS: + case AKEYCODE_SEARCH: + return true; + } + + return false; +} + +bool KeyEvent::isSystemKey() const { + return isSystemKey(getKeyCode()); +} + +void KeyEvent::initialize( + int32_t deviceId, + int32_t source, + int32_t action, + int32_t flags, + int32_t keyCode, + int32_t scanCode, + int32_t metaState, + int32_t repeatCount, + nsecs_t downTime, + nsecs_t eventTime) { + InputEvent::initialize(deviceId, source); + mAction = action; + mFlags = flags; + mKeyCode = keyCode; + mScanCode = scanCode; + mMetaState = metaState; + mRepeatCount = repeatCount; + mDownTime = downTime; + mEventTime = eventTime; +} + +void KeyEvent::initialize(const KeyEvent& from) { + InputEvent::initialize(from); + mAction = from.mAction; + mFlags = from.mFlags; + mKeyCode = from.mKeyCode; + mScanCode = from.mScanCode; + mMetaState = from.mMetaState; + mRepeatCount = from.mRepeatCount; + mDownTime = from.mDownTime; + mEventTime = from.mEventTime; +} + + +// --- PointerCoords --- + +float PointerCoords::getAxisValue(int32_t axis) const { + if (axis < 0 || axis > 63) { + return 0; + } + + uint64_t axisBit = 1LL << axis; + if (!(bits & axisBit)) { + return 0; + } + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + return values[index]; +} + +status_t PointerCoords::setAxisValue(int32_t axis, float value) { + if (axis < 0 || axis > 63) { + return NAME_NOT_FOUND; + } + + uint64_t axisBit = 1LL << axis; + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + if (!(bits & axisBit)) { + if (value == 0) { + return OK; // axes with value 0 do not need to be stored + } + uint32_t count = __builtin_popcountll(bits); + if (count >= MAX_AXES) { + tooManyAxes(axis); + return NO_MEMORY; + } + bits |= axisBit; + for (uint32_t i = count; i > index; i--) { + values[i] = values[i - 1]; + } + } + values[index] = value; + return OK; +} + +static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) { + float value = c.getAxisValue(axis); + if (value != 0) { + c.setAxisValue(axis, value * scaleFactor); + } +} + +void PointerCoords::scale(float scaleFactor) { + // No need to scale pressure or size since they are normalized. + // No need to scale orientation since it is meaningless to do so. + scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor); +} + +#ifdef HAVE_ANDROID_OS +status_t PointerCoords::readFromParcel(Parcel* parcel) { + bits = parcel->readInt64(); + + uint32_t count = __builtin_popcountll(bits); + if (count > MAX_AXES) { + return BAD_VALUE; + } + + for (uint32_t i = 0; i < count; i++) { + values[i] = parcel->readInt32(); + } + return OK; +} + +status_t PointerCoords::writeToParcel(Parcel* parcel) const { + parcel->writeInt64(bits); + + uint32_t count = __builtin_popcountll(bits); + for (uint32_t i = 0; i < count; i++) { + parcel->writeInt32(values[i]); + } + return OK; +} +#endif + +void PointerCoords::tooManyAxes(int axis) { + ALOGW("Could not set value for axis %d because the PointerCoords structure is full and " + "cannot contain more than %d axis values.", axis, int(MAX_AXES)); +} + +bool PointerCoords::operator==(const PointerCoords& other) const { + if (bits != other.bits) { + return false; + } + uint32_t count = __builtin_popcountll(bits); + for (uint32_t i = 0; i < count; i++) { + if (values[i] != other.values[i]) { + return false; + } + } + return true; +} + +void PointerCoords::copyFrom(const PointerCoords& other) { + bits = other.bits; + uint32_t count = __builtin_popcountll(bits); + for (uint32_t i = 0; i < count; i++) { + values[i] = other.values[i]; + } +} + + +// --- PointerProperties --- + +bool PointerProperties::operator==(const PointerProperties& other) const { + return id == other.id + && toolType == other.toolType; +} + +void PointerProperties::copyFrom(const PointerProperties& other) { + id = other.id; + toolType = other.toolType; +} + + +// --- MotionEvent --- + +void MotionEvent::initialize( + int32_t deviceId, + int32_t source, + int32_t action, + int32_t flags, + int32_t edgeFlags, + int32_t metaState, + int32_t buttonState, + float xOffset, + float yOffset, + float xPrecision, + float yPrecision, + nsecs_t downTime, + nsecs_t eventTime, + size_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords) { + InputEvent::initialize(deviceId, source); + mAction = action; + mFlags = flags; + mEdgeFlags = edgeFlags; + mMetaState = metaState; + mButtonState = buttonState; + mXOffset = xOffset; + mYOffset = yOffset; + mXPrecision = xPrecision; + mYPrecision = yPrecision; + mDownTime = downTime; + mPointerProperties.clear(); + mPointerProperties.appendArray(pointerProperties, pointerCount); + mSampleEventTimes.clear(); + mSamplePointerCoords.clear(); + addSample(eventTime, pointerCoords); +} + +void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { + InputEvent::initialize(other->mDeviceId, other->mSource); + mAction = other->mAction; + mFlags = other->mFlags; + mEdgeFlags = other->mEdgeFlags; + mMetaState = other->mMetaState; + mButtonState = other->mButtonState; + mXOffset = other->mXOffset; + mYOffset = other->mYOffset; + mXPrecision = other->mXPrecision; + mYPrecision = other->mYPrecision; + mDownTime = other->mDownTime; + mPointerProperties = other->mPointerProperties; + + if (keepHistory) { + mSampleEventTimes = other->mSampleEventTimes; + mSamplePointerCoords = other->mSamplePointerCoords; + } else { + mSampleEventTimes.clear(); + mSampleEventTimes.push(other->getEventTime()); + mSamplePointerCoords.clear(); + size_t pointerCount = other->getPointerCount(); + size_t historySize = other->getHistorySize(); + mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() + + (historySize * pointerCount), pointerCount); + } +} + +void MotionEvent::addSample( + int64_t eventTime, + const PointerCoords* pointerCoords) { + mSampleEventTimes.push(eventTime); + mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); +} + +const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { + return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; +} + +float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const { + return getRawPointerCoords(pointerIndex)->getAxisValue(axis); +} + +float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { + float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis); + switch (axis) { + case AMOTION_EVENT_AXIS_X: + return value + mXOffset; + case AMOTION_EVENT_AXIS_Y: + return value + mYOffset; + } + return value; +} + +const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( + size_t pointerIndex, size_t historicalIndex) const { + return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; +} + +float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, + size_t historicalIndex) const { + return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); +} + +float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, + size_t historicalIndex) const { + float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); + switch (axis) { + case AMOTION_EVENT_AXIS_X: + return value + mXOffset; + case AMOTION_EVENT_AXIS_Y: + return value + mYOffset; + } + return value; +} + +ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { + size_t pointerCount = mPointerProperties.size(); + for (size_t i = 0; i < pointerCount; i++) { + if (mPointerProperties.itemAt(i).id == pointerId) { + return i; + } + } + return -1; +} + +void MotionEvent::offsetLocation(float xOffset, float yOffset) { + mXOffset += xOffset; + mYOffset += yOffset; +} + +void MotionEvent::scale(float scaleFactor) { + mXOffset *= scaleFactor; + mYOffset *= scaleFactor; + mXPrecision *= scaleFactor; + mYPrecision *= scaleFactor; + + size_t numSamples = mSamplePointerCoords.size(); + for (size_t i = 0; i < numSamples; i++) { + mSamplePointerCoords.editItemAt(i).scale(scaleFactor); + } +} + +#ifdef HAVE_ANDROID_OS +static inline float transformAngle(const SkMatrix* matrix, float angleRadians) { + // Construct and transform a vector oriented at the specified clockwise angle from vertical. + // Coordinate system: down is increasing Y, right is increasing X. + SkPoint vector; + vector.fX = SkFloatToScalar(sinf(angleRadians)); + vector.fY = SkFloatToScalar(-cosf(angleRadians)); + matrix->mapVectors(& vector, 1); + + // Derive the transformed vector's clockwise angle from vertical. + float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY)); + if (result < - M_PI_2) { + result += M_PI; + } else if (result > M_PI_2) { + result -= M_PI; + } + return result; +} + +void MotionEvent::transform(const SkMatrix* matrix) { + float oldXOffset = mXOffset; + float oldYOffset = mYOffset; + + // The tricky part of this implementation is to preserve the value of + // rawX and rawY. So we apply the transformation to the first point + // then derive an appropriate new X/Y offset that will preserve rawX and rawY. + SkPoint point; + float rawX = getRawX(0); + float rawY = getRawY(0); + matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset), + & point); + float newX = SkScalarToFloat(point.fX); + float newY = SkScalarToFloat(point.fY); + float newXOffset = newX - rawX; + float newYOffset = newY - rawY; + + mXOffset = newXOffset; + mYOffset = newYOffset; + + // Apply the transformation to all samples. + size_t numSamples = mSamplePointerCoords.size(); + for (size_t i = 0; i < numSamples; i++) { + PointerCoords& c = mSamplePointerCoords.editItemAt(i); + float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset; + float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset; + matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point); + c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset); + c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset); + + float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); + c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation)); + } +} + +status_t MotionEvent::readFromParcel(Parcel* parcel) { + size_t pointerCount = parcel->readInt32(); + size_t sampleCount = parcel->readInt32(); + if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) { + return BAD_VALUE; + } + + mDeviceId = parcel->readInt32(); + mSource = parcel->readInt32(); + mAction = parcel->readInt32(); + mFlags = parcel->readInt32(); + mEdgeFlags = parcel->readInt32(); + mMetaState = parcel->readInt32(); + mButtonState = parcel->readInt32(); + mXOffset = parcel->readFloat(); + mYOffset = parcel->readFloat(); + mXPrecision = parcel->readFloat(); + mYPrecision = parcel->readFloat(); + mDownTime = parcel->readInt64(); + + mPointerProperties.clear(); + mPointerProperties.setCapacity(pointerCount); + mSampleEventTimes.clear(); + mSampleEventTimes.setCapacity(sampleCount); + mSamplePointerCoords.clear(); + mSamplePointerCoords.setCapacity(sampleCount * pointerCount); + + for (size_t i = 0; i < pointerCount; i++) { + mPointerProperties.push(); + PointerProperties& properties = mPointerProperties.editTop(); + properties.id = parcel->readInt32(); + properties.toolType = parcel->readInt32(); + } + + while (sampleCount-- > 0) { + mSampleEventTimes.push(parcel->readInt64()); + for (size_t i = 0; i < pointerCount; i++) { + mSamplePointerCoords.push(); + status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); + if (status) { + return status; + } + } + } + return OK; +} + +status_t MotionEvent::writeToParcel(Parcel* parcel) const { + size_t pointerCount = mPointerProperties.size(); + size_t sampleCount = mSampleEventTimes.size(); + + parcel->writeInt32(pointerCount); + parcel->writeInt32(sampleCount); + + parcel->writeInt32(mDeviceId); + parcel->writeInt32(mSource); + parcel->writeInt32(mAction); + parcel->writeInt32(mFlags); + parcel->writeInt32(mEdgeFlags); + parcel->writeInt32(mMetaState); + parcel->writeInt32(mButtonState); + parcel->writeFloat(mXOffset); + parcel->writeFloat(mYOffset); + parcel->writeFloat(mXPrecision); + parcel->writeFloat(mYPrecision); + parcel->writeInt64(mDownTime); + + for (size_t i = 0; i < pointerCount; i++) { + const PointerProperties& properties = mPointerProperties.itemAt(i); + parcel->writeInt32(properties.id); + parcel->writeInt32(properties.toolType); + } + + const PointerCoords* pc = mSamplePointerCoords.array(); + for (size_t h = 0; h < sampleCount; h++) { + parcel->writeInt64(mSampleEventTimes.itemAt(h)); + for (size_t i = 0; i < pointerCount; i++) { + status_t status = (pc++)->writeToParcel(parcel); + if (status) { + return status; + } + } + } + return OK; +} +#endif + +bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { + if (source & AINPUT_SOURCE_CLASS_POINTER) { + // Specifically excludes HOVER_MOVE and SCROLL. + switch (action & AMOTION_EVENT_ACTION_MASK) { + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_MOVE: + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_OUTSIDE: + return true; + } + } + return false; +} + + +// --- VelocityTracker --- + +const uint32_t VelocityTracker::DEFAULT_DEGREE; +const nsecs_t VelocityTracker::DEFAULT_HORIZON; +const uint32_t VelocityTracker::HISTORY_SIZE; + +static inline float vectorDot(const float* a, const float* b, uint32_t m) { + float r = 0; + while (m--) { + r += *(a++) * *(b++); + } + return r; +} + +static inline float vectorNorm(const float* a, uint32_t m) { + float r = 0; + while (m--) { + float t = *(a++); + r += t * t; + } + return sqrtf(r); +} + +#if DEBUG_LEAST_SQUARES || DEBUG_VELOCITY +static String8 vectorToString(const float* a, uint32_t m) { + String8 str; + str.append("["); + while (m--) { + str.appendFormat(" %f", *(a++)); + if (m) { + str.append(","); + } + } + str.append(" ]"); + return str; +} + +static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { + String8 str; + str.append("["); + for (size_t i = 0; i < m; i++) { + if (i) { + str.append(","); + } + str.append(" ["); + for (size_t j = 0; j < n; j++) { + if (j) { + str.append(","); + } + str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]); + } + str.append(" ]"); + } + str.append(" ]"); + return str; +} +#endif + +VelocityTracker::VelocityTracker() { + clear(); +} + +void VelocityTracker::clear() { + mIndex = 0; + mMovements[0].idBits.clear(); + mActivePointerId = -1; +} + +void VelocityTracker::clearPointers(BitSet32 idBits) { + BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); + mMovements[mIndex].idBits = remainingIdBits; + + if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) { + mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1; + } +} + +void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) { + if (++mIndex == HISTORY_SIZE) { + mIndex = 0; + } + + while (idBits.count() > MAX_POINTERS) { + idBits.clearLastMarkedBit(); + } + + Movement& movement = mMovements[mIndex]; + movement.eventTime = eventTime; + movement.idBits = idBits; + uint32_t count = idBits.count(); + for (uint32_t i = 0; i < count; i++) { + movement.positions[i] = positions[i]; + } + + if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) { + mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1; + } + +#if DEBUG_VELOCITY + ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d", + eventTime, idBits.value, mActivePointerId); + for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) { + uint32_t id = iterBits.firstMarkedBit(); + uint32_t index = idBits.getIndexOfBit(id); + iterBits.clearBit(id); + Estimator estimator; + getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator); + ALOGD(" %d: position (%0.3f, %0.3f), " + "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)", + id, positions[index].x, positions[index].y, + int(estimator.degree), + vectorToString(estimator.xCoeff, estimator.degree).string(), + vectorToString(estimator.yCoeff, estimator.degree).string(), + estimator.confidence); + } +#endif +} + +void VelocityTracker::addMovement(const MotionEvent* event) { + int32_t actionMasked = event->getActionMasked(); + + switch (actionMasked) { + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_HOVER_ENTER: + // Clear all pointers on down before adding the new movement. + clear(); + break; + case AMOTION_EVENT_ACTION_POINTER_DOWN: { + // Start a new movement trace for a pointer that just went down. + // We do this on down instead of on up because the client may want to query the + // final velocity for a pointer that just went up. + BitSet32 downIdBits; + downIdBits.markBit(event->getPointerId(event->getActionIndex())); + clearPointers(downIdBits); + break; + } + case AMOTION_EVENT_ACTION_MOVE: + case AMOTION_EVENT_ACTION_HOVER_MOVE: + break; + default: + // Ignore all other actions because they do not convey any new information about + // pointer movement. We also want to preserve the last known velocity of the pointers. + // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position + // of the pointers that went up. ACTION_POINTER_UP does include the new position of + // pointers that remained down but we will also receive an ACTION_MOVE with this + // information if any of them actually moved. Since we don't know how many pointers + // will be going up at once it makes sense to just wait for the following ACTION_MOVE + // before adding the movement. + return; + } + + size_t pointerCount = event->getPointerCount(); + if (pointerCount > MAX_POINTERS) { + pointerCount = MAX_POINTERS; + } + + BitSet32 idBits; + for (size_t i = 0; i < pointerCount; i++) { + idBits.markBit(event->getPointerId(i)); + } + + nsecs_t eventTime; + Position positions[pointerCount]; + + size_t historySize = event->getHistorySize(); + for (size_t h = 0; h < historySize; h++) { + eventTime = event->getHistoricalEventTime(h); + for (size_t i = 0; i < pointerCount; i++) { + positions[i].x = event->getHistoricalX(i, h); + positions[i].y = event->getHistoricalY(i, h); + } + addMovement(eventTime, idBits, positions); + } + + eventTime = event->getEventTime(); + for (size_t i = 0; i < pointerCount; i++) { + positions[i].x = event->getX(i); + positions[i].y = event->getY(i); + } + addMovement(eventTime, idBits, positions); +} + +/** + * Solves a linear least squares problem to obtain a N degree polynomial that fits + * the specified input data as nearly as possible. + * + * Returns true if a solution is found, false otherwise. + * + * The input consists of two vectors of data points X and Y with indices 0..m-1. + * The output is a vector B with indices 0..n-1 that describes a polynomial + * that fits the data, such the sum of abs(Y[i] - (B[0] + B[1] X[i] + B[2] X[i]^2 ... B[n] X[i]^n)) + * for all i between 0 and m-1 is minimized. + * + * That is to say, the function that generated the input data can be approximated + * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n. + * + * The coefficient of determination (R^2) is also returned to describe the goodness + * of fit of the model for the given data. It is a value between 0 and 1, where 1 + * indicates perfect correspondence. + * + * This function first expands the X vector to a m by n matrix A such that + * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n. + * + * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q + * and an m by n upper triangular matrix R. Because R is upper triangular (lower + * part is all zeroes), we can simplify the decomposition into an m by n matrix + * Q1 and a n by n matrix R1 such that A = Q1 R1. + * + * Finally we solve the system of linear equations given by R1 B = (Qtranspose Y) + * to find B. + * + * For efficiency, we lay out A and Q column-wise in memory because we frequently + * operate on the column vectors. Conversely, we lay out R row-wise. + * + * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares + * http://en.wikipedia.org/wiki/Gram-Schmidt + */ +static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32_t n, + float* outB, float* outDet) { +#if DEBUG_LEAST_SQUARES + ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s", int(m), int(n), + vectorToString(x, m).string(), vectorToString(y, m).string()); +#endif + + // Expand the X vector to a matrix A. + float a[n][m]; // column-major order + for (uint32_t h = 0; h < m; h++) { + a[0][h] = 1; + for (uint32_t i = 1; i < n; i++) { + a[i][h] = a[i - 1][h] * x[h]; + } + } +#if DEBUG_LEAST_SQUARES + ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string()); +#endif + + // Apply the Gram-Schmidt process to A to obtain its QR decomposition. + float q[n][m]; // orthonormal basis, column-major order + float r[n][n]; // upper triangular matrix, row-major order + for (uint32_t j = 0; j < n; j++) { + for (uint32_t h = 0; h < m; h++) { + q[j][h] = a[j][h]; + } + for (uint32_t i = 0; i < j; i++) { + float dot = vectorDot(&q[j][0], &q[i][0], m); + for (uint32_t h = 0; h < m; h++) { + q[j][h] -= dot * q[i][h]; + } + } + + float norm = vectorNorm(&q[j][0], m); + if (norm < 0.000001f) { + // vectors are linearly dependent or zero so no solution +#if DEBUG_LEAST_SQUARES + ALOGD(" - no solution, norm=%f", norm); +#endif + return false; + } + + float invNorm = 1.0f / norm; + for (uint32_t h = 0; h < m; h++) { + q[j][h] *= invNorm; + } + for (uint32_t i = 0; i < n; i++) { + r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m); + } + } +#if DEBUG_LEAST_SQUARES + ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string()); + ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string()); + + // calculate QR, if we factored A correctly then QR should equal A + float qr[n][m]; + for (uint32_t h = 0; h < m; h++) { + for (uint32_t i = 0; i < n; i++) { + qr[i][h] = 0; + for (uint32_t j = 0; j < n; j++) { + qr[i][h] += q[j][h] * r[j][i]; + } + } + } + ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string()); +#endif + + // Solve R B = Qt Y to find B. This is easy because R is upper triangular. + // We just work from bottom-right to top-left calculating B's coefficients. + for (uint32_t i = n; i-- != 0; ) { + outB[i] = vectorDot(&q[i][0], y, m); + for (uint32_t j = n - 1; j > i; j--) { + outB[i] -= r[i][j] * outB[j]; + } + outB[i] /= r[i][i]; + } +#if DEBUG_LEAST_SQUARES + ALOGD(" - b=%s", vectorToString(outB, n).string()); +#endif + + // Calculate the coefficient of determination as 1 - (SSerr / SStot) where + // SSerr is the residual sum of squares (squared variance of the error), + // and SStot is the total sum of squares (squared variance of the data). + float ymean = 0; + for (uint32_t h = 0; h < m; h++) { + ymean += y[h]; + } + ymean /= m; + + float sserr = 0; + float sstot = 0; + for (uint32_t h = 0; h < m; h++) { + float err = y[h] - outB[0]; + float term = 1; + for (uint32_t i = 1; i < n; i++) { + term *= x[h]; + err -= term * outB[i]; + } + sserr += err * err; + float var = y[h] - ymean; + sstot += var * var; + } + *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; +#if DEBUG_LEAST_SQUARES + ALOGD(" - sserr=%f", sserr); + ALOGD(" - sstot=%f", sstot); + ALOGD(" - det=%f", *outDet); +#endif + return true; +} + +bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { + Estimator estimator; + if (getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator)) { + if (estimator.degree >= 1) { + *outVx = estimator.xCoeff[1]; + *outVy = estimator.yCoeff[1]; + return true; + } + } + *outVx = 0; + *outVy = 0; + return false; +} + +bool VelocityTracker::getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon, + Estimator* outEstimator) const { + outEstimator->clear(); + + // Iterate over movement samples in reverse time order and collect samples. + float x[HISTORY_SIZE]; + float y[HISTORY_SIZE]; + float time[HISTORY_SIZE]; + uint32_t m = 0; + uint32_t index = mIndex; + const Movement& newestMovement = mMovements[mIndex]; + do { + const Movement& movement = mMovements[index]; + if (!movement.idBits.hasBit(id)) { + break; + } + + nsecs_t age = newestMovement.eventTime - movement.eventTime; + if (age > horizon) { + break; + } + + const Position& position = movement.getPosition(id); + x[m] = position.x; + y[m] = position.y; + time[m] = -age * 0.000000001f; + index = (index == 0 ? HISTORY_SIZE : index) - 1; + } while (++m < HISTORY_SIZE); + + if (m == 0) { + return false; // no data + } + + // Calculate a least squares polynomial fit. + if (degree > Estimator::MAX_DEGREE) { + degree = Estimator::MAX_DEGREE; + } + if (degree > m - 1) { + degree = m - 1; + } + if (degree >= 1) { + float xdet, ydet; + uint32_t n = degree + 1; + if (solveLeastSquares(time, x, m, n, outEstimator->xCoeff, &xdet) + && solveLeastSquares(time, y, m, n, outEstimator->yCoeff, &ydet)) { + outEstimator->degree = degree; + outEstimator->confidence = xdet * ydet; +#if DEBUG_LEAST_SQUARES + ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", + int(outEstimator->degree), + vectorToString(outEstimator->xCoeff, n).string(), + vectorToString(outEstimator->yCoeff, n).string(), + outEstimator->confidence); +#endif + return true; + } + } + + // No velocity data available for this pointer, but we do have its current position. + outEstimator->xCoeff[0] = x[0]; + outEstimator->yCoeff[0] = y[0]; + outEstimator->degree = 0; + outEstimator->confidence = 1; + return true; +} + + +// --- VelocityControl --- + +const nsecs_t VelocityControl::STOP_TIME; + +VelocityControl::VelocityControl() { + reset(); +} + +void VelocityControl::setParameters(const VelocityControlParameters& parameters) { + mParameters = parameters; + reset(); +} + +void VelocityControl::reset() { + mLastMovementTime = LLONG_MIN; + mRawPosition.x = 0; + mRawPosition.y = 0; + mVelocityTracker.clear(); +} + +void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { + if ((deltaX && *deltaX) || (deltaY && *deltaY)) { + if (eventTime >= mLastMovementTime + STOP_TIME) { +#if DEBUG_ACCELERATION + ALOGD("VelocityControl: stopped, last movement was %0.3fms ago", + (eventTime - mLastMovementTime) * 0.000001f); +#endif + reset(); + } + + mLastMovementTime = eventTime; + if (deltaX) { + mRawPosition.x += *deltaX; + } + if (deltaY) { + mRawPosition.y += *deltaY; + } + mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition); + + float vx, vy; + float scale = mParameters.scale; + if (mVelocityTracker.getVelocity(0, &vx, &vy)) { + float speed = hypotf(vx, vy) * scale; + if (speed >= mParameters.highThreshold) { + // Apply full acceleration above the high speed threshold. + scale *= mParameters.acceleration; + } else if (speed > mParameters.lowThreshold) { + // Linearly interpolate the acceleration to apply between the low and high + // speed thresholds. + scale *= 1 + (speed - mParameters.lowThreshold) + / (mParameters.highThreshold - mParameters.lowThreshold) + * (mParameters.acceleration - 1); + } + +#if DEBUG_ACCELERATION + ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " + "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", + mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, + mParameters.acceleration, + vx, vy, speed, scale / mParameters.scale); +#endif + } else { +#if DEBUG_ACCELERATION + ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", + mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, + mParameters.acceleration); +#endif + } + + if (deltaX) { + *deltaX *= scale; + } + if (deltaY) { + *deltaY *= scale; + } + } +} + + +// --- InputDeviceInfo --- + +InputDeviceInfo::InputDeviceInfo() { + initialize(-1, String8("uninitialized device info")); +} + +InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : + mId(other.mId), mName(other.mName), mSources(other.mSources), + mKeyboardType(other.mKeyboardType), + mMotionRanges(other.mMotionRanges) { +} + +InputDeviceInfo::~InputDeviceInfo() { +} + +void InputDeviceInfo::initialize(int32_t id, const String8& name) { + mId = id; + mName = name; + mSources = 0; + mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; + mMotionRanges.clear(); +} + +const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( + int32_t axis, uint32_t source) const { + size_t numRanges = mMotionRanges.size(); + for (size_t i = 0; i < numRanges; i++) { + const MotionRange& range = mMotionRanges.itemAt(i); + if (range.axis == axis && range.source == source) { + return ⦥ + } + } + return NULL; +} + +void InputDeviceInfo::addSource(uint32_t source) { + mSources |= source; +} + +void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, + float flat, float fuzz) { + MotionRange range = { axis, source, min, max, flat, fuzz }; + mMotionRanges.add(range); +} + +void InputDeviceInfo::addMotionRange(const MotionRange& range) { + mMotionRanges.add(range); +} + +} // namespace android diff --git a/widget/gonk/libui/Input.h b/widget/gonk/libui/Input.h index c2cbe1d6e87..6c17518369c 100644 --- a/widget/gonk/libui/Input.h +++ b/widget/gonk/libui/Input.h @@ -21,13 +21,13 @@ * Native input event structures. */ -#include +#include "android_input.h" #include #include -#include +#include "Timers.h" #include -#include -#include +#include "String8.h" +#include "BitSet.h" #ifdef HAVE_ANDROID_OS class SkMatrix; diff --git a/widget/gonk/libui/InputApplication.cpp b/widget/gonk/libui/InputApplication.cpp index a99e637fdf4..ce432356b0f 100644 --- a/widget/gonk/libui/InputApplication.cpp +++ b/widget/gonk/libui/InputApplication.cpp @@ -18,7 +18,7 @@ #include "InputApplication.h" -#include +#include "cutils_log.h" namespace android { diff --git a/widget/gonk/libui/InputApplication.h b/widget/gonk/libui/InputApplication.h index ba789559c97..ae9381b0cc5 100644 --- a/widget/gonk/libui/InputApplication.h +++ b/widget/gonk/libui/InputApplication.h @@ -20,8 +20,8 @@ #include "Input.h" #include -#include -#include +#include "Timers.h" +#include "String8.h" namespace android { diff --git a/widget/gonk/libui/InputDispatcher.cpp b/widget/gonk/libui/InputDispatcher.cpp index 7a48a686af5..3ec3727a3f8 100644 --- a/widget/gonk/libui/InputDispatcher.cpp +++ b/widget/gonk/libui/InputDispatcher.cpp @@ -53,7 +53,6 @@ #include "InputDispatcher.h" -#include #include #include diff --git a/widget/gonk/libui/InputDispatcher.h b/widget/gonk/libui/InputDispatcher.h index 832e180e0e5..eb0f413b5eb 100644 --- a/widget/gonk/libui/InputDispatcher.h +++ b/widget/gonk/libui/InputDispatcher.h @@ -17,16 +17,17 @@ #ifndef _UI_INPUT_DISPATCHER_H #define _UI_INPUT_DISPATCHER_H +#include "cutils_log.h" #include "Input.h" #include "InputTransport.h" #include #include #include -#include +#include "Timers.h" #include -#include +#include "String8.h" #include -#include +#include "BitSet.h" #include #include diff --git a/widget/gonk/libui/InputListener.cpp b/widget/gonk/libui/InputListener.cpp index 657a6b98b23..0baa7f390be 100644 --- a/widget/gonk/libui/InputListener.cpp +++ b/widget/gonk/libui/InputListener.cpp @@ -20,7 +20,7 @@ #include "InputListener.h" -#include +#include "cutils_log.h" namespace android { diff --git a/widget/gonk/libui/InputReader.cpp b/widget/gonk/libui/InputReader.cpp index 81998ffab31..07cbf09f57b 100644 --- a/widget/gonk/libui/InputReader.cpp +++ b/widget/gonk/libui/InputReader.cpp @@ -38,7 +38,7 @@ #include "InputReader.h" -#include +#include "cutils_log.h" #include "Keyboard.h" #include "VirtualKeyMap.h" @@ -5634,6 +5634,10 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { outPointer.tiltX = 0; outPointer.tiltY = 0; + // Mozilla bug 739417 + if (!outPointer.touchMajor) + continue; + outPointer.toolType = inSlot->getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); diff --git a/widget/gonk/libui/InputReader.h b/widget/gonk/libui/InputReader.h index 1005528c98d..16537e61122 100644 --- a/widget/gonk/libui/InputReader.h +++ b/widget/gonk/libui/InputReader.h @@ -27,10 +27,10 @@ #include "DisplayInfo.h" #include #include -#include +#include "Timers.h" #include -#include -#include +#include "String8.h" +#include "BitSet.h" #include #include diff --git a/widget/gonk/libui/InputTransport.cpp b/widget/gonk/libui/InputTransport.cpp index 4d9c92e40f9..95df2e49e9d 100644 --- a/widget/gonk/libui/InputTransport.cpp +++ b/widget/gonk/libui/InputTransport.cpp @@ -18,7 +18,7 @@ #include -#include +#include "cutils_log.h" #include #include #include diff --git a/widget/gonk/libui/InputTransport.h b/widget/gonk/libui/InputTransport.h index 83948ff2206..7faeaf88e5c 100644 --- a/widget/gonk/libui/InputTransport.h +++ b/widget/gonk/libui/InputTransport.h @@ -33,9 +33,9 @@ #include #include "Input.h" #include -#include +#include "Timers.h" #include -#include +#include "String8.h" namespace android { diff --git a/widget/gonk/libui/InputWindow.cpp b/widget/gonk/libui/InputWindow.cpp index 23c3f0c9a92..81509b98f6f 100644 --- a/widget/gonk/libui/InputWindow.cpp +++ b/widget/gonk/libui/InputWindow.cpp @@ -18,7 +18,7 @@ #include "InputWindow.h" -#include +#include "cutils_log.h" namespace android { diff --git a/widget/gonk/libui/InputWindow.h b/widget/gonk/libui/InputWindow.h index 3da7fd0a136..5361cc86f04 100644 --- a/widget/gonk/libui/InputWindow.h +++ b/widget/gonk/libui/InputWindow.h @@ -20,8 +20,8 @@ #include "Input.h" #include "InputTransport.h" #include -#include -#include +#include "Timers.h" +#include "String8.h" #include "SkRegion.h" diff --git a/widget/gonk/libui/KeyCharacterMap.cpp b/widget/gonk/libui/KeyCharacterMap.cpp index a1f80c87f77..bd18c5f3d6a 100644 --- a/widget/gonk/libui/KeyCharacterMap.cpp +++ b/widget/gonk/libui/KeyCharacterMap.cpp @@ -18,13 +18,13 @@ #include #include -#include +#include "utils_Log.h" +#include "android_keycodes.h" #include "Keyboard.h" #include "KeyCharacterMap.h" -#include #include -#include -#include +#include "Tokenizer.h" +#include "Timers.h" // Enables debug output for the parser. #define DEBUG_PARSER 0 diff --git a/widget/gonk/libui/KeyCharacterMap.h b/widget/gonk/libui/KeyCharacterMap.h index 1184fa7524d..3efe1cdf40e 100644 --- a/widget/gonk/libui/KeyCharacterMap.h +++ b/widget/gonk/libui/KeyCharacterMap.h @@ -22,9 +22,9 @@ #include "Input.h" #include #include -#include -#include -#include +#include "Tokenizer.h" +#include "String8.h" +#include "Unicode.h" namespace android { diff --git a/widget/gonk/libui/KeyLayoutMap.cpp b/widget/gonk/libui/KeyLayoutMap.cpp index 5f75005aa49..2c9cb24e2cf 100644 --- a/widget/gonk/libui/KeyLayoutMap.cpp +++ b/widget/gonk/libui/KeyLayoutMap.cpp @@ -17,13 +17,13 @@ #define LOG_TAG "KeyLayoutMap" #include -#include +#include "utils_Log.h" +#include "android_keycodes.h" #include "Keyboard.h" #include "KeyLayoutMap.h" -#include #include -#include -#include +#include "Tokenizer.h" +#include "Timers.h" // Enables debug output for the parser. #define DEBUG_PARSER 0 diff --git a/widget/gonk/libui/KeyLayoutMap.h b/widget/gonk/libui/KeyLayoutMap.h index d82d0c8e0ef..9b83114ea36 100644 --- a/widget/gonk/libui/KeyLayoutMap.h +++ b/widget/gonk/libui/KeyLayoutMap.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include "Tokenizer.h" namespace android { diff --git a/widget/gonk/libui/Keyboard.cpp b/widget/gonk/libui/Keyboard.cpp index a08ec95a63c..d10086f9aa3 100644 --- a/widget/gonk/libui/Keyboard.cpp +++ b/widget/gonk/libui/Keyboard.cpp @@ -20,12 +20,12 @@ #include #include +#include "utils_Log.h" #include "Keyboard.h" #include "KeycodeLabels.h" #include "KeyLayoutMap.h" #include "KeyCharacterMap.h" #include -#include #include namespace android { diff --git a/widget/gonk/libui/Keyboard.h b/widget/gonk/libui/Keyboard.h index 3e677a1f086..8e9e10abc8b 100644 --- a/widget/gonk/libui/Keyboard.h +++ b/widget/gonk/libui/Keyboard.h @@ -19,8 +19,8 @@ #include "Input.h" #include -#include -#include +#include "String8.h" +#include "PropertyMap.h" namespace android { diff --git a/widget/gonk/libui/KeycodeLabels.h b/widget/gonk/libui/KeycodeLabels.h index c5bd0c54467..cb4a1775253 100644 --- a/widget/gonk/libui/KeycodeLabels.h +++ b/widget/gonk/libui/KeycodeLabels.h @@ -17,7 +17,7 @@ #ifndef _UI_KEYCODE_LABELS_H #define _UI_KEYCODE_LABELS_H -#include +#include "android_keycodes.h" struct KeycodeLabel { const char *literal; diff --git a/widget/gonk/libui/PointerController.cpp b/widget/gonk/libui/PointerController.cpp deleted file mode 100644 index fc828a6afee..00000000000 --- a/widget/gonk/libui/PointerController.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "PointerController" - -//#define LOG_NDEBUG 0 - -// Log debug messages about pointer updates -#define DEBUG_POINTER_UPDATES 0 - -#include "PointerController.h" - -#include - -#include -#include -#include -#include -#include - -namespace android { - -// --- PointerController --- - -// Time to wait before starting the fade when the pointer is inactive. -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds - -// Time to wait between animation frames. -static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60; - -// Time to spend fading out the spot completely. -static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms - -// Time to spend fading out the pointer completely. -static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms - - -// --- PointerController --- - -PointerController::PointerController(const sp& policy, - const sp& looper, const sp& spriteController) : - mPolicy(policy), mLooper(looper), mSpriteController(spriteController) { - mHandler = new WeakMessageHandler(this); - - AutoMutex _l(mLock); - - mLocked.animationPending = false; - - mLocked.displayWidth = -1; - mLocked.displayHeight = -1; - mLocked.displayOrientation = DISPLAY_ORIENTATION_0; - - mLocked.presentation = PRESENTATION_POINTER; - mLocked.presentationChanged = false; - - mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL; - - mLocked.pointerFadeDirection = 0; - mLocked.pointerX = 0; - mLocked.pointerY = 0; - mLocked.pointerAlpha = 0.0f; // pointer is initially faded - mLocked.pointerSprite = mSpriteController->createSprite(); - mLocked.pointerIconChanged = false; - - mLocked.buttonState = 0; - - loadResources(); -} - -PointerController::~PointerController() { - mLooper->removeMessages(mHandler); - - AutoMutex _l(mLock); - - mLocked.pointerSprite.clear(); - - for (size_t i = 0; i < mLocked.spots.size(); i++) { - delete mLocked.spots.itemAt(i); - } - mLocked.spots.clear(); - mLocked.recycledSprites.clear(); -} - -bool PointerController::getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - AutoMutex _l(mLock); - - return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); -} - -bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { - return false; - } - - *outMinX = 0; - *outMinY = 0; - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - *outMaxX = mLocked.displayHeight - 1; - *outMaxY = mLocked.displayWidth - 1; - break; - default: - *outMaxX = mLocked.displayWidth - 1; - *outMaxY = mLocked.displayHeight - 1; - break; - } - return true; -} - -void PointerController::move(float deltaX, float deltaY) { -#if DEBUG_POINTER_UPDATES - ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); -#endif - if (deltaX == 0.0f && deltaY == 0.0f) { - return; - } - - AutoMutex _l(mLock); - - setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); -} - -void PointerController::setButtonState(int32_t buttonState) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set button state 0x%08x", buttonState); -#endif - AutoMutex _l(mLock); - - if (mLocked.buttonState != buttonState) { - mLocked.buttonState = buttonState; - } -} - -int32_t PointerController::getButtonState() const { - AutoMutex _l(mLock); - - return mLocked.buttonState; -} - -void PointerController::setPosition(float x, float y) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); -#endif - AutoMutex _l(mLock); - - setPositionLocked(x, y); -} - -void PointerController::setPositionLocked(float x, float y) { - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - if (x <= minX) { - mLocked.pointerX = minX; - } else if (x >= maxX) { - mLocked.pointerX = maxX; - } else { - mLocked.pointerX = x; - } - if (y <= minY) { - mLocked.pointerY = minY; - } else if (y >= maxY) { - mLocked.pointerY = maxY; - } else { - mLocked.pointerY = y; - } - updatePointerLocked(); - } -} - -void PointerController::getPosition(float* outX, float* outY) const { - AutoMutex _l(mLock); - - *outX = mLocked.pointerX; - *outY = mLocked.pointerY; -} - -void PointerController::fade(Transition transition) { - AutoMutex _l(mLock); - - // Remove the inactivity timeout, since we are fading now. - removeInactivityTimeoutLocked(); - - // Start fading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 0.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = -1; - startAnimationLocked(); - } -} - -void PointerController::unfade(Transition transition) { - AutoMutex _l(mLock); - - // Always reset the inactivity timer. - resetInactivityTimeoutLocked(); - - // Start unfading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 1.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = 1; - startAnimationLocked(); - } -} - -void PointerController::setPresentation(Presentation presentation) { - AutoMutex _l(mLock); - - if (mLocked.presentation != presentation) { - mLocked.presentation = presentation; - mLocked.presentationChanged = true; - - if (presentation != PRESENTATION_SPOT) { - fadeOutAndReleaseAllSpotsLocked(); - } - - updatePointerLocked(); - } -} - -void PointerController::setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { -#if DEBUG_POINTER_UPDATES - ALOGD("setSpots: idBits=%08x", spotIdBits.value); - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, - c.getAxisValue(AMOTION_EVENT_AXIS_X), - c.getAxisValue(AMOTION_EVENT_AXIS_Y), - c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - - AutoMutex _l(mLock); - - mSpriteController->openTransaction(); - - // Add or move spots for fingers that are down. - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 - ? mResources.spotTouch : mResources.spotHover; - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); - - Spot* spot = getSpotLocked(id); - if (!spot) { - spot = createAndAddSpotLocked(id); - } - - spot->updateSprite(&icon, x, y); - } - - // Remove spots for fingers that went up. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id != Spot::INVALID_ID - && !spotIdBits.hasBit(spot->id)) { - fadeOutAndReleaseSpotLocked(spot); - } - } - - mSpriteController->closeTransaction(); -} - -void PointerController::clearSpots() { -#if DEBUG_POINTER_UPDATES - ALOGD("clearSpots"); -#endif - - AutoMutex _l(mLock); - - fadeOutAndReleaseAllSpotsLocked(); -} - -void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { - AutoMutex _l(mLock); - - if (mLocked.inactivityTimeout != inactivityTimeout) { - mLocked.inactivityTimeout = inactivityTimeout; - resetInactivityTimeoutLocked(); - } -} - -void PointerController::setDisplaySize(int32_t width, int32_t height) { - AutoMutex _l(mLock); - - if (mLocked.displayWidth != width || mLocked.displayHeight != height) { - mLocked.displayWidth = width; - mLocked.displayHeight = height; - - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - mLocked.pointerX = (minX + maxX) * 0.5f; - mLocked.pointerY = (minY + maxY) * 0.5f; - } else { - mLocked.pointerX = 0; - mLocked.pointerY = 0; - } - - fadeOutAndReleaseAllSpotsLocked(); - updatePointerLocked(); - } -} - -void PointerController::setDisplayOrientation(int32_t orientation) { - AutoMutex _l(mLock); - - if (mLocked.displayOrientation != orientation) { - // Apply offsets to convert from the pixel top-left corner position to the pixel center. - // This creates an invariant frame of reference that we can easily rotate when - // taking into account that the pointer may be located at fractional pixel offsets. - float x = mLocked.pointerX + 0.5f; - float y = mLocked.pointerY + 0.5f; - float temp; - - // Undo the previous rotation. - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = mLocked.displayWidth - y; - y = temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = y; - y = mLocked.displayHeight - temp; - break; - } - - // Perform the new rotation. - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = y; - y = mLocked.displayWidth - temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = mLocked.displayHeight - y; - y = temp; - break; - } - - // Apply offsets to convert from the pixel center to the pixel top-left corner position - // and save the results. - mLocked.pointerX = x - 0.5f; - mLocked.pointerY = y - 0.5f; - mLocked.displayOrientation = orientation; - - updatePointerLocked(); - } -} - -void PointerController::setPointerIcon(const SpriteIcon& icon) { - AutoMutex _l(mLock); - - mLocked.pointerIcon = icon.copy(); - mLocked.pointerIconChanged = true; - - updatePointerLocked(); -} - -void PointerController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_ANIMATE: - doAnimate(); - break; - case MSG_INACTIVITY_TIMEOUT: - doInactivityTimeout(); - break; - } -} - -void PointerController::doAnimate() { - AutoMutex _l(mLock); - - bool keepAnimating = false; - mLocked.animationPending = false; - nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime; - - // Animate pointer fade. - if (mLocked.pointerFadeDirection < 0) { - mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha <= 0.0f) { - mLocked.pointerAlpha = 0.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } else if (mLocked.pointerFadeDirection > 0) { - mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha >= 1.0f) { - mLocked.pointerAlpha = 1.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } - - // Animate spots that are fading out and being removed. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; - if (spot->alpha <= 0) { - mLocked.spots.removeAt(i--); - releaseSpotLocked(spot); - } else { - spot->sprite->setAlpha(spot->alpha); - keepAnimating = true; - } - } - } - - if (keepAnimating) { - startAnimationLocked(); - } -} - -void PointerController::doInactivityTimeout() { - fade(TRANSITION_GRADUAL); -} - -void PointerController::startAnimationLocked() { - if (!mLocked.animationPending) { - mLocked.animationPending = true; - mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); - mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE)); - } -} - -void PointerController::resetInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); - - nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT - ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; - mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::removeInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::updatePointerLocked() { - mSpriteController->openTransaction(); - - mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); - mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); - - if (mLocked.pointerAlpha > 0) { - mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); - mLocked.pointerSprite->setVisible(true); - } else { - mLocked.pointerSprite->setVisible(false); - } - - if (mLocked.pointerIconChanged || mLocked.presentationChanged) { - mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER - ? mLocked.pointerIcon : mResources.spotAnchor); - mLocked.pointerIconChanged = false; - mLocked.presentationChanged = false; - } - - mSpriteController->closeTransaction(); -} - -PointerController::Spot* PointerController::getSpotLocked(uint32_t id) { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == id) { - return spot; - } - } - return NULL; -} - -PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) { - // Remove spots until we have fewer than MAX_SPOTS remaining. - while (mLocked.spots.size() >= MAX_SPOTS) { - Spot* spot = removeFirstFadingSpotLocked(); - if (!spot) { - spot = mLocked.spots.itemAt(0); - mLocked.spots.removeAt(0); - } - releaseSpotLocked(spot); - } - - // Obtain a sprite from the recycled pool. - sp sprite; - if (! mLocked.recycledSprites.isEmpty()) { - sprite = mLocked.recycledSprites.top(); - mLocked.recycledSprites.pop(); - } else { - sprite = mSpriteController->createSprite(); - } - - // Return the new spot. - Spot* spot = new Spot(id, sprite); - mLocked.spots.push(spot); - return spot; -} - -PointerController::Spot* PointerController::removeFirstFadingSpotLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - mLocked.spots.removeAt(i); - return spot; - } - } - return NULL; -} - -void PointerController::releaseSpotLocked(Spot* spot) { - spot->sprite->clearIcon(); - - if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { - mLocked.recycledSprites.push(spot->sprite); - } - - delete spot; -} - -void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) { - if (spot->id != Spot::INVALID_ID) { - spot->id = Spot::INVALID_ID; - startAnimationLocked(); - } -} - -void PointerController::fadeOutAndReleaseAllSpotsLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - fadeOutAndReleaseSpotLocked(spot); - } -} - -void PointerController::loadResources() { - mPolicy->loadPointerResources(&mResources); -} - - -// --- PointerController::Spot --- - -void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) { - sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); - sprite->setAlpha(alpha); - sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); - sprite->setPosition(x, y); - - this->x = x; - this->y = y; - - if (icon != lastIcon) { - lastIcon = icon; - if (icon) { - sprite->setIcon(*icon); - sprite->setVisible(true); - } else { - sprite->setVisible(false); - } - } -} - -} // namespace android diff --git a/widget/gonk/libui/PointerController.h b/widget/gonk/libui/PointerController.h deleted file mode 100644 index bf7b7bb7aa8..00000000000 --- a/widget/gonk/libui/PointerController.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_POINTER_CONTROLLER_H -#define _UI_POINTER_CONTROLLER_H - -#include "SpriteController.h" - -#include "DisplayInfo.h" -#include "Input.h" -#include -#include -#include - -#include - -namespace android { - -/** - * Interface for tracking a mouse / touch pad pointer and touch pad spots. - * - * The spots are sprites on screen that visually represent the positions of - * fingers - * - * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. - */ -class PointerControllerInterface : public virtual RefBase { -protected: - PointerControllerInterface() { } - virtual ~PointerControllerInterface() { } - -public: - /* Gets the bounds of the region that the pointer can traverse. - * Returns true if the bounds are available. */ - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const = 0; - - /* Move the pointer. */ - virtual void move(float deltaX, float deltaY) = 0; - - /* Sets a mask that indicates which buttons are pressed. */ - virtual void setButtonState(int32_t buttonState) = 0; - - /* Gets a mask that indicates which buttons are pressed. */ - virtual int32_t getButtonState() const = 0; - - /* Sets the absolute location of the pointer. */ - virtual void setPosition(float x, float y) = 0; - - /* Gets the absolute location of the pointer. */ - virtual void getPosition(float* outX, float* outY) const = 0; - - enum Transition { - // Fade/unfade immediately. - TRANSITION_IMMEDIATE, - // Fade/unfade gradually. - TRANSITION_GRADUAL, - }; - - /* Fades the pointer out now. */ - virtual void fade(Transition transition) = 0; - - /* Makes the pointer visible if it has faded out. - * The pointer never unfades itself automatically. This method must be called - * by the client whenever the pointer is moved or a button is pressed and it - * wants to ensure that the pointer becomes visible again. */ - virtual void unfade(Transition transition) = 0; - - enum Presentation { - // Show the mouse pointer. - PRESENTATION_POINTER, - // Show spots and a spot anchor in place of the mouse pointer. - PRESENTATION_SPOT, - }; - - /* Sets the mode of the pointer controller. */ - virtual void setPresentation(Presentation presentation) = 0; - - /* Sets the spots for the current gesture. - * The spots are not subject to the inactivity timeout like the pointer - * itself it since they are expected to remain visible for so long as - * the fingers are on the touch pad. - * - * The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant. - * For spotCoords, pressure != 0 indicates that the spot's location is being - * pressed (not hovering). - */ - virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits) = 0; - - /* Removes all spots. */ - virtual void clearSpots() = 0; -}; - - -/* - * Pointer resources. - */ -struct PointerResources { - SpriteIcon spotHover; - SpriteIcon spotTouch; - SpriteIcon spotAnchor; -}; - - -/* - * Pointer controller policy interface. - * - * The pointer controller policy is used by the pointer controller to interact with - * the Window Manager and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class PointerControllerPolicyInterface : public virtual RefBase { -protected: - PointerControllerPolicyInterface() { } - virtual ~PointerControllerPolicyInterface() { } - -public: - virtual void loadPointerResources(PointerResources* outResources) = 0; -}; - - -/* - * Tracks pointer movements and draws the pointer sprite to a surface. - * - * Handles pointer acceleration and animation. - */ -class PointerController : public PointerControllerInterface, public MessageHandler { -protected: - virtual ~PointerController(); - -public: - enum InactivityTimeout { - INACTIVITY_TIMEOUT_NORMAL = 0, - INACTIVITY_TIMEOUT_SHORT = 1, - }; - - PointerController(const sp& policy, - const sp& looper, const sp& spriteController); - - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const; - virtual void move(float deltaX, float deltaY); - virtual void setButtonState(int32_t buttonState); - virtual int32_t getButtonState() const; - virtual void setPosition(float x, float y); - virtual void getPosition(float* outX, float* outY) const; - virtual void fade(Transition transition); - virtual void unfade(Transition transition); - - virtual void setPresentation(Presentation presentation); - virtual void setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits); - virtual void clearSpots(); - - void setDisplaySize(int32_t width, int32_t height); - void setDisplayOrientation(int32_t orientation); - void setPointerIcon(const SpriteIcon& icon); - void setInactivityTimeout(InactivityTimeout inactivityTimeout); - -private: - static const size_t MAX_RECYCLED_SPRITES = 12; - static const size_t MAX_SPOTS = 12; - - enum { - MSG_ANIMATE, - MSG_INACTIVITY_TIMEOUT, - }; - - struct Spot { - static const uint32_t INVALID_ID = 0xffffffff; - - uint32_t id; - sp sprite; - float alpha; - float scale; - float x, y; - - inline Spot(uint32_t id, const sp& sprite) - : id(id), sprite(sprite), alpha(1.0f), scale(1.0f), - x(0.0f), y(0.0f), lastIcon(NULL) { } - - void updateSprite(const SpriteIcon* icon, float x, float y); - - private: - const SpriteIcon* lastIcon; - }; - - mutable Mutex mLock; - - sp mPolicy; - sp mLooper; - sp mSpriteController; - sp mHandler; - - PointerResources mResources; - - struct Locked { - bool animationPending; - nsecs_t animationTime; - - int32_t displayWidth; - int32_t displayHeight; - int32_t displayOrientation; - - InactivityTimeout inactivityTimeout; - - Presentation presentation; - bool presentationChanged; - - int32_t pointerFadeDirection; - float pointerX; - float pointerY; - float pointerAlpha; - sp pointerSprite; - SpriteIcon pointerIcon; - bool pointerIconChanged; - - int32_t buttonState; - - Vector spots; - Vector > recycledSprites; - } mLocked; - - bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; - void setPositionLocked(float x, float y); - - void handleMessage(const Message& message); - void doAnimate(); - void doInactivityTimeout(); - - void startAnimationLocked(); - - void resetInactivityTimeoutLocked(); - void removeInactivityTimeoutLocked(); - void updatePointerLocked(); - - Spot* getSpotLocked(uint32_t id); - Spot* createAndAddSpotLocked(uint32_t id); - Spot* removeFirstFadingSpotLocked(); - void releaseSpotLocked(Spot* spot); - void fadeOutAndReleaseSpotLocked(Spot* spot); - void fadeOutAndReleaseAllSpotsLocked(); - - void loadResources(); -}; - -} // namespace android - -#endif // _UI_POINTER_CONTROLLER_H diff --git a/widget/gonk/libui/PropertyMap.cpp b/widget/gonk/libui/PropertyMap.cpp new file mode 100644 index 00000000000..4775a0d151e --- /dev/null +++ b/widget/gonk/libui/PropertyMap.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "PropertyMap" + +#include +#include + +#include "utils_Log.h" +#include "PropertyMap.h" + +// Enables debug output for the parser. +#define DEBUG_PARSER 0 + +// Enables debug output for parser performance. +#define DEBUG_PARSER_PERFORMANCE 0 + + +namespace android { + +static const char* WHITESPACE = " \t\r"; +static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r="; + + +// --- PropertyMap --- + +PropertyMap::PropertyMap() { +} + +PropertyMap::~PropertyMap() { +} + +void PropertyMap::clear() { + mProperties.clear(); +} + +void PropertyMap::addProperty(const String8& key, const String8& value) { + mProperties.add(key, value); +} + +bool PropertyMap::hasProperty(const String8& key) const { + return mProperties.indexOfKey(key) >= 0; +} + +bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const { + ssize_t index = mProperties.indexOfKey(key); + if (index < 0) { + return false; + } + + outValue = mProperties.valueAt(index); + return true; +} + +bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { + int32_t intValue; + if (!tryGetProperty(key, intValue)) { + return false; + } + + outValue = intValue; + return true; +} + +bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + int value = strtol(stringValue.string(), & end, 10); + if (*end != '\0') { + ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + +bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + float value = strtof(stringValue.string(), & end); + if (*end != '\0') { + ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + +void PropertyMap::addAll(const PropertyMap* map) { + for (size_t i = 0; i < map->mProperties.size(); i++) { + mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); + } +} + +status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) { + *outMap = NULL; + + Tokenizer* tokenizer; + status_t status = Tokenizer::open(filename, &tokenizer); + if (status) { + ALOGE("Error %d opening property file %s.", status, filename.string()); + } else { + PropertyMap* map = new PropertyMap(); + if (!map) { + ALOGE("Error allocating property map."); + status = NO_MEMORY; + } else { +#if DEBUG_PARSER_PERFORMANCE + nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); +#endif + Parser parser(map, tokenizer); + status = parser.parse(); +#if DEBUG_PARSER_PERFORMANCE + nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; + ALOGD("Parsed property file '%s' %d lines in %0.3fms.", + tokenizer->getFilename().string(), tokenizer->getLineNumber(), + elapsedTime / 1000000.0); +#endif + if (status) { + delete map; + } else { + *outMap = map; + } + } + delete tokenizer; + } + return status; +} + + +// --- PropertyMap::Parser --- + +PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) : + mMap(map), mTokenizer(tokenizer) { +} + +PropertyMap::Parser::~Parser() { +} + +status_t PropertyMap::Parser::parse() { + while (!mTokenizer->isEof()) { +#if DEBUG_PARSER + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), + mTokenizer->peekRemainderOfLine().string()); +#endif + + mTokenizer->skipDelimiters(WHITESPACE); + + if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { + String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); + if (keyToken.isEmpty()) { + ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + + if (mTokenizer->nextChar() != '=') { + ALOGE("%s: Expected '=' between property key and value.", + mTokenizer->getLocation().string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + + String8 valueToken = mTokenizer->nextToken(WHITESPACE); + if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) { + ALOGE("%s: Found reserved character '\\' or '\"' in property value.", + mTokenizer->getLocation().string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + if (!mTokenizer->isEol()) { + ALOGE("%s: Expected end of line, got '%s'.", + mTokenizer->getLocation().string(), + mTokenizer->peekRemainderOfLine().string()); + return BAD_VALUE; + } + + if (mMap->hasProperty(keyToken)) { + ALOGE("%s: Duplicate property value for key '%s'.", + mTokenizer->getLocation().string(), keyToken.string()); + return BAD_VALUE; + } + + mMap->addProperty(keyToken, valueToken); + } + + mTokenizer->nextLine(); + } + return NO_ERROR; +} + +} // namespace android diff --git a/widget/gonk/libui/PropertyMap.h b/widget/gonk/libui/PropertyMap.h new file mode 100644 index 00000000000..bf012e96633 --- /dev/null +++ b/widget/gonk/libui/PropertyMap.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UTILS_PROPERTY_MAP_H +#define _UTILS_PROPERTY_MAP_H + +#include +#include "String8.h" +#include +#include "Tokenizer.h" + +namespace android { + +/* + * Provides a mechanism for passing around string-based property key / value pairs + * and loading them from property files. + * + * The property files have the following simple structure: + * + * # Comment + * key = value + * + * Keys and values are any sequence of printable ASCII characters. + * The '=' separates the key from the value. + * The key and value may not contain whitespace. + * + * The '\' character is reserved for escape sequences and is not currently supported. + * The '"" character is reserved for quoting and is not currently supported. + * Files that contain the '\' or '"' character will fail to parse. + * + * The file must not contain duplicate keys. + * + * TODO Support escape sequences and quoted values when needed. + */ +class PropertyMap { +public: + /* Creates an empty property map. */ + PropertyMap(); + ~PropertyMap(); + + /* Clears the property map. */ + void clear(); + + /* Adds a property. + * Replaces the property with the same key if it is already present. + */ + void addProperty(const String8& key, const String8& value); + + /* Returns true if the property map contains the specified key. */ + bool hasProperty(const String8& key) const; + + /* Gets the value of a property and parses it. + * Returns true and sets outValue if the key was found and its value was parsed successfully. + * Otherwise returns false and does not modify outValue. (Also logs a warning.) + */ + bool tryGetProperty(const String8& key, String8& outValue) const; + bool tryGetProperty(const String8& key, bool& outValue) const; + bool tryGetProperty(const String8& key, int32_t& outValue) const; + bool tryGetProperty(const String8& key, float& outValue) const; + + /* Adds all values from the specified property map. */ + void addAll(const PropertyMap* map); + + /* Gets the underlying property map. */ + inline const KeyedVector& getProperties() const { return mProperties; } + + /* Loads a property map from a file. */ + static status_t load(const String8& filename, PropertyMap** outMap); + +private: + class Parser { + PropertyMap* mMap; + Tokenizer* mTokenizer; + + public: + Parser(PropertyMap* map, Tokenizer* tokenizer); + ~Parser(); + status_t parse(); + + private: + status_t parseType(); + status_t parseKey(); + status_t parseKeyProperty(); + status_t parseModifier(const String8& token, int32_t* outMetaState); + status_t parseCharacterLiteral(char16_t* outCharacter); + }; + + KeyedVector mProperties; +}; + +} // namespace android + +#endif // _UTILS_PROPERTY_MAP_H diff --git a/widget/gonk/libui/SpriteController.cpp b/widget/gonk/libui/SpriteController.cpp deleted file mode 100644 index b15d4c8d309..00000000000 --- a/widget/gonk/libui/SpriteController.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "Sprites" - -//#define LOG_NDEBUG 0 - -#include "SpriteController.h" - -#include -#include - -#include -#include -#include -#include -#include - -namespace android { - -// --- SpriteController --- - -SpriteController::SpriteController(const sp& looper, int32_t overlayLayer) : - mLooper(looper), mOverlayLayer(overlayLayer) { - mHandler = new WeakMessageHandler(this); - - mLocked.transactionNestingCount = 0; - mLocked.deferredSpriteUpdate = false; -} - -SpriteController::~SpriteController() { - mLooper->removeMessages(mHandler); - - if (mSurfaceComposerClient != NULL) { - mSurfaceComposerClient->dispose(); - mSurfaceComposerClient.clear(); - } -} - -sp SpriteController::createSprite() { - return new SpriteImpl(this); -} - -void SpriteController::openTransaction() { - AutoMutex _l(mLock); - - mLocked.transactionNestingCount += 1; -} - -void SpriteController::closeTransaction() { - AutoMutex _l(mLock); - - LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0, - "Sprite closeTransaction() called but there is no open sprite transaction"); - - mLocked.transactionNestingCount -= 1; - if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) { - mLocked.deferredSpriteUpdate = false; - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); - } -} - -void SpriteController::invalidateSpriteLocked(const sp& sprite) { - bool wasEmpty = mLocked.invalidatedSprites.isEmpty(); - mLocked.invalidatedSprites.push(sprite); - if (wasEmpty) { - if (mLocked.transactionNestingCount != 0) { - mLocked.deferredSpriteUpdate = true; - } else { - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); - } - } -} - -void SpriteController::disposeSurfaceLocked(const sp& surfaceControl) { - bool wasEmpty = mLocked.disposedSurfaces.isEmpty(); - mLocked.disposedSurfaces.push(surfaceControl); - if (wasEmpty) { - mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES)); - } -} - -void SpriteController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_UPDATE_SPRITES: - doUpdateSprites(); - break; - case MSG_DISPOSE_SURFACES: - doDisposeSurfaces(); - break; - } -} - -void SpriteController::doUpdateSprites() { - // Collect information about sprite updates. - // Each sprite update record includes a reference to its associated sprite so we can - // be certain the sprites will not be deleted while this function runs. Sprites - // may invalidate themselves again during this time but we will handle those changes - // in the next iteration. - Vector updates; - size_t numSprites; - { // acquire lock - AutoMutex _l(mLock); - - numSprites = mLocked.invalidatedSprites.size(); - for (size_t i = 0; i < numSprites; i++) { - const sp& sprite = mLocked.invalidatedSprites.itemAt(i); - - updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); - sprite->resetDirtyLocked(); - } - mLocked.invalidatedSprites.clear(); - } // release lock - - // Create missing surfaces. - bool surfaceChanged = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { - update.state.surfaceWidth = update.state.icon.bitmap.width(); - update.state.surfaceHeight = update.state.icon.bitmap.height(); - update.state.surfaceDrawn = false; - update.state.surfaceVisible = false; - update.state.surfaceControl = obtainSurface( - update.state.surfaceWidth, update.state.surfaceHeight); - if (update.state.surfaceControl != NULL) { - update.surfaceChanged = surfaceChanged = true; - } - } - } - - // Resize sprites if needed, inside a global transaction. - bool haveGlobalTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { - int32_t desiredWidth = update.state.icon.bitmap.width(); - int32_t desiredHeight = update.state.icon.bitmap.height(); - if (update.state.surfaceWidth < desiredWidth - || update.state.surfaceHeight < desiredHeight) { - if (!haveGlobalTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveGlobalTransaction = true; - } - - status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight); - if (status) { - ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d", - status, update.state.surfaceWidth, update.state.surfaceHeight, - desiredWidth, desiredHeight); - } else { - update.state.surfaceWidth = desiredWidth; - update.state.surfaceHeight = desiredHeight; - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - - if (update.state.surfaceVisible) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface after resize.", status); - } else { - update.state.surfaceVisible = false; - } - } - } - } - } - } - if (haveGlobalTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } - - // Redraw sprites if needed. - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - } - - if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn - && update.state.wantSurfaceVisible()) { - sp surface = update.state.surfaceControl->getSurface(); - Surface::SurfaceInfo surfaceInfo; - status_t status = surface->lock(&surfaceInfo); - if (status) { - ALOGE("Error %d locking sprite surface before drawing.", status); - } else { - SkBitmap surfaceBitmap; - ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format); - surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, - surfaceInfo.w, surfaceInfo.h, bpr); - surfaceBitmap.setPixels(surfaceInfo.bits); - - SkCanvas surfaceCanvas; - surfaceCanvas.setBitmapDevice(surfaceBitmap); - - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); - - if (surfaceInfo.w > uint32_t(update.state.icon.bitmap.width())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0, - surfaceInfo.w, update.state.icon.bitmap.height(), paint); - } - if (surfaceInfo.h > uint32_t(update.state.icon.bitmap.height())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(), - surfaceInfo.w, surfaceInfo.h, paint); - } - - status = surface->unlockAndPost(); - if (status) { - ALOGE("Error %d unlocking and posting sprite surface after drawing.", status); - } else { - update.state.surfaceDrawn = true; - update.surfaceChanged = surfaceChanged = true; - } - } - } - } - - // Set sprite surface properties and make them visible. - bool haveTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() - && update.state.surfaceDrawn; - bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; - bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; - if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden - || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA - | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER - | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) { - status_t status; - if (!haveTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveTransaction = true; - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) { - status = update.state.surfaceControl->setAlpha(update.state.alpha); - if (status) { - ALOGE("Error %d setting sprite surface alpha.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & (DIRTY_POSITION - | DIRTY_HOTSPOT)))) { - status = update.state.surfaceControl->setPosition( - update.state.positionX - update.state.icon.hotSpotX, - update.state.positionY - update.state.icon.hotSpotY); - if (status) { - ALOGE("Error %d setting sprite surface position.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible - || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) { - status = update.state.surfaceControl->setMatrix( - update.state.transformationMatrix.dsdx, - update.state.transformationMatrix.dtdx, - update.state.transformationMatrix.dsdy, - update.state.transformationMatrix.dtdy); - if (status) { - ALOGE("Error %d setting sprite surface transformation matrix.", status); - } - } - - int32_t surfaceLayer = mOverlayLayer + update.state.layer; - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { - status = update.state.surfaceControl->setLayer(surfaceLayer); - if (status) { - ALOGE("Error %d setting sprite surface layer.", status); - } - } - - if (becomingVisible) { - status = update.state.surfaceControl->show(surfaceLayer); - if (status) { - ALOGE("Error %d showing sprite surface.", status); - } else { - update.state.surfaceVisible = true; - update.surfaceChanged = surfaceChanged = true; - } - } else if (becomingHidden) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface.", status); - } else { - update.state.surfaceVisible = false; - update.surfaceChanged = surfaceChanged = true; - } - } - } - } - - if (haveTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } - - // If any surfaces were changed, write back the new surface properties to the sprites. - if (surfaceChanged) { // acquire lock - AutoMutex _l(mLock); - - for (size_t i = 0; i < numSprites; i++) { - const SpriteUpdate& update = updates.itemAt(i); - - if (update.surfaceChanged) { - update.sprite->setSurfaceLocked(update.state.surfaceControl, - update.state.surfaceWidth, update.state.surfaceHeight, - update.state.surfaceDrawn, update.state.surfaceVisible); - } - } - } // release lock - - // Clear the sprite update vector outside the lock. It is very important that - // we do not clear sprite references inside the lock since we could be releasing - // the last remaining reference to the sprite here which would result in the - // sprite being deleted and the lock being reacquired by the sprite destructor - // while already held. - updates.clear(); -} - -void SpriteController::doDisposeSurfaces() { - // Collect disposed surfaces. - Vector > disposedSurfaces; - { // acquire lock - AutoMutex _l(mLock); - - disposedSurfaces = mLocked.disposedSurfaces; - mLocked.disposedSurfaces.clear(); - } // release lock - - // Release the last reference to each surface outside of the lock. - // We don't want the surfaces to be deleted while we are holding our lock. - disposedSurfaces.clear(); -} - -void SpriteController::ensureSurfaceComposerClient() { - if (mSurfaceComposerClient == NULL) { - mSurfaceComposerClient = new SurfaceComposerClient(); - } -} - -sp SpriteController::obtainSurface(int32_t width, int32_t height) { - ensureSurfaceComposerClient(); - - sp surfaceControl = mSurfaceComposerClient->createSurface( - String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888); - if (surfaceControl == NULL || !surfaceControl->isValid() - || !surfaceControl->getSurface()->isValid()) { - ALOGE("Error creating sprite surface."); - return NULL; - } - return surfaceControl; -} - - -// --- SpriteController::SpriteImpl --- - -SpriteController::SpriteImpl::SpriteImpl(const sp controller) : - mController(controller) { -} - -SpriteController::SpriteImpl::~SpriteImpl() { - AutoMutex _m(mController->mLock); - - // Let the controller take care of deleting the last reference to sprite - // surfaces so that we do not block the caller on an IPC here. - if (mLocked.state.surfaceControl != NULL) { - mController->disposeSurfaceLocked(mLocked.state.surfaceControl); - mLocked.state.surfaceControl.clear(); - } -} - -void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { - AutoMutex _l(mController->mLock); - - uint32_t dirty; - if (icon.isValid()) { - icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config); - - if (!mLocked.state.icon.isValid() - || mLocked.state.icon.hotSpotX != icon.hotSpotX - || mLocked.state.icon.hotSpotY != icon.hotSpotY) { - mLocked.state.icon.hotSpotX = icon.hotSpotX; - mLocked.state.icon.hotSpotY = icon.hotSpotY; - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - dirty = DIRTY_BITMAP; - } - } else if (mLocked.state.icon.isValid()) { - mLocked.state.icon.bitmap.reset(); - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - return; // setting to invalid icon and already invalid so nothing to do - } - - invalidateLocked(dirty); -} - -void SpriteController::SpriteImpl::setVisible(bool visible) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.visible != visible) { - mLocked.state.visible = visible; - invalidateLocked(DIRTY_VISIBILITY); - } -} - -void SpriteController::SpriteImpl::setPosition(float x, float y) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.positionX != x || mLocked.state.positionY != y) { - mLocked.state.positionX = x; - mLocked.state.positionY = y; - invalidateLocked(DIRTY_POSITION); - } -} - -void SpriteController::SpriteImpl::setLayer(int32_t layer) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.layer != layer) { - mLocked.state.layer = layer; - invalidateLocked(DIRTY_LAYER); - } -} - -void SpriteController::SpriteImpl::setAlpha(float alpha) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.alpha != alpha) { - mLocked.state.alpha = alpha; - invalidateLocked(DIRTY_ALPHA); - } -} - -void SpriteController::SpriteImpl::setTransformationMatrix( - const SpriteTransformationMatrix& matrix) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.transformationMatrix != matrix) { - mLocked.state.transformationMatrix = matrix; - invalidateLocked(DIRTY_TRANSFORMATION_MATRIX); - } -} - -void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) { - bool wasDirty = mLocked.state.dirty; - mLocked.state.dirty |= dirty; - - if (!wasDirty) { - mController->invalidateSpriteLocked(this); - } -} - -} // namespace android diff --git a/widget/gonk/libui/SpriteController.h b/widget/gonk/libui/SpriteController.h deleted file mode 100644 index 50ae8a53886..00000000000 --- a/widget/gonk/libui/SpriteController.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_SPRITES_H -#define _UI_SPRITES_H - -#include -#include - -#include -#include -#include - -#include - -namespace android { - -/* - * Transformation matrix for a sprite. - */ -struct SpriteTransformationMatrix { - inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { } - inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) : - dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { } - - float dsdx; - float dtdx; - float dsdy; - float dtdy; - - inline bool operator== (const SpriteTransformationMatrix& other) { - return dsdx == other.dsdx - && dtdx == other.dtdx - && dsdy == other.dsdy - && dtdy == other.dtdy; - } - - inline bool operator!= (const SpriteTransformationMatrix& other) { - return !(*this == other); - } -}; - -/* - * Icon that a sprite displays, including its hotspot. - */ -struct SpriteIcon { - inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { } - inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) : - bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } - - SkBitmap bitmap; - float hotSpotX; - float hotSpotY; - - inline SpriteIcon copy() const { - SkBitmap bitmapCopy; - bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config); - return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY); - } - - inline void reset() { - bitmap.reset(); - hotSpotX = 0; - hotSpotY = 0; - } - - inline bool isValid() const { - return !bitmap.isNull() && !bitmap.empty(); - } -}; - -/* - * A sprite is a simple graphical object that is displayed on-screen above other layers. - * The basic sprite class is an interface. - * The implementation is provided by the sprite controller. - */ -class Sprite : public RefBase { -protected: - Sprite() { } - virtual ~Sprite() { } - -public: - enum { - // The base layer for pointer sprites. - BASE_LAYER_POINTER = 0, // reserve space for 1 pointer - - // The base layer for spot sprites. - BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots - }; - - /* Sets the bitmap that is drawn by the sprite. - * The sprite retains a copy of the bitmap for subsequent rendering. */ - virtual void setIcon(const SpriteIcon& icon) = 0; - - inline void clearIcon() { - setIcon(SpriteIcon()); - } - - /* Sets whether the sprite is visible. */ - virtual void setVisible(bool visible) = 0; - - /* Sets the sprite position on screen, relative to the sprite's hot spot. */ - virtual void setPosition(float x, float y) = 0; - - /* Sets the layer of the sprite, relative to the system sprite overlay layer. - * Layer 0 is the overlay layer, > 0 appear above this layer. */ - virtual void setLayer(int32_t layer) = 0; - - /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */ - virtual void setAlpha(float alpha) = 0; - - /* Sets the sprite transformation matrix. */ - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0; -}; - -/* - * Displays sprites on the screen. - * - * This interface is used by PointerController and SpotController to draw pointers or - * spot representations of fingers. It is not intended for general purpose use - * by other components. - * - * All sprite position updates and rendering is performed asynchronously. - * - * Clients are responsible for animating sprites by periodically updating their properties. - */ -class SpriteController : public MessageHandler { -protected: - virtual ~SpriteController(); - -public: - SpriteController(const sp& looper, int32_t overlayLayer); - - /* Creates a new sprite, initially invisible. */ - sp createSprite(); - - /* Opens or closes a transaction to perform a batch of sprite updates as part of - * a single operation such as setPosition and setAlpha. It is not necessary to - * open a transaction when updating a single property. - * Calls to openTransaction() nest and must be matched by an equal number - * of calls to closeTransaction(). */ - void openTransaction(); - void closeTransaction(); - -private: - enum { - MSG_UPDATE_SPRITES, - MSG_DISPOSE_SURFACES, - }; - - enum { - DIRTY_BITMAP = 1 << 0, - DIRTY_ALPHA = 1 << 1, - DIRTY_POSITION = 1 << 2, - DIRTY_TRANSFORMATION_MATRIX = 1 << 3, - DIRTY_LAYER = 1 << 4, - DIRTY_VISIBILITY = 1 << 5, - DIRTY_HOTSPOT = 1 << 6, - }; - - /* Describes the state of a sprite. - * This structure is designed so that it can be copied during updates so that - * surfaces can be resized and redrawn without blocking the client by holding a lock - * on the sprites for a long time. - * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */ - struct SpriteState { - inline SpriteState() : - dirty(0), visible(false), - positionX(0), positionY(0), layer(0), alpha(1.0f), - surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) { - } - - uint32_t dirty; - - SpriteIcon icon; - bool visible; - float positionX; - float positionY; - int32_t layer; - float alpha; - SpriteTransformationMatrix transformationMatrix; - - sp surfaceControl; - int32_t surfaceWidth; - int32_t surfaceHeight; - bool surfaceDrawn; - bool surfaceVisible; - - inline bool wantSurfaceVisible() const { - return visible && alpha > 0.0f && icon.isValid(); - } - }; - - /* Client interface for a sprite. - * Requests acquire a lock on the controller, update local state and request the - * controller to invalidate the sprite. - * The real heavy lifting of creating, resizing and redrawing surfaces happens - * asynchronously with no locks held except in short critical section to copy - * the sprite state before the work and update the sprite surface control afterwards. - */ - class SpriteImpl : public Sprite { - protected: - virtual ~SpriteImpl(); - - public: - SpriteImpl(const sp controller); - - virtual void setIcon(const SpriteIcon& icon); - virtual void setVisible(bool visible); - virtual void setPosition(float x, float y); - virtual void setLayer(int32_t layer); - virtual void setAlpha(float alpha); - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix); - - inline const SpriteState& getStateLocked() const { - return mLocked.state; - } - - inline void resetDirtyLocked() { - mLocked.state.dirty = 0; - } - - inline void setSurfaceLocked(const sp& surfaceControl, - int32_t width, int32_t height, bool drawn, bool visible) { - mLocked.state.surfaceControl = surfaceControl; - mLocked.state.surfaceWidth = width; - mLocked.state.surfaceHeight = height; - mLocked.state.surfaceDrawn = drawn; - mLocked.state.surfaceVisible = visible; - } - - private: - sp mController; - - struct Locked { - SpriteState state; - } mLocked; // guarded by mController->mLock - - void invalidateLocked(uint32_t dirty); - }; - - /* Stores temporary information collected during the sprite update cycle. */ - struct SpriteUpdate { - inline SpriteUpdate() : surfaceChanged(false) { } - inline SpriteUpdate(const sp sprite, const SpriteState& state) : - sprite(sprite), state(state), surfaceChanged(false) { - } - - sp sprite; - SpriteState state; - bool surfaceChanged; - }; - - mutable Mutex mLock; - - sp mLooper; - const int32_t mOverlayLayer; - sp mHandler; - - sp mSurfaceComposerClient; - - struct Locked { - Vector > invalidatedSprites; - Vector > disposedSurfaces; - uint32_t transactionNestingCount; - bool deferredSpriteUpdate; - } mLocked; // guarded by mLock - - void invalidateSpriteLocked(const sp& sprite); - void disposeSurfaceLocked(const sp& surfaceControl); - - void handleMessage(const Message& message); - void doUpdateSprites(); - void doDisposeSurfaces(); - - void ensureSurfaceComposerClient(); - sp obtainSurface(int32_t width, int32_t height); -}; - -} // namespace android - -#endif // _UI_SPRITES_H diff --git a/widget/gonk/libui/Static.cpp b/widget/gonk/libui/Static.cpp new file mode 100644 index 00000000000..d8e39d0536d --- /dev/null +++ b/widget/gonk/libui/Static.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// All static variables go here, to control initialization and +// destruction order in the library. + +#include "Static.h" + +#include +#include "utils_Log.h" + +namespace android { + +class LibUtilsFirstStatics +{ +public: + LibUtilsFirstStatics() + { + initialize_string8(); + initialize_string16(); + } + + ~LibUtilsFirstStatics() + { + terminate_string16(); + terminate_string8(); + } +}; + +static LibUtilsFirstStatics gFirstStatics; +int gDarwinCantLoadAllObjects = 1; + +// ------------ Text output streams +#if 0 +Vector gTextBuffers; + +class LogTextOutput : public BufferedTextOutput +{ +public: + LogTextOutput() : BufferedTextOutput(MULTITHREADED) { } + virtual ~LogTextOutput() { }; + +protected: + virtual status_t writeLines(const struct iovec& vec, size_t N) + { + //android_writevLog(&vec, N); <-- this is now a no-op + if (N != 1) ALOGI("WARNING: writeLines N=%d\n", N); + ALOGI("%.*s", vec.iov_len, (const char*) vec.iov_base); + return NO_ERROR; + } +}; + +class FdTextOutput : public BufferedTextOutput +{ +public: + FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { } + virtual ~FdTextOutput() { }; + +protected: + virtual status_t writeLines(const struct iovec& vec, size_t N) + { + writev(mFD, &vec, N); + return NO_ERROR; + } + +private: + int mFD; +}; + +static LogTextOutput gLogTextOutput; +static FdTextOutput gStdoutTextOutput(STDOUT_FILENO); +static FdTextOutput gStderrTextOutput(STDERR_FILENO); + +TextOutput& alog(gLogTextOutput); +TextOutput& aout(gStdoutTextOutput); +TextOutput& aerr(gStderrTextOutput); +#endif +} // namespace android diff --git a/widget/gonk/libui/Static.h b/widget/gonk/libui/Static.h new file mode 100644 index 00000000000..309ff27a6ac --- /dev/null +++ b/widget/gonk/libui/Static.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// All static variables go here, to control initialization and +// destruction order in the library. + +#include +#include + +namespace android { +// For TextStream.cpp +//extern Vector gTextBuffers; + +// For String8.cpp +extern void initialize_string8(); +extern void terminate_string8(); + +// For String16.cpp +extern void initialize_string16(); +extern void terminate_string16(); + +} // namespace android diff --git a/widget/gonk/libui/String16.h b/widget/gonk/libui/String16.h new file mode 100644 index 00000000000..3bca09e23de --- /dev/null +++ b/widget/gonk/libui/String16.h @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_STRING16_H +#define ANDROID_STRING16_H + +#include +#include +#include "Unicode.h" + +// --------------------------------------------------------------------------- + +extern "C" { + +} + +// --------------------------------------------------------------------------- + +namespace android { + +// --------------------------------------------------------------------------- + +class String8; +class TextOutput; + +//! This is a string holding UTF-16 characters. +class String16 +{ +public: + String16(); + String16(const String16& o); + String16(const String16& o, + size_t len, + size_t begin=0); + explicit String16(const char16_t* o); + explicit String16(const char16_t* o, size_t len); + explicit String16(const String8& o); + explicit String16(const char* o); + explicit String16(const char* o, size_t len); + + ~String16(); + + inline const char16_t* string() const; + inline size_t size() const; + + inline const SharedBuffer* sharedBuffer() const; + + void setTo(const String16& other); + status_t setTo(const char16_t* other); + status_t setTo(const char16_t* other, size_t len); + status_t setTo(const String16& other, + size_t len, + size_t begin=0); + + status_t append(const String16& other); + status_t append(const char16_t* other, size_t len); + + inline String16& operator=(const String16& other); + + inline String16& operator+=(const String16& other); + inline String16 operator+(const String16& other) const; + + status_t insert(size_t pos, const char16_t* chrs); + status_t insert(size_t pos, + const char16_t* chrs, size_t len); + + ssize_t findFirst(char16_t c) const; + ssize_t findLast(char16_t c) const; + + bool startsWith(const String16& prefix) const; + bool startsWith(const char16_t* prefix) const; + + status_t makeLower(); + + status_t replaceAll(char16_t replaceThis, + char16_t withThis); + + status_t remove(size_t len, size_t begin=0); + + inline int compare(const String16& other) const; + + inline bool operator<(const String16& other) const; + inline bool operator<=(const String16& other) const; + inline bool operator==(const String16& other) const; + inline bool operator!=(const String16& other) const; + inline bool operator>=(const String16& other) const; + inline bool operator>(const String16& other) const; + + inline bool operator<(const char16_t* other) const; + inline bool operator<=(const char16_t* other) const; + inline bool operator==(const char16_t* other) const; + inline bool operator!=(const char16_t* other) const; + inline bool operator>=(const char16_t* other) const; + inline bool operator>(const char16_t* other) const; + + inline operator const char16_t*() const; + +private: + const char16_t* mString; +}; + +TextOutput& operator<<(TextOutput& to, const String16& val); + +// --------------------------------------------------------------------------- +// No user servicable parts below. + +inline int compare_type(const String16& lhs, const String16& rhs) +{ + return lhs.compare(rhs); +} + +inline int strictly_order_type(const String16& lhs, const String16& rhs) +{ + return compare_type(lhs, rhs) < 0; +} + +inline const char16_t* String16::string() const +{ + return mString; +} + +inline size_t String16::size() const +{ + return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1; +} + +inline const SharedBuffer* String16::sharedBuffer() const +{ + return SharedBuffer::bufferFromData(mString); +} + +inline String16& String16::operator=(const String16& other) +{ + setTo(other); + return *this; +} + +inline String16& String16::operator+=(const String16& other) +{ + append(other); + return *this; +} + +inline String16 String16::operator+(const String16& other) const +{ + String16 tmp(*this); + tmp += other; + return tmp; +} + +inline int String16::compare(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()); +} + +inline bool String16::operator<(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) < 0; +} + +inline bool String16::operator<=(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) <= 0; +} + +inline bool String16::operator==(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) == 0; +} + +inline bool String16::operator!=(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) != 0; +} + +inline bool String16::operator>=(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) >= 0; +} + +inline bool String16::operator>(const String16& other) const +{ + return strzcmp16(mString, size(), other.mString, other.size()) > 0; +} + +inline bool String16::operator<(const char16_t* other) const +{ + return strcmp16(mString, other) < 0; +} + +inline bool String16::operator<=(const char16_t* other) const +{ + return strcmp16(mString, other) <= 0; +} + +inline bool String16::operator==(const char16_t* other) const +{ + return strcmp16(mString, other) == 0; +} + +inline bool String16::operator!=(const char16_t* other) const +{ + return strcmp16(mString, other) != 0; +} + +inline bool String16::operator>=(const char16_t* other) const +{ + return strcmp16(mString, other) >= 0; +} + +inline bool String16::operator>(const char16_t* other) const +{ + return strcmp16(mString, other) > 0; +} + +inline String16::operator const char16_t*() const +{ + return mString; +} + +}; // namespace android + +// --------------------------------------------------------------------------- + +#endif // ANDROID_STRING16_H diff --git a/widget/gonk/libui/String8.cpp b/widget/gonk/libui/String8.cpp new file mode 100644 index 00000000000..ee3355c2d1e --- /dev/null +++ b/widget/gonk/libui/String8.cpp @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "String8.h" + +#include "utils_Log.h" +#include "Unicode.h" +#include +#include "String16.h" +#include +#include + +#include "Static.h" + +#include + +#define OS_PATH_SEPARATOR '/' + +/* + * Functions outside android is below the namespace android, since they use + * functions and constants in android namespace. + */ + +// --------------------------------------------------------------------------- + +namespace android { + +// Separator used by resource paths. This is not platform dependent contrary +// to OS_PATH_SEPARATOR. +#define RES_PATH_SEPARATOR '/' + +static SharedBuffer* gEmptyStringBuf = NULL; +static char* gEmptyString = NULL; + +extern int gDarwinCantLoadAllObjects; +int gDarwinIsReallyAnnoying; + +static inline char* getEmptyString() +{ + gEmptyStringBuf->acquire(); + return gEmptyString; +} + +void initialize_string8() +{ + // HACK: This dummy dependency forces linking libutils Static.cpp, + // which is needed to initialize String8/String16 classes. + // These variables are named for Darwin, but are needed elsewhere too, + // including static linking on any platform. + gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects; + + SharedBuffer* buf = SharedBuffer::alloc(1); + char* str = (char*)buf->data(); + *str = 0; + gEmptyStringBuf = buf; + gEmptyString = str; +} + +void terminate_string8() +{ + SharedBuffer::bufferFromData(gEmptyString)->release(); + gEmptyStringBuf = NULL; + gEmptyString = NULL; +} + +// --------------------------------------------------------------------------- + +static char* allocFromUTF8(const char* in, size_t len) +{ + if (len > 0) { + SharedBuffer* buf = SharedBuffer::alloc(len+1); + ALOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + char* str = (char*)buf->data(); + memcpy(str, in, len); + str[len] = 0; + return str; + } + return NULL; + } + + return getEmptyString(); +} + +static char* allocFromUTF16(const char16_t* in, size_t len) +{ + if (len == 0) return getEmptyString(); + + const ssize_t bytes = utf16_to_utf8_length(in, len); + if (bytes < 0) { + return getEmptyString(); + } + + SharedBuffer* buf = SharedBuffer::alloc(bytes+1); + ALOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (!buf) { + return getEmptyString(); + } + + char* str = (char*)buf->data(); + utf16_to_utf8(in, len, str); + return str; +} + +static char* allocFromUTF32(const char32_t* in, size_t len) +{ + if (len == 0) { + return getEmptyString(); + } + + const ssize_t bytes = utf32_to_utf8_length(in, len); + if (bytes < 0) { + return getEmptyString(); + } + + SharedBuffer* buf = SharedBuffer::alloc(bytes+1); + ALOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (!buf) { + return getEmptyString(); + } + + char* str = (char*) buf->data(); + utf32_to_utf8(in, len, str); + + return str; +} + +// --------------------------------------------------------------------------- + +String8::String8() + : mString(getEmptyString()) +{ +} + +String8::String8(const String8& o) + : mString(o.mString) +{ + SharedBuffer::bufferFromData(mString)->acquire(); +} + +String8::String8(const char* o) + : mString(allocFromUTF8(o, strlen(o))) +{ + if (mString == NULL) { + mString = getEmptyString(); + } +} + +String8::String8(const char* o, size_t len) + : mString(allocFromUTF8(o, len)) +{ + if (mString == NULL) { + mString = getEmptyString(); + } +} + +String8::String8(const String16& o) + : mString(allocFromUTF16(o.string(), o.size())) +{ +} + +String8::String8(const char16_t* o) + : mString(allocFromUTF16(o, strlen16(o))) +{ +} + +String8::String8(const char16_t* o, size_t len) + : mString(allocFromUTF16(o, len)) +{ +} + +String8::String8(const char32_t* o) + : mString(allocFromUTF32(o, strlen32(o))) +{ +} + +String8::String8(const char32_t* o, size_t len) + : mString(allocFromUTF32(o, len)) +{ +} + +String8::~String8() +{ + SharedBuffer::bufferFromData(mString)->release(); +} + +String8 String8::format(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + String8 result(formatV(fmt, args)); + + va_end(args); + return result; +} + +String8 String8::formatV(const char* fmt, va_list args) +{ + String8 result; + result.appendFormatV(fmt, args); + return result; +} + +void String8::clear() { + SharedBuffer::bufferFromData(mString)->release(); + mString = getEmptyString(); +} + +void String8::setTo(const String8& other) +{ + SharedBuffer::bufferFromData(other.mString)->acquire(); + SharedBuffer::bufferFromData(mString)->release(); + mString = other.mString; +} + +status_t String8::setTo(const char* other) +{ + const char *newString = allocFromUTF8(other, strlen(other)); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::setTo(const char* other, size_t len) +{ + const char *newString = allocFromUTF8(other, len); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::setTo(const char16_t* other, size_t len) +{ + const char *newString = allocFromUTF16(other, len); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::setTo(const char32_t* other, size_t len) +{ + const char *newString = allocFromUTF32(other, len); + SharedBuffer::bufferFromData(mString)->release(); + mString = newString; + if (mString) return NO_ERROR; + + mString = getEmptyString(); + return NO_MEMORY; +} + +status_t String8::append(const String8& other) +{ + const size_t otherLen = other.bytes(); + if (bytes() == 0) { + setTo(other); + return NO_ERROR; + } else if (otherLen == 0) { + return NO_ERROR; + } + + return real_append(other.string(), otherLen); +} + +status_t String8::append(const char* other) +{ + return append(other, strlen(other)); +} + +status_t String8::append(const char* other, size_t otherLen) +{ + if (bytes() == 0) { + return setTo(other, otherLen); + } else if (otherLen == 0) { + return NO_ERROR; + } + + return real_append(other, otherLen); +} + +status_t String8::appendFormat(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + status_t result = appendFormatV(fmt, args); + + va_end(args); + return result; +} + +status_t String8::appendFormatV(const char* fmt, va_list args) +{ + int result = NO_ERROR; + int n = vsnprintf(NULL, 0, fmt, args); + if (n != 0) { + size_t oldLength = length(); + char* buf = lockBuffer(oldLength + n); + if (buf) { + vsnprintf(buf + oldLength, n + 1, fmt, args); + } else { + result = NO_MEMORY; + } + } + return result; +} + +status_t String8::real_append(const char* other, size_t otherLen) +{ + const size_t myLen = bytes(); + + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize(myLen+otherLen+1); + if (buf) { + char* str = (char*)buf->data(); + mString = str; + str += myLen; + memcpy(str, other, otherLen); + str[otherLen] = '\0'; + return NO_ERROR; + } + return NO_MEMORY; +} + +char* String8::lockBuffer(size_t size) +{ + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize(size+1); + if (buf) { + char* str = (char*)buf->data(); + mString = str; + return str; + } + return NULL; +} + +void String8::unlockBuffer() +{ + unlockBuffer(strlen(mString)); +} + +status_t String8::unlockBuffer(size_t size) +{ + if (size != this->size()) { + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) + ->editResize(size+1); + if (! buf) { + return NO_MEMORY; + } + + char* str = (char*)buf->data(); + str[size] = 0; + mString = str; + } + + return NO_ERROR; +} + +ssize_t String8::find(const char* other, size_t start) const +{ + size_t len = size(); + if (start >= len) { + return -1; + } + const char* s = mString+start; + const char* p = strstr(s, other); + return p ? p-mString : -1; +} + +void String8::toLower() +{ + toLower(0, size()); +} + +void String8::toLower(size_t start, size_t length) +{ + const size_t len = size(); + if (start >= len) { + return; + } + if (start+length > len) { + length = len-start; + } + char* buf = lockBuffer(len); + buf += start; + while (length > 0) { + *buf = tolower(*buf); + buf++; + length--; + } + unlockBuffer(len); +} + +void String8::toUpper() +{ + toUpper(0, size()); +} + +void String8::toUpper(size_t start, size_t length) +{ + const size_t len = size(); + if (start >= len) { + return; + } + if (start+length > len) { + length = len-start; + } + char* buf = lockBuffer(len); + buf += start; + while (length > 0) { + *buf = toupper(*buf); + buf++; + length--; + } + unlockBuffer(len); +} + +size_t String8::getUtf32Length() const +{ + return utf8_to_utf32_length(mString, length()); +} + +int32_t String8::getUtf32At(size_t index, size_t *next_index) const +{ + return utf32_from_utf8_at(mString, length(), index, next_index); +} + +void String8::getUtf32(char32_t* dst) const +{ + utf8_to_utf32(mString, length(), dst); +} + +TextOutput& operator<<(TextOutput& to, const String8& val) +{ + to << val.string(); + return to; +} + +// --------------------------------------------------------------------------- +// Path functions + +void String8::setPathName(const char* name) +{ + setPathName(name, strlen(name)); +} + +void String8::setPathName(const char* name, size_t len) +{ + char* buf = lockBuffer(len); + + memcpy(buf, name, len); + + // remove trailing path separator, if present + if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR) + len--; + + buf[len] = '\0'; + + unlockBuffer(len); +} + +String8 String8::getPathLeaf(void) const +{ + const char* cp; + const char*const buf = mString; + + cp = strrchr(buf, OS_PATH_SEPARATOR); + if (cp == NULL) + return String8(*this); + else + return String8(cp+1); +} + +String8 String8::getPathDir(void) const +{ + const char* cp; + const char*const str = mString; + + cp = strrchr(str, OS_PATH_SEPARATOR); + if (cp == NULL) + return String8(""); + else + return String8(str, cp - str); +} + +String8 String8::walkPath(String8* outRemains) const +{ + const char* cp; + const char*const str = mString; + const char* buf = str; + + cp = strchr(buf, OS_PATH_SEPARATOR); + if (cp == buf) { + // don't include a leading '/'. + buf = buf+1; + cp = strchr(buf, OS_PATH_SEPARATOR); + } + + if (cp == NULL) { + String8 res = buf != str ? String8(buf) : *this; + if (outRemains) *outRemains = String8(""); + return res; + } + + String8 res(buf, cp-buf); + if (outRemains) *outRemains = String8(cp+1); + return res; +} + +/* + * Helper function for finding the start of an extension in a pathname. + * + * Returns a pointer inside mString, or NULL if no extension was found. + */ +char* String8::find_extension(void) const +{ + const char* lastSlash; + const char* lastDot; + int extLen; + const char* const str = mString; + + // only look at the filename + lastSlash = strrchr(str, OS_PATH_SEPARATOR); + if (lastSlash == NULL) + lastSlash = str; + else + lastSlash++; + + // find the last dot + lastDot = strrchr(lastSlash, '.'); + if (lastDot == NULL) + return NULL; + + // looks good, ship it + return const_cast(lastDot); +} + +String8 String8::getPathExtension(void) const +{ + char* ext; + + ext = find_extension(); + if (ext != NULL) + return String8(ext); + else + return String8(""); +} + +String8 String8::getBasePath(void) const +{ + char* ext; + const char* const str = mString; + + ext = find_extension(); + if (ext == NULL) + return String8(*this); + else + return String8(str, ext - str); +} + +String8& String8::appendPath(const char* name) +{ + // TODO: The test below will fail for Win32 paths. Fix later or ignore. + if (name[0] != OS_PATH_SEPARATOR) { + if (*name == '\0') { + // nothing to do + return *this; + } + + size_t len = length(); + if (len == 0) { + // no existing filename, just use the new one + setPathName(name); + return *this; + } + + // make room for oldPath + '/' + newPath + int newlen = strlen(name); + + char* buf = lockBuffer(len+1+newlen); + + // insert a '/' if needed + if (buf[len-1] != OS_PATH_SEPARATOR) + buf[len++] = OS_PATH_SEPARATOR; + + memcpy(buf+len, name, newlen+1); + len += newlen; + + unlockBuffer(len); + + return *this; + } else { + setPathName(name); + return *this; + } +} + +String8& String8::convertToResPath() +{ +#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR + size_t len = length(); + if (len > 0) { + char * buf = lockBuffer(len); + for (char * end = buf + len; buf < end; ++buf) { + if (*buf == OS_PATH_SEPARATOR) + *buf = RES_PATH_SEPARATOR; + } + unlockBuffer(len); + } +#endif + return *this; +} + +}; // namespace android diff --git a/widget/gonk/libui/String8.h b/widget/gonk/libui/String8.h new file mode 100644 index 00000000000..28cc9f1f8de --- /dev/null +++ b/widget/gonk/libui/String8.h @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_STRING8_H +#define ANDROID_STRING8_H + +#include +#include +#include "Unicode.h" + +#include // for strcmp +#include + +// --------------------------------------------------------------------------- + +namespace android { + +class String16; +class TextOutput; + +//! This is a string holding UTF-8 characters. Does not allow the value more +// than 0x10FFFF, which is not valid unicode codepoint. +class String8 +{ +public: + String8(); + String8(const String8& o); + explicit String8(const char* o); + explicit String8(const char* o, size_t numChars); + + explicit String8(const String16& o); + explicit String8(const char16_t* o); + explicit String8(const char16_t* o, size_t numChars); + explicit String8(const char32_t* o); + explicit String8(const char32_t* o, size_t numChars); + ~String8(); + + static inline const String8 empty(); + + static String8 format(const char* fmt, ...) __attribute__((format (printf, 1, 2))); + static String8 formatV(const char* fmt, va_list args); + + inline const char* string() const; + inline size_t size() const; + inline size_t length() const; + inline size_t bytes() const; + inline bool isEmpty() const; + + inline const SharedBuffer* sharedBuffer() const; + + void clear(); + + void setTo(const String8& other); + status_t setTo(const char* other); + status_t setTo(const char* other, size_t numChars); + status_t setTo(const char16_t* other, size_t numChars); + status_t setTo(const char32_t* other, + size_t length); + + status_t append(const String8& other); + status_t append(const char* other); + status_t append(const char* other, size_t numChars); + + status_t appendFormat(const char* fmt, ...) + __attribute__((format (printf, 2, 3))); + status_t appendFormatV(const char* fmt, va_list args); + + // Note that this function takes O(N) time to calculate the value. + // No cache value is stored. + size_t getUtf32Length() const; + int32_t getUtf32At(size_t index, + size_t *next_index) const; + void getUtf32(char32_t* dst) const; + + inline String8& operator=(const String8& other); + inline String8& operator=(const char* other); + + inline String8& operator+=(const String8& other); + inline String8 operator+(const String8& other) const; + + inline String8& operator+=(const char* other); + inline String8 operator+(const char* other) const; + + inline int compare(const String8& other) const; + + inline bool operator<(const String8& other) const; + inline bool operator<=(const String8& other) const; + inline bool operator==(const String8& other) const; + inline bool operator!=(const String8& other) const; + inline bool operator>=(const String8& other) const; + inline bool operator>(const String8& other) const; + + inline bool operator<(const char* other) const; + inline bool operator<=(const char* other) const; + inline bool operator==(const char* other) const; + inline bool operator!=(const char* other) const; + inline bool operator>=(const char* other) const; + inline bool operator>(const char* other) const; + + inline operator const char*() const; + + char* lockBuffer(size_t size); + void unlockBuffer(); + status_t unlockBuffer(size_t size); + + // return the index of the first byte of other in this at or after + // start, or -1 if not found + ssize_t find(const char* other, size_t start = 0) const; + + void toLower(); + void toLower(size_t start, size_t numChars); + void toUpper(); + void toUpper(size_t start, size_t numChars); + + /* + * These methods operate on the string as if it were a path name. + */ + + /* + * Set the filename field to a specific value. + * + * Normalizes the filename, removing a trailing '/' if present. + */ + void setPathName(const char* name); + void setPathName(const char* name, size_t numChars); + + /* + * Get just the filename component. + * + * "/tmp/foo/bar.c" --> "bar.c" + */ + String8 getPathLeaf(void) const; + + /* + * Remove the last (file name) component, leaving just the directory + * name. + * + * "/tmp/foo/bar.c" --> "/tmp/foo" + * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX + * "bar.c" --> "" + */ + String8 getPathDir(void) const; + + /* + * Retrieve the front (root dir) component. Optionally also return the + * remaining components. + * + * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c") + * "/tmp" --> "tmp" (remain = "") + * "bar.c" --> "bar.c" (remain = "") + */ + String8 walkPath(String8* outRemains = NULL) const; + + /* + * Return the filename extension. This is the last '.' and any number + * of characters that follow it. The '.' is included in case we + * decide to expand our definition of what constitutes an extension. + * + * "/tmp/foo/bar.c" --> ".c" + * "/tmp" --> "" + * "/tmp/foo.bar/baz" --> "" + * "foo.jpeg" --> ".jpeg" + * "foo." --> "" + */ + String8 getPathExtension(void) const; + + /* + * Return the path without the extension. Rules for what constitutes + * an extension are described in the comment for getPathExtension(). + * + * "/tmp/foo/bar.c" --> "/tmp/foo/bar" + */ + String8 getBasePath(void) const; + + /* + * Add a component to the pathname. We guarantee that there is + * exactly one path separator between the old path and the new. + * If there is no existing name, we just copy the new name in. + * + * If leaf is a fully qualified path (i.e. starts with '/', it + * replaces whatever was there before. + */ + String8& appendPath(const char* leaf); + String8& appendPath(const String8& leaf) { return appendPath(leaf.string()); } + + /* + * Like appendPath(), but does not affect this string. Returns a new one instead. + */ + String8 appendPathCopy(const char* leaf) const + { String8 p(*this); p.appendPath(leaf); return p; } + String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); } + + /* + * Converts all separators in this string to /, the default path separator. + * + * If the default OS separator is backslash, this converts all + * backslashes to slashes, in-place. Otherwise it does nothing. + * Returns self. + */ + String8& convertToResPath(); + +private: + status_t real_append(const char* other, size_t numChars); + char* find_extension(void) const; + + const char* mString; +}; + +TextOutput& operator<<(TextOutput& to, const String16& val); + +// --------------------------------------------------------------------------- +// No user servicable parts below. + +inline int compare_type(const String8& lhs, const String8& rhs) +{ + return lhs.compare(rhs); +} + +inline int strictly_order_type(const String8& lhs, const String8& rhs) +{ + return compare_type(lhs, rhs) < 0; +} + +inline const String8 String8::empty() { + return String8(); +} + +inline const char* String8::string() const +{ + return mString; +} + +inline size_t String8::length() const +{ + return SharedBuffer::sizeFromData(mString)-1; +} + +inline size_t String8::size() const +{ + return length(); +} + +inline bool String8::isEmpty() const +{ + return length() == 0; +} + +inline size_t String8::bytes() const +{ + return SharedBuffer::sizeFromData(mString)-1; +} + +inline const SharedBuffer* String8::sharedBuffer() const +{ + return SharedBuffer::bufferFromData(mString); +} + +inline String8& String8::operator=(const String8& other) +{ + setTo(other); + return *this; +} + +inline String8& String8::operator=(const char* other) +{ + setTo(other); + return *this; +} + +inline String8& String8::operator+=(const String8& other) +{ + append(other); + return *this; +} + +inline String8 String8::operator+(const String8& other) const +{ + String8 tmp(*this); + tmp += other; + return tmp; +} + +inline String8& String8::operator+=(const char* other) +{ + append(other); + return *this; +} + +inline String8 String8::operator+(const char* other) const +{ + String8 tmp(*this); + tmp += other; + return tmp; +} + +inline int String8::compare(const String8& other) const +{ + return strcmp(mString, other.mString); +} + +inline bool String8::operator<(const String8& other) const +{ + return strcmp(mString, other.mString) < 0; +} + +inline bool String8::operator<=(const String8& other) const +{ + return strcmp(mString, other.mString) <= 0; +} + +inline bool String8::operator==(const String8& other) const +{ + return strcmp(mString, other.mString) == 0; +} + +inline bool String8::operator!=(const String8& other) const +{ + return strcmp(mString, other.mString) != 0; +} + +inline bool String8::operator>=(const String8& other) const +{ + return strcmp(mString, other.mString) >= 0; +} + +inline bool String8::operator>(const String8& other) const +{ + return strcmp(mString, other.mString) > 0; +} + +inline bool String8::operator<(const char* other) const +{ + return strcmp(mString, other) < 0; +} + +inline bool String8::operator<=(const char* other) const +{ + return strcmp(mString, other) <= 0; +} + +inline bool String8::operator==(const char* other) const +{ + return strcmp(mString, other) == 0; +} + +inline bool String8::operator!=(const char* other) const +{ + return strcmp(mString, other) != 0; +} + +inline bool String8::operator>=(const char* other) const +{ + return strcmp(mString, other) >= 0; +} + +inline bool String8::operator>(const char* other) const +{ + return strcmp(mString, other) > 0; +} + +inline String8::operator const char*() const +{ + return mString; +} + +} // namespace android + +// --------------------------------------------------------------------------- + +#endif // ANDROID_STRING8_H diff --git a/widget/gonk/libui/Timers.cpp b/widget/gonk/libui/Timers.cpp new file mode 100644 index 00000000000..4534615329e --- /dev/null +++ b/widget/gonk/libui/Timers.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2005 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. + */ + +// +// Timer functions. +// +#include "utils_Log.h" +#include "Timers.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_WIN32_THREADS +#include +#endif + +nsecs_t systemTime(int clock) +{ +#if defined(HAVE_POSIX_CLOCKS) + static const clockid_t clocks[] = { + CLOCK_REALTIME, + CLOCK_MONOTONIC, + CLOCK_PROCESS_CPUTIME_ID, + CLOCK_THREAD_CPUTIME_ID + }; + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(clocks[clock], &t); + return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; +#else + // we don't support the clocks here. + struct timeval t; + t.tv_sec = t.tv_usec = 0; + gettimeofday(&t, NULL); + return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL; +#endif +} + +int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) +{ + int timeoutDelayMillis; + if (timeoutTime > referenceTime) { + uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime); + if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { + timeoutDelayMillis = -1; + } else { + timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL; + } + } else { + timeoutDelayMillis = 0; + } + return timeoutDelayMillis; +} + + +/* + * =========================================================================== + * DurationTimer + * =========================================================================== + */ + +using namespace android; + +// Start the timer. +void DurationTimer::start(void) +{ + gettimeofday(&mStartWhen, NULL); +} + +// Stop the timer. +void DurationTimer::stop(void) +{ + gettimeofday(&mStopWhen, NULL); +} + +// Get the duration in microseconds. +long long DurationTimer::durationUsecs(void) const +{ + return (long) subtractTimevals(&mStopWhen, &mStartWhen); +} + +// Subtract two timevals. Returns the difference (ptv1-ptv2) in +// microseconds. +/*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1, + const struct timeval* ptv2) +{ + long long stop = ((long long) ptv1->tv_sec) * 1000000LL + + ((long long) ptv1->tv_usec); + long long start = ((long long) ptv2->tv_sec) * 1000000LL + + ((long long) ptv2->tv_usec); + return stop - start; +} + +// Add the specified amount of time to the timeval. +/*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec) +{ + if (usec < 0) { + ALOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n"); + return; + } + + // normalize tv_usec if necessary + if (ptv->tv_usec >= 1000000) { + ptv->tv_sec += ptv->tv_usec / 1000000; + ptv->tv_usec %= 1000000; + } + + ptv->tv_usec += usec % 1000000; + if (ptv->tv_usec >= 1000000) { + ptv->tv_usec -= 1000000; + ptv->tv_sec++; + } + ptv->tv_sec += usec / 1000000; +} + diff --git a/widget/gonk/libui/Timers.h b/widget/gonk/libui/Timers.h new file mode 100644 index 00000000000..8b4d322873e --- /dev/null +++ b/widget/gonk/libui/Timers.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2005 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. + */ + +// +// Timer functions. +// +#ifndef _LIBS_UTILS_TIMERS_H +#define _LIBS_UTILS_TIMERS_H + +#include +#include +#include + +// ------------------------------------------------------------------ +// C API + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int64_t nsecs_t; // nano-seconds + +static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) +{ + return secs*1000000000; +} + +static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) +{ + return secs*1000000; +} + +static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) +{ + return secs*1000; +} + +static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) +{ + return secs/1000000000; +} + +static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) +{ + return secs/1000000; +} + +static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) +{ + return secs/1000; +} + +static inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);} +static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);} +static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);} +static inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);} +static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);} +static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);} + +static inline nsecs_t seconds(nsecs_t v) { return s2ns(v); } +static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); } +static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); } + +enum { + SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock + SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point + SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock + SYSTEM_TIME_THREAD = 3 // high-resolution per-thread clock +}; + +// return the system-time according to the specified clock +#ifdef __cplusplus +nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC); +#else +nsecs_t systemTime(int clock); +#endif // def __cplusplus + +/** + * Returns the number of milliseconds to wait between the reference time and the timeout time. + * If the timeout is in the past relative to the reference time, returns 0. + * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time, + * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay. + * Otherwise, returns the difference between the reference time and timeout time + * rounded up to the next millisecond. + */ +int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime); + +#ifdef __cplusplus +} // extern "C" +#endif + +// ------------------------------------------------------------------ +// C++ API + +#ifdef __cplusplus + +namespace android { +/* + * Time the duration of something. + * + * Includes some timeval manipulation functions. + */ +class DurationTimer { +public: + DurationTimer() {} + ~DurationTimer() {} + + // Start the timer. + void start(); + // Stop the timer. + void stop(); + // Get the duration in microseconds. + long long durationUsecs() const; + + // Subtract two timevals. Returns the difference (ptv1-ptv2) in + // microseconds. + static long long subtractTimevals(const struct timeval* ptv1, + const struct timeval* ptv2); + + // Add the specified amount of time to the timeval. + static void addToTimeval(struct timeval* ptv, long usec); + +private: + struct timeval mStartWhen; + struct timeval mStopWhen; +}; + +}; // android +#endif // def __cplusplus + +#endif // _LIBS_UTILS_TIMERS_H diff --git a/widget/gonk/libui/Tokenizer.cpp b/widget/gonk/libui/Tokenizer.cpp new file mode 100644 index 00000000000..3aacd302123 --- /dev/null +++ b/widget/gonk/libui/Tokenizer.cpp @@ -0,0 +1,163 @@ +/* + * 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 "Tokenizer" + +#include +#include +#include +#include +#include +#include +#include "utils_Log.h" +#include "Tokenizer.h" + +// Enables debug output for the tokenizer. +#define DEBUG_TOKENIZER 0 + + +namespace android { + +static inline bool isDelimiter(char ch, const char* delimiters) { + return strchr(delimiters, ch) != NULL; +} + +Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length) : + mFilename(filename), mFileMap(fileMap), + mBuffer(buffer), mLength(length), mCurrent(buffer), mLineNumber(1) { +} + +Tokenizer::~Tokenizer() { + if (mFileMap) { + mFileMap->release(); + } else { + delete[] mBuffer; + } +} + +status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { + *outTokenizer = NULL; + + int result = NO_ERROR; + int fd = ::open(filename.string(), O_RDONLY); + if (fd < 0) { + result = -errno; + ALOGE("Error opening file '%s', %s.", filename.string(), strerror(errno)); + } else { + struct stat stat; + if (fstat(fd, &stat)) { + result = -errno; + ALOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); + } else { + size_t length = size_t(stat.st_size); + + FileMap* fileMap = new FileMap(); + char* buffer; + if (fileMap->create(NULL, fd, 0, length, true)) { + fileMap->advise(FileMap::SEQUENTIAL); + buffer = static_cast(fileMap->getDataPtr()); + } else { + fileMap->release(); + fileMap = NULL; + + // Fall back to reading into a buffer since we can't mmap files in sysfs. + // The length we obtained from stat is wrong too (it will always be 4096) + // so we must trust that read will read the entire file. + buffer = new char[length]; + ssize_t nrd = read(fd, buffer, length); + if (nrd < 0) { + result = -errno; + ALOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); + delete[] buffer; + buffer = NULL; + } else { + length = size_t(nrd); + } + } + + if (!result) { + *outTokenizer = new Tokenizer(filename, fileMap, buffer, length); + } + } + close(fd); + } + return result; +} + +String8 Tokenizer::getLocation() const { + String8 result; + result.appendFormat("%s:%d", mFilename.string(), mLineNumber); + return result; +} + +String8 Tokenizer::peekRemainderOfLine() const { + const char* end = getEnd(); + const char* eol = mCurrent; + while (eol != end) { + char ch = *eol; + if (ch == '\n') { + break; + } + eol += 1; + } + return String8(mCurrent, eol - mCurrent); +} + +String8 Tokenizer::nextToken(const char* delimiters) { +#if DEBUG_TOKENIZER + ALOGD("nextToken"); +#endif + const char* end = getEnd(); + const char* tokenStart = mCurrent; + while (mCurrent != end) { + char ch = *mCurrent; + if (ch == '\n' || isDelimiter(ch, delimiters)) { + break; + } + mCurrent += 1; + } + return String8(tokenStart, mCurrent - tokenStart); +} + +void Tokenizer::nextLine() { +#if DEBUG_TOKENIZER + ALOGD("nextLine"); +#endif + const char* end = getEnd(); + while (mCurrent != end) { + char ch = *(mCurrent++); + if (ch == '\n') { + mLineNumber += 1; + break; + } + } +} + +void Tokenizer::skipDelimiters(const char* delimiters) { +#if DEBUG_TOKENIZER + ALOGD("skipDelimiters"); +#endif + const char* end = getEnd(); + while (mCurrent != end) { + char ch = *mCurrent; + if (ch == '\n' || !isDelimiter(ch, delimiters)) { + break; + } + mCurrent += 1; + } +} + +} // namespace android diff --git a/widget/gonk/libui/Tokenizer.h b/widget/gonk/libui/Tokenizer.h new file mode 100644 index 00000000000..21748305850 --- /dev/null +++ b/widget/gonk/libui/Tokenizer.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UTILS_TOKENIZER_H +#define _UTILS_TOKENIZER_H + +#include +#include +#include +#include "String8.h" + +namespace android { + +/** + * A simple tokenizer for loading and parsing ASCII text files line by line. + */ +class Tokenizer { + Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length); + +public: + ~Tokenizer(); + + /** + * Opens a file and maps it into memory. + * + * Returns NO_ERROR and a tokenizer for the file, if successful. + * Otherwise returns an error and sets outTokenizer to NULL. + */ + static status_t open(const String8& filename, Tokenizer** outTokenizer); + + /** + * Returns true if at the end of the file. + */ + inline bool isEof() const { return mCurrent == getEnd(); } + + /** + * Returns true if at the end of the line or end of the file. + */ + inline bool isEol() const { return isEof() || *mCurrent == '\n'; } + + /** + * Gets the name of the file. + */ + inline String8 getFilename() const { return mFilename; } + + /** + * Gets a 1-based line number index for the current position. + */ + inline int32_t getLineNumber() const { return mLineNumber; } + + /** + * Formats a location string consisting of the filename and current line number. + * Returns a string like "MyFile.txt:33". + */ + String8 getLocation() const; + + /** + * Gets the character at the current position. + * Returns null at end of file. + */ + inline char peekChar() const { return isEof() ? '\0' : *mCurrent; } + + /** + * Gets the remainder of the current line as a string, excluding the newline character. + */ + String8 peekRemainderOfLine() const; + + /** + * Gets the character at the current position and advances past it. + * Returns null at end of file. + */ + inline char nextChar() { return isEof() ? '\0' : *(mCurrent++); } + + /** + * Gets the next token on this line stopping at the specified delimiters + * or the end of the line whichever comes first and advances past it. + * Also stops at embedded nulls. + * Returns the token or an empty string if the current character is a delimiter + * or is at the end of the line. + */ + String8 nextToken(const char* delimiters); + + /** + * Advances to the next line. + * Does nothing if already at the end of the file. + */ + void nextLine(); + + /** + * Skips over the specified delimiters in the line. + * Also skips embedded nulls. + */ + void skipDelimiters(const char* delimiters); + +private: + Tokenizer(const Tokenizer& other); // not copyable + + String8 mFilename; + FileMap* mFileMap; + char* mBuffer; + size_t mLength; + + const char* mCurrent; + int32_t mLineNumber; + + inline const char* getEnd() const { return mBuffer + mLength; } + +}; + +} // namespace android + +#endif // _UTILS_TOKENIZER_H diff --git a/widget/gonk/libui/Unicode.cpp b/widget/gonk/libui/Unicode.cpp new file mode 100644 index 00000000000..711a7957ccc --- /dev/null +++ b/widget/gonk/libui/Unicode.cpp @@ -0,0 +1,576 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Unicode.h" + +#include + +#ifdef HAVE_WINSOCK +# undef nhtol +# undef htonl +# undef nhtos +# undef htons + +# ifdef HAVE_LITTLE_ENDIAN +# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) +# define htonl(x) ntohl(x) +# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) +# define htons(x) ntohs(x) +# else +# define ntohl(x) (x) +# define htonl(x) (x) +# define ntohs(x) (x) +# define htons(x) (x) +# endif +#else +# include +#endif + +extern "C" { + +static const char32_t kByteMask = 0x000000BF; +static const char32_t kByteMark = 0x00000080; + +// Surrogates aren't valid for UTF-32 characters, so define some +// constants that will let us screen them out. +static const char32_t kUnicodeSurrogateHighStart = 0x0000D800; +static const char32_t kUnicodeSurrogateHighEnd = 0x0000DBFF; +static const char32_t kUnicodeSurrogateLowStart = 0x0000DC00; +static const char32_t kUnicodeSurrogateLowEnd = 0x0000DFFF; +static const char32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart; +static const char32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd; +static const char32_t kUnicodeMaxCodepoint = 0x0010FFFF; + +// Mask used to set appropriate bits in first byte of UTF-8 sequence, +// indexed by number of bytes in the sequence. +// 0xxxxxxx +// -> (00-7f) 7bit. Bit mask for the first byte is 0x00000000 +// 110yyyyx 10xxxxxx +// -> (c0-df)(80-bf) 11bit. Bit mask is 0x000000C0 +// 1110yyyy 10yxxxxx 10xxxxxx +// -> (e0-ef)(80-bf)(80-bf) 16bit. Bit mask is 0x000000E0 +// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx +// -> (f0-f7)(80-bf)(80-bf)(80-bf) 21bit. Bit mask is 0x000000F0 +static const char32_t kFirstByteMark[] = { + 0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0 +}; + +// -------------------------------------------------------------------------- +// UTF-32 +// -------------------------------------------------------------------------- + +/** + * Return number of UTF-8 bytes required for the character. If the character + * is invalid, return size of 0. + */ +static inline size_t utf32_codepoint_utf8_length(char32_t srcChar) +{ + // Figure out how many bytes the result will require. + if (srcChar < 0x00000080) { + return 1; + } else if (srcChar < 0x00000800) { + return 2; + } else if (srcChar < 0x00010000) { + if ((srcChar < kUnicodeSurrogateStart) || (srcChar > kUnicodeSurrogateEnd)) { + return 3; + } else { + // Surrogates are invalid UTF-32 characters. + return 0; + } + } + // Max code point for Unicode is 0x0010FFFF. + else if (srcChar <= kUnicodeMaxCodepoint) { + return 4; + } else { + // Invalid UTF-32 character. + return 0; + } +} + +// Write out the source character to . + +static inline void utf32_codepoint_to_utf8(uint8_t* dstP, char32_t srcChar, size_t bytes) +{ + dstP += bytes; + switch (bytes) + { /* note: everything falls through. */ + case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; + case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; + case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; + case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]); + } +} + +size_t strlen32(const char32_t *s) +{ + const char32_t *ss = s; + while ( *ss ) + ss++; + return ss-s; +} + +size_t strnlen32(const char32_t *s, size_t maxlen) +{ + const char32_t *ss = s; + while ((maxlen > 0) && *ss) { + ss++; + maxlen--; + } + return ss-s; +} + +static inline int32_t utf32_at_internal(const char* cur, size_t *num_read) +{ + const char first_char = *cur; + if ((first_char & 0x80) == 0) { // ASCII + *num_read = 1; + return *cur; + } + cur++; + char32_t mask, to_ignore_mask; + size_t num_to_read = 0; + char32_t utf32 = first_char; + for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0xFFFFFF80; + (first_char & mask); + num_to_read++, to_ignore_mask |= mask, mask >>= 1) { + // 0x3F == 00111111 + utf32 = (utf32 << 6) + (*cur++ & 0x3F); + } + to_ignore_mask |= mask; + utf32 &= ~(to_ignore_mask << (6 * (num_to_read - 1))); + + *num_read = num_to_read; + return static_cast(utf32); +} + +int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index) +{ + if (index >= src_len) { + return -1; + } + size_t dummy_index; + if (next_index == NULL) { + next_index = &dummy_index; + } + size_t num_read; + int32_t ret = utf32_at_internal(src + index, &num_read); + if (ret >= 0) { + *next_index = index + num_read; + } + + return ret; +} + +ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len) +{ + if (src == NULL || src_len == 0) { + return -1; + } + + size_t ret = 0; + const char32_t *end = src + src_len; + while (src < end) { + ret += utf32_codepoint_utf8_length(*src++); + } + return ret; +} + +void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst) +{ + if (src == NULL || src_len == 0 || dst == NULL) { + return; + } + + const char32_t *cur_utf32 = src; + const char32_t *end_utf32 = src + src_len; + char *cur = dst; + while (cur_utf32 < end_utf32) { + size_t len = utf32_codepoint_utf8_length(*cur_utf32); + utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len); + cur += len; + } + *cur = '\0'; +} + +// -------------------------------------------------------------------------- +// UTF-16 +// -------------------------------------------------------------------------- + +int strcmp16(const char16_t *s1, const char16_t *s2) +{ + char16_t ch; + int d = 0; + + while ( 1 ) { + d = (int)(ch = *s1++) - (int)*s2++; + if ( d || !ch ) + break; + } + + return d; +} + +int strncmp16(const char16_t *s1, const char16_t *s2, size_t n) +{ + char16_t ch; + int d = 0; + + while ( n-- ) { + d = (int)(ch = *s1++) - (int)*s2++; + if ( d || !ch ) + break; + } + + return d; +} + +char16_t *strcpy16(char16_t *dst, const char16_t *src) +{ + char16_t *q = dst; + const char16_t *p = src; + char16_t ch; + + do { + *q++ = ch = *p++; + } while ( ch ); + + return dst; +} + +size_t strlen16(const char16_t *s) +{ + const char16_t *ss = s; + while ( *ss ) + ss++; + return ss-s; +} + + +char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n) +{ + char16_t *q = dst; + const char16_t *p = src; + char ch; + + while (n) { + n--; + *q++ = ch = *p++; + if ( !ch ) + break; + } + + *q = 0; + + return dst; +} + +size_t strnlen16(const char16_t *s, size_t maxlen) +{ + const char16_t *ss = s; + + /* Important: the maxlen test must precede the reference through ss; + since the byte beyond the maximum may segfault */ + while ((maxlen > 0) && *ss) { + ss++; + maxlen--; + } + return ss-s; +} + +int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2) +{ + const char16_t* e1 = s1+n1; + const char16_t* e2 = s2+n2; + + while (s1 < e1 && s2 < e2) { + const int d = (int)*s1++ - (int)*s2++; + if (d) { + return d; + } + } + + return n1 < n2 + ? (0 - (int)*s2) + : (n1 > n2 + ? ((int)*s1 - 0) + : 0); +} + +int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2) +{ + const char16_t* e1 = s1H+n1; + const char16_t* e2 = s2N+n2; + + while (s1H < e1 && s2N < e2) { + const char16_t c2 = ntohs(*s2N); + const int d = (int)*s1H++ - (int)c2; + s2N++; + if (d) { + return d; + } + } + + return n1 < n2 + ? (0 - (int)ntohs(*s2N)) + : (n1 > n2 + ? ((int)*s1H - 0) + : 0); +} + +void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst) +{ + if (src == NULL || src_len == 0 || dst == NULL) { + return; + } + + const char16_t* cur_utf16 = src; + const char16_t* const end_utf16 = src + src_len; + char *cur = dst; + while (cur_utf16 < end_utf16) { + char32_t utf32; + // surrogate pairs + if ((*cur_utf16 & 0xFC00) == 0xD800) { + utf32 = (*cur_utf16++ - 0xD800) << 10; + utf32 |= *cur_utf16++ - 0xDC00; + utf32 += 0x10000; + } else { + utf32 = (char32_t) *cur_utf16++; + } + const size_t len = utf32_codepoint_utf8_length(utf32); + utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len); + cur += len; + } + *cur = '\0'; +} + +// -------------------------------------------------------------------------- +// UTF-8 +// -------------------------------------------------------------------------- + +ssize_t utf8_length(const char *src) +{ + const char *cur = src; + size_t ret = 0; + while (*cur != '\0') { + const char first_char = *cur++; + if ((first_char & 0x80) == 0) { // ASCII + ret += 1; + continue; + } + // (UTF-8's character must not be like 10xxxxxx, + // but 110xxxxx, 1110xxxx, ... or 1111110x) + if ((first_char & 0x40) == 0) { + return -1; + } + + int32_t mask, to_ignore_mask; + size_t num_to_read = 0; + char32_t utf32 = 0; + for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80; + num_to_read < 5 && (first_char & mask); + num_to_read++, to_ignore_mask |= mask, mask >>= 1) { + if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx + return -1; + } + // 0x3F == 00111111 + utf32 = (utf32 << 6) + (*cur++ & 0x3F); + } + // "first_char" must be (110xxxxx - 11110xxx) + if (num_to_read == 5) { + return -1; + } + to_ignore_mask |= mask; + utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1)); + if (utf32 > kUnicodeMaxCodepoint) { + return -1; + } + + ret += num_to_read; + } + return ret; +} + +ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len) +{ + if (src == NULL || src_len == 0) { + return -1; + } + + size_t ret = 0; + const char16_t* const end = src + src_len; + while (src < end) { + if ((*src & 0xFC00) == 0xD800 && (src + 1) < end + && (*++src & 0xFC00) == 0xDC00) { + // surrogate pairs are always 4 bytes. + ret += 4; + src++; + } else { + ret += utf32_codepoint_utf8_length((char32_t) *src++); + } + } + return ret; +} + +/** + * Returns 1-4 based on the number of leading bits. + * + * 1111 -> 4 + * 1110 -> 3 + * 110x -> 2 + * 10xx -> 1 + * 0xxx -> 1 + */ +static inline size_t utf8_codepoint_len(uint8_t ch) +{ + return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1; +} + +static inline void utf8_shift_and_mask(uint32_t* codePoint, const uint8_t byte) +{ + *codePoint <<= 6; + *codePoint |= 0x3F & byte; +} + +size_t utf8_to_utf32_length(const char *src, size_t src_len) +{ + if (src == NULL || src_len == 0) { + return 0; + } + size_t ret = 0; + const char* cur; + const char* end; + size_t num_to_skip; + for (cur = src, end = src + src_len, num_to_skip = 1; + cur < end; + cur += num_to_skip, ret++) { + const char first_char = *cur; + num_to_skip = 1; + if ((first_char & 0x80) == 0) { // ASCII + continue; + } + int32_t mask; + + for (mask = 0x40; (first_char & mask); num_to_skip++, mask >>= 1) { + } + } + return ret; +} + +void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst) +{ + if (src == NULL || src_len == 0 || dst == NULL) { + return; + } + + const char* cur = src; + const char* const end = src + src_len; + char32_t* cur_utf32 = dst; + while (cur < end) { + size_t num_read; + *cur_utf32++ = static_cast(utf32_at_internal(cur, &num_read)); + cur += num_read; + } + *cur_utf32 = 0; +} + +static inline uint32_t utf8_to_utf32_codepoint(const uint8_t *src, size_t length) +{ + uint32_t unicode; + + switch (length) + { + case 1: + return src[0]; + case 2: + unicode = src[0] & 0x1f; + utf8_shift_and_mask(&unicode, src[1]); + return unicode; + case 3: + unicode = src[0] & 0x0f; + utf8_shift_and_mask(&unicode, src[1]); + utf8_shift_and_mask(&unicode, src[2]); + return unicode; + case 4: + unicode = src[0] & 0x07; + utf8_shift_and_mask(&unicode, src[1]); + utf8_shift_and_mask(&unicode, src[2]); + utf8_shift_and_mask(&unicode, src[3]); + return unicode; + default: + return 0xffff; + } + + //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result); +} + +ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len) +{ + const uint8_t* const u8end = u8str + u8len; + const uint8_t* u8cur = u8str; + + /* Validate that the UTF-8 is the correct len */ + size_t u16measuredLen = 0; + while (u8cur < u8end) { + u16measuredLen++; + int u8charLen = utf8_codepoint_len(*u8cur); + uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8charLen); + if (codepoint > 0xFFFF) u16measuredLen++; // this will be a surrogate pair in utf16 + u8cur += u8charLen; + } + + /** + * Make sure that we ended where we thought we would and the output UTF-16 + * will be exactly how long we were told it would be. + */ + if (u8cur != u8end) { + return -1; + } + + return u16measuredLen; +} + +char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* u8str, size_t u8len, char16_t* u16str) +{ + const uint8_t* const u8end = u8str + u8len; + const uint8_t* u8cur = u8str; + char16_t* u16cur = u16str; + + while (u8cur < u8end) { + size_t u8len = utf8_codepoint_len(*u8cur); + uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8len); + + // Convert the UTF32 codepoint to one or more UTF16 codepoints + if (codepoint <= 0xFFFF) { + // Single UTF16 character + *u16cur++ = (char16_t) codepoint; + } else { + // Multiple UTF16 characters with surrogates + codepoint = codepoint - 0x10000; + *u16cur++ = (char16_t) ((codepoint >> 10) + 0xD800); + *u16cur++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00); + } + + u8cur += u8len; + } + return u16cur; +} + +void utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str) { + char16_t* end = utf8_to_utf16_no_null_terminator(u8str, u8len, u16str); + *end = 0; +} + +} diff --git a/widget/gonk/libui/Unicode.h b/widget/gonk/libui/Unicode.h new file mode 100644 index 00000000000..93a677df685 --- /dev/null +++ b/widget/gonk/libui/Unicode.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_UNICODE_H +#define ANDROID_UNICODE_H + +#define __STDC_LIMIT_MACROS 1 + +#include +#include + +extern "C" { + +// char32_t and char16_t are built-in types as of c++0x. +#if !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L +typedef uint32_t char32_t; +typedef uint16_t char16_t; +#endif + +// Standard string functions on char16_t strings. +int strcmp16(const char16_t *, const char16_t *); +int strncmp16(const char16_t *s1, const char16_t *s2, size_t n); +size_t strlen16(const char16_t *); +size_t strnlen16(const char16_t *, size_t); +char16_t *strcpy16(char16_t *, const char16_t *); +char16_t *strncpy16(char16_t *, const char16_t *, size_t); + +// Version of comparison that supports embedded nulls. +// This is different than strncmp() because we don't stop +// at a nul character and consider the strings to be different +// if the lengths are different (thus we need to supply the +// lengths of both strings). This can also be used when +// your string is not nul-terminated as it will have the +// equivalent result as strcmp16 (unlike strncmp16). +int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2); + +// Version of strzcmp16 for comparing strings in different endianness. +int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2); + +// Standard string functions on char32_t strings. +size_t strlen32(const char32_t *); +size_t strnlen32(const char32_t *, size_t); + +/** + * Measure the length of a UTF-32 string in UTF-8. If the string is invalid + * such as containing a surrogate character, -1 will be returned. + */ +ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len); + +/** + * Stores a UTF-8 string converted from "src" in "dst", if "dst_length" is not + * large enough to store the string, the part of the "src" string is stored + * into "dst" as much as possible. See the examples for more detail. + * Returns the size actually used for storing the string. + * dst" is not null-terminated when dst_len is fully used (like strncpy). + * + * Example 1 + * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) + * "src_len" == 2 + * "dst_len" >= 7 + * -> + * Returned value == 6 + * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0 + * (note that "dst" is null-terminated) + * + * Example 2 + * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) + * "src_len" == 2 + * "dst_len" == 5 + * -> + * Returned value == 3 + * "dst" becomes \xE3\x81\x82\0 + * (note that "dst" is null-terminated, but \u3044 is not stored in "dst" + * since "dst" does not have enough size to store the character) + * + * Example 3 + * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) + * "src_len" == 2 + * "dst_len" == 6 + * -> + * Returned value == 6 + * "dst" becomes \xE3\x81\x82\xE3\x81\x84 + * (note that "dst" is NOT null-terminated, like strncpy) + */ +void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst); + +/** + * Returns the unicode value at "index". + * Returns -1 when the index is invalid (equals to or more than "src_len"). + * If returned value is positive, it is able to be converted to char32_t, which + * is unsigned. Then, if "next_index" is not NULL, the next index to be used is + * stored in "next_index". "next_index" can be NULL. + */ +int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index); + + +/** + * Returns the UTF-8 length of UTF-16 string "src". + */ +ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len); + +/** + * Converts a UTF-16 string to UTF-8. The destination buffer must be large + * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added + * NULL terminator. + */ +void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst); + +/** + * Returns the length of "src" when "src" is valid UTF-8 string. + * Returns 0 if src is NULL or 0-length string. Returns -1 when the source + * is an invalid string. + * + * This function should be used to determine whether "src" is valid UTF-8 + * characters with valid unicode codepoints. "src" must be null-terminated. + * + * If you are going to use other utf8_to_... functions defined in this header + * with string which may not be valid UTF-8 with valid codepoint (form 0 to + * 0x10FFFF), you should use this function before calling others, since the + * other functions do not check whether the string is valid UTF-8 or not. + * + * If you do not care whether "src" is valid UTF-8 or not, you should use + * strlen() as usual, which should be much faster. + */ +ssize_t utf8_length(const char *src); + +/** + * Measure the length of a UTF-32 string. + */ +size_t utf8_to_utf32_length(const char *src, size_t src_len); + +/** + * Stores a UTF-32 string converted from "src" in "dst". "dst" must be large + * enough to store the entire converted string as measured by + * utf8_to_utf32_length plus space for a NULL terminator. + */ +void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst); + +/** + * Returns the UTF-16 length of UTF-8 string "src". + */ +ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen); + +/** + * Convert UTF-8 to UTF-16 including surrogate pairs. + * Returns a pointer to the end of the string (where a null terminator might go + * if you wanted to add one). + */ +char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* src, size_t srcLen, char16_t* dst); + +/** + * Convert UTF-8 to UTF-16 including surrogate pairs. The destination buffer + * must be large enough to hold the result as measured by utf8_to_utf16_length + * plus an added NULL terminator. + */ +void utf8_to_utf16(const uint8_t* src, size_t srcLen, char16_t* dst); + +} + +#undef __STDC_LIMIT_MACROS +#endif diff --git a/widget/gonk/libui/VirtualKeyMap.cpp b/widget/gonk/libui/VirtualKeyMap.cpp index fe283898da1..b91ceebdfa3 100644 --- a/widget/gonk/libui/VirtualKeyMap.cpp +++ b/widget/gonk/libui/VirtualKeyMap.cpp @@ -18,11 +18,11 @@ #include #include +#include "utils_Log.h" #include "VirtualKeyMap.h" -#include #include -#include -#include +#include "Tokenizer.h" +#include "Timers.h" // Enables debug output for the parser. #define DEBUG_PARSER 0 diff --git a/widget/gonk/libui/VirtualKeyMap.h b/widget/gonk/libui/VirtualKeyMap.h index 2810b3afe4c..2fbc123b765 100644 --- a/widget/gonk/libui/VirtualKeyMap.h +++ b/widget/gonk/libui/VirtualKeyMap.h @@ -22,9 +22,9 @@ #include "Input.h" #include #include -#include -#include -#include +#include "Tokenizer.h" +#include "String8.h" +#include "Unicode.h" namespace android { diff --git a/widget/gonk/libui/android_input.h b/widget/gonk/libui/android_input.h new file mode 100644 index 00000000000..5f27df48d47 --- /dev/null +++ b/widget/gonk/libui/android_input.h @@ -0,0 +1,848 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_INPUT_H +#define _ANDROID_INPUT_H + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +/* + * Structures and functions to receive and process input events in + * native code. + * + * NOTE: These functions MUST be implemented by /system/lib/libui.so + */ + +#include +#include +#include "android_keycodes.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Key states (may be returned by queries about the current state of a + * particular key code, scan code or switch). + */ +enum { + /* The key state is unknown or the requested key itself is not supported. */ + AKEY_STATE_UNKNOWN = -1, + + /* The key is up. */ + AKEY_STATE_UP = 0, + + /* The key is down. */ + AKEY_STATE_DOWN = 1, + + /* The key is down but is a virtual key press that is being emulated by the system. */ + AKEY_STATE_VIRTUAL = 2 +}; + +/* + * Meta key / modifer state. + */ +enum { + /* No meta keys are pressed. */ + AMETA_NONE = 0, + + /* This mask is used to check whether one of the ALT meta keys is pressed. */ + AMETA_ALT_ON = 0x02, + + /* This mask is used to check whether the left ALT meta key is pressed. */ + AMETA_ALT_LEFT_ON = 0x10, + + /* This mask is used to check whether the right ALT meta key is pressed. */ + AMETA_ALT_RIGHT_ON = 0x20, + + /* This mask is used to check whether one of the SHIFT meta keys is pressed. */ + AMETA_SHIFT_ON = 0x01, + + /* This mask is used to check whether the left SHIFT meta key is pressed. */ + AMETA_SHIFT_LEFT_ON = 0x40, + + /* This mask is used to check whether the right SHIFT meta key is pressed. */ + AMETA_SHIFT_RIGHT_ON = 0x80, + + /* This mask is used to check whether the SYM meta key is pressed. */ + AMETA_SYM_ON = 0x04, + + /* This mask is used to check whether the FUNCTION meta key is pressed. */ + AMETA_FUNCTION_ON = 0x08, + + /* This mask is used to check whether one of the CTRL meta keys is pressed. */ + AMETA_CTRL_ON = 0x1000, + + /* This mask is used to check whether the left CTRL meta key is pressed. */ + AMETA_CTRL_LEFT_ON = 0x2000, + + /* This mask is used to check whether the right CTRL meta key is pressed. */ + AMETA_CTRL_RIGHT_ON = 0x4000, + + /* This mask is used to check whether one of the META meta keys is pressed. */ + AMETA_META_ON = 0x10000, + + /* This mask is used to check whether the left META meta key is pressed. */ + AMETA_META_LEFT_ON = 0x20000, + + /* This mask is used to check whether the right META meta key is pressed. */ + AMETA_META_RIGHT_ON = 0x40000, + + /* This mask is used to check whether the CAPS LOCK meta key is on. */ + AMETA_CAPS_LOCK_ON = 0x100000, + + /* This mask is used to check whether the NUM LOCK meta key is on. */ + AMETA_NUM_LOCK_ON = 0x200000, + + /* This mask is used to check whether the SCROLL LOCK meta key is on. */ + AMETA_SCROLL_LOCK_ON = 0x400000, +}; + +/* + * Input events. + * + * Input events are opaque structures. Use the provided accessors functions to + * read their properties. + */ +struct AInputEvent; +typedef struct AInputEvent AInputEvent; + +/* + * Input event types. + */ +enum { + /* Indicates that the input event is a key event. */ + AINPUT_EVENT_TYPE_KEY = 1, + + /* Indicates that the input event is a motion event. */ + AINPUT_EVENT_TYPE_MOTION = 2 +}; + +/* + * Key event actions. + */ +enum { + /* The key has been pressed down. */ + AKEY_EVENT_ACTION_DOWN = 0, + + /* The key has been released. */ + AKEY_EVENT_ACTION_UP = 1, + + /* Multiple duplicate key events have occurred in a row, or a complex string is + * being delivered. The repeat_count property of the key event contains the number + * of times the given key code should be executed. + */ + AKEY_EVENT_ACTION_MULTIPLE = 2 +}; + +/* + * Key event flags. + */ +enum { + /* This mask is set if the device woke because of this key event. */ + AKEY_EVENT_FLAG_WOKE_HERE = 0x1, + + /* This mask is set if the key event was generated by a software keyboard. */ + AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2, + + /* This mask is set if we don't want the key event to cause us to leave touch mode. */ + AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4, + + /* This mask is set if an event was known to come from a trusted part + * of the system. That is, the event is known to come from the user, + * and could not have been spoofed by a third party component. */ + AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8, + + /* This mask is used for compatibility, to identify enter keys that are + * coming from an IME whose enter key has been auto-labelled "next" or + * "done". This allows TextView to dispatch these as normal enter keys + * for old applications, but still do the appropriate action when + * receiving them. */ + AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10, + + /* When associated with up key events, this indicates that the key press + * has been canceled. Typically this is used with virtual touch screen + * keys, where the user can slide from the virtual key area on to the + * display: in that case, the application will receive a canceled up + * event and should not perform the action normally associated with the + * key. Note that for this to work, the application can not perform an + * action for a key until it receives an up or the long press timeout has + * expired. */ + AKEY_EVENT_FLAG_CANCELED = 0x20, + + /* This key event was generated by a virtual (on-screen) hard key area. + * Typically this is an area of the touchscreen, outside of the regular + * display, dedicated to "hardware" buttons. */ + AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40, + + /* This flag is set for the first key repeat that occurs after the + * long press timeout. */ + AKEY_EVENT_FLAG_LONG_PRESS = 0x80, + + /* Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long + * press action was executed while it was down. */ + AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100, + + /* Set for AKEY_EVENT_ACTION_UP when this event's key code is still being + * tracked from its initial down. That is, somebody requested that tracking + * started on the key down and a long press has not caused + * the tracking to be canceled. */ + AKEY_EVENT_FLAG_TRACKING = 0x200, + + /* Set when a key event has been synthesized to implement default behavior + * for an event that the application did not handle. + * Fallback key events are generated by unhandled trackball motions + * (to emulate a directional keypad) and by certain unhandled key presses + * that are declared in the key map (such as special function numeric keypad + * keys when numlock is off). */ + AKEY_EVENT_FLAG_FALLBACK = 0x400, +}; + +/* + * Motion event actions. + */ + +/* Bit shift for the action bits holding the pointer index as + * defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK. + */ +#define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8 + +enum { + /* Bit mask of the parts of the action code that are the action itself. + */ + AMOTION_EVENT_ACTION_MASK = 0xff, + + /* Bits in the action code that represent a pointer index, used with + * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting + * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer + * index where the data for the pointer going up or down can be found. + */ + AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00, + + /* A pressed gesture has started, the motion contains the initial starting location. + */ + AMOTION_EVENT_ACTION_DOWN = 0, + + /* A pressed gesture has finished, the motion contains the final release location + * as well as any intermediate points since the last down or move event. + */ + AMOTION_EVENT_ACTION_UP = 1, + + /* A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and + * AMOTION_EVENT_ACTION_UP). The motion contains the most recent point, as well as + * any intermediate points since the last down or move event. + */ + AMOTION_EVENT_ACTION_MOVE = 2, + + /* The current gesture has been aborted. + * You will not receive any more points in it. You should treat this as + * an up event, but not perform any action that you normally would. + */ + AMOTION_EVENT_ACTION_CANCEL = 3, + + /* A movement has happened outside of the normal bounds of the UI element. + * This does not provide a full gesture, but only the initial location of the movement/touch. + */ + AMOTION_EVENT_ACTION_OUTSIDE = 4, + + /* A non-primary pointer has gone down. + * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. + */ + AMOTION_EVENT_ACTION_POINTER_DOWN = 5, + + /* A non-primary pointer has gone up. + * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. + */ + AMOTION_EVENT_ACTION_POINTER_UP = 6, + + /* A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE). + * The motion contains the most recent point, as well as any intermediate points since + * the last hover move event. + */ + AMOTION_EVENT_ACTION_HOVER_MOVE = 7, + + /* The motion event contains relative vertical and/or horizontal scroll offsets. + * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL + * and AMOTION_EVENT_AXIS_HSCROLL. + * The pointer may or may not be down when this event is dispatched. + * This action is always delivered to the winder under the pointer, which + * may not be the window currently touched. + */ + AMOTION_EVENT_ACTION_SCROLL = 8, + + /* The pointer is not down but has entered the boundaries of a window or view. + */ + AMOTION_EVENT_ACTION_HOVER_ENTER = 9, + + /* The pointer is not down but has exited the boundaries of a window or view. + */ + AMOTION_EVENT_ACTION_HOVER_EXIT = 10, +}; + +/* + * Motion event flags. + */ +enum { + /* This flag indicates that the window that received this motion event is partly + * or wholly obscured by another visible window above it. This flag is set to true + * even if the event did not directly pass through the obscured area. + * A security sensitive application can check this flag to identify situations in which + * a malicious application may have covered up part of its content for the purpose + * of misleading the user or hijacking touches. An appropriate response might be + * to drop the suspect touches or to take additional precautions to confirm the user's + * actual intent. + */ + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1, +}; + +/* + * Motion event edge touch flags. + */ +enum { + /* No edges intersected */ + AMOTION_EVENT_EDGE_FLAG_NONE = 0, + + /* Flag indicating the motion event intersected the top edge of the screen. */ + AMOTION_EVENT_EDGE_FLAG_TOP = 0x01, + + /* Flag indicating the motion event intersected the bottom edge of the screen. */ + AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02, + + /* Flag indicating the motion event intersected the left edge of the screen. */ + AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04, + + /* Flag indicating the motion event intersected the right edge of the screen. */ + AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08 +}; + +/* + * Constants that identify each individual axis of a motion event. + * Refer to the documentation on the MotionEvent class for descriptions of each axis. + */ +enum { + AMOTION_EVENT_AXIS_X = 0, + AMOTION_EVENT_AXIS_Y = 1, + AMOTION_EVENT_AXIS_PRESSURE = 2, + AMOTION_EVENT_AXIS_SIZE = 3, + AMOTION_EVENT_AXIS_TOUCH_MAJOR = 4, + AMOTION_EVENT_AXIS_TOUCH_MINOR = 5, + AMOTION_EVENT_AXIS_TOOL_MAJOR = 6, + AMOTION_EVENT_AXIS_TOOL_MINOR = 7, + AMOTION_EVENT_AXIS_ORIENTATION = 8, + AMOTION_EVENT_AXIS_VSCROLL = 9, + AMOTION_EVENT_AXIS_HSCROLL = 10, + AMOTION_EVENT_AXIS_Z = 11, + AMOTION_EVENT_AXIS_RX = 12, + AMOTION_EVENT_AXIS_RY = 13, + AMOTION_EVENT_AXIS_RZ = 14, + AMOTION_EVENT_AXIS_HAT_X = 15, + AMOTION_EVENT_AXIS_HAT_Y = 16, + AMOTION_EVENT_AXIS_LTRIGGER = 17, + AMOTION_EVENT_AXIS_RTRIGGER = 18, + AMOTION_EVENT_AXIS_THROTTLE = 19, + AMOTION_EVENT_AXIS_RUDDER = 20, + AMOTION_EVENT_AXIS_WHEEL = 21, + AMOTION_EVENT_AXIS_GAS = 22, + AMOTION_EVENT_AXIS_BRAKE = 23, + AMOTION_EVENT_AXIS_DISTANCE = 24, + AMOTION_EVENT_AXIS_TILT = 25, + AMOTION_EVENT_AXIS_GENERIC_1 = 32, + AMOTION_EVENT_AXIS_GENERIC_2 = 33, + AMOTION_EVENT_AXIS_GENERIC_3 = 34, + AMOTION_EVENT_AXIS_GENERIC_4 = 35, + AMOTION_EVENT_AXIS_GENERIC_5 = 36, + AMOTION_EVENT_AXIS_GENERIC_6 = 37, + AMOTION_EVENT_AXIS_GENERIC_7 = 38, + AMOTION_EVENT_AXIS_GENERIC_8 = 39, + AMOTION_EVENT_AXIS_GENERIC_9 = 40, + AMOTION_EVENT_AXIS_GENERIC_10 = 41, + AMOTION_EVENT_AXIS_GENERIC_11 = 42, + AMOTION_EVENT_AXIS_GENERIC_12 = 43, + AMOTION_EVENT_AXIS_GENERIC_13 = 44, + AMOTION_EVENT_AXIS_GENERIC_14 = 45, + AMOTION_EVENT_AXIS_GENERIC_15 = 46, + AMOTION_EVENT_AXIS_GENERIC_16 = 47, + + // NOTE: If you add a new axis here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. +}; + +/* + * Constants that identify buttons that are associated with motion events. + * Refer to the documentation on the MotionEvent class for descriptions of each button. + */ +enum { + AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, + AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1, + AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, + AMOTION_EVENT_BUTTON_BACK = 1 << 3, + AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, +}; + +/* + * Constants that identify tool types. + * Refer to the documentation on the MotionEvent class for descriptions of each tool type. + */ +enum { + AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0, + AMOTION_EVENT_TOOL_TYPE_FINGER = 1, + AMOTION_EVENT_TOOL_TYPE_STYLUS = 2, + AMOTION_EVENT_TOOL_TYPE_MOUSE = 3, + AMOTION_EVENT_TOOL_TYPE_ERASER = 4, +}; + +/* + * Input sources. + * + * Refer to the documentation on android.view.InputDevice for more details about input sources + * and their correct interpretation. + */ +enum { + AINPUT_SOURCE_CLASS_MASK = 0x000000ff, + + AINPUT_SOURCE_CLASS_BUTTON = 0x00000001, + AINPUT_SOURCE_CLASS_POINTER = 0x00000002, + AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004, + AINPUT_SOURCE_CLASS_POSITION = 0x00000008, + AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010, +}; + +enum { + AINPUT_SOURCE_UNKNOWN = 0x00000000, + + AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON, + AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON, + AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON, + AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER, + AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, + AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER, + AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, + AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, + AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK, + + AINPUT_SOURCE_ANY = 0xffffff00, +}; + +/* + * Keyboard types. + * + * Refer to the documentation on android.view.InputDevice for more details. + */ +enum { + AINPUT_KEYBOARD_TYPE_NONE = 0, + AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1, + AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2, +}; + +/* + * Constants used to retrieve information about the range of motion for a particular + * coordinate of a motion event. + * + * Refer to the documentation on android.view.InputDevice for more details about input sources + * and their correct interpretation. + * + * DEPRECATION NOTICE: These constants are deprecated. Use AMOTION_EVENT_AXIS_* constants instead. + */ +enum { + AINPUT_MOTION_RANGE_X = AMOTION_EVENT_AXIS_X, + AINPUT_MOTION_RANGE_Y = AMOTION_EVENT_AXIS_Y, + AINPUT_MOTION_RANGE_PRESSURE = AMOTION_EVENT_AXIS_PRESSURE, + AINPUT_MOTION_RANGE_SIZE = AMOTION_EVENT_AXIS_SIZE, + AINPUT_MOTION_RANGE_TOUCH_MAJOR = AMOTION_EVENT_AXIS_TOUCH_MAJOR, + AINPUT_MOTION_RANGE_TOUCH_MINOR = AMOTION_EVENT_AXIS_TOUCH_MINOR, + AINPUT_MOTION_RANGE_TOOL_MAJOR = AMOTION_EVENT_AXIS_TOOL_MAJOR, + AINPUT_MOTION_RANGE_TOOL_MINOR = AMOTION_EVENT_AXIS_TOOL_MINOR, + AINPUT_MOTION_RANGE_ORIENTATION = AMOTION_EVENT_AXIS_ORIENTATION, +} __attribute__ ((deprecated)); + + +/* + * Input event accessors. + * + * Note that most functions can only be used on input events that are of a given type. + * Calling these functions on input events of other types will yield undefined behavior. + */ + +/*** Accessors for all input events. ***/ + +/* Get the input event type. */ +int32_t AInputEvent_getType(const AInputEvent* event); + +/* Get the id for the device that an input event came from. + * + * Input events can be generated by multiple different input devices. + * Use the input device id to obtain information about the input + * device that was responsible for generating a particular event. + * + * An input device id of 0 indicates that the event didn't come from a physical device; + * other numbers are arbitrary and you shouldn't depend on the values. + * Use the provided input device query API to obtain information about input devices. + */ +int32_t AInputEvent_getDeviceId(const AInputEvent* event); + +/* Get the input event source. */ +int32_t AInputEvent_getSource(const AInputEvent* event); + +/*** Accessors for key events only. ***/ + +/* Get the key event action. */ +int32_t AKeyEvent_getAction(const AInputEvent* key_event); + +/* Get the key event flags. */ +int32_t AKeyEvent_getFlags(const AInputEvent* key_event); + +/* Get the key code of the key event. + * This is the physical key that was pressed, not the Unicode character. */ +int32_t AKeyEvent_getKeyCode(const AInputEvent* key_event); + +/* Get the hardware key id of this key event. + * These values are not reliable and vary from device to device. */ +int32_t AKeyEvent_getScanCode(const AInputEvent* key_event); + +/* Get the meta key state. */ +int32_t AKeyEvent_getMetaState(const AInputEvent* key_event); + +/* Get the repeat count of the event. + * For both key up an key down events, this is the number of times the key has + * repeated with the first down starting at 0 and counting up from there. For + * multiple key events, this is the number of down/up pairs that have occurred. */ +int32_t AKeyEvent_getRepeatCount(const AInputEvent* key_event); + +/* Get the time of the most recent key down event, in the + * java.lang.System.nanoTime() time base. If this is a down event, + * this will be the same as eventTime. + * Note that when chording keys, this value is the down time of the most recently + * pressed key, which may not be the same physical key of this event. */ +int64_t AKeyEvent_getDownTime(const AInputEvent* key_event); + +/* Get the time this event occurred, in the + * java.lang.System.nanoTime() time base. */ +int64_t AKeyEvent_getEventTime(const AInputEvent* key_event); + +/*** Accessors for motion events only. ***/ + +/* Get the combined motion event action code and pointer index. */ +int32_t AMotionEvent_getAction(const AInputEvent* motion_event); + +/* Get the motion event flags. */ +int32_t AMotionEvent_getFlags(const AInputEvent* motion_event); + +/* Get the state of any meta / modifier keys that were in effect when the + * event was generated. */ +int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event); + +/* Get the button state of all buttons that are pressed. */ +int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); + +/* Get a bitfield indicating which edges, if any, were touched by this motion event. + * For touch events, clients can use this to determine if the user's finger was + * touching the edge of the display. */ +int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event); + +/* Get the time when the user originally pressed down to start a stream of + * position events, in the java.lang.System.nanoTime() time base. */ +int64_t AMotionEvent_getDownTime(const AInputEvent* motion_event); + +/* Get the time when this specific event was generated, + * in the java.lang.System.nanoTime() time base. */ +int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event); + +/* Get the X coordinate offset. + * For touch events on the screen, this is the delta that was added to the raw + * screen coordinates to adjust for the absolute position of the containing windows + * and views. */ +float AMotionEvent_getXOffset(const AInputEvent* motion_event); + +/* Get the precision of the Y coordinates being reported. + * For touch events on the screen, this is the delta that was added to the raw + * screen coordinates to adjust for the absolute position of the containing windows + * and views. */ +float AMotionEvent_getYOffset(const AInputEvent* motion_event); + +/* Get the precision of the X coordinates being reported. + * You can multiply this number with an X coordinate sample to find the + * actual hardware value of the X coordinate. */ +float AMotionEvent_getXPrecision(const AInputEvent* motion_event); + +/* Get the precision of the Y coordinates being reported. + * You can multiply this number with a Y coordinate sample to find the + * actual hardware value of the Y coordinate. */ +float AMotionEvent_getYPrecision(const AInputEvent* motion_event); + +/* Get the number of pointers of data contained in this event. + * Always >= 1. */ +size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event); + +/* Get the pointer identifier associated with a particular pointer + * data index in this event. The identifier tells you the actual pointer + * number associated with the data, accounting for individual pointers + * going up and down since the start of the current gesture. */ +int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the tool type of a pointer for the given pointer index. + * The tool type indicates the type of tool used to make contact such as a + * finger or stylus, if known. */ +int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the original raw X coordinate of this event. + * For touch events on the screen, this is the original location of the event + * on the screen, before it had been adjusted for the containing window + * and views. */ +float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the original raw X coordinate of this event. + * For touch events on the screen, this is the original location of the event + * on the screen, before it had been adjusted for the containing window + * and views. */ +float AMotionEvent_getRawY(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current X coordinate of this event for the given pointer index. + * Whole numbers are pixels; the value may have a fraction for input devices + * that are sub-pixel precise. */ +float AMotionEvent_getX(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current Y coordinate of this event for the given pointer index. + * Whole numbers are pixels; the value may have a fraction for input devices + * that are sub-pixel precise. */ +float AMotionEvent_getY(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current pressure of this event for the given pointer index. + * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), + * although values higher than 1 may be generated depending on the calibration of + * the input device. */ +float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current scaled value of the approximate size for the given pointer index. + * This represents some approximation of the area of the screen being + * pressed; the actual value in pixels corresponding to the + * touch is normalized with the device specific range of values + * and scaled to a value between 0 and 1. The value of size can be used to + * determine fat touch events. */ +float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current length of the major axis of an ellipse that describes the touch area + * at the point of contact for the given pointer index. */ +float AMotionEvent_getTouchMajor(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current length of the minor axis of an ellipse that describes the touch area + * at the point of contact for the given pointer index. */ +float AMotionEvent_getTouchMinor(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current length of the major axis of an ellipse that describes the size + * of the approaching tool for the given pointer index. + * The tool area represents the estimated size of the finger or pen that is + * touching the device independent of its actual touch area at the point of contact. */ +float AMotionEvent_getToolMajor(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current length of the minor axis of an ellipse that describes the size + * of the approaching tool for the given pointer index. + * The tool area represents the estimated size of the finger or pen that is + * touching the device independent of its actual touch area at the point of contact. */ +float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the current orientation of the touch area and tool area in radians clockwise from + * vertical for the given pointer index. + * An angle of 0 degrees indicates that the major axis of contact is oriented + * upwards, is perfectly circular or is of unknown orientation. A positive angle + * indicates that the major axis of contact is oriented to the right. A negative angle + * indicates that the major axis of contact is oriented to the left. + * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians + * (finger pointing fully right). */ +float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index); + +/* Get the value of the request axis for the given pointer index. */ +float AMotionEvent_getAxisValue(const AInputEvent* motion_event, + int32_t axis, size_t pointer_index); + +/* Get the number of historical points in this event. These are movements that + * have occurred between this event and the previous event. This only applies + * to AMOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0. + * Historical samples are indexed from oldest to newest. */ +size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event); + +/* Get the time that a historical movement occurred between this event and + * the previous event, in the java.lang.System.nanoTime() time base. */ +int64_t AMotionEvent_getHistoricalEventTime(AInputEvent* motion_event, + size_t history_index); + +/* Get the historical raw X coordinate of this event for the given pointer index that + * occurred between this event and the previous motion event. + * For touch events on the screen, this is the original location of the event + * on the screen, before it had been adjusted for the containing window + * and views. + * Whole numbers are pixels; the value may have a fraction for input devices + * that are sub-pixel precise. */ +float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical raw Y coordinate of this event for the given pointer index that + * occurred between this event and the previous motion event. + * For touch events on the screen, this is the original location of the event + * on the screen, before it had been adjusted for the containing window + * and views. + * Whole numbers are pixels; the value may have a fraction for input devices + * that are sub-pixel precise. */ +float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical X coordinate of this event for the given pointer index that + * occurred between this event and the previous motion event. + * Whole numbers are pixels; the value may have a fraction for input devices + * that are sub-pixel precise. */ +float AMotionEvent_getHistoricalX(AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical Y coordinate of this event for the given pointer index that + * occurred between this event and the previous motion event. + * Whole numbers are pixels; the value may have a fraction for input devices + * that are sub-pixel precise. */ +float AMotionEvent_getHistoricalY(AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical pressure of this event for the given pointer index that + * occurred between this event and the previous motion event. + * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), + * although values higher than 1 may be generated depending on the calibration of + * the input device. */ +float AMotionEvent_getHistoricalPressure(AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the current scaled value of the approximate size for the given pointer index that + * occurred between this event and the previous motion event. + * This represents some approximation of the area of the screen being + * pressed; the actual value in pixels corresponding to the + * touch is normalized with the device specific range of values + * and scaled to a value between 0 and 1. The value of size can be used to + * determine fat touch events. */ +float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical length of the major axis of an ellipse that describes the touch area + * at the point of contact for the given pointer index that + * occurred between this event and the previous motion event. */ +float AMotionEvent_getHistoricalTouchMajor(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical length of the minor axis of an ellipse that describes the touch area + * at the point of contact for the given pointer index that + * occurred between this event and the previous motion event. */ +float AMotionEvent_getHistoricalTouchMinor(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical length of the major axis of an ellipse that describes the size + * of the approaching tool for the given pointer index that + * occurred between this event and the previous motion event. + * The tool area represents the estimated size of the finger or pen that is + * touching the device independent of its actual touch area at the point of contact. */ +float AMotionEvent_getHistoricalToolMajor(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical length of the minor axis of an ellipse that describes the size + * of the approaching tool for the given pointer index that + * occurred between this event and the previous motion event. + * The tool area represents the estimated size of the finger or pen that is + * touching the device independent of its actual touch area at the point of contact. */ +float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical orientation of the touch area and tool area in radians clockwise from + * vertical for the given pointer index that + * occurred between this event and the previous motion event. + * An angle of 0 degrees indicates that the major axis of contact is oriented + * upwards, is perfectly circular or is of unknown orientation. A positive angle + * indicates that the major axis of contact is oriented to the right. A negative angle + * indicates that the major axis of contact is oriented to the left. + * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians + * (finger pointing fully right). */ +float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); + +/* Get the historical value of the request axis for the given pointer index + * that occurred between this event and the previous motion event. */ +float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, + int32_t axis, size_t pointer_index, size_t history_index); + + +/* + * Input queue + * + * An input queue is the facility through which you retrieve input + * events. + */ +struct AInputQueue; +typedef struct AInputQueue AInputQueue; + +/* + * Add this input queue to a looper for processing. See + * ALooper_addFd() for information on the ident, callback, and data params. + */ +void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, + int ident, ALooper_callbackFunc callback, void* data); + +/* + * Remove the input queue from the looper it is currently attached to. + */ +void AInputQueue_detachLooper(AInputQueue* queue); + +/* + * Returns true if there are one or more events available in the + * input queue. Returns 1 if the queue has events; 0 if + * it does not have events; and a negative value if there is an error. + */ +int32_t AInputQueue_hasEvents(AInputQueue* queue); + +/* + * Returns the next available event from the queue. Returns a negative + * value if no events are available or an error has occurred. + */ +int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent); + +/* + * Sends the key for standard pre-dispatching -- that is, possibly deliver + * it to the current IME to be consumed before the app. Returns 0 if it + * was not pre-dispatched, meaning you can process it right now. If non-zero + * is returned, you must abandon the current event processing and allow the + * event to appear again in the event queue (if it does not get consumed during + * pre-dispatching). + */ +int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); + +/* + * Report that dispatching has finished with the given event. + * This must be called after receiving an event with AInputQueue_get_event(). + */ +void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); + +#ifdef __cplusplus +} +#endif + +#endif // _ANDROID_INPUT_H diff --git a/widget/gonk/libui/android_keycodes.h b/widget/gonk/libui/android_keycodes.h new file mode 100644 index 00000000000..8414ff6eadc --- /dev/null +++ b/widget/gonk/libui/android_keycodes.h @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_KEYCODES_H +#define _ANDROID_KEYCODES_H + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Key codes. + */ +enum { + AKEYCODE_UNKNOWN = 0, + AKEYCODE_SOFT_LEFT = 1, + AKEYCODE_SOFT_RIGHT = 2, + AKEYCODE_HOME = 3, + AKEYCODE_BACK = 4, + AKEYCODE_CALL = 5, + AKEYCODE_ENDCALL = 6, + AKEYCODE_0 = 7, + AKEYCODE_1 = 8, + AKEYCODE_2 = 9, + AKEYCODE_3 = 10, + AKEYCODE_4 = 11, + AKEYCODE_5 = 12, + AKEYCODE_6 = 13, + AKEYCODE_7 = 14, + AKEYCODE_8 = 15, + AKEYCODE_9 = 16, + AKEYCODE_STAR = 17, + AKEYCODE_POUND = 18, + AKEYCODE_DPAD_UP = 19, + AKEYCODE_DPAD_DOWN = 20, + AKEYCODE_DPAD_LEFT = 21, + AKEYCODE_DPAD_RIGHT = 22, + AKEYCODE_DPAD_CENTER = 23, + AKEYCODE_VOLUME_UP = 24, + AKEYCODE_VOLUME_DOWN = 25, + AKEYCODE_POWER = 26, + AKEYCODE_CAMERA = 27, + AKEYCODE_CLEAR = 28, + AKEYCODE_A = 29, + AKEYCODE_B = 30, + AKEYCODE_C = 31, + AKEYCODE_D = 32, + AKEYCODE_E = 33, + AKEYCODE_F = 34, + AKEYCODE_G = 35, + AKEYCODE_H = 36, + AKEYCODE_I = 37, + AKEYCODE_J = 38, + AKEYCODE_K = 39, + AKEYCODE_L = 40, + AKEYCODE_M = 41, + AKEYCODE_N = 42, + AKEYCODE_O = 43, + AKEYCODE_P = 44, + AKEYCODE_Q = 45, + AKEYCODE_R = 46, + AKEYCODE_S = 47, + AKEYCODE_T = 48, + AKEYCODE_U = 49, + AKEYCODE_V = 50, + AKEYCODE_W = 51, + AKEYCODE_X = 52, + AKEYCODE_Y = 53, + AKEYCODE_Z = 54, + AKEYCODE_COMMA = 55, + AKEYCODE_PERIOD = 56, + AKEYCODE_ALT_LEFT = 57, + AKEYCODE_ALT_RIGHT = 58, + AKEYCODE_SHIFT_LEFT = 59, + AKEYCODE_SHIFT_RIGHT = 60, + AKEYCODE_TAB = 61, + AKEYCODE_SPACE = 62, + AKEYCODE_SYM = 63, + AKEYCODE_EXPLORER = 64, + AKEYCODE_ENVELOPE = 65, + AKEYCODE_ENTER = 66, + AKEYCODE_DEL = 67, + AKEYCODE_GRAVE = 68, + AKEYCODE_MINUS = 69, + AKEYCODE_EQUALS = 70, + AKEYCODE_LEFT_BRACKET = 71, + AKEYCODE_RIGHT_BRACKET = 72, + AKEYCODE_BACKSLASH = 73, + AKEYCODE_SEMICOLON = 74, + AKEYCODE_APOSTROPHE = 75, + AKEYCODE_SLASH = 76, + AKEYCODE_AT = 77, + AKEYCODE_NUM = 78, + AKEYCODE_HEADSETHOOK = 79, + AKEYCODE_FOCUS = 80, // *Camera* focus + AKEYCODE_PLUS = 81, + AKEYCODE_MENU = 82, + AKEYCODE_NOTIFICATION = 83, + AKEYCODE_SEARCH = 84, + AKEYCODE_MEDIA_PLAY_PAUSE= 85, + AKEYCODE_MEDIA_STOP = 86, + AKEYCODE_MEDIA_NEXT = 87, + AKEYCODE_MEDIA_PREVIOUS = 88, + AKEYCODE_MEDIA_REWIND = 89, + AKEYCODE_MEDIA_FAST_FORWARD = 90, + AKEYCODE_MUTE = 91, + AKEYCODE_PAGE_UP = 92, + AKEYCODE_PAGE_DOWN = 93, + AKEYCODE_PICTSYMBOLS = 94, + AKEYCODE_SWITCH_CHARSET = 95, + AKEYCODE_BUTTON_A = 96, + AKEYCODE_BUTTON_B = 97, + AKEYCODE_BUTTON_C = 98, + AKEYCODE_BUTTON_X = 99, + AKEYCODE_BUTTON_Y = 100, + AKEYCODE_BUTTON_Z = 101, + AKEYCODE_BUTTON_L1 = 102, + AKEYCODE_BUTTON_R1 = 103, + AKEYCODE_BUTTON_L2 = 104, + AKEYCODE_BUTTON_R2 = 105, + AKEYCODE_BUTTON_THUMBL = 106, + AKEYCODE_BUTTON_THUMBR = 107, + AKEYCODE_BUTTON_START = 108, + AKEYCODE_BUTTON_SELECT = 109, + AKEYCODE_BUTTON_MODE = 110, + AKEYCODE_ESCAPE = 111, + AKEYCODE_FORWARD_DEL = 112, + AKEYCODE_CTRL_LEFT = 113, + AKEYCODE_CTRL_RIGHT = 114, + AKEYCODE_CAPS_LOCK = 115, + AKEYCODE_SCROLL_LOCK = 116, + AKEYCODE_META_LEFT = 117, + AKEYCODE_META_RIGHT = 118, + AKEYCODE_FUNCTION = 119, + AKEYCODE_SYSRQ = 120, + AKEYCODE_BREAK = 121, + AKEYCODE_MOVE_HOME = 122, + AKEYCODE_MOVE_END = 123, + AKEYCODE_INSERT = 124, + AKEYCODE_FORWARD = 125, + AKEYCODE_MEDIA_PLAY = 126, + AKEYCODE_MEDIA_PAUSE = 127, + AKEYCODE_MEDIA_CLOSE = 128, + AKEYCODE_MEDIA_EJECT = 129, + AKEYCODE_MEDIA_RECORD = 130, + AKEYCODE_F1 = 131, + AKEYCODE_F2 = 132, + AKEYCODE_F3 = 133, + AKEYCODE_F4 = 134, + AKEYCODE_F5 = 135, + AKEYCODE_F6 = 136, + AKEYCODE_F7 = 137, + AKEYCODE_F8 = 138, + AKEYCODE_F9 = 139, + AKEYCODE_F10 = 140, + AKEYCODE_F11 = 141, + AKEYCODE_F12 = 142, + AKEYCODE_NUM_LOCK = 143, + AKEYCODE_NUMPAD_0 = 144, + AKEYCODE_NUMPAD_1 = 145, + AKEYCODE_NUMPAD_2 = 146, + AKEYCODE_NUMPAD_3 = 147, + AKEYCODE_NUMPAD_4 = 148, + AKEYCODE_NUMPAD_5 = 149, + AKEYCODE_NUMPAD_6 = 150, + AKEYCODE_NUMPAD_7 = 151, + AKEYCODE_NUMPAD_8 = 152, + AKEYCODE_NUMPAD_9 = 153, + AKEYCODE_NUMPAD_DIVIDE = 154, + AKEYCODE_NUMPAD_MULTIPLY = 155, + AKEYCODE_NUMPAD_SUBTRACT = 156, + AKEYCODE_NUMPAD_ADD = 157, + AKEYCODE_NUMPAD_DOT = 158, + AKEYCODE_NUMPAD_COMMA = 159, + AKEYCODE_NUMPAD_ENTER = 160, + AKEYCODE_NUMPAD_EQUALS = 161, + AKEYCODE_NUMPAD_LEFT_PAREN = 162, + AKEYCODE_NUMPAD_RIGHT_PAREN = 163, + AKEYCODE_VOLUME_MUTE = 164, + AKEYCODE_INFO = 165, + AKEYCODE_CHANNEL_UP = 166, + AKEYCODE_CHANNEL_DOWN = 167, + AKEYCODE_ZOOM_IN = 168, + AKEYCODE_ZOOM_OUT = 169, + AKEYCODE_TV = 170, + AKEYCODE_WINDOW = 171, + AKEYCODE_GUIDE = 172, + AKEYCODE_DVR = 173, + AKEYCODE_BOOKMARK = 174, + AKEYCODE_CAPTIONS = 175, + AKEYCODE_SETTINGS = 176, + AKEYCODE_TV_POWER = 177, + AKEYCODE_TV_INPUT = 178, + AKEYCODE_STB_POWER = 179, + AKEYCODE_STB_INPUT = 180, + AKEYCODE_AVR_POWER = 181, + AKEYCODE_AVR_INPUT = 182, + AKEYCODE_PROG_RED = 183, + AKEYCODE_PROG_GREEN = 184, + AKEYCODE_PROG_YELLOW = 185, + AKEYCODE_PROG_BLUE = 186, + AKEYCODE_APP_SWITCH = 187, + AKEYCODE_BUTTON_1 = 188, + AKEYCODE_BUTTON_2 = 189, + AKEYCODE_BUTTON_3 = 190, + AKEYCODE_BUTTON_4 = 191, + AKEYCODE_BUTTON_5 = 192, + AKEYCODE_BUTTON_6 = 193, + AKEYCODE_BUTTON_7 = 194, + AKEYCODE_BUTTON_8 = 195, + AKEYCODE_BUTTON_9 = 196, + AKEYCODE_BUTTON_10 = 197, + AKEYCODE_BUTTON_11 = 198, + AKEYCODE_BUTTON_12 = 199, + AKEYCODE_BUTTON_13 = 200, + AKEYCODE_BUTTON_14 = 201, + AKEYCODE_BUTTON_15 = 202, + AKEYCODE_BUTTON_16 = 203, + AKEYCODE_LANGUAGE_SWITCH = 204, + AKEYCODE_MANNER_MODE = 205, + AKEYCODE_3D_MODE = 206, + AKEYCODE_CONTACTS = 207, + AKEYCODE_CALENDAR = 208, + AKEYCODE_MUSIC = 209, + AKEYCODE_CALCULATOR = 210, + + // NOTE: If you add a new keycode here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. +}; + +#ifdef __cplusplus +} +#endif + +#endif // _ANDROID_KEYCODES_H diff --git a/widget/gonk/libui/cutils_log.h b/widget/gonk/libui/cutils_log.h new file mode 100644 index 00000000000..2997a0cee10 --- /dev/null +++ b/widget/gonk/libui/cutils_log.h @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2005 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. + */ + +// +// C/C++ logging functions. See the logging documentation for API details. +// +// We'd like these to be available from C code (in case we import some from +// somewhere), so this has a C interface. +// +// The output will be correct when the log file is shared between multiple +// threads and/or multiple processes so long as the operating system +// supports O_APPEND. These calls have mutex-protected data structures +// and so are NOT reentrant. Do not use LOG in a signal handler. +// +#ifndef _LIBS_CUTILS_LOG_H +#define _LIBS_CUTILS_LOG_H + +#include +#include +#include +#include +#ifdef HAVE_PTHREADS +#include +#endif +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------- + +/* + * Normally we strip ALOGV (VERBOSE messages) from release builds. + * You can modify this (for example with "#define LOG_NDEBUG 0" + * at the top of your source file) to change that behavior. + */ +#ifndef LOG_NDEBUG +#ifdef NDEBUG +#define LOG_NDEBUG 1 +#else +#define LOG_NDEBUG 0 +#endif +#endif + +/* + * This is the local tag used for the following simplified + * logging macros. You can change this preprocessor definition + * before using the other macros to change the tag. + */ +#ifndef LOG_TAG +#define LOG_TAG NULL +#endif + +// --------------------------------------------------------------------- + +/* + * Simplified macro to send a verbose log message using the current LOG_TAG. + */ +#ifndef ALOGV +#if LOG_NDEBUG +#define ALOGV(...) ((void)0) +#else +#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#endif +// Temporary measure for code still using old LOG macros. +#ifndef LOGV +#define LOGV ALOGV +#endif +#endif + +#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) + +#ifndef ALOGV_IF +#if LOG_NDEBUG +#define ALOGV_IF(cond, ...) ((void)0) +#else +#define ALOGV_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif +// Temporary measure for code still using old LOG macros. +#ifndef LOGV_IF +#define LOGV_IF ALOGV_IF +#endif +#endif + +/* + * Simplified macro to send a debug log message using the current LOG_TAG. + */ +#ifndef ALOGD +#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +// Temporary measure for code still using old LOG macros. +#ifndef LOGD +#define LOGD ALOGD +#endif +#endif + +#ifndef ALOGD_IF +#define ALOGD_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +// Temporary measure for code still using old LOG macros. +#ifndef LOGD_IF +#define LOGD_IF ALOGD_IF +#endif +#endif + +/* + * Simplified macro to send an info log message using the current LOG_TAG. + */ +#ifndef ALOGI +#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) +// Temporary measure for code still using old LOG macros. +#ifndef LOGI +#define LOGI ALOGI +#endif +#endif + +#ifndef ALOGI_IF +#define ALOGI_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +// Temporary measure for code still using old LOG macros. +#ifndef LOGI_IF +#define LOGI_IF ALOGI_IF +#endif +#endif + +/* + * Simplified macro to send a warning log message using the current LOG_TAG. + */ +#ifndef ALOGW +#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) +// Temporary measure for code still using old LOG macros. +#ifndef LOGW +#define LOGW ALOGW +#endif +#endif + +#ifndef ALOGW_IF +#define ALOGW_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +// Temporary measure for code still using old LOG macros. +#ifndef LOGW_IF +#define LOGW_IF ALOGW_IF +#endif +#endif + +/* + * Simplified macro to send an error log message using the current LOG_TAG. + */ +#ifndef ALOGE +#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) +// Temporary measure for code still using old LOG macros. +#ifndef LOGE +#define LOGE ALOGE +#endif +#endif + +#ifndef ALOGE_IF +#define ALOGE_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +// Temporary measure for code still using old LOG macros. +#ifndef LOGE_IF +#define LOGE_IF ALOGE_IF +#endif +#endif + +// --------------------------------------------------------------------- + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * verbose priority. + */ +#ifndef IF_ALOGV +#if LOG_NDEBUG +#define IF_ALOGV() if (false) +#else +#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG) +#endif +// Temporary measure for code still using old LOG macros. +#ifndef IF_LOGV +#define IF_LOGV IF_ALOGV +#endif +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * debug priority. + */ +#ifndef IF_ALOGD +#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG) +// Temporary measure for code still using old LOG macros. +#ifndef IF_LOGD +#define IF_LOGD IF_ALOGD +#endif +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * info priority. + */ +#ifndef IF_ALOGI +#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG) +// Temporary measure for code still using old LOG macros. +#ifndef IF_LOGI +#define IF_LOGI IF_ALOGI +#endif +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * warn priority. + */ +#ifndef IF_ALOGW +#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG) +// Temporary measure for code still using old LOG macros. +#ifndef IF_LOGW +#define IF_LOGW IF_ALOGW +#endif +#endif + +/* + * Conditional based on whether the current LOG_TAG is enabled at + * error priority. + */ +#ifndef IF_ALOGE +#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG) +// Temporary measure for code still using old LOG macros. +#ifndef IF_LOGE +#define IF_LOGE IF_ALOGE +#endif +#endif + + +// --------------------------------------------------------------------- + +/* + * Simplified macro to send a verbose system log message using the current LOG_TAG. + */ +#ifndef SLOGV +#if LOG_NDEBUG +#define SLOGV(...) ((void)0) +#else +#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#endif +#endif + +#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) + +#ifndef SLOGV_IF +#if LOG_NDEBUG +#define SLOGV_IF(cond, ...) ((void)0) +#else +#define SLOGV_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif +#endif + +/* + * Simplified macro to send a debug system log message using the current LOG_TAG. + */ +#ifndef SLOGD +#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGD_IF +#define SLOGD_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send an info system log message using the current LOG_TAG. + */ +#ifndef SLOGI +#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGI_IF +#define SLOGI_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send a warning system log message using the current LOG_TAG. + */ +#ifndef SLOGW +#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGW_IF +#define SLOGW_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send an error system log message using the current LOG_TAG. + */ +#ifndef SLOGE +#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGE_IF +#define SLOGE_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + + + +// --------------------------------------------------------------------- + +/* + * Log a fatal error. If the given condition fails, this stops program + * execution like a normal assertion, but also generating the given message. + * It is NOT stripped from release builds. Note that the condition test + * is -inverted- from the normal assert() semantics. + */ +#ifndef LOG_ALWAYS_FATAL_IF +#define LOG_ALWAYS_FATAL_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ + : (void)0 ) +#endif + +#ifndef LOG_ALWAYS_FATAL +#define LOG_ALWAYS_FATAL(...) \ + ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) ) +#endif + +/* + * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that + * are stripped out of release builds. + */ +#if LOG_NDEBUG + +#ifndef LOG_FATAL_IF +#define LOG_FATAL_IF(cond, ...) ((void)0) +#endif +#ifndef LOG_FATAL +#define LOG_FATAL(...) ((void)0) +#endif + +#else + +#ifndef LOG_FATAL_IF +#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__) +#endif +#ifndef LOG_FATAL +#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) +#endif + +#endif + +/* + * Assertion that generates a log message when the assertion fails. + * Stripped out of release builds. Uses the current LOG_TAG. + */ +#ifndef ALOG_ASSERT +#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) +//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) +// Temporary measure for code still using old LOG macros. +#ifndef LOG_ASSERT +#define LOG_ASSERT ALOG_ASSERT +#endif +#endif + +// --------------------------------------------------------------------- + +/* + * Basic log message macro. + * + * Example: + * ALOG(LOG_WARN, NULL, "Failed with error %d", errno); + * + * The second argument may be NULL or "" to indicate the "global" tag. + */ +#ifndef ALOG +#define ALOG(priority, tag, ...) \ + LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) +// Temporary measure for code still using old LOG macros. +#ifndef LOG +#define LOG ALOG +#endif +#endif + +/* + * Log macro that allows you to specify a number for the priority. + */ +#ifndef LOG_PRI +#define LOG_PRI(priority, tag, ...) \ + android_printLog(priority, tag, __VA_ARGS__) +#endif + +/* + * Log macro that allows you to pass in a varargs ("args" is a va_list). + */ +#ifndef LOG_PRI_VA +#define LOG_PRI_VA(priority, tag, fmt, args) \ + android_vprintLog(priority, NULL, tag, fmt, args) +#endif + +/* + * Conditional given a desired logging priority and tag. + */ +#ifndef IF_ALOG +#define IF_ALOG(priority, tag) \ + if (android_testLog(ANDROID_##priority, tag)) +// Temporary measure for code still using old LOG macros. +#ifndef IF_LOG +#define IF_LOG IF_ALOG +#endif +#endif + +// --------------------------------------------------------------------- + +/* + * Event logging. + */ + +/* + * Event log entry types. These must match up with the declarations in + * java/android/android/util/EventLog.java. + */ +typedef enum { + EVENT_TYPE_INT = 0, + EVENT_TYPE_LONG = 1, + EVENT_TYPE_STRING = 2, + EVENT_TYPE_LIST = 3, +} AndroidEventLogType; + + +#ifndef LOG_EVENT_INT +#define LOG_EVENT_INT(_tag, _value) { \ + int intBuf = _value; \ + (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \ + sizeof(intBuf)); \ + } +#endif +#ifndef LOG_EVENT_LONG +#define LOG_EVENT_LONG(_tag, _value) { \ + long long longBuf = _value; \ + (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \ + sizeof(longBuf)); \ + } +#endif +#ifndef LOG_EVENT_STRING +#define LOG_EVENT_STRING(_tag, _value) \ + ((void) 0) /* not implemented -- must combine len with string */ +#endif +/* TODO: something for LIST */ + +/* + * =========================================================================== + * + * The stuff in the rest of this file should not be used directly. + */ + +#define android_printLog(prio, tag, fmt...) \ + __android_log_print(prio, tag, fmt) + +#define android_vprintLog(prio, cond, tag, fmt...) \ + __android_log_vprint(prio, tag, fmt) + +/* XXX Macros to work around syntax errors in places where format string + * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF + * (happens only in debug builds). + */ + +/* Returns 2nd arg. Used to substitute default value if caller's vararg list + * is empty. + */ +#define __android_second(dummy, second, ...) second + +/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise + * returns nothing. + */ +#define __android_rest(first, ...) , ## __VA_ARGS__ + +#define android_printAssert(cond, tag, fmt...) \ + __android_log_assert(cond, tag, \ + __android_second(0, ## fmt, NULL) __android_rest(fmt)) + +#define android_writeLog(prio, tag, text) \ + __android_log_write(prio, tag, text) + +#define android_bWriteLog(tag, payload, len) \ + __android_log_bwrite(tag, payload, len) +#define android_btWriteLog(tag, type, payload, len) \ + __android_log_btwrite(tag, type, payload, len) + +// TODO: remove these prototypes and their users +#define android_testLog(prio, tag) (1) +#define android_writevLog(vec,num) do{}while(0) +#define android_write1Log(str,len) do{}while (0) +#define android_setMinPriority(tag, prio) do{}while(0) +//#define android_logToCallback(func) do{}while(0) +#define android_logToFile(tag, file) (0) +#define android_logToFd(tag, fd) (0) + +typedef enum { + LOG_ID_MAIN = 0, + LOG_ID_RADIO = 1, + LOG_ID_EVENTS = 2, + LOG_ID_SYSTEM = 3, + + LOG_ID_MAX +} log_id_t; + +/* + * Send a simple string to the log. + */ +int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); +int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...); + + +#ifdef __cplusplus +} +#endif + +#endif // _LIBS_CUTILS_LOG_H diff --git a/widget/gonk/libui/linux_input.h b/widget/gonk/libui/linux_input.h new file mode 100644 index 00000000000..4045eb0c8ea --- /dev/null +++ b/widget/gonk/libui/linux_input.h @@ -0,0 +1,815 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _INPUT_H +#define _INPUT_H +#include +#include +#include +#include +struct input_event { + struct timeval time; + __u16 type; + __u16 code; + __s32 value; +}; +#define EV_VERSION 0x010001 +struct input_id { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; +struct input_absinfo { + __s32 value; + __s32 minimum; + __s32 maximum; + __s32 fuzz; + __s32 flat; + __s32 resolution; +}; +struct input_keymap_entry { +#define INPUT_KEYMAP_BY_INDEX (1 << 0) + __u8 flags; + __u8 len; + __u16 index; + __u32 keycode; + __u8 scancode[32]; +}; +#define EVIOCGVERSION _IOR('E', 0x01, int) +#define EVIOCGID _IOR('E', 0x02, struct input_id) +#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) +#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) +#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) +#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) +#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) +#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) +#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) +#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) +#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) +#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) +#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) +#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) +#define EVIOCRMFF _IOW('E', 0x81, int) +#define EVIOCGEFFECTS _IOR('E', 0x84, int) +#define EVIOCGRAB _IOW('E', 0x90, int) +#define INPUT_PROP_POINTER 0x00 +#define INPUT_PROP_DIRECT 0x01 +#define INPUT_PROP_BUTTONPAD 0x02 +#define INPUT_PROP_SEMI_MT 0x03 +#define INPUT_PROP_MAX 0x1f +#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f +#define EV_CNT (EV_MAX+1) +#define SYN_REPORT 0 +#define SYN_CONFIG 1 +#define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 +#define KEY_ZENKAKUHANKAKU 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_RO 89 +#define KEY_KATAKANA 90 +#define KEY_HIRAGANA 91 +#define KEY_HENKAN 92 +#define KEY_KATAKANAHIRAGANA 93 +#define KEY_MUHENKAN 94 +#define KEY_KPJPCOMMA 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_SCALE 120 +#define KEY_KPCOMMA 121 +#define KEY_HANGEUL 122 +#define KEY_HANGUEL KEY_HANGEUL +#define KEY_HANJA 123 +#define KEY_YEN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 +#define KEY_STOP 128 +#define KEY_AGAIN 129 +#define KEY_PROPS 130 +#define KEY_UNDO 131 +#define KEY_FRONT 132 +#define KEY_COPY 133 +#define KEY_OPEN 134 +#define KEY_PASTE 135 +#define KEY_FIND 136 +#define KEY_CUT 137 +#define KEY_HELP 138 +#define KEY_MENU 139 +#define KEY_CALC 140 +#define KEY_SETUP 141 +#define KEY_SLEEP 142 +#define KEY_WAKEUP 143 +#define KEY_FILE 144 +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 +#define KEY_SCREENLOCK KEY_COFFEE +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 +#define KEY_COMPUTER 157 +#define KEY_BACK 158 +#define KEY_FORWARD 159 +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 +#define KEY_ISO 170 +#define KEY_CONFIG 171 +#define KEY_HOMEPAGE 172 +#define KEY_REFRESH 173 +#define KEY_EXIT 174 +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 +#define KEY_NEW 181 +#define KEY_REDO 182 +#define KEY_F13 183 +#define KEY_F14 184 +#define KEY_F15 185 +#define KEY_F16 186 +#define KEY_F17 187 +#define KEY_F18 188 +#define KEY_F19 189 +#define KEY_F20 190 +#define KEY_F21 191 +#define KEY_F22 192 +#define KEY_F23 193 +#define KEY_F24 194 +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_DASHBOARD 204 +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 +#define KEY_MEDIA 226 +#define KEY_SWITCHVIDEOMODE 227 +#define KEY_KBDILLUMTOGGLE 228 +#define KEY_KBDILLUMDOWN 229 +#define KEY_KBDILLUMUP 230 +#define KEY_SEND 231 +#define KEY_REPLY 232 +#define KEY_FORWARDMAIL 233 +#define KEY_SAVE 234 +#define KEY_DOCUMENTS 235 +#define KEY_BATTERY 236 +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 +#define KEY_UWB 239 +#define KEY_UNKNOWN 240 +#define KEY_VIDEO_NEXT 241 +#define KEY_VIDEO_PREV 242 +#define KEY_BRIGHTNESS_CYCLE 243 +#define KEY_BRIGHTNESS_ZERO 244 +#define KEY_DISPLAY_OFF 245 +#define KEY_WIMAX 246 +#define KEY_RFKILL 247 +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e +#define BTN_TOOL_QUADTAP 0x14f +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_ZOOM 0x174 +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_SCREEN 0x177 +#define KEY_PC 0x178 +#define KEY_TV 0x179 +#define KEY_TV2 0x17a +#define KEY_VCR 0x17b +#define KEY_VCR2 0x17c +#define KEY_SAT 0x17d +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f +#define KEY_TAPE 0x180 +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 +#define KEY_VIDEO 0x189 +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 +#define KEY_CHANNELDOWN 0x193 +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f +#define KEY_VIDEOPHONE 0x1a0 +#define KEY_GAMES 0x1a1 +#define KEY_ZOOMIN 0x1a2 +#define KEY_ZOOMOUT 0x1a3 +#define KEY_ZOOMRESET 0x1a4 +#define KEY_WORDPROCESSOR 0x1a5 +#define KEY_EDITOR 0x1a6 +#define KEY_SPREADSHEET 0x1a7 +#define KEY_GRAPHICSEDITOR 0x1a8 +#define KEY_PRESENTATION 0x1a9 +#define KEY_DATABASE 0x1aa +#define KEY_NEWS 0x1ab +#define KEY_VOICEMAIL 0x1ac +#define KEY_ADDRESSBOOK 0x1ad +#define KEY_MESSENGER 0x1ae +#define KEY_DISPLAYTOGGLE 0x1af +#define KEY_SPELLCHECK 0x1b0 +#define KEY_LOGOFF 0x1b1 +#define KEY_DOLLAR 0x1b2 +#define KEY_EURO 0x1b3 +#define KEY_FRAMEBACK 0x1b4 +#define KEY_FRAMEFORWARD 0x1b5 +#define KEY_CONTEXT_MENU 0x1b6 +#define KEY_MEDIA_REPEAT 0x1b7 +#define KEY_10CHANNELSUP 0x1b8 +#define KEY_10CHANNELSDOWN 0x1b9 +#define KEY_IMAGES 0x1ba +#define KEY_DEL_EOL 0x1c0 +#define KEY_DEL_EOS 0x1c1 +#define KEY_INS_LINE 0x1c2 +#define KEY_DEL_LINE 0x1c3 +#define KEY_FN 0x1d0 +#define KEY_FN_ESC 0x1d1 +#define KEY_FN_F1 0x1d2 +#define KEY_FN_F2 0x1d3 +#define KEY_FN_F3 0x1d4 +#define KEY_FN_F4 0x1d5 +#define KEY_FN_F5 0x1d6 +#define KEY_FN_F6 0x1d7 +#define KEY_FN_F7 0x1d8 +#define KEY_FN_F8 0x1d9 +#define KEY_FN_F9 0x1da +#define KEY_FN_F10 0x1db +#define KEY_FN_F11 0x1dc +#define KEY_FN_F12 0x1dd +#define KEY_FN_1 0x1de +#define KEY_FN_2 0x1df +#define KEY_FN_D 0x1e0 +#define KEY_FN_E 0x1e1 +#define KEY_FN_F 0x1e2 +#define KEY_FN_S 0x1e3 +#define KEY_FN_B 0x1e4 +#define KEY_BRL_DOT1 0x1f1 +#define KEY_BRL_DOT2 0x1f2 +#define KEY_BRL_DOT3 0x1f3 +#define KEY_BRL_DOT4 0x1f4 +#define KEY_BRL_DOT5 0x1f5 +#define KEY_BRL_DOT6 0x1f6 +#define KEY_BRL_DOT7 0x1f7 +#define KEY_BRL_DOT8 0x1f8 +#define KEY_BRL_DOT9 0x1f9 +#define KEY_BRL_DOT10 0x1fa +#define KEY_NUMERIC_0 0x200 +#define KEY_NUMERIC_1 0x201 +#define KEY_NUMERIC_2 0x202 +#define KEY_NUMERIC_3 0x203 +#define KEY_NUMERIC_4 0x204 +#define KEY_NUMERIC_5 0x205 +#define KEY_NUMERIC_6 0x206 +#define KEY_NUMERIC_7 0x207 +#define KEY_NUMERIC_8 0x208 +#define KEY_NUMERIC_9 0x209 +#define KEY_NUMERIC_STAR 0x20a +#define KEY_NUMERIC_POUND 0x20b +#define KEY_CAMERA_FOCUS 0x210 +#define KEY_WPS_BUTTON 0x211 +#define KEY_TOUCHPAD_TOGGLE 0x212 +#define KEY_TOUCHPAD_ON 0x213 +#define KEY_TOUCHPAD_OFF 0x214 +#define KEY_CAMERA_ZOOMIN 0x215 +#define KEY_CAMERA_ZOOMOUT 0x216 +#define KEY_CAMERA_UP 0x217 +#define KEY_CAMERA_DOWN 0x218 +#define KEY_CAMERA_LEFT 0x219 +#define KEY_CAMERA_RIGHT 0x21a +#define BTN_TRIGGER_HAPPY 0x2c0 +#define BTN_TRIGGER_HAPPY1 0x2c0 +#define BTN_TRIGGER_HAPPY2 0x2c1 +#define BTN_TRIGGER_HAPPY3 0x2c2 +#define BTN_TRIGGER_HAPPY4 0x2c3 +#define BTN_TRIGGER_HAPPY5 0x2c4 +#define BTN_TRIGGER_HAPPY6 0x2c5 +#define BTN_TRIGGER_HAPPY7 0x2c6 +#define BTN_TRIGGER_HAPPY8 0x2c7 +#define BTN_TRIGGER_HAPPY9 0x2c8 +#define BTN_TRIGGER_HAPPY10 0x2c9 +#define BTN_TRIGGER_HAPPY11 0x2ca +#define BTN_TRIGGER_HAPPY12 0x2cb +#define BTN_TRIGGER_HAPPY13 0x2cc +#define BTN_TRIGGER_HAPPY14 0x2cd +#define BTN_TRIGGER_HAPPY15 0x2ce +#define BTN_TRIGGER_HAPPY16 0x2cf +#define BTN_TRIGGER_HAPPY17 0x2d0 +#define BTN_TRIGGER_HAPPY18 0x2d1 +#define BTN_TRIGGER_HAPPY19 0x2d2 +#define BTN_TRIGGER_HAPPY20 0x2d3 +#define BTN_TRIGGER_HAPPY21 0x2d4 +#define BTN_TRIGGER_HAPPY22 0x2d5 +#define BTN_TRIGGER_HAPPY23 0x2d6 +#define BTN_TRIGGER_HAPPY24 0x2d7 +#define BTN_TRIGGER_HAPPY25 0x2d8 +#define BTN_TRIGGER_HAPPY26 0x2d9 +#define BTN_TRIGGER_HAPPY27 0x2da +#define BTN_TRIGGER_HAPPY28 0x2db +#define BTN_TRIGGER_HAPPY29 0x2dc +#define BTN_TRIGGER_HAPPY30 0x2dd +#define BTN_TRIGGER_HAPPY31 0x2de +#define BTN_TRIGGER_HAPPY32 0x2df +#define BTN_TRIGGER_HAPPY33 0x2e0 +#define BTN_TRIGGER_HAPPY34 0x2e1 +#define BTN_TRIGGER_HAPPY35 0x2e2 +#define BTN_TRIGGER_HAPPY36 0x2e3 +#define BTN_TRIGGER_HAPPY37 0x2e4 +#define BTN_TRIGGER_HAPPY38 0x2e5 +#define BTN_TRIGGER_HAPPY39 0x2e6 +#define BTN_TRIGGER_HAPPY40 0x2e7 +#define KEY_MIN_INTERESTING KEY_MUTE +#define KEY_MAX 0x2ff +#define KEY_CNT (KEY_MAX+1) +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f +#define REL_CNT (REL_MAX+1) +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MT_SLOT 0x2f +#define ABS_MT_TOUCH_MAJOR 0x30 +#define ABS_MT_TOUCH_MINOR 0x31 +#define ABS_MT_WIDTH_MAJOR 0x32 +#define ABS_MT_WIDTH_MINOR 0x33 +#define ABS_MT_ORIENTATION 0x34 +#define ABS_MT_POSITION_X 0x35 +#define ABS_MT_POSITION_Y 0x36 +#define ABS_MT_TOOL_TYPE 0x37 +#define ABS_MT_BLOB_ID 0x38 +#define ABS_MT_TRACKING_ID 0x39 +#define ABS_MT_PRESSURE 0x3a +#define ABS_MT_DISTANCE 0x3b +#define ABS_MAX 0x3f +#define ABS_CNT (ABS_MAX+1) +#define SW_LID 0x00 +#define SW_TABLET_MODE 0x01 +#define SW_HEADPHONE_INSERT 0x02 +#define SW_RFKILL_ALL 0x03 +#define SW_RADIO SW_RFKILL_ALL +#define SW_MICROPHONE_INSERT 0x04 +#define SW_DOCK 0x05 +#define SW_LINEOUT_INSERT 0x06 +#define SW_JACK_PHYSICAL_INSERT 0x07 +#define SW_VIDEOOUT_INSERT 0x08 +#define SW_CAMERA_LENS_COVER 0x09 +#define SW_KEYPAD_SLIDE 0x0a +#define SW_FRONT_PROXIMITY 0x0b +#define SW_ROTATE_LOCK 0x0c +#define SW_MAX 0x0f +#define SW_CNT (SW_MAX+1) +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_MAX 0x07 +#define MSC_CNT (MSC_MAX+1) +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAIL 0x09 +#define LED_CHARGING 0x0a +#define LED_MAX 0x0f +#define LED_CNT (LED_MAX+1) +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 +#define REP_CNT (REP_MAX+1) +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_TONE 0x02 +#define SND_MAX 0x07 +#define SND_CNT (SND_MAX+1) +#define ID_BUS 0 +#define ID_VENDOR 1 +#define ID_PRODUCT 2 +#define ID_VERSION 3 +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 +#define BUS_GSC 0x1A +#define BUS_ATARI 0x1B +#define BUS_SPI 0x1C +#define MT_TOOL_FINGER 0 +#define MT_TOOL_PEN 1 +#define MT_TOOL_MAX 1 +#define FF_STATUS_STOPPED 0x00 +#define FF_STATUS_PLAYING 0x01 +#define FF_STATUS_MAX 0x01 +struct ff_replay { + __u16 length; + __u16 delay; +}; +struct ff_trigger { + __u16 button; + __u16 interval; +}; +struct ff_envelope { + __u16 attack_length; + __u16 attack_level; + __u16 fade_length; + __u16 fade_level; +}; +struct ff_constant_effect { + __s16 level; + struct ff_envelope envelope; +}; +struct ff_ramp_effect { + __s16 start_level; + __s16 end_level; + struct ff_envelope envelope; +}; +struct ff_condition_effect { + __u16 right_saturation; + __u16 left_saturation; + __s16 right_coeff; + __s16 left_coeff; + __u16 deadband; + __s16 center; +}; +struct ff_periodic_effect { + __u16 waveform; + __u16 period; + __s16 magnitude; + __s16 offset; + __u16 phase; + struct ff_envelope envelope; + __u32 custom_len; + __s16 *custom_data; +}; +struct ff_rumble_effect { + __u16 strong_magnitude; + __u16 weak_magnitude; +}; +struct ff_effect { + __u16 type; + __s16 id; + __u16 direction; + struct ff_trigger trigger; + struct ff_replay replay; + union { + struct ff_constant_effect constant; + struct ff_ramp_effect ramp; + struct ff_periodic_effect periodic; + struct ff_condition_effect condition[2]; + struct ff_rumble_effect rumble; + } u; +}; +#define FF_RUMBLE 0x50 +#define FF_PERIODIC 0x51 +#define FF_CONSTANT 0x52 +#define FF_SPRING 0x53 +#define FF_FRICTION 0x54 +#define FF_DAMPER 0x55 +#define FF_INERTIA 0x56 +#define FF_RAMP 0x57 +#define FF_EFFECT_MIN FF_RUMBLE +#define FF_EFFECT_MAX FF_RAMP +#define FF_SQUARE 0x58 +#define FF_TRIANGLE 0x59 +#define FF_SINE 0x5a +#define FF_SAW_UP 0x5b +#define FF_SAW_DOWN 0x5c +#define FF_CUSTOM 0x5d +#define FF_WAVEFORM_MIN FF_SQUARE +#define FF_WAVEFORM_MAX FF_CUSTOM +#define FF_GAIN 0x60 +#define FF_AUTOCENTER 0x61 +#define FF_MAX 0x7f +#define FF_CNT (FF_MAX+1) +#endif + diff --git a/widget/gonk/libui/utils_Log.h b/widget/gonk/libui/utils_Log.h new file mode 100644 index 00000000000..66ea7d31307 --- /dev/null +++ b/widget/gonk/libui/utils_Log.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2005 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. + */ + +// +// C/C++ logging functions. See the logging documentation for API details. +// +// We'd like these to be available from C code (in case we import some from +// somewhere), so this has a C interface. +// +// The output will be correct when the log file is shared between multiple +// threads and/or multiple processes so long as the operating system +// supports O_APPEND. These calls have mutex-protected data structures +// and so are NOT reentrant. Do not use LOG in a signal handler. +// +#ifndef _LIBS_UTILS_LOG_H +#define _LIBS_UTILS_LOG_H + +#include "cutils_log.h" + +#endif // _LIBS_UTILS_LOG_H diff --git a/widget/gonk/nsAppShell.cpp b/widget/gonk/nsAppShell.cpp index 57ba60bcce1..80cb46702ba 100644 --- a/widget/gonk/nsAppShell.cpp +++ b/widget/gonk/nsAppShell.cpp @@ -678,7 +678,8 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) for (int i = 0; i < event_count; i++) mHandlers[events[i].data.u32].run(); - mDispatcher->dispatchOnce(); + if (mDispatcher.get()) + mDispatcher->dispatchOnce(); // NativeEventCallback always schedules more if it needs it // so we can coalesce these. diff --git a/xpcom/base/nsSystemInfo.cpp b/xpcom/base/nsSystemInfo.cpp index d29af934743..39525461314 100644 --- a/xpcom/base/nsSystemInfo.cpp +++ b/xpcom/base/nsSystemInfo.cpp @@ -51,7 +51,13 @@ #ifdef MOZ_WIDGET_ANDROID #include "AndroidBridge.h" +#endif +#ifdef MOZ_WIDGET_GONK +#include +#endif + +#ifdef ANDROID extern "C" { NS_EXPORT int android_sdk_version; } @@ -204,6 +210,13 @@ nsSystemInfo::Init() SetPropertyAsBool(NS_LITERAL_STRING("tablet"), isTablet); } #endif + +#ifdef MOZ_WIDGET_GONK + char sdk[PROP_VALUE_MAX]; + if (__system_property_get("ro.build.version.sdk", sdk)) + android_sdk_version = atoi(sdk); +#endif + return NS_OK; }