am cb27bc7d: am 0846a2f5: cherrypick Change-Id: I7033e605213db4b5c73c09c2207bed68a704aa72 docs: update sitemap add new webmaster tools verification file
* commit 'cb27bc7d29685182ad0694ce7830664bcb758203':
cherrypick Change-Id: I7033e605213db4b5c73c09c2207bed68a704aa72 docs: update sitemap add new webmaster tools verification file
diff --git a/NOTICE b/NOTICE
index 2006201..8d6f583 100644
--- a/NOTICE
+++ b/NOTICE
@@ -17,7 +17,7 @@
=========================================================================
Apache Commons
-Copyright 1999-2004 The Apache Software Foundation
+Copyright 1999-2006 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
@@ -53,6 +53,26 @@
These files are Copyright 1998 - 2009 PacketVideo, but released under
the Apache2 License.
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the TagSoup code. ==
+ =========================================================================
+
+This file is part of TagSoup and is Copyright 2002-2008 by John Cowan.
+
+TagSoup is licensed under the Apache License,
+Version 2.0. You may obtain a copy of this license at
+http://www.apache.org/licenses/LICENSE-2.0 . You may also have
+additional legal rights not granted by this license.
+
+TagSoup is distributed in the hope that it will be useful, but
+unless required by applicable law or agreed to in writing, TagSoup
+is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, either express or implied; not even the implied warranty
+of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
new file mode 100644
index 0000000..4fbff2a
--- /dev/null
+++ b/include/binder/CursorWindow.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID__DATABASE_WINDOW_H
+#define _ANDROID__DATABASE_WINDOW_H
+
+#include <cutils/log.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <binder/IMemory.h>
+#include <utils/RefBase.h>
+
+#define DEFAULT_WINDOW_SIZE 4096
+#define MAX_WINDOW_SIZE (1024 * 1024)
+#define WINDOW_ALLOCATION_SIZE 4096
+
+#define ROW_SLOT_CHUNK_NUM_ROWS 16
+
+// Row slots are allocated in chunks of ROW_SLOT_CHUNK_NUM_ROWS,
+// with an offset after the rows that points to the next chunk
+#define ROW_SLOT_CHUNK_SIZE ((ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)) + sizeof(uint32_t))
+
+
+#if LOG_NDEBUG
+
+#define IF_LOG_WINDOW() if (false)
+#define LOG_WINDOW(...)
+
+#else
+
+#define IF_LOG_WINDOW() IF_LOG(LOG_DEBUG, "CursorWindow")
+#define LOG_WINDOW(...) LOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__)
+
+#endif
+
+
+// When defined to true strings are stored as UTF8, otherwise they're UTF16
+#define WINDOW_STORAGE_UTF8 1
+
+// When defined to true numberic values are stored inline in the field_slot_t, otherwise they're allocated in the window
+#define WINDOW_STORAGE_INLINE_NUMERICS 1
+
+namespace android {
+
+typedef struct
+{
+ uint32_t numRows;
+ uint32_t numColumns;
+} window_header_t;
+
+typedef struct
+{
+ uint32_t offset;
+} row_slot_t;
+
+typedef struct
+{
+ uint8_t type;
+ union {
+ double d;
+ int64_t l;
+ struct {
+ uint32_t offset;
+ uint32_t size;
+ } buffer;
+ } data;
+} __attribute__((packed)) field_slot_t;
+
+#define FIELD_TYPE_NULL 0
+#define FIELD_TYPE_INTEGER 1
+#define FIELD_TYPE_FLOAT 2
+#define FIELD_TYPE_STRING 3
+#define FIELD_TYPE_BLOB 4
+
+/**
+ * This class stores a set of rows from a database in a buffer. The begining of the
+ * window has first chunk of row_slot_ts, which are offsets to the row directory, followed by
+ * an offset to the next chunk in a linked-list of additional chunk of row_slot_ts in case
+ * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
+ * field_slot_t per column, which has the size, offset, and type of the data for that field.
+ * Note that the data types come from sqlite3.h.
+ */
+class CursorWindow
+{
+public:
+ CursorWindow(size_t maxSize);
+ CursorWindow(){}
+ bool setMemory(const sp<IMemory>&);
+ ~CursorWindow();
+
+ bool initBuffer(bool localOnly);
+ sp<IMemory> getMemory() {return mMemory;}
+
+ size_t size() {return mSize;}
+ uint8_t * data() {return mData;}
+ uint32_t getNumRows() {return mHeader->numRows;}
+ uint32_t getNumColumns() {return mHeader->numColumns;}
+ void freeLastRow() {
+ if (mHeader->numRows > 0) {
+ mHeader->numRows--;
+ }
+ }
+ bool setNumColumns(uint32_t numColumns)
+ {
+ uint32_t cur = mHeader->numColumns;
+ if (cur > 0 && cur != numColumns) {
+ LOGE("Trying to go from %d columns to %d", cur, numColumns);
+ return false;
+ }
+ mHeader->numColumns = numColumns;
+ return true;
+ }
+
+ int32_t freeSpace();
+
+ void clear();
+
+ /**
+ * Allocate a row slot and its directory. The returned
+ * pointer points to the begining of the row's directory
+ * or NULL if there wasn't room. The directory is
+ * initialied with NULL entries for each field.
+ */
+ field_slot_t * allocRow();
+
+ /**
+ * Allocate a portion of the window. Returns the offset
+ * of the allocation, or 0 if there isn't enough space.
+ * If aligned is true, the allocation gets 4 byte alignment.
+ */
+ uint32_t alloc(size_t size, bool aligned = false);
+
+ uint32_t read_field_slot(int row, int column, field_slot_t * slot);
+
+ /**
+ * Copy data into the window at the given offset.
+ */
+ void copyIn(uint32_t offset, uint8_t const * data, size_t size);
+ void copyIn(uint32_t offset, int64_t data);
+ void copyIn(uint32_t offset, double data);
+
+ void copyOut(uint32_t offset, uint8_t * data, size_t size);
+ int64_t copyOutLong(uint32_t offset);
+ double copyOutDouble(uint32_t offset);
+
+ bool putLong(unsigned int row, unsigned int col, int64_t value);
+ bool putDouble(unsigned int row, unsigned int col, double value);
+ bool putNull(unsigned int row, unsigned int col);
+
+ bool getLong(unsigned int row, unsigned int col, int64_t * valueOut);
+ bool getDouble(unsigned int row, unsigned int col, double * valueOut);
+ bool getNull(unsigned int row, unsigned int col, bool * valueOut);
+
+ uint8_t * offsetToPtr(uint32_t offset) {return mData + offset;}
+
+ row_slot_t * allocRowSlot();
+
+ row_slot_t * getRowSlot(int row);
+
+ /**
+ * return NULL if Failed to find rowSlot or
+ * Invalid rowSlot
+ */
+ field_slot_t * getFieldSlotWithCheck(int row, int column);
+ field_slot_t * getFieldSlot(int row, int column)
+ {
+ int fieldDirOffset = getRowSlot(row)->offset;
+ return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
+ }
+
+private:
+ uint8_t * mData;
+ size_t mSize;
+ size_t mMaxSize;
+ window_header_t * mHeader;
+ sp<IMemory> mMemory;
+
+ /**
+ * Offset of the lowest unused data byte in the array.
+ */
+ uint32_t mFreeOffset;
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index b54718f..3378d97 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -33,6 +33,7 @@
{
public:
static IPCThreadState* self();
+ static IPCThreadState* selfOrNull(); // self(), but won't instantiate
sp<ProcessState> process();
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index d6ae5e9..9d589cf 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -285,6 +285,8 @@
uint32_t getTransform(int buffer) const;
status_t resize(int newNumBuffers);
+ status_t grow(int newNumBuffers);
+ status_t shrink(int newNumBuffers);
SharedBufferStack::Statistics getStats() const;
@@ -346,6 +348,14 @@
int mNumBuffers;
BufferList mBufferList;
+ struct BuffersAvailableCondition : public ConditionBase {
+ int mNumBuffers;
+ inline BuffersAvailableCondition(SharedBufferServer* sbs,
+ int numBuffers);
+ inline bool operator()() const;
+ inline const char* name() const { return "BuffersAvailableCondition"; }
+ };
+
struct UnlockUpdate : public UpdateBase {
const int lockedBuffer;
inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
diff --git a/include/private/ui/sw_gralloc_handle.h b/include/private/ui/sw_gralloc_handle.h
deleted file mode 100644
index b3d333e..0000000
--- a/include/private/ui/sw_gralloc_handle.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_UI_PRIVATE_SW_GRALLOC_HANDLE_H
-#define ANDROID_UI_PRIVATE_SW_GRALLOC_HANDLE_H
-
-#include <stdint.h>
-#include <limits.h>
-#include <sys/cdefs.h>
-#include <hardware/gralloc.h>
-#include <errno.h>
-
-#include <cutils/native_handle.h>
-
-namespace android {
-
-/*****************************************************************************/
-
-struct sw_gralloc_handle_t : public native_handle
-{
- // file-descriptors
- int fd;
- // ints
- int magic;
- int size;
- int base;
- int prot;
- int pid;
-
- static const int sNumInts = 5;
- static const int sNumFds = 1;
- static const int sMagic = '_sgh';
-
- sw_gralloc_handle_t() :
- fd(-1), magic(sMagic), size(0), base(0), prot(0), pid(getpid())
- {
- version = sizeof(native_handle);
- numInts = sNumInts;
- numFds = sNumFds;
- }
- ~sw_gralloc_handle_t() {
- magic = 0;
- }
-
- static int validate(const native_handle* h) {
- const sw_gralloc_handle_t* hnd = (const sw_gralloc_handle_t*)h;
- if (!h || h->version != sizeof(native_handle) ||
- h->numInts != sNumInts || h->numFds != sNumFds ||
- hnd->magic != sMagic)
- {
- return -EINVAL;
- }
- return 0;
- }
-
- static status_t alloc(uint32_t w, uint32_t h, int format,
- int usage, buffer_handle_t* handle, int32_t* stride);
- static status_t free(sw_gralloc_handle_t* hnd);
- static status_t registerBuffer(sw_gralloc_handle_t* hnd);
- static status_t unregisterBuffer(sw_gralloc_handle_t* hnd);
- static status_t lock(sw_gralloc_handle_t* hnd, int usage,
- int l, int t, int w, int h, void** vaddr);
- static status_t unlock(sw_gralloc_handle_t* hnd);
-};
-
-/*****************************************************************************/
-
-}; // namespace android
-
-#endif /* ANDROID_UI_PRIVATE_SW_GRALLOC_HANDLE_H */
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index ddbe03d..cd0ee40 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -34,18 +34,15 @@
typedef int32_t SurfaceID;
-class IMemoryHeap;
-class OverlayRef;
class GraphicBuffer;
class ISurface : public IInterface
{
protected:
enum {
- REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
- UNREGISTER_BUFFERS,
- POST_BUFFER, // one-way transaction
- CREATE_OVERLAY,
+ RESERVED0 = IBinder::FIRST_CALL_TRANSACTION,
+ RESERVED1,
+ RESERVED2,
REQUEST_BUFFER,
SET_BUFFER_COUNT,
};
@@ -66,49 +63,6 @@
* sets the number of buffers dequeuable for this surface.
*/
virtual status_t setBufferCount(int bufferCount) = 0;
-
- // ------------------------------------------------------------------------
- // Deprecated...
- // ------------------------------------------------------------------------
-
- class BufferHeap {
- public:
- enum {
- /* rotate source image */
- ROT_0 = 0,
- ROT_90 = HAL_TRANSFORM_ROT_90,
- ROT_180 = HAL_TRANSFORM_ROT_180,
- ROT_270 = HAL_TRANSFORM_ROT_270,
- };
- BufferHeap();
-
- BufferHeap(uint32_t w, uint32_t h,
- int32_t hor_stride, int32_t ver_stride,
- PixelFormat format, const sp<IMemoryHeap>& heap);
-
- BufferHeap(uint32_t w, uint32_t h,
- int32_t hor_stride, int32_t ver_stride,
- PixelFormat format, uint32_t transform, uint32_t flags,
- const sp<IMemoryHeap>& heap);
-
- ~BufferHeap();
-
- uint32_t w;
- uint32_t h;
- int32_t hor_stride;
- int32_t ver_stride;
- PixelFormat format;
- uint32_t transform;
- uint32_t flags;
- sp<IMemoryHeap> heap;
- };
-
- virtual status_t registerBuffers(const BufferHeap& buffers) = 0;
- virtual void postBuffer(ssize_t offset) = 0; // one-way
- virtual void unregisterBuffers() = 0;
-
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format, int32_t orientation) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index da4d56f..693fbfb 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -42,7 +42,7 @@
eDestroyBackbuffer = 0x00000020,
eSecure = 0x00000080,
eNonPremultiplied = 0x00000100,
- ePushBuffers = 0x00000200,
+ eOpaque = 0x00000400,
eFXSurfaceNormal = 0x00000000,
eFXSurfaceBlur = 0x00010000,
@@ -121,7 +121,8 @@
virtual status_t captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight) = 0;
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
virtual status_t turnElectronBeamOff(int32_t mode) = 0;
virtual status_t turnElectronBeamOn(int32_t mode) = 0;
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 22684db..2df8ca3 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -94,7 +94,7 @@
friend class SurfaceComposerClient;
// camera and camcorder need access to the ISurface binder interface for preview
- friend class Camera;
+ friend class CameraService;
friend class MediaRecorder;
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
@@ -173,11 +173,12 @@
* (eventually this should go away and be replaced by proper APIs)
*/
// camera and camcorder need access to the ISurface binder interface for preview
- friend class Camera;
+ friend class CameraService;
friend class MediaRecorder;
// MediaPlayer needs access to ISurface for display
friend class MediaPlayer;
friend class IOMX;
+ friend class SoftwareRenderer;
// this is just to be able to write some unit tests
friend class Test;
@@ -248,7 +249,7 @@
uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const;
- static void cleanCachedSurfaces();
+ static void cleanCachedSurfacesLocked();
class BufferInfo {
uint32_t mWidth;
@@ -314,4 +315,3 @@
}; // namespace android
#endif // ANDROID_SF_SURFACE_H
-
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index a80832d..25b2ebf 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -183,6 +183,8 @@
// frees the previous screenshot and capture a new one
status_t update();
status_t update(uint32_t reqWidth, uint32_t reqHeight);
+ status_t update(uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
// release memory occupied by the screenshot
void release();
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index d78e35f..6c6c297 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -18,13 +18,19 @@
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
-#include <android/input.h>
+#include <ui/Input.h>
+#include <ui/Keyboard.h>
+#include <ui/KeyLayoutMap.h>
+#include <ui/KeyCharacterMap.h>
+#include <ui/VirtualKeyMap.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
+#include <utils/PropertyMap.h>
+#include <utils/Vector.h>
#include <linux/input.h>
@@ -57,8 +63,6 @@
namespace android {
-class KeyLayoutMap;
-
/*
* A raw event as retrieved from the EventHub.
*/
@@ -155,6 +159,8 @@
virtual String8 getDeviceName(int32_t deviceId) const = 0;
+ virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
+
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const = 0;
@@ -187,6 +193,12 @@
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags) const = 0;
+ virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
+ virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
+
+ virtual void getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
+
virtual void dump(String8& dump) = 0;
};
@@ -198,9 +210,11 @@
status_t errorCheck() const;
virtual uint32_t getDeviceClasses(int32_t deviceId) const;
-
+
virtual String8 getDeviceName(int32_t deviceId) const;
-
+
+ virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
+
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const;
@@ -218,6 +232,12 @@
virtual bool getEvent(RawEvent* outEvent);
+ virtual bool hasLed(int32_t deviceId, int32_t led) const;
+ virtual void setLedState(int32_t deviceId, int32_t led, bool on);
+
+ virtual void getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const;
+
virtual void dump(String8& dump);
protected:
@@ -226,71 +246,80 @@
private:
bool openPlatformInput(void);
- int openDevice(const char *device);
- int closeDevice(const char *device);
+ int openDevice(const char *devicePath);
+ int closeDevice(const char *devicePath);
int scanDir(const char *dirname);
int readNotify(int nfd);
status_t mError;
- struct device_t {
- const int32_t id;
- const String8 path;
- String8 name;
- uint32_t classes;
- uint8_t* keyBitmask;
- KeyLayoutMap* layoutMap;
- String8 keylayoutFilename;
- int fd;
- device_t* next;
-
- device_t(int32_t _id, const char* _path, const char* name);
- ~device_t();
+ struct Device {
+ Device* next;
+
+ int fd;
+ const int32_t id;
+ const String8 path;
+ const InputDeviceIdentifier identifier;
+
+ uint32_t classes;
+ uint8_t* keyBitmask;
+ String8 configurationFile;
+ PropertyMap* configuration;
+ VirtualKeyMap* virtualKeyMap;
+ KeyMap keyMap;
+
+ Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
+ ~Device();
+
+ void close();
};
- device_t* getDeviceLocked(int32_t deviceId) const;
- bool hasKeycodeLocked(device_t* device, int keycode) const;
-
- int32_t getScanCodeStateLocked(device_t* device, int32_t scanCode) const;
- int32_t getKeyCodeStateLocked(device_t* device, int32_t keyCode) const;
- int32_t getSwitchStateLocked(device_t* device, int32_t sw) const;
- bool markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
+ Device* getDeviceLocked(int32_t deviceId) const;
+ bool hasKeycodeLocked(Device* device, int keycode) const;
+
+ int32_t getScanCodeStateLocked(Device* device, int32_t scanCode) const;
+ int32_t getKeyCodeStateLocked(Device* device, int32_t keyCode) const;
+ int32_t getSwitchStateLocked(Device* device, int32_t sw) const;
+ bool markSupportedKeyCodesLocked(Device* device, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
- // Protect all internal state.
- mutable Mutex mLock;
-
- bool mHaveFirstKeyboard;
- int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
-
- struct device_ent {
- device_t* device;
- uint32_t seq;
- };
- device_ent *mDevicesById;
- int mNumDevicesById;
-
- device_t *mOpeningDevices;
- device_t *mClosingDevices;
-
- device_t **mDevices;
- struct pollfd *mFDs;
- int mFDCount;
+ void loadConfiguration(Device* device);
+ status_t loadVirtualKeyMap(Device* device);
+ status_t loadKeyMap(Device* device);
+ void setKeyboardProperties(Device* device, bool builtInKeyboard);
+ void clearKeyboardProperties(Device* device, bool builtInKeyboard);
- bool mOpened;
- bool mNeedToSendFinishedDeviceScan;
- List<String8> mExcludedDevices;
+ // Protect all internal state.
+ mutable Mutex mLock;
+
+ // The actual id of the built-in keyboard, or -1 if none.
+ // EventHub remaps the built-in keyboard to id 0 externally as required by the API.
+ int32_t mBuiltInKeyboardId;
+
+ int32_t mNextDeviceId;
+
+ // Parallel arrays of fds and devices.
+ // First index is reserved for inotify.
+ Vector<struct pollfd> mFds;
+ Vector<Device*> mDevices;
+
+ Device *mOpeningDevices;
+ Device *mClosingDevices;
+
+ bool mOpened;
+ bool mNeedToSendFinishedDeviceScan;
+ List<String8> mExcludedDevices;
// device ids that report particular switches.
#ifdef EV_SW
- int32_t mSwitches[SW_MAX + 1];
+ int32_t mSwitches[SW_MAX + 1];
#endif
static const int INPUT_BUFFER_SIZE = 64;
struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
- int32_t mInputBufferIndex;
- int32_t mInputBufferCount;
- int32_t mInputDeviceIndex;
+ size_t mInputBufferIndex;
+ size_t mInputBufferCount;
+ size_t mInputFdIndex;
};
}; // namespace android
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 2cd0911..16117ad 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -23,6 +23,7 @@
#include <EGL/egl.h>
#include <utils/threads.h>
+#include <utils/String8.h>
#include <ui/Rect.h>
#include <pixelflinger/pixelflinger.h>
@@ -56,7 +57,9 @@
bool isUpdateOnDemand() const { return mUpdateOnDemand; }
status_t setUpdateRectangle(const Rect& updateRect);
status_t compositionComplete();
-
+
+ void dump(String8& result);
+
// for debugging only
int getCurrentBufferIndex() const;
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 0be26a7..aa65d93 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -26,8 +26,6 @@
#include <utils/Flattenable.h>
#include <pixelflinger/pixelflinger.h>
-#include <hardware/hardware.h>
-
struct android_native_buffer_t;
namespace android {
@@ -65,13 +63,6 @@
USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK
};
- enum {
- TRANSFORM_IDENTITY = 0,
- TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
- TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
- TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270
- };
-
GraphicBuffer();
// creates w * h buffer
@@ -81,6 +72,9 @@
GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
uint32_t stride, native_handle_t* handle, bool keepOwnership);
+ // create a buffer from an existing android_native_buffer_t
+ GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership);
+
// return status
status_t initCheck() const;
@@ -88,7 +82,6 @@
uint32_t getHeight() const { return height; }
uint32_t getStride() const { return stride; }
uint32_t getUsage() const { return usage; }
- uint32_t getTransform() const { return transform; }
PixelFormat getPixelFormat() const { return format; }
Rect getBounds() const { return Rect(width, height); }
@@ -150,6 +143,10 @@
GraphicBufferMapper& mBufferMapper;
ssize_t mInitCheck;
int mIndex;
+
+ // If we're wrapping another buffer then this reference will make sure it
+ // doesn't get freed.
+ sp<android_native_buffer_t> mWrappedBuffer;
};
}; // namespace android
diff --git a/include/ui/IOverlay.h b/include/ui/IOverlay.h
deleted file mode 100644
index af3add1..0000000
--- a/include/ui/IOverlay.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007 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_IOVERLAY_H
-#define ANDROID_IOVERLAY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <utils/RefBase.h>
-#include <ui/PixelFormat.h>
-
-namespace android {
-
-class IOverlay : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(Overlay);
-
- virtual void destroy() = 0; // one-way
-};
-
-// ----------------------------------------------------------------------------
-
-class BnOverlay : public BnInterface<IOverlay>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IOVERLAY_H
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 8c6018b..27f65bc 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -76,7 +76,7 @@
*/
enum {
/* These flags originate in RawEvents and are generally set in the key map.
- * See also labels for policy flags in KeycodeLabels.h. */
+ * NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */
POLICY_FLAG_WAKE = 0x00000001,
POLICY_FLAG_WAKE_DROPPED = 0x00000002,
@@ -87,6 +87,7 @@
POLICY_FLAG_MENU = 0x00000040,
POLICY_FLAG_LAUNCHER = 0x00000080,
POLICY_FLAG_VIRTUAL = 0x00000100,
+ POLICY_FLAG_FUNCTION = 0x00000200,
POLICY_FLAG_RAW_MASK = 0x0000ffff,
@@ -496,6 +497,54 @@
KeyedVector<int32_t, MotionRange> mMotionRanges;
};
+/*
+ * Identifies a device.
+ */
+struct InputDeviceIdentifier {
+ inline InputDeviceIdentifier() :
+ bus(0), vendor(0), product(0), version(0) {
+ }
+
+ String8 name;
+ String8 location;
+ String8 uniqueId;
+ uint16_t bus;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+};
+
+/* Types of input device configuration files. */
+enum InputDeviceConfigurationFileType {
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
+};
+
+/*
+ * Gets the path of an input device configuration file, if one is available.
+ * Considers both system provided and user installed configuration files.
+ *
+ * The device identifier is used to construct several default configuration file
+ * names to try based on the device name, vendor, product, and version.
+ *
+ * Returns an empty string if not found.
+ */
+extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ const InputDeviceIdentifier& deviceIdentifier,
+ InputDeviceConfigurationFileType type);
+
+/*
+ * Gets the path of an input device configuration file, if one is available.
+ * Considers both system provided and user installed configuration files.
+ *
+ * The name is case-sensitive and is used to construct the filename to resolve.
+ * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
+ *
+ * Returns an empty string if not found.
+ */
+extern String8 getInputDeviceConfigurationFilePathByName(
+ const String8& name, InputDeviceConfigurationFileType type);
} // namespace android
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 5f77cba..7305601 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -179,8 +179,10 @@
TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11,
TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13,
- TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14,
+ TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+14,
TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
+ TYPE_DRAG = FIRST_SYSTEM_WINDOW+16,
+ TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+17,
LAST_SYSTEM_WINDOW = 2999,
};
@@ -219,6 +221,8 @@
* motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
*/
bool isTrustedOverlay() const;
+
+ bool supportsSplitTouch() const;
};
@@ -287,9 +291,7 @@
* This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
* should be dispatched to applications.
*/
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags) = 0;
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0;
/* Intercepts a generic touch, trackball or other event before queueing it.
* The policy can use this method as an opportunity to perform power management functions
@@ -304,6 +306,11 @@
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
+ /* Allows the policy a chance to perform default processing for an unhandled key.
+ * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
+ virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+ const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;
+
/* Notifies the policy about switch events.
*/
virtual void notifySwitch(nsecs_t when,
@@ -387,6 +394,14 @@
*/
virtual void setInputDispatchMode(bool enabled, bool frozen) = 0;
+ /* Transfers touch focus from the window associated with one channel to the
+ * window associated with the other channel.
+ *
+ * Returns true on success. False if the window did not actually have touch focus.
+ */
+ virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel) = 0;
+
/* Registers or unregister input channels that may be used as targets for input events.
* If monitor is true, the channel will receive a copy of all input events.
*
@@ -443,6 +458,9 @@
virtual void setFocusedApplication(const InputApplication* inputApplication);
virtual void setInputDispatchMode(bool enabled, bool frozen);
+ virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel);
+
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
@@ -598,6 +616,7 @@
sp<InputChannel> inputChannel;
sp<InputApplicationHandle> inputApplicationHandle;
int32_t userActivityEventType;
+ bool handled;
};
// Generic queue implementation.
@@ -717,6 +736,7 @@
CANCEL_ALL_EVENTS = 0,
CANCEL_POINTER_EVENTS = 1,
CANCEL_NON_POINTER_EVENTS = 2,
+ CANCEL_FALLBACK_EVENTS = 3,
};
InputState();
@@ -744,12 +764,16 @@
// Clears the current state.
void clear();
+ // Copies pointer-related parts of the input state to another instance.
+ void copyPointerStateTo(InputState& other) const;
+
private:
struct KeyMemento {
int32_t deviceId;
int32_t source;
int32_t keyCode;
int32_t scanCode;
+ int32_t flags;
nsecs_t downTime;
};
@@ -769,7 +793,10 @@
Vector<KeyMemento> mKeyMementos;
Vector<MotionMemento> mMotionMementos;
- static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options);
+ static bool shouldCancelKey(const KeyMemento& memento,
+ CancelationOptions options);
+ static bool shouldCancelMotion(const MotionMemento& memento,
+ CancelationOptions options);
};
/* Manages the dispatch state associated with a single input channel. */
@@ -871,9 +898,6 @@
// Input channels that will receive a copy of all input events.
Vector<sp<InputChannel> > mMonitoringChannels;
- // Preallocated key event object used for policy inquiries.
- KeyEvent mReusableKeyEvent;
-
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
@@ -927,7 +951,7 @@
struct TouchedWindow {
const InputWindow* window;
int32_t targetFlags;
- BitSet32 pointerIds;
+ BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
sp<InputChannel> channel;
};
struct TouchState {
@@ -1016,7 +1040,8 @@
EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
- void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+ void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
+ bool handled);
void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void drainOutboundQueueLocked(Connection* connection);
@@ -1047,7 +1072,7 @@
void onDispatchCycleStartedLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection);
+ nsecs_t currentTime, const sp<Connection>& connection, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onANRLocked(
@@ -1059,7 +1084,9 @@
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
+ void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
+ void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
// Statistics gathering.
void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 49351b0..b466ff1 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -35,34 +35,6 @@
class InputDevice;
class InputMapper;
-/* Describes a virtual key. */
-struct VirtualKeyDefinition {
- int32_t scanCode;
-
- // configured position data, specified in display coords
- int32_t centerX;
- int32_t centerY;
- int32_t width;
- int32_t height;
-};
-
-
-/* Specifies input device calibration settings. */
-class InputDeviceCalibration {
-public:
- InputDeviceCalibration();
-
- void clear();
- void addProperty(const String8& key, const String8& value);
-
- bool tryGetProperty(const String8& key, String8& outValue) const;
- bool tryGetProperty(const String8& key, int32_t& outValue) const;
- bool tryGetProperty(const String8& key, float& outValue) const;
-
-private:
- KeyedVector<String8, String8> mProperties;
-};
-
/*
* Input reader policy interface.
@@ -103,14 +75,6 @@
*/
virtual bool filterJumpyTouchEvents() = 0;
- /* Gets the configured virtual key definitions for an input device. */
- virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
-
- /* Gets the calibration for an input device. */
- virtual void getInputDeviceCalibration(const String8& deviceName,
- InputDeviceCalibration& outCalibration) = 0;
-
/* Gets the excluded device names for the platform. */
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
};
@@ -314,8 +278,8 @@
int32_t getMetaState();
- inline const InputDeviceCalibration& getCalibration() {
- return mCalibration;
+ inline const PropertyMap& getConfiguration() {
+ return mConfiguration;
}
private:
@@ -330,7 +294,7 @@
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
- InputDeviceCalibration mCalibration;
+ PropertyMap mConfiguration;
};
@@ -389,13 +353,13 @@
class KeyboardInputMapper : public InputMapper {
public:
- KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId, uint32_t sources,
- int32_t keyboardType);
+ KeyboardInputMapper(InputDevice* device, uint32_t sources, int32_t keyboardType);
virtual ~KeyboardInputMapper();
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
virtual void dump(String8& dump);
+ virtual void configure();
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -414,35 +378,58 @@
int32_t scanCode;
};
- int32_t mAssociatedDisplayId;
uint32_t mSources;
int32_t mKeyboardType;
+ // Immutable configuration parameters.
+ struct Parameters {
+ int32_t associatedDisplayId;
+ bool orientationAware;
+ } mParameters;
+
struct LockedState {
Vector<KeyDown> keyDowns; // keys that are down
int32_t metaState;
nsecs_t downTime; // time of most recent key down
+
+ struct LedState {
+ bool avail; // led is available
+ bool on; // we think the led is currently on
+ };
+ LedState capsLockLedState;
+ LedState numLockLedState;
+ LedState scrollLockLedState;
} mLocked;
void initializeLocked();
+ void configureParameters();
+ void dumpParameters(String8& dump);
+
bool isKeyboardOrGamepadKey(int32_t scanCode);
void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
uint32_t policyFlags);
ssize_t findKeyDownLocked(int32_t scanCode);
+
+ void resetLedStateLocked();
+ void initializeLedStateLocked(LockedState::LedState& ledState, int32_t led);
+ void updateLedStateLocked(bool reset);
+ void updateLedStateForModifierLocked(LockedState::LedState& ledState, int32_t led,
+ int32_t modifier, bool reset);
};
class TrackballInputMapper : public InputMapper {
public:
- TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ TrackballInputMapper(InputDevice* device);
virtual ~TrackballInputMapper();
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
virtual void dump(String8& dump);
+ virtual void configure();
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -454,7 +441,11 @@
Mutex mLock;
- int32_t mAssociatedDisplayId;
+ // Immutable configuration parameters.
+ struct Parameters {
+ int32_t associatedDisplayId;
+ bool orientationAware;
+ } mParameters;
struct Accumulator {
enum {
@@ -486,13 +477,16 @@
void initializeLocked();
+ void configureParameters();
+ void dumpParameters(String8& dump);
+
void sync(nsecs_t when);
};
class TouchInputMapper : public InputMapper {
public:
- TouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ TouchInputMapper(InputDevice* device);
virtual ~TouchInputMapper();
virtual uint32_t getSources();
@@ -578,10 +572,17 @@
}
};
- int32_t mAssociatedDisplayId;
-
// Immutable configuration parameters.
struct Parameters {
+ enum DeviceType {
+ DEVICE_TYPE_TOUCH_SCREEN,
+ DEVICE_TYPE_TOUCH_PAD,
+ };
+
+ DeviceType deviceType;
+ int32_t associatedDisplayId;
+ bool orientationAware;
+
bool useBadTouchFilter;
bool useJumpyTouchFilter;
bool useAveragingTouchFilter;
@@ -589,6 +590,16 @@
// Immutable calibration parameters in parsed form.
struct Calibration {
+ // Position
+ bool haveXOrigin;
+ int32_t xOrigin;
+ bool haveYOrigin;
+ int32_t yOrigin;
+ bool haveXScale;
+ float xScale;
+ bool haveYScale;
+ float yScale;
+
// Touch Size
enum TouchSizeCalibration {
TOUCH_SIZE_CALIBRATION_DEFAULT,
@@ -618,7 +629,7 @@
bool haveToolSizeAreaBias;
float toolSizeAreaBias;
bool haveToolSizeIsSummed;
- int32_t toolSizeIsSummed;
+ bool toolSizeIsSummed;
// Pressure
enum PressureCalibration {
@@ -823,7 +834,7 @@
class SingleTouchInputMapper : public TouchInputMapper {
public:
- SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ SingleTouchInputMapper(InputDevice* device);
virtual ~SingleTouchInputMapper();
virtual void reset();
@@ -869,7 +880,7 @@
class MultiTouchInputMapper : public TouchInputMapper {
public:
- MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ MultiTouchInputMapper(InputDevice* device);
virtual ~MultiTouchInputMapper();
virtual void reset();
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index dc9e27a..119db81 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -250,12 +250,13 @@
status_t sendDispatchSignal();
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
+ * Returns whether the consumer handled the message.
*
* Returns OK on success.
* Returns WOULD_BLOCK if there is no signal present.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveFinishedSignal();
+ status_t receiveFinishedSignal(bool* outHandled);
private:
sp<InputChannel> mChannel;
@@ -305,12 +306,12 @@
status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
/* Sends a finished signal to the publisher to inform it that the current message is
- * finished processing.
+ * finished processing and specifies whether the message was handled by the consumer.
*
* Returns OK on success.
* Errors probably indicate that the channel is broken.
*/
- status_t sendFinishedSignal();
+ status_t sendFinishedSignal(bool handled);
/* Receives the dispatched signal from the publisher.
*
diff --git a/include/ui/KeyCharacterMap.h b/include/ui/KeyCharacterMap.h
index bad2cf8..10a3810 100644
--- a/include/ui/KeyCharacterMap.h
+++ b/include/ui/KeyCharacterMap.h
@@ -18,55 +18,183 @@
#define _UI_KEY_CHARACTER_MAP_H
#include <stdint.h>
-#include <utils/Vector.h>
-using namespace android;
+#include <ui/Input.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Tokenizer.h>
+#include <utils/String8.h>
+#include <utils/Unicode.h>
-class KeyCharacterMap
-{
+namespace android {
+
+/**
+ * Describes a mapping from Android key codes to characters.
+ * Also specifies other functions of the keyboard such as the keyboard type
+ * and key modifier semantics.
+ */
+class KeyCharacterMap {
public:
+ enum KeyboardType {
+ KEYBOARD_TYPE_UNKNOWN = 0,
+ KEYBOARD_TYPE_NUMERIC = 1,
+ KEYBOARD_TYPE_PREDICTIVE = 2,
+ KEYBOARD_TYPE_ALPHA = 3,
+ KEYBOARD_TYPE_FULL = 4,
+ KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
+ };
+
+ // Substitute key code and meta state for fallback action.
+ struct FallbackAction {
+ int32_t keyCode;
+ int32_t metaState;
+ };
+
~KeyCharacterMap();
- // see the javadoc for android.text.method.KeyCharacterMap for what
- // these do
- unsigned short get(int keycode, int meta);
- unsigned short getNumber(int keycode);
- unsigned short getMatch(int keycode, const unsigned short* chars,
- int charsize, uint32_t modifiers);
- unsigned short getDisplayLabel(int keycode);
- bool getKeyData(int keycode, unsigned short *displayLabel,
- unsigned short *number, unsigned short* results);
- inline unsigned int getKeyboardType() { return m_type; }
- bool getEvents(uint16_t* chars, size_t len,
- Vector<int32_t>* keys, Vector<uint32_t>* modifiers);
+ static status_t load(const String8& filename, KeyCharacterMap** outMap);
+ static status_t loadByDeviceId(int32_t deviceId, KeyCharacterMap** outMap);
- static KeyCharacterMap* load(int id);
+ /* Gets the keyboard type. */
+ int32_t getKeyboardType() const;
- enum {
- NUMERIC = 1,
- Q14 = 2,
- QWERTY = 3 // or AZERTY or whatever
- };
+ /* Gets the primary character for this key as in the label physically printed on it.
+ * Returns 0 if none (eg. for non-printing keys). */
+ char16_t getDisplayLabel(int32_t keyCode) const;
-#define META_MASK 3
+ /* Gets the Unicode character for the number or symbol generated by the key
+ * when the keyboard is used as a dialing pad.
+ * Returns 0 if no number or symbol is generated.
+ */
+ char16_t getNumber(int32_t keyCode) const;
+
+ /* Gets the Unicode character generated by the key and meta key modifiers.
+ * Returns 0 if no character is generated.
+ */
+ char16_t getCharacter(int32_t keyCode, int32_t metaState) const;
+
+ /* Gets the fallback action to use by default if the application does not
+ * handle the specified key.
+ * Returns true if an action was available, false if none.
+ */
+ bool getFallbackAction(int32_t keyCode, int32_t metaState,
+ FallbackAction* outFallbackAction) const;
+
+ /* Gets the first matching Unicode character that can be generated by the key,
+ * preferring the one with the specified meta key modifiers.
+ * Returns 0 if no matching character is generated.
+ */
+ char16_t getMatch(int32_t keyCode, const char16_t* chars,
+ size_t numChars, int32_t metaState) const;
+
+ /* Gets a sequence of key events that could plausibly generate the specified
+ * character sequence. Returns false if some of the characters cannot be generated.
+ */
+ bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
+ Vector<KeyEvent>& outEvents) const;
private:
- struct Key
- {
- int32_t keycode;
- uint16_t display_label;
- uint16_t number;
- uint16_t data[META_MASK + 1];
+ struct Behavior {
+ Behavior();
+
+ /* The next behavior in the list, or NULL if none. */
+ Behavior* next;
+
+ /* The meta key modifiers for this behavior. */
+ int32_t metaState;
+
+ /* The character to insert. */
+ char16_t character;
+
+ /* The fallback keycode if the key is not handled. */
+ int32_t fallbackKeyCode;
};
- KeyCharacterMap();
- static KeyCharacterMap* try_file(const char* filename);
- Key* find_key(int keycode);
- bool find_char(uint16_t c, uint32_t* key, uint32_t* mods);
+ struct Key {
+ Key();
+ ~Key();
- unsigned int m_type;
- unsigned int m_keyCount;
- Key* m_keys;
+ /* The single character label printed on the key, or 0 if none. */
+ char16_t label;
+
+ /* The number or symbol character generated by the key, or 0 if none. */
+ char16_t number;
+
+ /* The list of key behaviors sorted from most specific to least specific
+ * meta key binding. */
+ Behavior* firstBehavior;
+ };
+
+ class Parser {
+ enum State {
+ STATE_TOP = 0,
+ STATE_KEY = 1,
+ };
+
+ enum {
+ PROPERTY_LABEL = 1,
+ PROPERTY_NUMBER = 2,
+ PROPERTY_META = 3,
+ };
+
+ struct Property {
+ inline Property(int32_t property = 0, int32_t metaState = 0) :
+ property(property), metaState(metaState) { }
+
+ int32_t property;
+ int32_t metaState;
+ };
+
+ KeyCharacterMap* mMap;
+ Tokenizer* mTokenizer;
+ State mState;
+ int32_t mKeyCode;
+
+ public:
+ Parser(KeyCharacterMap* 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<int32_t, Key*> mKeys;
+ int mType;
+
+ KeyCharacterMap();
+
+ bool getKey(int32_t keyCode, const Key** outKey) const;
+ bool getKeyBehavior(int32_t keyCode, int32_t metaState,
+ const Key** outKey, const Behavior** outBehavior) const;
+
+ bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
+
+ static void addKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
+ static void addMetaKeys(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
+ int32_t* currentMetaState);
+ static bool addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
+ int32_t keyCode, int32_t keyMetaState,
+ int32_t* currentMetaState);
+ static void addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
+ int32_t leftKeyCode, int32_t leftKeyMetaState,
+ int32_t rightKeyCode, int32_t rightKeyMetaState,
+ int32_t eitherKeyMetaState,
+ int32_t* currentMetaState);
+ static void addLockedMetaKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, nsecs_t time,
+ int32_t keyCode, int32_t keyMetaState,
+ int32_t* currentMetaState);
};
+} // namespace android
+
#endif // _UI_KEY_CHARACTER_MAP_H
diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h
new file mode 100644
index 0000000..f0a6d00
--- /dev/null
+++ b/include/ui/KeyLayoutMap.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_KEY_LAYOUT_MAP_H
+#define _UI_KEY_LAYOUT_MAP_H
+
+#include <stdint.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Tokenizer.h>
+
+namespace android {
+
+/**
+ * Describes a mapping from keyboard scan codes to Android key codes.
+ */
+class KeyLayoutMap {
+public:
+ ~KeyLayoutMap();
+
+ static status_t load(const String8& filename, KeyLayoutMap** outMap);
+
+ status_t map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
+ status_t findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
+
+private:
+ struct Key {
+ int32_t keyCode;
+ uint32_t flags;
+ };
+
+ KeyedVector<int32_t,Key> mKeys;
+
+ KeyLayoutMap();
+
+ class Parser {
+ KeyLayoutMap* mMap;
+ Tokenizer* mTokenizer;
+
+ public:
+ Parser(KeyLayoutMap* map, Tokenizer* tokenizer);
+ ~Parser();
+ status_t parse();
+
+ private:
+ status_t parseKey();
+ };
+};
+
+} // namespace android
+
+#endif // _UI_KEY_LAYOUT_MAP_H
diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h
new file mode 100644
index 0000000..50296e2
--- /dev/null
+++ b/include/ui/Keyboard.h
@@ -0,0 +1,120 @@
+/*
+ * 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_KEYBOARD_H
+#define _UI_KEYBOARD_H
+
+#include <ui/Input.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/PropertyMap.h>
+
+namespace android {
+
+enum {
+ /* Device id of the built in keyboard. */
+ DEVICE_ID_BUILT_IN_KEYBOARD = 0,
+
+ /* Device id of a generic virtual keyboard with a full layout that can be used
+ * to synthesize key events. */
+ DEVICE_ID_VIRTUAL_KEYBOARD = -1,
+};
+
+class KeyLayoutMap;
+class KeyCharacterMap;
+
+/**
+ * Loads the key layout map and key character map for a keyboard device.
+ */
+class KeyMap {
+public:
+ String8 keyLayoutFile;
+ KeyLayoutMap* keyLayoutMap;
+
+ String8 keyCharacterMapFile;
+ KeyCharacterMap* keyCharacterMap;
+
+ KeyMap();
+ ~KeyMap();
+
+ status_t load(const InputDeviceIdentifier& deviceIdenfier,
+ const PropertyMap* deviceConfiguration);
+
+ inline bool haveKeyLayout() const {
+ return !keyLayoutFile.isEmpty();
+ }
+
+ inline bool haveKeyCharacterMap() const {
+ return !keyCharacterMapFile.isEmpty();
+ }
+
+ inline bool isComplete() const {
+ return haveKeyLayout() && haveKeyCharacterMap();
+ }
+
+private:
+ bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+ status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+ status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name);
+ String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name, InputDeviceConfigurationFileType type);
+};
+
+/**
+ * Returns true if the keyboard is eligible for use as a built-in keyboard.
+ */
+extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
+ const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
+
+/**
+ * Sets keyboard system properties.
+ */
+extern void setKeyboardProperties(int32_t deviceId, const InputDeviceIdentifier& deviceIdentifier,
+ const String8& keyLayoutFile, const String8& keyCharacterMapFile);
+
+/**
+ * Clears keyboard system properties.
+ */
+extern void clearKeyboardProperties(int32_t deviceId);
+
+/**
+ * Gets the key character map filename for a device using inspecting system properties
+ * and then falling back on a default key character map if necessary.
+ * Returns a NAME_NOT_FOUND if none found.
+ */
+extern status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile);
+
+/**
+ * Gets a key code by its short form label, eg. "HOME".
+ * Returns 0 if unknown.
+ */
+extern int32_t getKeyCodeByLabel(const char* label);
+
+/**
+ * Gets a key flag by its short form label, eg. "WAKE".
+ * Returns 0 if unknown.
+ */
+extern uint32_t getKeyFlagByLabel(const char* label);
+
+/**
+ * Updates a meta state field when a key is pressed or released.
+ */
+extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
+
+} // namespace android
+
+#endif // _UI_KEYBOARD_H
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index f71d9cd..9b1a897 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -135,6 +135,83 @@
{ "BUTTON_START", 108 },
{ "BUTTON_SELECT", 109 },
{ "BUTTON_MODE", 110 },
+ { "ESCAPE", 111 },
+ { "FORWARD_DEL", 112 },
+ { "CTRL_LEFT", 113 },
+ { "CTRL_RIGHT", 114 },
+ { "CAPS_LOCK", 115 },
+ { "SCROLL_LOCK", 116 },
+ { "META_LEFT", 117 },
+ { "META_RIGHT", 118 },
+ { "FUNCTION", 119 },
+ { "SYSRQ", 120 },
+ { "BREAK", 121 },
+ { "MOVE_HOME", 122 },
+ { "MOVE_END", 123 },
+ { "INSERT", 124 },
+ { "FORWARD", 125 },
+ { "MEDIA_PLAY", 126 },
+ { "MEDIA_PAUSE", 127 },
+ { "MEDIA_CLOSE", 128 },
+ { "MEDIA_EJECT", 129 },
+ { "MEDIA_RECORD", 130 },
+ { "F1", 131 },
+ { "F2", 132 },
+ { "F3", 133 },
+ { "F4", 134 },
+ { "F5", 135 },
+ { "F6", 136 },
+ { "F7", 137 },
+ { "F8", 138 },
+ { "F9", 139 },
+ { "F10", 140 },
+ { "F11", 141 },
+ { "F12", 142 },
+ { "NUM_LOCK", 143 },
+ { "NUMPAD_0", 144 },
+ { "NUMPAD_1", 145 },
+ { "NUMPAD_2", 146 },
+ { "NUMPAD_3", 147 },
+ { "NUMPAD_4", 148 },
+ { "NUMPAD_5", 149 },
+ { "NUMPAD_6", 150 },
+ { "NUMPAD_7", 151 },
+ { "NUMPAD_8", 152 },
+ { "NUMPAD_9", 153 },
+ { "NUMPAD_DIVIDE", 154 },
+ { "NUMPAD_MULTIPLY", 155 },
+ { "NUMPAD_SUBTRACT", 156 },
+ { "NUMPAD_ADD", 157 },
+ { "NUMPAD_DOT", 158 },
+ { "NUMPAD_COMMA", 159 },
+ { "NUMPAD_ENTER", 160 },
+ { "NUMPAD_EQUALS", 161 },
+ { "NUMPAD_LEFT_PAREN", 162 },
+ { "NUMPAD_RIGHT_PAREN", 163 },
+ { "VOLUME_MUTE", 164 },
+ { "INFO", 165 },
+ { "CHANNEL_UP", 166 },
+ { "CHANNEL_DOWN", 167 },
+ { "ZOOM_IN", 168 },
+ { "ZOOM_OUT", 169 },
+ { "TV", 170 },
+ { "WINDOW", 171 },
+ { "GUIDE", 172 },
+ { "DVR", 173 },
+ { "BOOKMARK", 174 },
+ { "CAPTIONS", 175 },
+ { "SETTINGS", 176 },
+ { "TV_POWER", 177 },
+ { "TV_INPUT", 178 },
+ { "STB_POWER", 179 },
+ { "STB_INPUT", 180 },
+ { "AVR_POWER", 181 },
+ { "AVR_INPUT", 182 },
+ { "PROG_RED", 183 },
+ { "PROG_GREEN", 184 },
+ { "PROG_YELLOW", 185 },
+ { "PROG_BLUE", 186 },
+ { "APP_SWITCH", 187 },
// 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.
@@ -142,7 +219,7 @@
{ NULL, 0 }
};
-// See also policy flags in Input.h.
+// NOTE: If you edit these flags, also edit policy flags in Input.h.
static const KeycodeLabel FLAGS[] = {
{ "WAKE", 0x00000001 },
{ "WAKE_DROPPED", 0x00000002 },
@@ -153,6 +230,7 @@
{ "MENU", 0x00000040 },
{ "LAUNCHER", 0x00000080 },
{ "VIRTUAL", 0x00000100 },
+ { "FUNCTION", 0x00000200 },
{ NULL, 0 }
};
diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h
deleted file mode 100644
index a9ae1c4..0000000
--- a/include/ui/Overlay.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2007 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_OVERLAY_H
-#define ANDROID_OVERLAY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-
-#include <ui/PixelFormat.h>
-#include <ui/IOverlay.h>
-
-#include <hardware/overlay.h>
-
-namespace android {
-
-class IMemory;
-class IMemoryHeap;
-
-// ----------------------------------------------------------------------------
-
-class OverlayRef : public LightRefBase<OverlayRef>
-{
-public:
- OverlayRef(overlay_handle_t, const sp<IOverlay>&,
- uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs);
-
- static sp<OverlayRef> readFromParcel(const Parcel& data);
- static status_t writeToParcel(Parcel* reply, const sp<OverlayRef>& o);
-
-private:
- friend class LightRefBase<OverlayRef>;
- friend class Overlay;
-
- OverlayRef();
- virtual ~OverlayRef();
-
- overlay_handle_t mOverlayHandle;
- sp<IOverlay> mOverlayChannel;
- uint32_t mWidth;
- uint32_t mHeight;
- int32_t mFormat;
- int32_t mWidthStride;
- int32_t mHeightStride;
- bool mOwnHandle;
-};
-
-// ----------------------------------------------------------------------------
-
-class Overlay : public virtual RefBase
-{
-public:
- Overlay(const sp<OverlayRef>& overlayRef);
-
- /* destroys this overlay */
- void destroy();
-
- /* get the HAL handle for this overlay */
- overlay_handle_t getHandleRef() const;
-
- /* blocks until an overlay buffer is available and return that buffer. */
- status_t dequeueBuffer(overlay_buffer_t* buffer);
-
- /* release the overlay buffer and post it */
- status_t queueBuffer(overlay_buffer_t buffer);
-
- /* change the width and height of the overlay */
- status_t resizeInput(uint32_t width, uint32_t height);
-
- status_t setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
-
- status_t getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
-
- /* set the buffer attributes */
- status_t setParameter(int param, int value);
-
- /* returns the address of a given buffer if supported, NULL otherwise. */
- void* getBufferAddress(overlay_buffer_t buffer);
-
- /* get physical informations about the overlay */
- uint32_t getWidth() const;
- uint32_t getHeight() const;
- int32_t getFormat() const;
- int32_t getWidthStride() const;
- int32_t getHeightStride() const;
- int32_t getBufferCount() const;
- status_t getStatus() const;
-
-private:
- virtual ~Overlay();
-
- sp<OverlayRef> mOverlayRef;
- overlay_data_device_t *mOverlayData;
- status_t mStatus;
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_OVERLAY_H
diff --git a/include/ui/PowerManager.h b/include/ui/PowerManager.h
index 5434b4f..dd80318 100644
--- a/include/ui/PowerManager.h
+++ b/include/ui/PowerManager.h
@@ -22,14 +22,10 @@
enum {
POWER_MANAGER_OTHER_EVENT = 0,
- POWER_MANAGER_CHEEK_EVENT = 1,
- POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
- // up events or LONG_TOUCH events.
- POWER_MANAGER_LONG_TOUCH_EVENT = 3,
- POWER_MANAGER_TOUCH_UP_EVENT = 4,
- POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
+ POWER_MANAGER_BUTTON_EVENT = 1,
+ POWER_MANAGER_TOUCH_EVENT = 2,
- POWER_MANAGER_LAST_EVENT = POWER_MANAGER_BUTTON_EVENT, // Last valid event code.
+ POWER_MANAGER_LAST_EVENT = POWER_MANAGER_TOUCH_EVENT, // Last valid event code.
};
} // namespace android
diff --git a/include/ui/VirtualKeyMap.h b/include/ui/VirtualKeyMap.h
new file mode 100644
index 0000000..7813d9d
--- /dev/null
+++ b/include/ui/VirtualKeyMap.h
@@ -0,0 +1,79 @@
+/*
+ * 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_VIRTUAL_KEY_MAP_H
+#define _UI_VIRTUAL_KEY_MAP_H
+
+#include <stdint.h>
+
+#include <ui/Input.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Tokenizer.h>
+#include <utils/String8.h>
+#include <utils/Unicode.h>
+
+namespace android {
+
+/* Describes a virtual key. */
+struct VirtualKeyDefinition {
+ int32_t scanCode;
+
+ // configured position data, specified in display coords
+ int32_t centerX;
+ int32_t centerY;
+ int32_t width;
+ int32_t height;
+};
+
+
+/**
+ * Describes a collection of virtual keys on a touch screen in terms of
+ * virtual scan codes and hit rectangles.
+ */
+class VirtualKeyMap {
+public:
+ ~VirtualKeyMap();
+
+ static status_t load(const String8& filename, VirtualKeyMap** outMap);
+
+ inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
+ return mVirtualKeys;
+ }
+
+private:
+ class Parser {
+ VirtualKeyMap* mMap;
+ Tokenizer* mTokenizer;
+
+ public:
+ Parser(VirtualKeyMap* map, Tokenizer* tokenizer);
+ ~Parser();
+ status_t parse();
+
+ private:
+ bool consumeFieldDelimiterAndSkipWhitespace();
+ bool parseNextIntField(int32_t* outValue);
+ };
+
+ Vector<VirtualKeyDefinition> mVirtualKeys;
+
+ VirtualKeyMap();
+};
+
+} // namespace android
+
+#endif // _UI_KEY_CHARACTER_MAP_H
diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h
index a472824..402843e 100644
--- a/include/ui/android_native_buffer.h
+++ b/include/ui/android_native_buffer.h
@@ -51,12 +51,8 @@
int stride;
int format;
int usage;
-
- /* transformation as defined in hardware.h */
- uint8_t transform;
-
- uint8_t reserved_bytes[3];
- void* reserved[1];
+
+ void* reserved[2];
buffer_handle_t handle;
diff --git a/include/utils/Asset.h b/include/utils/Asset.h
index 2a09095..1fe0e06 100644
--- a/include/utils/Asset.h
+++ b/include/utils/Asset.h
@@ -23,9 +23,11 @@
#include <stdio.h>
#include <sys/types.h>
-#include "FileMap.h"
-#include "String8.h"
-#include "Errors.h"
+
+#include <utils/Compat.h>
+#include <utils/Errors.h>
+#include <utils/FileMap.h>
+#include <utils/String8.h>
namespace android {
@@ -69,10 +71,10 @@
/*
* Seek to the specified offset. "whence" uses the same values as
- * lseek/fseek. Returns the new position on success, or (off_t) -1
+ * lseek/fseek. Returns the new position on success, or (off64_t) -1
* on failure.
*/
- virtual off_t seek(off_t offset, int whence) = 0;
+ virtual off64_t seek(off64_t offset, int whence) = 0;
/*
* Close the asset, freeing all associated resources.
@@ -87,26 +89,26 @@
/*
* Get the total amount of data that can be read.
*/
- virtual off_t getLength(void) const = 0;
+ virtual off64_t getLength(void) const = 0;
/*
* Get the total amount of data that can be read from the current position.
*/
- virtual off_t getRemainingLength(void) const = 0;
+ virtual off64_t getRemainingLength(void) const = 0;
/*
* Open a new file descriptor that can be used to read this asset.
* Returns -1 if you can not use the file descriptor (for example if the
* asset is compressed).
*/
- virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const = 0;
-
+ virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const = 0;
+
/*
* Return whether this asset's buffer is allocated in RAM (not mmapped).
* Note: not virtual so it is safe to call even when being destroyed.
*/
virtual bool isAllocated(void) const { return false; }
-
+
/*
* Get a string identifying the asset's source. This might be a full
* path, it might be a colon-separated list of identifiers.
@@ -120,7 +122,7 @@
Asset(void); // constructor; only invoked indirectly
/* handle common seek() housekeeping */
- off_t handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn);
+ off64_t handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn);
/* set the asset source string */
void setAssetSource(const String8& path) { mAssetSource = path; }
@@ -153,7 +155,7 @@
*
* The asset takes ownership of the file descriptor.
*/
- static Asset* createFromFileSegment(int fd, off_t offset, size_t length,
+ static Asset* createFromFileSegment(int fd, off64_t offset, size_t length,
AccessMode mode);
/*
@@ -166,7 +168,7 @@
* This may not verify the validity of the compressed data until first
* use.
*/
- static Asset* createFromCompressedData(int fd, off_t offset,
+ static Asset* createFromCompressedData(int fd, off64_t offset,
int compressionMethod, size_t compressedLength,
size_t uncompressedLength, AccessMode mode);
#endif
@@ -221,7 +223,7 @@
*
* On success, the object takes ownership of "fd".
*/
- status_t openChunk(const char* fileName, int fd, off_t offset, size_t length);
+ status_t openChunk(const char* fileName, int fd, off64_t offset, size_t length);
/*
* Use a memory-mapped region.
@@ -234,18 +236,18 @@
* Standard Asset interfaces.
*/
virtual ssize_t read(void* buf, size_t count);
- virtual off_t seek(off_t offset, int whence);
+ virtual off64_t seek(off64_t offset, int whence);
virtual void close(void);
virtual const void* getBuffer(bool wordAligned);
- virtual off_t getLength(void) const { return mLength; }
- virtual off_t getRemainingLength(void) const { return mLength-mOffset; }
- virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const;
+ virtual off64_t getLength(void) const { return mLength; }
+ virtual off64_t getRemainingLength(void) const { return mLength-mOffset; }
+ virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const;
virtual bool isAllocated(void) const { return mBuf != NULL; }
private:
- off_t mStart; // absolute file offset of start of chunk
- off_t mLength; // length of the chunk
- off_t mOffset; // current local offset, 0 == mStart
+ off64_t mStart; // absolute file offset of start of chunk
+ off64_t mLength; // length of the chunk
+ off64_t mOffset; // current local offset, 0 == mStart
FILE* mFp; // for read/seek
char* mFileName; // for opening
@@ -276,7 +278,7 @@
*
* On success, the object takes ownership of "fd".
*/
- status_t openChunk(int fd, off_t offset, int compressionMethod,
+ status_t openChunk(int fd, off64_t offset, int compressionMethod,
size_t uncompressedLen, size_t compressedLen);
/*
@@ -291,19 +293,19 @@
* Standard Asset interfaces.
*/
virtual ssize_t read(void* buf, size_t count);
- virtual off_t seek(off_t offset, int whence);
+ virtual off64_t seek(off64_t offset, int whence);
virtual void close(void);
virtual const void* getBuffer(bool wordAligned);
- virtual off_t getLength(void) const { return mUncompressedLen; }
- virtual off_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
- virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const { return -1; }
+ virtual off64_t getLength(void) const { return mUncompressedLen; }
+ virtual off64_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
+ virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const { return -1; }
virtual bool isAllocated(void) const { return mBuf != NULL; }
private:
- off_t mStart; // offset to start of compressed data
- off_t mCompressedLen; // length of the compressed data
- off_t mUncompressedLen; // length of the uncompressed data
- off_t mOffset; // current offset, 0 == start of uncomp data
+ off64_t mStart; // offset to start of compressed data
+ off64_t mCompressedLen; // length of the compressed data
+ off64_t mUncompressedLen; // length of the uncompressed data
+ off64_t mOffset; // current offset, 0 == start of uncomp data
FileMap* mMap; // for memory-mapped input
int mFd; // for file input
diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h
index c2c8ce5..8817120 100644
--- a/include/utils/CallStack.h
+++ b/include/utils/CallStack.h
@@ -50,7 +50,7 @@
void clear();
- void update(int32_t ignoreDepth=0, int32_t maxDepth=MAX_DEPTH);
+ void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH);
// Dump a stack trace to the log
void dump(const char* prefix = 0) const;
diff --git a/include/utils/Compat.h b/include/utils/Compat.h
new file mode 100644
index 0000000..1819266
--- /dev/null
+++ b/include/utils/Compat.h
@@ -0,0 +1,42 @@
+/*
+ * 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 __LIB_UTILS_COMPAT_H
+#define __LIB_UTILS_COMPAT_H
+
+#include <unistd.h>
+
+/* Compatibility definitions for non-Linux (i.e., BSD-based) hosts. */
+#ifndef HAVE_OFF64_T
+#if _FILE_OFFSET_BITS < 64
+#error "_FILE_OFFSET_BITS < 64; large files are not supported on this platform"
+#endif /* _FILE_OFFSET_BITS < 64 */
+
+typedef off_t off64_t;
+
+static inline off64_t lseek64(int fd, off64_t offset, int whence) {
+ return lseek(fd, offset, whence);
+}
+
+#ifdef HAVE_PREAD
+static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) {
+ return pread(fd, buf, nbytes, offset);
+}
+#endif
+
+#endif /* !HAVE_OFF64_T */
+
+#endif /* __LIB_UTILS_COMPAT_H */
diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h
index 8dfd3be..dfe6d51 100644
--- a/include/utils/FileMap.h
+++ b/include/utils/FileMap.h
@@ -22,6 +22,8 @@
#include <sys/types.h>
+#include <utils/Compat.h>
+
#ifdef HAVE_WIN32_FILEMAP
#include <windows.h>
#endif
@@ -55,7 +57,7 @@
* Returns "false" on failure.
*/
bool create(const char* origFileName, int fd,
- off_t offset, size_t length, bool readOnly);
+ off64_t offset, size_t length, bool readOnly);
/*
* Return the name of the file this map came from, if known.
@@ -75,7 +77,7 @@
/*
* Get the data offset used to create this map.
*/
- off_t getDataOffset(void) const { return mDataOffset; }
+ off64_t getDataOffset(void) const { return mDataOffset; }
/*
* Get a "copy" of the object.
@@ -118,7 +120,7 @@
char* mFileName; // original file name, if known
void* mBasePtr; // base of mmap area; page aligned
size_t mBaseLength; // length, measured from "mBasePtr"
- off_t mDataOffset; // offset used when map was created
+ off64_t mDataOffset; // offset used when map was created
void* mDataPtr; // start of requested data, offset from base
size_t mDataLength; // length, measured from "mDataPtr"
#ifdef HAVE_WIN32_FILEMAP
diff --git a/include/utils/PropertyMap.h b/include/utils/PropertyMap.h
new file mode 100644
index 0000000..a54f819
--- /dev/null
+++ b/include/utils/PropertyMap.h
@@ -0,0 +1,100 @@
+/*
+ * 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 <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+#include <utils/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;
+
+ /* 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<String8, String8> mProperties;
+};
+
+} // namespace android
+
+#endif // _UTILS_PROPERTY_MAP_H
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index da86da4..ed7f53d 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1771,12 +1771,14 @@
*
* @return ssize_t Either a >= 0 table index or a negative error code.
*/
- ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag=false,
- uint32_t* outSpecFlags=NULL, ResTable_config* outConfig=NULL) const;
+ ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag = false,
+ uint16_t density = 0,
+ uint32_t* outSpecFlags = NULL,
+ ResTable_config* outConfig = NULL) const;
inline ssize_t getResource(const ResTable_ref& res, Res_value* outValue,
uint32_t* outSpecFlags=NULL) const {
- return getResource(res.ident, outValue, false, outSpecFlags, NULL);
+ return getResource(res.ident, outValue, false, 0, outSpecFlags, NULL);
}
ssize_t resolveReference(Res_value* inOutValue,
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index 3b975b4..e1ee8eb 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -37,6 +37,11 @@
}
return *instance;
}
+
+ static bool hasInstance() {
+ Mutex::Autolock _l(sLock);
+ return sInstance != 0;
+ }
protected:
~Singleton() { };
diff --git a/include/utils/StreamingZipInflater.h b/include/utils/StreamingZipInflater.h
index 16867d8..3ace5d5 100644
--- a/include/utils/StreamingZipInflater.h
+++ b/include/utils/StreamingZipInflater.h
@@ -21,6 +21,8 @@
#include <inttypes.h>
#include <zlib.h>
+#include <utils/Compat.h>
+
namespace android {
class StreamingZipInflater {
@@ -29,7 +31,7 @@
static const size_t OUTPUT_CHUNK_SIZE = 64 * 1024;
// Flavor that pages in the compressed data from a fd
- StreamingZipInflater(int fd, off_t compDataStart, size_t uncompSize, size_t compSize);
+ StreamingZipInflater(int fd, off64_t compDataStart, size_t uncompSize, size_t compSize);
// Flavor that gets the compressed data from an in-memory buffer
StreamingZipInflater(class FileMap* dataMap, size_t uncompSize);
@@ -43,7 +45,7 @@
// seeking backwards requires uncompressing fom the beginning, so is very
// expensive. seeking forwards only requires uncompressing from the current
// position to the destination.
- off_t seekAbsolute(off_t absoluteInputPosition);
+ off64_t seekAbsolute(off64_t absoluteInputPosition);
private:
void initInflateState();
@@ -51,7 +53,7 @@
// where to find the uncompressed data
int mFd;
- off_t mInFileStart; // where the compressed data lives in the file
+ off64_t mInFileStart; // where the compressed data lives in the file
class FileMap* mDataMap;
z_stream mInflateState;
@@ -63,7 +65,7 @@
size_t mOutTotalSize; // total uncompressed size of the blob
// current output state bookkeeping
- off_t mOutCurPosition; // current position in total offset
+ off64_t mOutCurPosition; // current position in total offset
size_t mOutLastDecoded; // last decoded byte + 1 in mOutbuf
size_t mOutDeliverable; // next undelivered byte of decoded output in mOutBuf
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 07a0c11..584f53f 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -19,39 +19,12 @@
#include <utils/Errors.h>
#include <utils/SharedBuffer.h>
-
-#include <stdint.h>
-#include <sys/types.h>
+#include <utils/Unicode.h>
// ---------------------------------------------------------------------------
extern "C" {
-typedef uint16_t char16_t;
-
-// Standard string functions on char16 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);
-
-// Convert UTF-8 to UTF-16 including surrogate pairs
-void utf8_to_utf16(const uint8_t *src, size_t srcLen, char16_t* dst, const size_t dstLen);
-
}
// ---------------------------------------------------------------------------
diff --git a/include/utils/String8.h b/include/utils/String8.h
index ef0b51a..6b49ff5 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -18,122 +18,17 @@
#define ANDROID_STRING8_H
#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+#include <utils/Unicode.h>
-// Need this for the char16_t type; String8.h should not
-// be depedent on the String16 class.
-#include <utils/String16.h>
-
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-
-// ---------------------------------------------------------------------------
-
-extern "C" {
-
-typedef uint32_t char32_t;
-
-size_t strlen32(const char32_t *);
-size_t strnlen32(const char32_t *, size_t);
-
-/*
- * Returns the length of "src" when "src" is valid UTF-8 string.
- * Returns 0 if src is NULL, 0-length string or non UTF-8 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 GetUtf... 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.
- */
-size_t utf8_length(const char *src);
-
-/*
- * Returns the UTF-32 length of "src".
- */
-size_t utf32_length(const char *src, size_t src_len);
-
-/*
- * Returns the UTF-8 length of "src".
- */
-size_t utf8_length_from_utf16(const char16_t *src, size_t src_len);
-
-/*
- * Returns the UTF-8 length of "src".
- */
-size_t utf8_length_from_utf32(const char32_t *src, size_t src_len);
-
-/*
- * 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_at(const char *src, size_t src_len,
- size_t index, size_t *next_index);
-
-/*
- * Stores a UTF-32 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".
- * Returns the size actually used for storing the string.
- * "dst" is not null-terminated when dst_len is fully used (like strncpy).
- */
-size_t utf8_to_utf32(const char* src, size_t src_len,
- char32_t* dst, size_t dst_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)
- */
-size_t utf32_to_utf8(const char32_t* src, size_t src_len,
- char* dst, size_t dst_len);
-
-size_t utf16_to_utf8(const char16_t* src, size_t src_len,
- char* dst, size_t dst_len);
-
-}
+#include <string.h> // for strcmp
+#include <stdarg.h>
// ---------------------------------------------------------------------------
namespace android {
+class String16;
class TextOutput;
//! This is a string holding UTF-8 characters. Does not allow the value more
@@ -152,14 +47,22 @@
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);
@@ -173,13 +76,14 @@
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;
- size_t getUtf32(char32_t* dst, size_t dst_len) const;
+ void getUtf32(char32_t* dst) const;
inline String8& operator=(const String8& other);
inline String8& operator=(const char* other);
@@ -330,6 +234,10 @@
return compare_type(lhs, rhs) < 0;
}
+inline const String8 String8::empty() {
+ return String8();
+}
+
inline const char* String8::string() const
{
return mString;
@@ -345,6 +253,11 @@
return length();
}
+inline bool String8::isEmpty() const
+{
+ return length() == 0;
+}
+
inline size_t String8::bytes() const
{
return SharedBuffer::sizeFromData(mString)-1;
diff --git a/include/utils/Tokenizer.h b/include/utils/Tokenizer.h
new file mode 100644
index 0000000..c7db5fb
--- /dev/null
+++ b/include/utils/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 <assert.h>
+#include <utils/Errors.h>
+#include <utils/FileMap.h>
+#include <utils/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/include/utils/Unicode.h b/include/utils/Unicode.h
new file mode 100644
index 0000000..6afb291
--- /dev/null
+++ b/include/utils/Unicode.h
@@ -0,0 +1,161 @@
+/*
+ * 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
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern "C" {
+
+typedef uint32_t char32_t;
+typedef uint16_t char16_t;
+
+// 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. 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);
+
+}
+
+#endif
diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h
index e38bf66..3e42a95 100644
--- a/include/utils/ZipFileCRO.h
+++ b/include/utils/ZipFileCRO.h
@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <unistd.h>
+#include <utils/Compat.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -48,7 +50,7 @@
extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry,
int* pMethod, size_t* pUncompLen,
- size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
+ size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32);
extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd);
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 3c1f3ca..3a99979 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -30,6 +30,7 @@
#ifndef __LIBS_ZIPFILERO_H
#define __LIBS_ZIPFILERO_H
+#include <utils/Compat.h>
#include <utils/Errors.h>
#include <utils/FileMap.h>
#include <utils/threads.h>
@@ -128,7 +129,7 @@
* appears to be bad.
*/
bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
- size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
+ size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const;
/*
* Create a new FileMap object that maps a subset of the archive. For
@@ -231,7 +232,7 @@
int mNumEntries;
/* CD directory offset in the Zip archive */
- off_t mDirectoryOffset;
+ off64_t mDirectoryOffset;
/*
* We know how many entries are in the Zip archive, so we have a
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 13dc500..f9d9f25 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -16,6 +16,7 @@
sources := \
Binder.cpp \
BpBinder.cpp \
+ CursorWindow.cpp \
IInterface.cpp \
IMemory.cpp \
IPCThreadState.cpp \
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
new file mode 100644
index 0000000..47bbd04
--- /dev/null
+++ b/libs/binder/CursorWindow.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2006-2007 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CursorWindow"
+
+#include <utils/Log.h>
+#include <binder/CursorWindow.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+namespace android {
+
+CursorWindow::CursorWindow(size_t maxSize) :
+ mMaxSize(maxSize)
+{
+}
+
+bool CursorWindow::setMemory(const sp<IMemory>& memory)
+{
+ mMemory = memory;
+ mData = (uint8_t *) memory->pointer();
+ if (mData == NULL) {
+ return false;
+ }
+ mHeader = (window_header_t *) mData;
+
+ // Make the window read-only
+ ssize_t size = memory->size();
+ mSize = size;
+ mMaxSize = size;
+ mFreeOffset = size;
+LOG_WINDOW("Created CursorWindow from existing IMemory: mFreeOffset = %d, numRows = %d, numColumns = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mHeader->numRows, mHeader->numColumns, mSize, mMaxSize, mData);
+ return true;
+}
+
+bool CursorWindow::initBuffer(bool localOnly)
+{
+ //TODO Use a non-memory dealer mmap region for localOnly
+
+ sp<MemoryHeapBase> heap;
+ heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow");
+ if (heap != NULL) {
+ mMemory = new MemoryBase(heap, 0, mMaxSize);
+ if (mMemory != NULL) {
+ mData = (uint8_t *) mMemory->pointer();
+ if (mData) {
+ mHeader = (window_header_t *) mData;
+ mSize = mMaxSize;
+
+ // Put the window into a clean state
+ clear();
+ LOG_WINDOW("Created CursorWindow with new MemoryDealer: mFreeOffset = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mSize, mMaxSize, mData);
+ return true;
+ }
+ }
+ LOGE("CursorWindow heap allocation failed");
+ return false;
+ } else {
+ LOGE("failed to create the CursorWindow heap");
+ return false;
+ }
+}
+
+CursorWindow::~CursorWindow()
+{
+ // Everything that matters is a smart pointer
+}
+
+void CursorWindow::clear()
+{
+ mHeader->numRows = 0;
+ mHeader->numColumns = 0;
+ mFreeOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE;
+ // Mark the first chunk's next 'pointer' as null
+ *((uint32_t *)(mData + mFreeOffset - sizeof(uint32_t))) = 0;
+}
+
+int32_t CursorWindow::freeSpace()
+{
+ int32_t freeSpace = mSize - mFreeOffset;
+ if (freeSpace < 0) {
+ freeSpace = 0;
+ }
+ return freeSpace;
+}
+
+field_slot_t * CursorWindow::allocRow()
+{
+ // Fill in the row slot
+ row_slot_t * rowSlot = allocRowSlot();
+ if (rowSlot == NULL) {
+ return NULL;
+ }
+
+ // Allocate the slots for the field directory
+ size_t fieldDirSize = mHeader->numColumns * sizeof(field_slot_t);
+ uint32_t fieldDirOffset = alloc(fieldDirSize);
+ if (!fieldDirOffset) {
+ mHeader->numRows--;
+ LOG_WINDOW("The row failed, so back out the new row accounting from allocRowSlot %d", mHeader->numRows);
+ return NULL;
+ }
+ field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(fieldDirOffset);
+ memset(fieldDir, 0x0, fieldDirSize);
+
+LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", (mHeader->numRows - 1), ((uint8_t *)rowSlot) - mData, fieldDirSize, fieldDirOffset);
+ rowSlot->offset = fieldDirOffset;
+
+ return fieldDir;
+}
+
+uint32_t CursorWindow::alloc(size_t requestedSize, bool aligned)
+{
+ int32_t size;
+ uint32_t padding;
+ if (aligned) {
+ // 4 byte alignment
+ padding = 4 - (mFreeOffset & 0x3);
+ } else {
+ padding = 0;
+ }
+
+ size = requestedSize + padding;
+
+ if (size > freeSpace()) {
+ LOGV("need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d", mSize, size,
+ freeSpace(), mHeader->numRows);
+ // Only grow the window if the first row doesn't fit
+ if (mHeader->numRows > 1) {
+ LOGV("not growing since there are already %d row(s), max size %d", mHeader->numRows,
+ mMaxSize);
+ return 0;
+ }
+
+ // Find a new size that will fit the allocation
+ int allocated = mSize - freeSpace();
+ int newSize = mSize + WINDOW_ALLOCATION_SIZE;
+ while (size > (newSize - allocated)) {
+ newSize += WINDOW_ALLOCATION_SIZE;
+ if (newSize > mMaxSize) {
+ LOGE("Attempting to grow window beyond max size (%d)", mMaxSize);
+ return 0;
+ }
+ }
+LOG_WINDOW("found size %d", newSize);
+ mSize = newSize;
+ }
+
+ uint32_t offset = mFreeOffset + padding;
+ mFreeOffset += size;
+ return offset;
+}
+
+row_slot_t * CursorWindow::getRowSlot(int row)
+{
+ LOG_WINDOW("enter getRowSlot current row num %d, this row %d", mHeader->numRows, row);
+ int chunkNum = row / ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPos = row % ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
+ uint8_t * rowChunk = mData + sizeof(window_header_t);
+ for (int i = 0; i < chunkNum; i++) {
+ rowChunk = offsetToPtr(*((uint32_t *)(mData + chunkPtrOffset)));
+ chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
+ }
+ return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
+ LOG_WINDOW("exit getRowSlot current row num %d, this row %d", mHeader->numRows, row);
+}
+
+row_slot_t * CursorWindow::allocRowSlot()
+{
+ int chunkNum = mHeader->numRows / ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPos = mHeader->numRows % ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
+ uint8_t * rowChunk = mData + sizeof(window_header_t);
+LOG_WINDOW("Allocating row slot, mHeader->numRows is %d, chunkNum is %d, chunkPos is %d", mHeader->numRows, chunkNum, chunkPos);
+ for (int i = 0; i < chunkNum; i++) {
+ uint32_t nextChunkOffset = *((uint32_t *)(mData + chunkPtrOffset));
+LOG_WINDOW("nextChunkOffset is %d", nextChunkOffset);
+ if (nextChunkOffset == 0) {
+ // Allocate a new row chunk
+ nextChunkOffset = alloc(ROW_SLOT_CHUNK_SIZE, true);
+ if (nextChunkOffset == 0) {
+ return NULL;
+ }
+ rowChunk = offsetToPtr(nextChunkOffset);
+LOG_WINDOW("allocated new chunk at %d, rowChunk = %p", nextChunkOffset, rowChunk);
+ *((uint32_t *)(mData + chunkPtrOffset)) = rowChunk - mData;
+ // Mark the new chunk's next 'pointer' as null
+ *((uint32_t *)(rowChunk + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t))) = 0;
+ } else {
+LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chunkPtrOffset);
+ rowChunk = offsetToPtr(nextChunkOffset);
+ chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
+ }
+ }
+ mHeader->numRows++;
+
+ return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
+}
+
+field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column)
+{
+ if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
+ LOGE("Failed to read row# %d, column# from a CursorWindow which has %d rows, %d columns.",
+ row, column, mHeader->numRows, mHeader->numColumns);
+ return NULL;
+ }
+ row_slot_t * rowSlot = getRowSlot(row);
+ if (!rowSlot) {
+ LOGE("Failed to find rowSlot for row %d", row);
+ return NULL;
+ }
+ if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
+ LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
+ return NULL;
+ }
+ int fieldDirOffset = rowSlot->offset;
+ return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
+}
+
+uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut)
+{
+ if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
+ LOGE("Can't read row# %d, col# %d from CursorWindow. Make sure your Cursor is initialized correctly.",
+ row, column);
+ return -1;
+ }
+ row_slot_t * rowSlot = getRowSlot(row);
+ if (!rowSlot) {
+ LOGE("Failed to find rowSlot for row %d", row);
+ return -1;
+ }
+ if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
+ LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
+ return -1;
+ }
+LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset);
+ field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset);
+LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type);
+
+ // Copy the data to the out param
+ slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset;
+ slotOut->data.buffer.size = fieldDir[column].data.buffer.size;
+ slotOut->type = fieldDir[column].type;
+ return 0;
+}
+
+void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size)
+{
+ assert(offset + size <= mSize);
+ memcpy(mData + offset, data, size);
+}
+
+void CursorWindow::copyIn(uint32_t offset, int64_t data)
+{
+ assert(offset + sizeof(int64_t) <= mSize);
+ memcpy(mData + offset, (uint8_t *)&data, sizeof(int64_t));
+}
+
+void CursorWindow::copyIn(uint32_t offset, double data)
+{
+ assert(offset + sizeof(double) <= mSize);
+ memcpy(mData + offset, (uint8_t *)&data, sizeof(double));
+}
+
+void CursorWindow::copyOut(uint32_t offset, uint8_t * data, size_t size)
+{
+ assert(offset + size <= mSize);
+ memcpy(data, mData + offset, size);
+}
+
+int64_t CursorWindow::copyOutLong(uint32_t offset)
+{
+ int64_t value;
+ assert(offset + sizeof(int64_t) <= mSize);
+ memcpy(&value, mData + offset, sizeof(int64_t));
+ return value;
+}
+
+double CursorWindow::copyOutDouble(uint32_t offset)
+{
+ double value;
+ assert(offset + sizeof(double) <= mSize);
+ memcpy(&value, mData + offset, sizeof(double));
+ return value;
+}
+
+bool CursorWindow::putLong(unsigned int row, unsigned int col, int64_t value)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ fieldSlot->data.l = value;
+#else
+ int offset = alloc(sizeof(int64_t));
+ if (!offset) {
+ return false;
+ }
+
+ copyIn(offset, value);
+
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = sizeof(int64_t);
+#endif
+ fieldSlot->type = FIELD_TYPE_INTEGER;
+ return true;
+}
+
+bool CursorWindow::putDouble(unsigned int row, unsigned int col, double value)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ fieldSlot->data.d = value;
+#else
+ int offset = alloc(sizeof(int64_t));
+ if (!offset) {
+ return false;
+ }
+
+ copyIn(offset, value);
+
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = sizeof(double);
+#endif
+ fieldSlot->type = FIELD_TYPE_FLOAT;
+ return true;
+}
+
+bool CursorWindow::putNull(unsigned int row, unsigned int col)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+ fieldSlot->type = FIELD_TYPE_NULL;
+ fieldSlot->data.buffer.offset = 0;
+ fieldSlot->data.buffer.size = 0;
+ return true;
+}
+
+bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ *valueOut = fieldSlot->data.l;
+#else
+ *valueOut = copyOutLong(fieldSlot->data.buffer.offset);
+#endif
+ return true;
+}
+
+bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot || fieldSlot->type != FIELD_TYPE_FLOAT) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ *valueOut = fieldSlot->data.d;
+#else
+ *valueOut = copyOutDouble(fieldSlot->data.buffer.offset);
+#endif
+ return true;
+}
+
+bool CursorWindow::getNull(unsigned int row, unsigned int col, bool * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+ if (fieldSlot->type != FIELD_TYPE_NULL) {
+ *valueOut = false;
+ } else {
+ *valueOut = true;
+ }
+ return true;
+}
+
+}; // namespace android
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 13c58f0..95cfddf 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -318,6 +318,16 @@
goto restart;
}
+IPCThreadState* IPCThreadState::selfOrNull()
+{
+ if (gHaveTLS) {
+ const pthread_key_t k = gTLS;
+ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
+ return st;
+ }
+ return NULL;
+}
+
void IPCThreadState::shutdown()
{
gShutdown = true;
diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp
index 7049d9e..23b90af 100644
--- a/libs/surfaceflinger_client/ISurface.cpp
+++ b/libs/surfaceflinger_client/ISurface.cpp
@@ -21,9 +21,7 @@
#include <sys/types.h>
#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <ui/Overlay.h>
#include <ui/GraphicBuffer.h>
#include <surfaceflinger/Surface.h>
@@ -33,36 +31,6 @@
// ----------------------------------------------------------------------
-ISurface::BufferHeap::BufferHeap()
- : w(0), h(0), hor_stride(0), ver_stride(0), format(0),
- transform(0), flags(0)
-{
-}
-
-ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
- int32_t hor_stride, int32_t ver_stride,
- PixelFormat format, const sp<IMemoryHeap>& heap)
- : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
- format(format), transform(0), flags(0), heap(heap)
-{
-}
-
-ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
- int32_t hor_stride, int32_t ver_stride,
- PixelFormat format, uint32_t transform, uint32_t flags,
- const sp<IMemoryHeap>& heap)
- : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
- format(format), transform(transform), flags(flags), heap(heap)
-{
-}
-
-
-ISurface::BufferHeap::~BufferHeap()
-{
-}
-
-// ----------------------------------------------------------------------
-
class BpSurface : public BpInterface<ISurface>
{
public:
@@ -96,51 +64,6 @@
status_t err = reply.readInt32();
return err;
}
-
- virtual status_t registerBuffers(const BufferHeap& buffers)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- data.writeInt32(buffers.w);
- data.writeInt32(buffers.h);
- data.writeInt32(buffers.hor_stride);
- data.writeInt32(buffers.ver_stride);
- data.writeInt32(buffers.format);
- data.writeInt32(buffers.transform);
- data.writeInt32(buffers.flags);
- data.writeStrongBinder(buffers.heap->asBinder());
- remote()->transact(REGISTER_BUFFERS, data, &reply);
- status_t result = reply.readInt32();
- return result;
- }
-
- virtual void postBuffer(ssize_t offset)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- data.writeInt32(offset);
- remote()->transact(POST_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- virtual void unregisterBuffers()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- remote()->transact(UNREGISTER_BUFFERS, data, &reply);
- }
-
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format, int32_t orientation)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- data.writeInt32(w);
- data.writeInt32(h);
- data.writeInt32(format);
- data.writeInt32(orientation);
- remote()->transact(CREATE_OVERLAY, data, &reply);
- return OverlayRef::readFromParcel(reply);
- }
};
IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
@@ -170,41 +93,6 @@
reply->writeInt32(err);
return NO_ERROR;
}
- case REGISTER_BUFFERS: {
- CHECK_INTERFACE(ISurface, data, reply);
- BufferHeap buffer;
- buffer.w = data.readInt32();
- buffer.h = data.readInt32();
- buffer.hor_stride = data.readInt32();
- buffer.ver_stride= data.readInt32();
- buffer.format = data.readInt32();
- buffer.transform = data.readInt32();
- buffer.flags = data.readInt32();
- buffer.heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
- status_t err = registerBuffers(buffer);
- reply->writeInt32(err);
- return NO_ERROR;
- } break;
- case UNREGISTER_BUFFERS: {
- CHECK_INTERFACE(ISurface, data, reply);
- unregisterBuffers();
- return NO_ERROR;
- } break;
- case POST_BUFFER: {
- CHECK_INTERFACE(ISurface, data, reply);
- ssize_t offset = data.readInt32();
- postBuffer(offset);
- return NO_ERROR;
- } break;
- case CREATE_OVERLAY: {
- CHECK_INTERFACE(ISurface, data, reply);
- int w = data.readInt32();
- int h = data.readInt32();
- int f = data.readInt32();
- int orientation = data.readInt32();
- sp<OverlayRef> o = createOverlay(w, h, f, orientation);
- return OverlayRef::writeToParcel(reply, o);
- } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 969ee79..b8a7a79 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -127,13 +127,16 @@
virtual status_t captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight)
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeInt32(dpy);
data.writeInt32(reqWidth);
data.writeInt32(reqHeight);
+ data.writeInt32(minLayerZ);
+ data.writeInt32(maxLayerZ);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
*width = reply.readInt32();
@@ -231,11 +234,13 @@
DisplayID dpy = data.readInt32();
uint32_t reqWidth = data.readInt32();
uint32_t reqHeight = data.readInt32();
+ uint32_t minLayerZ = data.readInt32();
+ uint32_t maxLayerZ = data.readInt32();
sp<IMemoryHeap> heap;
uint32_t w, h;
PixelFormat f;
status_t res = captureScreen(dpy, &heap, &w, &h, &f,
- reqWidth, reqHeight);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ);
reply->writeStrongBinder(heap->asBinder());
reply->writeInt32(w);
reply->writeInt32(h);
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 4bc5d9e..3b2ef84 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -265,6 +265,14 @@
(stack.queued > 0 && stack.inUse != buf));
}
+SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
+ SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
+ mNumBuffers(numBuffers) {
+}
+bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
+ return stack.available == mNumBuffers;
+}
+
// ----------------------------------------------------------------------------
SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
@@ -380,11 +388,6 @@
{
SharedBufferStack& stack( *mSharedStack );
- if (stack.head == tail && stack.available == mNumBuffers) {
- LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
- tail, stack.head, stack.available, stack.queued);
- }
-
RWLock::AutoRLock _rd(mLock);
const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
@@ -453,6 +456,7 @@
const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
+
return err;
}
@@ -497,6 +501,7 @@
if (err == NO_ERROR) {
mNumBuffers = bufferCount;
queued_head = (stack.head + stack.queued) % mNumBuffers;
+ tail = computeTail();
}
return err;
}
@@ -611,17 +616,24 @@
*/
status_t SharedBufferServer::resize(int newNumBuffers)
{
- if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX)
+ if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
+ (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
return BAD_VALUE;
+ }
RWLock::AutoWLock _l(mLock);
- // for now we're not supporting shrinking
- const int numBuffers = mNumBuffers;
- if (newNumBuffers < numBuffers)
- return BAD_VALUE;
+ if (newNumBuffers < mNumBuffers) {
+ return shrink(newNumBuffers);
+ } else {
+ return grow(newNumBuffers);
+ }
+}
+status_t SharedBufferServer::grow(int newNumBuffers)
+{
SharedBufferStack& stack( *mSharedStack );
+ const int numBuffers = mNumBuffers;
const int extra = newNumBuffers - numBuffers;
// read the head, make sure it's valid
@@ -655,6 +667,54 @@
return NO_ERROR;
}
+status_t SharedBufferServer::shrink(int newNumBuffers)
+{
+ SharedBufferStack& stack( *mSharedStack );
+
+ // Shrinking is only supported if there are no buffers currently dequeued.
+ int32_t avail = stack.available;
+ int32_t queued = stack.queued;
+ if (avail + queued != mNumBuffers) {
+ return INVALID_OPERATION;
+ }
+
+ // Wait for any queued buffers to be displayed.
+ BuffersAvailableCondition condition(this, mNumBuffers);
+ status_t err = waitForCondition(condition);
+ if (err < 0) {
+ return err;
+ }
+
+ // Reset head to index 0 and make it refer to buffer 0. The same renaming
+ // (head -> 0) is done in the BufferManager.
+ int32_t head = stack.head;
+ int8_t* index = const_cast<int8_t*>(stack.index);
+ for (int8_t i = 0; i < newNumBuffers; i++) {
+ index[i] = i;
+ }
+ stack.head = 0;
+ stack.headBuf = 0;
+
+ // If one of the buffers is in use it must be the head buffer, which we are
+ // renaming to buffer 0.
+ if (stack.inUse > 0) {
+ stack.inUse = 0;
+ }
+
+ // Free the buffers from the end of the list that are no longer needed.
+ for (int i = newNumBuffers; i < mNumBuffers; i++) {
+ mBufferList.remove(i);
+ }
+
+ // Tell the client to reallocate all the buffers.
+ reallocateAll();
+
+ mNumBuffers = newNumBuffers;
+ stack.available = newNumBuffers;
+
+ return NO_ERROR;
+}
+
SharedBufferStack::Statistics SharedBufferServer::getStats() const
{
SharedBufferStack& stack( *mSharedStack );
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 854a3c6..aa0c2e8 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -364,6 +364,13 @@
height = surface->mHeight;
format = surface->mFormat;
flags = surface->mFlags;
+ } else if (surface != 0 && surface->mSurface != 0) {
+ LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
+ "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
+ "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
+ surface->mSurface.get(), surface->mIdentity, surface->mWidth,
+ surface->mHeight, surface->mFormat, surface->mFlags,
+ surface->mInitCheck);
}
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
parcel->writeInt32(identity);
@@ -377,7 +384,7 @@
Mutex Surface::sCachedSurfacesLock;
-DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces(wp<Surface>(0));
+DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
sp<Surface> Surface::readFromParcel(const Parcel& data) {
Mutex::Autolock _l(sCachedSurfacesLock);
@@ -390,13 +397,13 @@
if (surface->mSurface == 0) {
surface = 0;
}
- cleanCachedSurfaces();
+ cleanCachedSurfacesLocked();
return surface;
}
// Remove the stale entries from the surface cache. This should only be called
// with sCachedSurfacesLock held.
-void Surface::cleanCachedSurfaces() {
+void Surface::cleanCachedSurfacesLocked() {
for (int i = sCachedSurfaces.size()-1; i >= 0; --i) {
wp<Surface> s(sCachedSurfaces.valueAt(i));
if (s == 0 || s.promote() == 0) {
@@ -438,21 +445,15 @@
mSharedBufferClient = new SharedBufferClient(
mClient.getSharedClient(), token, 2, mIdentity);
mInitCheck = mClient.getSharedClient()->validate(token);
+ } else {
+ LOGW("Not initializing the shared buffer client because token = %d",
+ token);
}
}
}
Surface::~Surface()
{
- // this is a client-side operation, the surface is destroyed, unmap
- // its buffers in this process.
- size_t size = mBuffers.size();
- for (size_t i=0 ; i<size ; i++) {
- if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
- getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
- }
- }
-
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
mBuffers.clear();
@@ -488,6 +489,9 @@
LOGE("[Surface] using an invalid surface, "
"identity=%u should be %d",
mIdentity, identity);
+ CallStack stack;
+ stack.update();
+ stack.dump("Surface");
return NO_INIT;
}
@@ -496,6 +500,9 @@
if (err != NO_ERROR) {
LOGE("surface (identity=%u) is invalid, err=%d (%s)",
mIdentity, err, strerror(-err));
+ CallStack stack;
+ stack.update();
+ stack.dump("Surface");
return err;
}
@@ -854,6 +861,12 @@
status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
bufferCount, strerror(-err));
+
+ if (err == NO_ERROR) {
+ // Clear out any references to the old buffers.
+ mBuffers.clear();
+ }
+
return err;
}
@@ -1022,7 +1035,20 @@
int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
{
- return buffer->getIndex();
+ int idx = buffer->getIndex();
+ if (idx < 0) {
+ // The buffer doesn't have an index set. See if the handle the same as
+ // one of the buffers for which we do know the index. This can happen
+ // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
+ // was dequeued from an ANativeWindow.
+ for (size_t i = 0; i < mBuffers.size(); i++) {
+ if (buffer->handle == mBuffers[i]->handle) {
+ idx = mBuffers[i]->getIndex();
+ break;
+ }
+ }
+ }
+ return idx;
}
status_t Surface::getBufferLocked(int index,
@@ -1036,7 +1062,6 @@
// free the current buffer
sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
if (currentBuffer != 0) {
- getBufferMapper().unregisterBuffer(currentBuffer->handle);
currentBuffer.clear();
}
@@ -1044,7 +1069,7 @@
LOGE_IF(buffer==0,
"ISurface::getBuffer(%d, %08x) returned NULL",
index, usage);
- if (buffer != 0) { // this should never happen by construction
+ if (buffer != 0) { // this should always happen by construction
LOGE_IF(buffer->handle == NULL,
"Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
"returned a buffer with a null handle",
@@ -1052,13 +1077,8 @@
err = mSharedBufferClient->getStatus();
LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err);
if (!err && buffer->handle != NULL) {
- err = getBufferMapper().registerBuffer(buffer->handle);
- LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
- err, strerror(-err));
- if (err == NO_ERROR) {
- currentBuffer = buffer;
- currentBuffer->setIndex(index);
- }
+ currentBuffer = buffer;
+ currentBuffer->setIndex(index);
} else {
err = err<0 ? err : status_t(NO_MEMORY);
}
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index f270461..d336724 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -555,7 +555,8 @@
if (s == NULL) return NO_INIT;
mHeap = 0;
return s->captureScreen(0, &mHeap,
- &mWidth, &mHeight, &mFormat, 0, 0);
+ &mWidth, &mHeight, &mFormat, 0, 0,
+ 0, -1UL);
}
status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) {
@@ -563,7 +564,18 @@
if (s == NULL) return NO_INIT;
mHeap = 0;
return s->captureScreen(0, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight);
+ &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
+ 0, -1UL);
+}
+
+status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
+ minLayerZ, maxLayerZ);
}
void ScreenshotClient::release() {
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
index f409f48..7ef5926 100644
--- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
+++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
@@ -32,7 +32,8 @@
int main(int argc, char** argv)
{
SharedClient client;
- SharedBufferServer s(&client, 0, 4, 0);
+ sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0));
+ SharedBufferServer& s(*ps);
SharedBufferClient c(&client, 0, 4, 0);
printf("basic test 0\n");
@@ -67,6 +68,10 @@
int list3[6] = {3, 2, 1, 4, 5, 0};
test0(s, c, 6, list3);
+ c.setBufferCount(4, resize);
+ int list4[4] = {1, 2, 3, 0};
+ test0(s, c, 4, list4);
+
return 0;
}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index c4a09d6..4ba8b5b 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -1,7 +1,47 @@
+# 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.
+
LOCAL_PATH:= $(call my-dir)
+
+# libui is partially built for the host (used by build time keymap validation tool)
+# These files are common to host and target builds.
+commonSources:= \
+ Input.cpp \
+ Keyboard.cpp \
+ KeyLayoutMap.cpp \
+ KeyCharacterMap.cpp \
+ VirtualKeyMap.cpp
+
+# For the host
+# =====================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= $(commonSources)
+
+LOCAL_MODULE:= libui
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# For the device
+# =====================================================
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ $(commonSources) \
EGLUtils.cpp \
EventHub.cpp \
EventRecurrence.cpp \
@@ -10,15 +50,10 @@
GraphicBufferAllocator.cpp \
GraphicBufferMapper.cpp \
GraphicLog.cpp \
- KeyLayoutMap.cpp \
- KeyCharacterMap.cpp \
- Input.cpp \
InputDispatcher.cpp \
InputManager.cpp \
InputReader.cpp \
InputTransport.cpp \
- IOverlay.cpp \
- Overlay.cpp \
PixelFormat.cpp \
Rect.cpp \
Region.cpp
@@ -27,7 +62,6 @@
libcutils \
libutils \
libEGL \
- libbinder \
libpixelflinger \
libhardware \
libhardware_legacy
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 41daa9c..8f4bac6 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -16,7 +16,6 @@
//#define LOG_NDEBUG 0
#include <ui/EventHub.h>
-#include <ui/KeycodeLabels.h>
#include <hardware_legacy/power.h>
#include <cutils/properties.h>
@@ -33,7 +32,9 @@
#include <errno.h>
#include <assert.h>
-#include "KeyLayoutMap.h"
+#include <ui/KeyLayoutMap.h>
+#include <ui/KeyCharacterMap.h>
+#include <ui/VirtualKeyMap.h>
#include <string.h>
#include <stdint.h>
@@ -57,10 +58,6 @@
/* this macro computes the number of bytes needed to represent a bit array of the specified size */
#define sizeof_bit_array(bits) ((bits + 7) / 8)
-#define ID_MASK 0x0000ffff
-#define SEQ_MASK 0x7fff0000
-#define SEQ_SHIFT 16
-
#ifndef ABS_MT_TOUCH_MAJOR
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#endif
@@ -73,6 +70,9 @@
#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
#endif
+// Fd at index 0 is always reserved for inotify
+#define FIRST_ACTUAL_DEVICE_INDEX 1
+
#define INDENT " "
#define INDENT2 " "
#define INDENT3 " "
@@ -80,7 +80,7 @@
namespace android {
static const char *WAKE_LOCK_ID = "KeyEvents";
-static const char *device_path = "/dev/input";
+static const char *DEVICE_PATH = "/dev/input";
/* return the larger integer */
static inline int max(int v1, int v2)
@@ -92,72 +92,89 @@
return value ? "true" : "false";
}
-EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
- : id(_id), path(_path), name(name), classes(0)
- , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), fd(-1), next(NULL) {
+// --- EventHub::Device ---
+
+EventHub::Device::Device(int fd, int32_t id, const String8& path,
+ const InputDeviceIdentifier& identifier) :
+ next(NULL),
+ fd(fd), id(id), path(path), identifier(identifier),
+ classes(0), keyBitmask(NULL), configuration(NULL), virtualKeyMap(NULL) {
}
-EventHub::device_t::~device_t() {
- delete [] keyBitmask;
- delete layoutMap;
+EventHub::Device::~Device() {
+ close();
+ delete[] keyBitmask;
+ delete configuration;
+ delete virtualKeyMap;
}
-EventHub::EventHub(void)
- : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
- , mDevicesById(0), mNumDevicesById(0)
- , mOpeningDevices(0), mClosingDevices(0)
- , mDevices(0), mFDs(0), mFDCount(0), mOpened(false), mNeedToSendFinishedDeviceScan(false)
- , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0)
-{
+void EventHub::Device::close() {
+ if (fd >= 0) {
+ ::close(fd);
+ fd = -1;
+ }
+}
+
+
+// --- EventHub ---
+
+EventHub::EventHub(void) :
+ mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
+ mOpeningDevices(0), mClosingDevices(0),
+ mOpened(false), mNeedToSendFinishedDeviceScan(false),
+ mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
#ifdef EV_SW
memset(mSwitches, 0, sizeof(mSwitches));
#endif
}
-/*
- * Clean up.
- */
-EventHub::~EventHub(void)
-{
+EventHub::~EventHub(void) {
release_wake_lock(WAKE_LOCK_ID);
// we should free stuff here...
}
-status_t EventHub::errorCheck() const
-{
+status_t EventHub::errorCheck() const {
return mError;
}
-String8 EventHub::getDeviceName(int32_t deviceId) const
-{
+String8 EventHub::getDeviceName(int32_t deviceId) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device == NULL) return String8();
- return device->name;
+ return device->identifier.name;
}
-uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
-{
+uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device == NULL) return 0;
return device->classes;
}
+void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device && device->configuration) {
+ *outConfiguration = *device->configuration;
+ } else {
+ outConfiguration->clear();
+ }
+}
+
status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const {
outAxisInfo->clear();
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device == NULL) return -1;
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
LOGW("Error reading absolute controller %d for device %s fd %d\n",
- axis, device->name.string(), device->fd);
+ axis, device->identifier.name.string(), device->fd);
return -errno;
}
@@ -175,7 +192,7 @@
if (scanCode >= 0 && scanCode <= KEY_MAX) {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return getScanCodeStateLocked(device, scanCode);
}
@@ -183,7 +200,7 @@
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
+int32_t EventHub::getScanCodeStateLocked(Device* device, int32_t scanCode) const {
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
memset(key_bitmask, 0, sizeof(key_bitmask));
if (ioctl(device->fd,
@@ -196,16 +213,20 @@
int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return getKeyCodeStateLocked(device, keyCode);
}
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const {
+int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const {
+ if (!device->keyMap.haveKeyLayout()) {
+ return AKEY_STATE_UNKNOWN;
+ }
+
Vector<int32_t> scanCodes;
- device->layoutMap->findScancodes(keyCode, &scanCodes);
+ device->keyMap.keyLayoutMap->findScanCodes(keyCode, &scanCodes);
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
memset(key_bitmask, 0, sizeof(key_bitmask));
@@ -233,7 +254,7 @@
if (sw >= 0 && sw <= SW_MAX) {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return getSwitchStateLocked(device, sw);
}
@@ -242,7 +263,7 @@
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
+int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const {
uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
memset(sw_bitmask, 0, sizeof(sw_bitmask));
if (ioctl(device->fd,
@@ -256,16 +277,16 @@
const int32_t* keyCodes, uint8_t* outFlags) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags);
}
return false;
}
-bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
+bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const {
- if (device->layoutMap == NULL || device->keyBitmask == NULL) {
+ if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
return false;
}
@@ -273,7 +294,7 @@
for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
scanCodes.clear();
- status_t err = device->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
+ status_t err = device->keyMap.keyLayoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes);
if (! err) {
// check the possible scan codes identified by the layout map against the
// map of codes actually emitted by the driver
@@ -292,20 +313,20 @@
int32_t* outKeycode, uint32_t* outFlags) const
{
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
- if (device != NULL && device->layoutMap != NULL) {
- status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (device && device->keyMap.haveKeyLayout()) {
+ status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags);
if (err == NO_ERROR) {
return NO_ERROR;
}
}
- if (mHaveFirstKeyboard) {
- device = getDeviceLocked(mFirstKeyboardId);
+ if (mBuiltInKeyboardId != -1) {
+ device = getDeviceLocked(mBuiltInKeyboardId);
- if (device != NULL && device->layoutMap != NULL) {
- status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (device && device->keyMap.haveKeyLayout()) {
+ status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags);
if (err == NO_ERROR) {
return NO_ERROR;
}
@@ -325,21 +346,66 @@
mExcludedDevices.push_back(name);
}
-EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const
-{
- if (deviceId == 0) deviceId = mFirstKeyboardId;
- int32_t id = deviceId & ID_MASK;
- if (id >= mNumDevicesById || id < 0) return NULL;
- device_t* dev = mDevicesById[id].device;
- if (dev == NULL) return NULL;
- if (dev->id == deviceId) {
- return dev;
+bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device) {
+ uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)];
+ memset(bitmask, 0, sizeof(bitmask));
+ if (ioctl(device->fd, EVIOCGBIT(EV_LED, sizeof(bitmask)), bitmask) >= 0) {
+ if (test_bit(led, bitmask)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device) {
+ struct input_event ev;
+ ev.time.tv_sec = 0;
+ ev.time.tv_usec = 0;
+ ev.type = EV_LED;
+ ev.code = led;
+ ev.value = on ? 1 : 0;
+
+ ssize_t nWrite;
+ do {
+ nWrite = write(device->fd, &ev, sizeof(struct input_event));
+ } while (nWrite == -1 && errno == EINTR);
+ }
+}
+
+void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+ outVirtualKeys.clear();
+
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device && device->virtualKeyMap) {
+ outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys());
+ }
+}
+
+EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
+ if (deviceId == 0) {
+ deviceId = mBuiltInKeyboardId;
+ }
+
+ size_t numDevices = mDevices.size();
+ for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < numDevices; i++) {
+ Device* device = mDevices[i];
+ if (device->id == deviceId) {
+ return device;
+ }
}
return NULL;
}
-bool EventHub::getEvent(RawEvent* outEvent)
-{
+bool EventHub::getEvent(RawEvent* outEvent) {
outEvent->deviceId = 0;
outEvent->type = 0;
outEvent->scanCode = 0;
@@ -360,11 +426,11 @@
for (;;) {
// Report any devices that had last been added/removed.
if (mClosingDevices != NULL) {
- device_t* device = mClosingDevices;
- LOGV("Reporting device closed: id=0x%x, name=%s\n",
+ Device* device = mClosingDevices;
+ LOGV("Reporting device closed: id=%d, name=%s\n",
device->id, device->path.string());
mClosingDevices = device->next;
- if (device->id == mFirstKeyboardId) {
+ if (device->id == mBuiltInKeyboardId) {
outEvent->deviceId = 0;
} else {
outEvent->deviceId = device->id;
@@ -377,11 +443,11 @@
}
if (mOpeningDevices != NULL) {
- device_t* device = mOpeningDevices;
- LOGV("Reporting device opened: id=0x%x, name=%s\n",
+ Device* device = mOpeningDevices;
+ LOGV("Reporting device opened: id=%d, name=%s\n",
device->id, device->path.string());
mOpeningDevices = device->next;
- if (device->id == mFirstKeyboardId) {
+ if (device->id == mBuiltInKeyboardId) {
outEvent->deviceId = 0;
} else {
outEvent->deviceId = device->id;
@@ -404,25 +470,25 @@
// Consume buffered input events, if any.
if (mInputBufferIndex < mInputBufferCount) {
const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
- const device_t* device = mDevices[mInputDeviceIndex];
+ const Device* device = mDevices[mInputFdIndex];
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
- if (device->id == mFirstKeyboardId) {
+ if (device->id == mBuiltInKeyboardId) {
outEvent->deviceId = 0;
} else {
outEvent->deviceId = device->id;
}
outEvent->type = iev.type;
outEvent->scanCode = iev.code;
+ outEvent->flags = 0;
if (iev.type == EV_KEY) {
- status_t err = device->layoutMap->map(iev.code,
- & outEvent->keyCode, & outEvent->flags);
- LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
- iev.code, outEvent->keyCode, outEvent->flags, err);
- if (err != 0) {
- outEvent->keyCode = AKEYCODE_UNKNOWN;
- outEvent->flags = 0;
+ outEvent->keyCode = AKEYCODE_UNKNOWN;
+ if (device->keyMap.haveKeyLayout()) {
+ status_t err = device->keyMap.keyLayoutMap->map(iev.code,
+ &outEvent->keyCode, &outEvent->flags);
+ LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
+ iev.code, outEvent->keyCode, outEvent->flags, err);
}
} else {
outEvent->keyCode = iev.code;
@@ -439,13 +505,13 @@
// Finish reading all events from devices identified in previous poll().
// This code assumes that mInputDeviceIndex is initially 0 and that the
// revents member of pollfd is initialized to 0 when the device is first added.
- // Since mFDs[0] is used for inotify, we process regular events starting at index 1.
- mInputDeviceIndex += 1;
- if (mInputDeviceIndex >= mFDCount) {
+ // Since mFds[0] is used for inotify, we process regular events starting at index 1.
+ mInputFdIndex += 1;
+ if (mInputFdIndex >= mFds.size()) {
break;
}
- const struct pollfd& pfd = mFDs[mInputDeviceIndex];
+ const struct pollfd& pfd = mFds[mInputFdIndex];
if (pfd.revents & POLLIN) {
int32_t readSize = read(pfd.fd, mInputBufferData,
sizeof(struct input_event) * INPUT_BUFFER_SIZE);
@@ -456,7 +522,7 @@
} else if ((readSize % sizeof(struct input_event)) != 0) {
LOGE("could not get event (wrong size: %d)", readSize);
} else {
- mInputBufferCount = readSize / sizeof(struct input_event);
+ mInputBufferCount = size_t(readSize) / sizeof(struct input_event);
mInputBufferIndex = 0;
}
}
@@ -465,14 +531,14 @@
#if HAVE_INOTIFY
// readNotify() will modify mFDs and mFDCount, so this must be done after
// processing all other events.
- if(mFDs[0].revents & POLLIN) {
- readNotify(mFDs[0].fd);
- mFDs[0].revents = 0;
+ if(mFds[0].revents & POLLIN) {
+ readNotify(mFds[0].fd);
+ mFds.editItemAt(0).revents = 0;
continue; // report added or removed devices immediately
}
#endif
- mInputDeviceIndex = 0;
+ mInputFdIndex = 0;
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during poll(). This works due to some
@@ -484,7 +550,7 @@
// pending or currently being processed.
release_wake_lock(WAKE_LOCK_ID);
- int pollResult = poll(mFDs, mFDCount, -1);
+ int pollResult = poll(mFds.editArray(), mFds.size(), -1);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
@@ -500,36 +566,37 @@
/*
* Open the platform-specific input device.
*/
-bool EventHub::openPlatformInput(void)
-{
+bool EventHub::openPlatformInput(void) {
/*
* Open platform-specific input device(s).
*/
- int res;
+ int res, fd;
- mFDCount = 1;
- mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
- mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
- mFDs[0].events = POLLIN;
- mFDs[0].revents = 0;
- mDevices[0] = NULL;
#ifdef HAVE_INOTIFY
- mFDs[0].fd = inotify_init();
- res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
+ fd = inotify_init();
+ res = inotify_add_watch(fd, DEVICE_PATH, IN_DELETE | IN_CREATE);
if(res < 0) {
- LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
+ LOGE("could not add watch for %s, %s\n", DEVICE_PATH, strerror(errno));
}
#else
/*
* The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
* We allocate space for it and set it to something invalid.
*/
- mFDs[0].fd = -1;
+ fd = -1;
#endif
- res = scanDir(device_path);
+ // Reserve fd index 0 for inotify.
+ struct pollfd pollfd;
+ pollfd.fd = fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+ mFds.push(pollfd);
+ mDevices.push(NULL);
+
+ res = scanDir(DEVICE_PATH);
if(res < 0) {
- LOGE("scan dir failed for %s\n", device_path);
+ LOGE("scan dir failed for %s\n", DEVICE_PATH);
}
return true;
@@ -557,128 +624,104 @@
AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
};
-int EventHub::openDevice(const char *deviceName) {
- int version;
- int fd;
- struct pollfd *new_mFDs;
- device_t **new_devices;
- char **new_device_names;
- char name[80];
- char location[80];
- char idstr[80];
- struct input_id id;
+int EventHub::openDevice(const char *devicePath) {
+ char buffer[80];
- LOGV("Opening device: %s", deviceName);
+ LOGV("Opening device: %s", devicePath);
AutoMutex _l(mLock);
- fd = open(deviceName, O_RDWR);
+ int fd = open(devicePath, O_RDWR);
if(fd < 0) {
- LOGE("could not open %s, %s\n", deviceName, strerror(errno));
+ LOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
- if(ioctl(fd, EVIOCGVERSION, &version)) {
- LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
- return -1;
- }
- if(ioctl(fd, EVIOCGID, &id)) {
- LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
- return -1;
- }
- name[sizeof(name) - 1] = '\0';
- location[sizeof(location) - 1] = '\0';
- idstr[sizeof(idstr) - 1] = '\0';
- if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
- //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
- name[0] = '\0';
+ InputDeviceIdentifier identifier;
+
+ // Get device name.
+ if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
+ //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
+ } else {
+ buffer[sizeof(buffer) - 1] = '\0';
+ identifier.name.setTo(buffer);
}
- // check to see if the device is on our excluded list
+ // Check to see if the device is on our excluded list
List<String8>::iterator iter = mExcludedDevices.begin();
List<String8>::iterator end = mExcludedDevices.end();
for ( ; iter != end; iter++) {
const char* test = *iter;
- if (strcmp(name, test) == 0) {
- LOGI("ignoring event id %s driver %s\n", deviceName, test);
+ if (identifier.name == test) {
+ LOGI("ignoring event id %s driver %s\n", devicePath, test);
close(fd);
return -1;
}
}
- if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
- //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
- location[0] = '\0';
- }
- if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
- //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
- idstr[0] = '\0';
+ // Get device driver version.
+ int driverVersion;
+ if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
+ LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
+ close(fd);
+ return -1;
}
+ // Get device identifier.
+ struct input_id inputId;
+ if(ioctl(fd, EVIOCGID, &inputId)) {
+ LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ identifier.bus = inputId.bustype;
+ identifier.product = inputId.product;
+ identifier.vendor = inputId.vendor;
+ identifier.version = inputId.version;
+
+ // Get device physical location.
+ if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
+ //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
+ } else {
+ buffer[sizeof(buffer) - 1] = '\0';
+ identifier.location.setTo(buffer);
+ }
+
+ // Get device unique id.
+ if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
+ //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
+ } else {
+ buffer[sizeof(buffer) - 1] = '\0';
+ identifier.uniqueId.setTo(buffer);
+ }
+
+ // Make file descriptor non-blocking for use with poll().
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
LOGE("Error %d making device file descriptor non-blocking.", errno);
close(fd);
return -1;
}
- int devid = 0;
- while (devid < mNumDevicesById) {
- if (mDevicesById[devid].device == NULL) {
- break;
- }
- devid++;
- }
- if (devid >= mNumDevicesById) {
- device_ent* new_devids = (device_ent*)realloc(mDevicesById,
- sizeof(mDevicesById[0]) * (devid + 1));
- if (new_devids == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mDevicesById = new_devids;
- mNumDevicesById = devid+1;
- mDevicesById[devid].device = NULL;
- mDevicesById[devid].seq = 0;
- }
-
- mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
- if (mDevicesById[devid].seq == 0) {
- mDevicesById[devid].seq = 1<<SEQ_SHIFT;
- }
-
- new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
- new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
- if (new_mFDs == NULL || new_devices == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mFDs = new_mFDs;
- mDevices = new_devices;
+ // Allocate device. (The device object takes ownership of the fd at this point.)
+ int32_t deviceId = mNextDeviceId++;
+ Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
#if 0
- LOGI("add device %d: %s\n", mFDCount, deviceName);
- LOGI(" bus: %04x\n"
- " vendor %04x\n"
- " product %04x\n"
- " version %04x\n",
- id.bustype, id.vendor, id.product, id.version);
- LOGI(" name: \"%s\"\n", name);
- LOGI(" location: \"%s\"\n"
- " id: \"%s\"\n", location, idstr);
- LOGI(" version: %d.%d.%d\n",
- version >> 16, (version >> 8) & 0xff, version & 0xff);
+ LOGI("add device %d: %s\n", deviceId, devicePath);
+ LOGI(" bus: %04x\n"
+ " vendor %04x\n"
+ " product %04x\n"
+ " version %04x\n",
+ identifier.bus, identifier.vendor, identifier.product, identifier.version);
+ LOGI(" name: \"%s\"\n", identifier.name.string());
+ LOGI(" location: \"%s\"\n", identifier.location.string());
+ LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string());
+ LOGI(" driver: v%d.%d.%d\n",
+ driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
#endif
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
- if (device == NULL) {
- LOGE("out of memory");
- return -1;
- }
-
- device->fd = fd;
- mFDs[mFDCount].fd = fd;
- mFDs[mFDCount].events = POLLIN;
- mFDs[mFDCount].revents = 0;
+ // Load the configuration file for the device.
+ loadConfiguration(device);
// Figure out the kinds of events the device reports.
@@ -748,7 +791,7 @@
bool hasSwitches = false;
if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
for (int i=0; i<EV_SW; i++) {
- //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
+ //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
if (test_bit(i, sw_bitmask)) {
hasSwitches = true;
if (mSwitches[i] == 0) {
@@ -762,55 +805,36 @@
}
#endif
+ if ((device->classes & INPUT_DEVICE_CLASS_TOUCHSCREEN)) {
+ // Load the virtual keys for the touch screen, if any.
+ // We do this now so that we can make sure to load the keymap if necessary.
+ status_t status = loadVirtualKeyMap(device);
+ if (!status) {
+ device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
+ }
+ }
+
if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
- char tmpfn[sizeof(name)];
- char keylayoutFilename[300];
+ // Load the keymap for the device.
+ status_t status = loadKeyMap(device);
- // a more descriptive name
- device->name = name;
+ // Set system properties for the keyboard.
+ setKeyboardProperties(device, false);
- // replace all the spaces with underscores
- strcpy(tmpfn, name);
- for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
- *p = '_';
-
- // find the .kl file we need for this device
- const char* root = getenv("ANDROID_ROOT");
- snprintf(keylayoutFilename, sizeof(keylayoutFilename),
- "%s/usr/keylayout/%s.kl", root, tmpfn);
- bool defaultKeymap = false;
- if (access(keylayoutFilename, R_OK)) {
- snprintf(keylayoutFilename, sizeof(keylayoutFilename),
- "%s/usr/keylayout/%s", root, "qwerty.kl");
- defaultKeymap = true;
+ // Register the keyboard as a built-in keyboard if it is eligible.
+ if (!status
+ && mBuiltInKeyboardId == -1
+ && isEligibleBuiltInKeyboard(device->identifier,
+ device->configuration, &device->keyMap)) {
+ mBuiltInKeyboardId = device->id;
+ setKeyboardProperties(device, true);
}
- status_t status = device->layoutMap->load(keylayoutFilename);
- if (status) {
- LOGE("Error %d loading key layout.", status);
- }
-
- // tell the world about the devname (the descriptive name)
- if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
- // the built-in keyboard has a well-known device ID of 0,
- // this device better not go away.
- mHaveFirstKeyboard = true;
- mFirstKeyboardId = device->id;
- property_set("hw.keyboards.0.devname", name);
- } else {
- // ensure mFirstKeyboardId is set to -something-.
- if (mFirstKeyboardId == 0) {
- mFirstKeyboardId = device->id;
- }
- }
- char propName[100];
- sprintf(propName, "hw.keyboards.%u.devname", device->id);
- property_set(propName, name);
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
if (hasKeycodeLocked(device, AKEYCODE_Q)) {
device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
}
-
+
// See if this device has a DPAD.
if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
@@ -819,7 +843,7 @@
hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
device->classes |= INPUT_DEVICE_CLASS_DPAD;
}
-
+
// See if this device has a gamepad.
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
@@ -827,42 +851,87 @@
break;
}
}
-
- LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
- device->id, name, propName, keylayoutFilename);
}
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
- LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid);
- close(fd);
+ LOGV("Dropping device: id=%d, path='%s', name='%s'",
+ deviceId, devicePath, device->identifier.name.string());
delete device;
return -1;
}
- LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
-
- LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
- deviceName, device, mFDCount, devid, device->classes);
+ LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
+ "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
+ deviceId, fd, devicePath, device->identifier.name.string(),
+ device->classes,
+ device->configurationFile.string(),
+ device->keyMap.keyLayoutFile.string(),
+ device->keyMap.keyCharacterMapFile.string(),
+ toString(mBuiltInKeyboardId == deviceId));
- mDevicesById[devid].device = device;
+ struct pollfd pollfd;
+ pollfd.fd = fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+ mFds.push(pollfd);
+ mDevices.push(device);
+
device->next = mOpeningDevices;
mOpeningDevices = device;
- mDevices[mFDCount] = device;
-
- mFDCount++;
return 0;
}
-bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const
-{
- if (device->keyBitmask == NULL || device->layoutMap == NULL) {
+void EventHub::loadConfiguration(Device* device) {
+ device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
+ if (device->configurationFile.isEmpty()) {
+ LOGD("No input device configuration file found for device '%s'.",
+ device->identifier.name.string());
+ } else {
+ status_t status = PropertyMap::load(device->configurationFile,
+ &device->configuration);
+ if (status) {
+ LOGE("Error loading input device configuration file for device '%s'. "
+ "Using default configuration.",
+ device->identifier.name.string());
+ }
+ }
+}
+
+status_t EventHub::loadVirtualKeyMap(Device* device) {
+ // The virtual key map is supplied by the kernel as a system board property file.
+ String8 path;
+ path.append("/sys/board_properties/virtualkeys.");
+ path.append(device->identifier.name);
+ if (access(path.string(), R_OK)) {
+ return NAME_NOT_FOUND;
+ }
+ return VirtualKeyMap::load(path, &device->virtualKeyMap);
+}
+
+status_t EventHub::loadKeyMap(Device* device) {
+ return device->keyMap.load(device->identifier, device->configuration);
+}
+
+void EventHub::setKeyboardProperties(Device* device, bool builtInKeyboard) {
+ int32_t id = builtInKeyboard ? 0 : device->id;
+ android::setKeyboardProperties(id, device->identifier,
+ device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile);
+}
+
+void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) {
+ int32_t id = builtInKeyboard ? 0 : device->id;
+ android::clearKeyboardProperties(id);
+}
+
+bool EventHub::hasKeycodeLocked(Device* device, int keycode) const {
+ if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
return false;
}
Vector<int32_t> scanCodes;
- device->layoutMap->findScancodes(keycode, &scanCodes);
+ device->keyMap.keyLayoutMap->findScanCodes(keycode, &scanCodes);
const size_t N = scanCodes.size();
for (size_t i=0; i<N && i<=KEY_MAX; i++) {
int32_t sc = scanCodes.itemAt(i);
@@ -874,29 +943,15 @@
return false;
}
-int EventHub::closeDevice(const char *deviceName) {
+int EventHub::closeDevice(const char *devicePath) {
AutoMutex _l(mLock);
- int i;
- for(i = 1; i < mFDCount; i++) {
- if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
- //LOGD("remove device %d: %s\n", i, deviceName);
- device_t* device = mDevices[i];
-
- LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- device->path.string(), device->name.string(), device->id,
- mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
-
- // Clear this device's entry.
- int index = (device->id&ID_MASK);
- mDevicesById[index].device = NULL;
-
- // Close the file descriptor and compact the fd array.
- close(mFDs[i].fd);
- int count = mFDCount - i - 1;
- memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
- memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
- mFDCount--;
+ for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
+ Device* device = mDevices[i];
+ if (device->path == devicePath) {
+ LOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
+ device->path.string(), device->identifier.name.string(), device->id,
+ device->fd, device->classes);
#ifdef EV_SW
for (int j=0; j<EV_SW; j++) {
@@ -905,24 +960,25 @@
}
}
#endif
-
+
+ if (device->id == mBuiltInKeyboardId) {
+ LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
+ device->path.string(), mBuiltInKeyboardId);
+ mBuiltInKeyboardId = -1;
+ clearKeyboardProperties(device, true);
+ }
+ clearKeyboardProperties(device, false);
+
+ mFds.removeAt(i);
+ mDevices.removeAt(i);
+ device->close();
+
device->next = mClosingDevices;
mClosingDevices = device;
-
- if (device->id == mFirstKeyboardId) {
- LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
- device->path.string(), mFirstKeyboardId);
- mFirstKeyboardId = 0;
- property_set("hw.keyboards.0.devname", NULL);
- }
- // clear the property
- char propName[100];
- sprintf(propName, "hw.keyboards.%u.devname", device->id);
- property_set(propName, NULL);
return 0;
}
}
- LOGE("remove device: %s not found\n", deviceName);
+ LOGE("remove device: %s not found\n", devicePath);
return -1;
}
@@ -946,7 +1002,7 @@
}
//printf("got %d bytes of event information\n", res);
- strcpy(devname, device_path);
+ strcpy(devname, DEVICE_PATH);
filename = devname + strlen(devname);
*filename++ = '/';
@@ -970,7 +1026,6 @@
return 0;
}
-
int EventHub::scanDir(const char *dirname)
{
char devname[PATH_MAX];
@@ -1001,23 +1056,34 @@
{ // acquire lock
AutoMutex _l(mLock);
- dump.appendFormat(INDENT "HaveFirstKeyboard: %s\n", toString(mHaveFirstKeyboard));
- dump.appendFormat(INDENT "FirstKeyboardId: 0x%x\n", mFirstKeyboardId);
+ dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
dump.append(INDENT "Devices:\n");
- for (int i = 0; i < mNumDevicesById; i++) {
- const device_t* device = mDevicesById[i].device;
+ for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
+ const Device* device = mDevices[i];
if (device) {
- if (mFirstKeyboardId == device->id) {
- dump.appendFormat(INDENT2 "0x%x: %s (aka device 0 - first keyboard)\n",
- device->id, device->name.string());
+ if (mBuiltInKeyboardId == device->id) {
+ dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
+ device->id, device->identifier.name.string());
} else {
- dump.appendFormat(INDENT2 "0x%x: %s\n", device->id, device->name.string());
+ dump.appendFormat(INDENT2 "%d: %s\n", device->id,
+ device->identifier.name.string());
}
dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
- dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", device->keylayoutFilename.string());
+ dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
+ dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
+ dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
+ "product=0x%04x, version=0x%04x\n",
+ device->identifier.bus, device->identifier.vendor,
+ device->identifier.product, device->identifier.version);
+ dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
+ device->keyMap.keyLayoutFile.string());
+ dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
+ device->keyMap.keyCharacterMapFile.string());
+ dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
+ device->configurationFile.string());
}
}
} // release lock
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 04a0195..0702d49 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -182,6 +182,16 @@
return fb->setSwapInterval(fb, interval);
}
+void FramebufferNativeWindow::dump(String8& result) {
+ if (fbDev->common.version >= 1 && fbDev->dump) {
+ const size_t SIZE = 4096;
+ char buffer[SIZE];
+
+ fbDev->dump(fbDev, buffer, SIZE);
+ result.append(buffer);
+ }
+}
+
// only for debugging / logging
int FramebufferNativeWindow::getCurrentBufferIndex() const
{
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 3671954..97312a6 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -45,7 +45,6 @@
stride =
format =
usage = 0;
- transform = 0;
handle = NULL;
}
@@ -58,8 +57,7 @@
height =
stride =
format =
- usage =
- transform = 0;
+ usage = 0;
handle = NULL;
mInitCheck = initSize(w, h, reqFormat, reqUsage);
}
@@ -76,10 +74,22 @@
stride = inStride;
format = inFormat;
usage = inUsage;
- transform = 0;
handle = inHandle;
}
+GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership)
+ : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+ mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer)
+{
+ width = buffer->width;
+ height = buffer->height;
+ stride = buffer->stride;
+ format = buffer->format;
+ usage = buffer->usage;
+ handle = buffer->handle;
+}
+
GraphicBuffer::~GraphicBuffer()
{
if (handle) {
@@ -90,12 +100,14 @@
void GraphicBuffer::free_handle()
{
if (mOwner == ownHandle) {
+ mBufferMapper.unregisterBuffer(handle);
native_handle_close(handle);
native_handle_delete(const_cast<native_handle*>(handle));
} else if (mOwner == ownData) {
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
}
+ mWrappedBuffer = 0;
}
status_t GraphicBuffer::initCheck() const {
@@ -185,10 +197,8 @@
return res;
}
-const int kFlattenFdsOffset = 9;
-
size_t GraphicBuffer::getFlattenedSize() const {
- return (kFlattenFdsOffset + (handle ? handle->numInts : 0))*sizeof(int);
+ return (8 + (handle ? handle->numInts : 0))*sizeof(int);
}
size_t GraphicBuffer::getFdCount() const {
@@ -213,14 +223,13 @@
buf[5] = usage;
buf[6] = 0;
buf[7] = 0;
- buf[8] = transform;
if (handle) {
buf[6] = handle->numFds;
buf[7] = handle->numInts;
native_handle_t const* const h = handle;
memcpy(fds, h->data, h->numFds*sizeof(int));
- memcpy(&buf[kFlattenFdsOffset], h->data + h->numFds, h->numInts*sizeof(int));
+ memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int));
}
return NO_ERROR;
@@ -229,7 +238,7 @@
status_t GraphicBuffer::unflatten(void const* buffer, size_t size,
int fds[], size_t count)
{
- if (size < kFlattenFdsOffset*sizeof(int)) return NO_MEMORY;
+ if (size < 8*sizeof(int)) return NO_MEMORY;
int const* buf = static_cast<int const*>(buffer);
if (buf[0] != 'GBFR') return BAD_TYPE;
@@ -237,7 +246,7 @@
const size_t numFds = buf[6];
const size_t numInts = buf[7];
- const size_t sizeNeeded = (kFlattenFdsOffset + numInts) * sizeof(int);
+ const size_t sizeNeeded = (8 + numInts) * sizeof(int);
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = 0;
@@ -254,10 +263,9 @@
stride = buf[3];
format = buf[4];
usage = buf[5];
- transform = buf[8];
native_handle* h = native_handle_create(numFds, numInts);
memcpy(h->data, fds, numFds*sizeof(int));
- memcpy(h->data + numFds, &buf[kFlattenFdsOffset], numInts*sizeof(int));
+ memcpy(h->data + numFds, &buf[8], numInts*sizeof(int));
handle = h;
} else {
width = height = stride = format = usage = 0;
@@ -265,6 +273,11 @@
}
mOwner = ownHandle;
+
+ if (handle != 0) {
+ mBufferMapper.registerBuffer(handle);
+ }
+
return NO_ERROR;
}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index fa46ab7..ce84683 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -24,8 +24,6 @@
#include <ui/GraphicBufferAllocator.h>
-#include <private/ui/sw_gralloc_handle.h>
-
namespace android {
// ---------------------------------------------------------------------------
@@ -56,7 +54,7 @@
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
size_t total = 0;
- const size_t SIZE = 512;
+ const size_t SIZE = 4096;
char buffer[SIZE];
snprintf(buffer, SIZE, "Allocated buffers:\n");
result.append(buffer);
@@ -71,6 +69,10 @@
}
snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
result.append(buffer);
+ if (mAllocDev->common.version >= 1 && mAllocDev->dump) {
+ mAllocDev->dump(mAllocDev, buffer, SIZE);
+ result.append(buffer);
+ }
}
void GraphicBufferAllocator::dumpToSystemLog()
@@ -91,11 +93,7 @@
// we have a h/w allocator and h/w buffer is requested
status_t err;
- if (usage & GRALLOC_USAGE_HW_MASK) {
- err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
- } else {
- err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride);
- }
+ err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
w, h, format, usage, err, strerror(-err));
@@ -119,11 +117,8 @@
status_t GraphicBufferAllocator::free(buffer_handle_t handle)
{
status_t err;
- if (sw_gralloc_handle_t::validate(handle) < 0) {
- err = mAllocDev->free(mAllocDev, handle);
- } else {
- err = sw_gralloc_handle_t::free((sw_gralloc_handle_t*)handle);
- }
+
+ err = mAllocDev->free(mAllocDev, handle);
LOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
if (err == NO_ERROR) {
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index ce2acd0..07c0674 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -17,15 +17,7 @@
#define LOG_TAG "GraphicBufferMapper"
#include <stdint.h>
-#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define
-# include <asm/page.h>
-#else
-# include <sys/user.h>
-#endif
#include <errno.h>
-#include <sys/mman.h>
-
-#include <cutils/ashmem.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -35,8 +27,6 @@
#include <hardware/gralloc.h>
-#include <private/ui/sw_gralloc_handle.h>
-
namespace android {
// ---------------------------------------------------------------------------
@@ -57,11 +47,9 @@
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
{
status_t err;
- if (sw_gralloc_handle_t::validate(handle) < 0) {
- err = mAllocMod->registerBuffer(mAllocMod, handle);
- } else {
- err = sw_gralloc_handle_t::registerBuffer((sw_gralloc_handle_t*)handle);
- }
+
+ err = mAllocMod->registerBuffer(mAllocMod, handle);
+
LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
handle, err, strerror(-err));
return err;
@@ -70,11 +58,9 @@
status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
{
status_t err;
- if (sw_gralloc_handle_t::validate(handle) < 0) {
- err = mAllocMod->unregisterBuffer(mAllocMod, handle);
- } else {
- err = sw_gralloc_handle_t::unregisterBuffer((sw_gralloc_handle_t*)handle);
- }
+
+ err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+
LOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
handle, err, strerror(-err));
return err;
@@ -84,15 +70,11 @@
int usage, const Rect& bounds, void** vaddr)
{
status_t err;
- if (sw_gralloc_handle_t::validate(handle) < 0) {
- err = mAllocMod->lock(mAllocMod, handle, usage,
- bounds.left, bounds.top, bounds.width(), bounds.height(),
- vaddr);
- } else {
- err = sw_gralloc_handle_t::lock((sw_gralloc_handle_t*)handle, usage,
- bounds.left, bounds.top, bounds.width(), bounds.height(),
- vaddr);
- }
+
+ err = mAllocMod->lock(mAllocMod, handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(),
+ vaddr);
+
LOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
return err;
}
@@ -100,129 +82,12 @@
status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
{
status_t err;
- if (sw_gralloc_handle_t::validate(handle) < 0) {
- err = mAllocMod->unlock(mAllocMod, handle);
- } else {
- err = sw_gralloc_handle_t::unlock((sw_gralloc_handle_t*)handle);
- }
+
+ err = mAllocMod->unlock(mAllocMod, handle);
+
LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
return err;
}
// ---------------------------------------------------------------------------
-
-status_t sw_gralloc_handle_t::alloc(uint32_t w, uint32_t h, int format,
- int usage, buffer_handle_t* pHandle, int32_t* pStride)
-{
- int align = 4;
- int bpp = 0;
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- bpp = 4;
- break;
- case HAL_PIXEL_FORMAT_RGB_888:
- bpp = 3;
- break;
- case HAL_PIXEL_FORMAT_RGB_565:
- case HAL_PIXEL_FORMAT_RGBA_5551:
- case HAL_PIXEL_FORMAT_RGBA_4444:
- bpp = 2;
- break;
- default:
- return -EINVAL;
- }
- size_t bpr = (w*bpp + (align-1)) & ~(align-1);
- size_t size = bpr * h;
- size_t stride = bpr / bpp;
- size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
-
- int fd = ashmem_create_region("sw-gralloc-buffer", size);
- if (fd < 0) {
- LOGE("ashmem_create_region(size=%d) failed (%s)",
- size, strerror(-errno));
- return -errno;
- }
-
- int prot = PROT_READ;
- if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
- prot |= PROT_WRITE;
-
- if (ashmem_set_prot_region(fd, prot) < 0) {
- LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)",
- fd, prot, strerror(-errno));
- close(fd);
- return -errno;
- }
-
- void* base = mmap(0, size, prot, MAP_SHARED, fd, 0);
- if (base == MAP_FAILED) {
- LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)",
- fd, size, prot, strerror(-errno));
- close(fd);
- return -errno;
- }
-
- sw_gralloc_handle_t* hnd = new sw_gralloc_handle_t();
- hnd->fd = fd;
- hnd->size = size;
- hnd->base = intptr_t(base);
- hnd->prot = prot;
- *pStride = stride;
- *pHandle = hnd;
-
- return NO_ERROR;
-}
-
-status_t sw_gralloc_handle_t::free(sw_gralloc_handle_t* hnd)
-{
- if (hnd->base) {
- munmap((void*)hnd->base, hnd->size);
- }
- if (hnd->fd >= 0) {
- close(hnd->fd);
- }
- delete hnd;
- return NO_ERROR;
-}
-
-status_t sw_gralloc_handle_t::registerBuffer(sw_gralloc_handle_t* hnd)
-{
- if (hnd->pid != getpid()) {
- void* base = mmap(0, hnd->size, hnd->prot, MAP_SHARED, hnd->fd, 0);
- if (base == MAP_FAILED) {
- LOGE("registerBuffer mmap(fd=%d, size=%d, prot=%x) failed (%s)",
- hnd->fd, hnd->size, hnd->prot, strerror(-errno));
- return -errno;
- }
- hnd->base = intptr_t(base);
- }
- return NO_ERROR;
-}
-
-status_t sw_gralloc_handle_t::unregisterBuffer(sw_gralloc_handle_t* hnd)
-{
- if (hnd->pid != getpid()) {
- if (hnd->base) {
- munmap((void*)hnd->base, hnd->size);
- }
- hnd->base = 0;
- }
- return NO_ERROR;
-}
-
-status_t sw_gralloc_handle_t::lock(sw_gralloc_handle_t* hnd, int usage,
- int l, int t, int w, int h, void** vaddr)
-{
- *vaddr = (void*)hnd->base;
- return NO_ERROR;
-}
-
-status_t sw_gralloc_handle_t::unlock(sw_gralloc_handle_t* hnd)
-{
- return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
deleted file mode 100644
index 65e6b4f..0000000
--- a/libs/ui/IOverlay.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2007 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 <stdio.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <binder/IInterface.h>
-
-#include <ui/IOverlay.h>
-
-namespace android {
-
-enum {
- DESTROY = IBinder::FIRST_CALL_TRANSACTION, // one-way transaction
-};
-
-class BpOverlay : public BpInterface<IOverlay>
-{
-public:
- BpOverlay(const sp<IBinder>& impl)
- : BpInterface<IOverlay>(impl)
- {
- }
-
- virtual void destroy()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IOverlay::getInterfaceDescriptor());
- remote()->transact(DESTROY, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(Overlay, "android.ui.IOverlay");
-
-// ----------------------------------------------------------------------
-
-status_t BnOverlay::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case DESTROY: {
- CHECK_INTERFACE(IOverlay, data, reply);
- destroy();
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 811edaf..b8d59e6 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -7,11 +7,117 @@
//#define LOG_NDEBUG 0
+#define DEBUG_PROBE 0
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
#include <ui/Input.h>
namespace android {
-// class InputEvent
+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
+ LOGD("Probing for system provided input device configuration file: path='%s'", path.string());
+#endif
+ if (!access(path.string(), R_OK)) {
+#if DEBUG_PROBE
+ LOGD("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
+ LOGD("Probing for system user input device configuration file: path='%s'", path.string());
+#endif
+ if (!access(path.string(), R_OK)) {
+#if DEBUG_PROBE
+ LOGD("Found");
+#endif
+ return path;
+ }
+
+ // Not found.
+#if DEBUG_PROBE
+ LOGD("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;
@@ -23,7 +129,7 @@
mSource = from.mSource;
}
-// class KeyEvent
+// --- KeyEvent ---
bool KeyEvent::hasDefaultAction(int32_t keyCode) {
switch (keyCode) {
@@ -33,6 +139,7 @@
case AKEYCODE_ENDCALL:
case AKEYCODE_VOLUME_UP:
case AKEYCODE_VOLUME_DOWN:
+ case AKEYCODE_VOLUME_MUTE:
case AKEYCODE_POWER:
case AKEYCODE_CAMERA:
case AKEYCODE_HEADSETHOOK:
@@ -40,11 +147,14 @@
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;
@@ -67,14 +177,18 @@
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:
@@ -123,7 +237,7 @@
mEventTime = from.mEventTime;
}
-// class MotionEvent
+// --- MotionEvent ---
void MotionEvent::initialize(
int32_t deviceId,
@@ -170,7 +284,7 @@
mYOffset += yOffset;
}
-// class InputDeviceInfo
+// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
initialize(-1, String8("uninitialized device info"));
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 28ccc43..ed0cb8e 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -51,9 +51,6 @@
namespace android {
-// Delay before reporting long touch events to the power manager.
-const nsecs_t LONG_TOUCH_DELAY = 300 * 1000000LL; // 300 ms
-
// Default input dispatching timeout if there is no focused application or paused window
// from which to determine an appropriate dispatching timeout.
const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
@@ -160,6 +157,10 @@
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
+bool InputWindow::supportsSplitTouch() const {
+ return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH;
+}
+
// --- InputDispatcher ---
@@ -314,7 +315,7 @@
// Throttle it!
#if DEBUG_THROTTLING
LOGD("Throttling - Delaying motion event for "
- "device 0x%x, source 0x%08x by up to %0.3fms.",
+ "device %d, source 0x%08x by up to %0.3fms.",
deviceId, source, (nextTime - currentTime) * 0.000001);
#endif
if (nextTime < *nextWakeupTime) {
@@ -703,7 +704,7 @@
void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
+ LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
"repeatCount=%d, downTime=%lld",
prefix,
@@ -766,7 +767,7 @@
void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
+ LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, flags=0x%x, "
"metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
prefix,
@@ -907,9 +908,11 @@
ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- synthesizeCancelationEventsForConnectionLocked(
- connection, InputState::CANCEL_ALL_EVENTS,
- "application not responding");
+ if (connection->status == Connection::STATUS_NORMAL) {
+ synthesizeCancelationEventsForConnectionLocked(
+ connection, InputState::CANCEL_ALL_EVENTS,
+ "application not responding");
+ }
}
}
}
@@ -1113,8 +1116,7 @@
}
// Figure out whether splitting will be allowed for this window.
- if (newTouchedWindow
- && (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH)) {
+ if (newTouchedWindow && newTouchedWindow->supportsSplitTouch()) {
// New window supports splitting.
isSplit = true;
} else if (isSplit) {
@@ -1163,7 +1165,10 @@
// If the pointer is not currently down, then ignore the event.
if (! mTempTouchState.down) {
- LOGI("Dropping event because the pointer is not down.");
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ LOGD("Dropping event because the pointer is not down or we previously "
+ "dropped the pointer down event.");
+#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
@@ -1405,25 +1410,25 @@
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
int32_t eventType = POWER_MANAGER_BUTTON_EVENT;
- if (eventEntry->type == EventEntry::TYPE_MOTION) {
+ switch (eventEntry->type) {
+ case EventEntry::TYPE_MOTION: {
const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry);
- if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
- switch (motionEntry->action) {
- case AMOTION_EVENT_ACTION_DOWN:
- eventType = POWER_MANAGER_TOUCH_EVENT;
- break;
- case AMOTION_EVENT_ACTION_UP:
- eventType = POWER_MANAGER_TOUCH_UP_EVENT;
- break;
- default:
- if (motionEntry->eventTime - motionEntry->downTime < LONG_TOUCH_DELAY) {
- eventType = POWER_MANAGER_TOUCH_EVENT;
- } else {
- eventType = POWER_MANAGER_LONG_TOUCH_EVENT;
- }
- break;
- }
+ if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
+ return;
}
+
+ if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
+ eventType = POWER_MANAGER_TOUCH_EVENT;
+ }
+ break;
+ }
+ case EventEntry::TYPE_KEY: {
+ const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
+ if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
+ return;
+ }
+ break;
+ }
}
CommandEntry* commandEntry = postCommandLocked(
@@ -1753,13 +1758,14 @@
}
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
+ const sp<Connection>& connection, bool handled) {
#if DEBUG_DISPATCH_CYCLE
LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
- "%01.1fms since dispatch",
+ "%01.1fms since dispatch, handled=%s",
connection->getInputChannelName(),
connection->getEventLatencyMillis(currentTime),
- connection->getDispatchLatencyMillis(currentTime));
+ connection->getDispatchLatencyMillis(currentTime),
+ toString(handled));
#endif
if (connection->status == Connection::STATUS_BROKEN
@@ -1767,9 +1773,6 @@
return;
}
- // Notify other system components.
- onDispatchCycleFinishedLocked(currentTime, connection);
-
// Reset the publisher since the event has been consumed.
// We do this now so that the publisher can release some of its internal resources
// while waiting for the next dispatch cycle to begin.
@@ -1781,7 +1784,8 @@
return;
}
- startNextDispatchCycleLocked(currentTime, connection);
+ // Notify other system components and prepare to start the next dispatch cycle.
+ onDispatchCycleFinishedLocked(currentTime, connection, handled);
}
void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime,
@@ -1881,7 +1885,8 @@
return 1;
}
- status_t status = connection->inputPublisher.receiveFinishedSignal();
+ bool handled = false;
+ status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
if (status) {
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
@@ -1890,7 +1895,7 @@
return 0; // remove the callback
}
- d->finishDispatchCycleLocked(currentTime, connection);
+ d->finishDispatchCycleLocked(currentTime, connection, handled);
d->runCommandsLockedInterruptible();
return 1;
} // release lock
@@ -2069,7 +2074,7 @@
uint32_t policyFlags, int32_t action, int32_t flags,
int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyKey - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, "
+ LOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
eventTime, deviceId, source, policyFlags, action, flags,
keyCode, scanCode, metaState, downTime);
@@ -2078,9 +2083,22 @@
return;
}
+ if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
+ policyFlags |= POLICY_FLAG_VIRTUAL;
+ flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
+ }
+
policyFlags |= POLICY_FLAG_TRUSTED;
- mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
- keyCode, scanCode, /*byref*/ policyFlags);
+
+ KeyEvent event;
+ event.initialize(deviceId, source, action, flags, keyCode, scanCode,
+ metaState, 0, downTime, eventTime);
+
+ mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
+
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
+ flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
bool needWake;
{ // acquire lock
@@ -2104,7 +2122,7 @@
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
+ LOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, flags=0x%x, metaState=0x%x, edgeFlags=0x%x, "
"xPrecision=%f, yPrecision=%f, downTime=%lld",
eventTime, deviceId, source, policyFlags, action, flags, metaState, edgeFlags,
@@ -2286,17 +2304,22 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- nsecs_t eventTime = keyEvent->getEventTime();
- int32_t deviceId = keyEvent->getDeviceId();
int32_t flags = keyEvent->getFlags();
- int32_t keyCode = keyEvent->getKeyCode();
- int32_t scanCode = keyEvent->getScanCode();
- mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
- keyCode, scanCode, /*byref*/ policyFlags);
+ if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
+ policyFlags |= POLICY_FLAG_VIRTUAL;
+ }
+
+ mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
+
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
+ flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
mLock.lock();
- injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
- policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(),
+ injectedEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
+ keyEvent->getDeviceId(), keyEvent->getSource(),
+ policyFlags, action, flags,
+ keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
keyEvent->getRepeatCount(), keyEvent->getDownTime());
break;
}
@@ -2615,6 +2638,77 @@
}
}
+bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel) {
+#if DEBUG_FOCUS
+ LOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
+ fromChannel->getName().string(), toChannel->getName().string());
+#endif
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ const InputWindow* fromWindow = getWindowLocked(fromChannel);
+ const InputWindow* toWindow = getWindowLocked(toChannel);
+ if (! fromWindow || ! toWindow) {
+#if DEBUG_FOCUS
+ LOGD("Cannot transfer focus because from or to window not found.");
+#endif
+ return false;
+ }
+ if (fromWindow == toWindow) {
+#if DEBUG_FOCUS
+ LOGD("Trivial transfer to same window.");
+#endif
+ return true;
+ }
+
+ bool found = false;
+ for (size_t i = 0; i < mTouchState.windows.size(); i++) {
+ const TouchedWindow& touchedWindow = mTouchState.windows[i];
+ if (touchedWindow.window == fromWindow) {
+ int32_t oldTargetFlags = touchedWindow.targetFlags;
+ BitSet32 pointerIds = touchedWindow.pointerIds;
+
+ mTouchState.windows.removeAt(i);
+
+ int32_t newTargetFlags = oldTargetFlags
+ & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT);
+ mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
+
+ found = true;
+ break;
+ }
+ }
+
+ if (! found) {
+#if DEBUG_FOCUS
+ LOGD("Focus transfer failed because from window did not have focus.");
+#endif
+ return false;
+ }
+
+ ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
+ ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
+ if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
+ sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
+ sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+
+ fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
+ synthesizeCancelationEventsForConnectionLocked(fromConnection,
+ InputState::CANCEL_POINTER_EVENTS,
+ "transferring touch focus from this window to another window");
+ }
+
+#if DEBUG_FOCUS
+ logDispatchStateLocked();
+#endif
+ } // release lock
+
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+ return true;
+}
+
void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
#if DEBUG_FOCUS
LOGD("Resetting and dropping all events (%s).", reason);
@@ -2721,7 +2815,7 @@
dump.append(INDENT "ActiveConnections:\n");
for (size_t i = 0; i < mActiveConnections.size(); i++) {
const Connection* connection = mActiveConnections[i];
- dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u"
+ dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u, "
"inputState.isNeutral=%s\n",
i, connection->getInputChannelName(), connection->getStatusLabel(),
connection->outboundQueue.count(),
@@ -2852,7 +2946,11 @@
}
void InputDispatcher::onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection) {
+ nsecs_t currentTime, const sp<Connection>& connection, bool handled) {
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
+ commandEntry->connection = connection;
+ commandEntry->handled = handled;
}
void InputDispatcher::onDispatchCycleBrokenLocked(
@@ -2921,14 +3019,14 @@
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
- mReusableKeyEvent.initialize(entry->deviceId, entry->source, entry->action, entry->flags,
- entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
- entry->downTime, entry->eventTime);
+
+ KeyEvent event;
+ initializeKeyEvent(&event, entry);
mLock.unlock();
bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel,
- & mReusableKeyEvent, entry->policyFlags);
+ &event, entry->policyFlags);
mLock.lock();
@@ -2938,6 +3036,74 @@
mAllocator.releaseKeyEntry(entry);
}
+void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
+ CommandEntry* commandEntry) {
+ sp<Connection> connection = commandEntry->connection;
+ bool handled = commandEntry->handled;
+
+ if (!connection->outboundQueue.isEmpty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
+ if (dispatchEntry->inProgress
+ && dispatchEntry->hasForegroundTarget()
+ && dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
+ if (handled) {
+ // If the application handled a non-fallback key, then immediately
+ // cancel all fallback keys previously dispatched to the application.
+ // This behavior will prevent chording with fallback keys (so they cannot
+ // be used as modifiers) but it will ensure that fallback keys do not
+ // get stuck. This takes care of the case where the application does not handle
+ // the original DOWN so we generate a fallback DOWN but it does handle
+ // the original UP in which case we would not generate the fallback UP.
+ synthesizeCancelationEventsForConnectionLocked(connection,
+ InputState::CANCEL_FALLBACK_EVENTS,
+ "application handled a non-fallback event, canceling all fallback events");
+ } else {
+ // If the application did not handle a non-fallback key, then ask
+ // the policy what to do with it. We might generate a fallback key
+ // event here.
+ KeyEvent event;
+ initializeKeyEvent(&event, keyEntry);
+
+ mLock.unlock();
+
+ bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel,
+ &event, keyEntry->policyFlags, &event);
+
+ mLock.lock();
+
+ if (connection->status != Connection::STATUS_NORMAL) {
+ return;
+ }
+
+ assert(connection->outboundQueue.headSentinel.next == dispatchEntry);
+
+ if (fallback) {
+ // Restart the dispatch cycle using the fallback key.
+ keyEntry->eventTime = event.getEventTime();
+ keyEntry->deviceId = event.getDeviceId();
+ keyEntry->source = event.getSource();
+ keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
+ keyEntry->keyCode = event.getKeyCode();
+ keyEntry->scanCode = event.getScanCode();
+ keyEntry->metaState = event.getMetaState();
+ keyEntry->repeatCount = event.getRepeatCount();
+ keyEntry->downTime = event.getDownTime();
+ keyEntry->syntheticRepeat = false;
+
+ dispatchEntry->inProgress = false;
+ startDispatchCycleLocked(now(), connection);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ startNextDispatchCycleLocked(now(), connection);
+}
+
void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) {
mLock.unlock();
@@ -2946,6 +3112,12 @@
mLock.lock();
}
+void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) {
+ event->initialize(entry->deviceId, entry->source, entry->action, entry->flags,
+ entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
+ entry->downTime, entry->eventTime);
+}
+
void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) {
// TODO Write some statistics about how long we spend waiting.
@@ -3243,6 +3415,7 @@
memento.source = entry->source;
memento.keyCode = entry->keyCode;
memento.scanCode = entry->scanCode;
+ memento.flags = entry->flags;
memento.downTime = entry->downTime;
return CONSISTENT;
}
@@ -3325,10 +3498,10 @@
CancelationOptions options) {
for (size_t i = 0; i < mKeyMementos.size(); ) {
const KeyMemento& memento = mKeyMementos.itemAt(i);
- if (shouldCancelEvent(memento.source, options)) {
+ if (shouldCancelKey(memento, options)) {
outEvents.push(allocator->obtainKeyEntry(currentTime,
memento.deviceId, memento.source, 0,
- AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
+ AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
mKeyMementos.removeAt(i);
} else {
@@ -3338,7 +3511,7 @@
for (size_t i = 0; i < mMotionMementos.size(); ) {
const MotionMemento& memento = mMotionMementos.itemAt(i);
- if (shouldCancelEvent(memento.source, options)) {
+ if (shouldCancelMotion(memento, options)) {
outEvents.push(allocator->obtainMotionEntry(currentTime,
memento.deviceId, memento.source, 0,
AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
@@ -3356,15 +3529,48 @@
mMotionMementos.clear();
}
-bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
+void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos.itemAt(i);
+ if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
+ for (size_t j = 0; j < other.mMotionMementos.size(); ) {
+ const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
+ if (memento.deviceId == otherMemento.deviceId
+ && memento.source == otherMemento.source) {
+ other.mMotionMementos.removeAt(j);
+ } else {
+ j += 1;
+ }
+ }
+ other.mMotionMementos.push(memento);
+ }
+ }
+}
+
+bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
CancelationOptions options) {
switch (options) {
- case CANCEL_POINTER_EVENTS:
- return eventSource & AINPUT_SOURCE_CLASS_POINTER;
+ case CANCEL_ALL_EVENTS:
case CANCEL_NON_POINTER_EVENTS:
- return !(eventSource & AINPUT_SOURCE_CLASS_POINTER);
- default:
return true;
+ case CANCEL_FALLBACK_EVENTS:
+ return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
+ default:
+ return false;
+ }
+}
+
+bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
+ CancelationOptions options) {
+ switch (options) {
+ case CANCEL_ALL_EVENTS:
+ return true;
+ case CANCEL_POINTER_EVENTS:
+ return memento.source & AINPUT_SOURCE_CLASS_POINTER;
+ case CANCEL_NON_POINTER_EVENTS:
+ return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
+ default:
+ return false;
}
}
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 3197ab2..51ed09f 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -24,6 +24,8 @@
#include <cutils/log.h>
#include <ui/InputReader.h>
+#include <ui/Keyboard.h>
+#include <ui/VirtualKeyMap.h>
#include <stddef.h>
#include <stdlib.h>
@@ -70,43 +72,6 @@
return value ? "true" : "false";
}
-
-int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
- int32_t mask;
- switch (keyCode) {
- case AKEYCODE_ALT_LEFT:
- mask = AMETA_ALT_LEFT_ON;
- break;
- case AKEYCODE_ALT_RIGHT:
- mask = AMETA_ALT_RIGHT_ON;
- break;
- case AKEYCODE_SHIFT_LEFT:
- mask = AMETA_SHIFT_LEFT_ON;
- break;
- case AKEYCODE_SHIFT_RIGHT:
- mask = AMETA_SHIFT_RIGHT_ON;
- break;
- case AKEYCODE_SYM:
- mask = AMETA_SYM_ON;
- break;
- default:
- return oldMetaState;
- }
-
- int32_t newMetaState = down ? oldMetaState | mask : oldMetaState & ~ mask
- & ~ (AMETA_ALT_ON | AMETA_SHIFT_ON);
-
- if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
- newMetaState |= AMETA_ALT_ON;
- }
-
- if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
- newMetaState |= AMETA_SHIFT_ON;
- }
-
- return newMetaState;
-}
-
static const int32_t keyCodeRotationMap[][4] = {
// key codes enumerated counter-clockwise with the original (unrotated) key first
// no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
@@ -134,64 +99,6 @@
}
-// --- InputDeviceCalibration ---
-
-InputDeviceCalibration::InputDeviceCalibration() {
-}
-
-void InputDeviceCalibration::clear() {
- mProperties.clear();
-}
-
-void InputDeviceCalibration::addProperty(const String8& key, const String8& value) {
- mProperties.add(key, value);
-}
-
-bool InputDeviceCalibration::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 InputDeviceCalibration::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') {
- LOGW("Input device calibration key '%s' has invalid value '%s'. Expected an integer.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-bool InputDeviceCalibration::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') {
- LOGW("Input device calibration key '%s' has invalid value '%s'. Expected a float.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -215,7 +122,7 @@
mEventHub->getEvent(& rawEvent);
#if DEBUG_RAW_EVENTS
- LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
+ LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d",
rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
rawEvent.value);
#endif
@@ -251,9 +158,9 @@
device->configure();
if (device->isIgnored()) {
- LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", deviceId, name.string());
+ LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string());
} else {
- LOGI("Device added: id=0x%x, name=%s, sources=%08x", deviceId, name.string(),
+ LOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(),
device->getSources());
}
@@ -295,10 +202,10 @@
}
if (device->isIgnored()) {
- LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)",
+ LOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
device->getId(), device->getName().string());
} else {
- LOGI("Device removed: id=0x%x, name=%s, sources=%08x",
+ LOGI("Device removed: id=%d, name='%s', sources=0x%08x",
device->getId(), device->getName().string(), device->getSources());
}
@@ -310,8 +217,6 @@
InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) {
InputDevice* device = new InputDevice(this, deviceId, name);
- const int32_t associatedDisplayId = 0; // FIXME: hardcoded for current single-display devices
-
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device));
@@ -331,20 +236,19 @@
}
if (keyboardSources != 0) {
- device->addMapper(new KeyboardInputMapper(device,
- associatedDisplayId, keyboardSources, keyboardType));
+ device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType));
}
// Trackball-like devices.
if (classes & INPUT_DEVICE_CLASS_TRACKBALL) {
- device->addMapper(new TrackballInputMapper(device, associatedDisplayId));
+ device->addMapper(new TrackballInputMapper(device));
}
// Touchscreen-like devices.
if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) {
- device->addMapper(new MultiTouchInputMapper(device, associatedDisplayId));
+ device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
- device->addMapper(new SingleTouchInputMapper(device, associatedDisplayId));
+ device->addMapper(new SingleTouchInputMapper(device));
}
return device;
@@ -632,7 +536,7 @@
InputDeviceInfo deviceInfo;
getDeviceInfo(& deviceInfo);
- dump.appendFormat(INDENT "Device 0x%x: %s\n", deviceInfo.getId(),
+ dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(),
deviceInfo.getName().string());
dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
@@ -662,7 +566,7 @@
void InputDevice::configure() {
if (! isIgnored()) {
- mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration);
+ mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
}
mSources = 0;
@@ -828,9 +732,9 @@
// --- KeyboardInputMapper ---
-KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId,
+KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
uint32_t sources, int32_t keyboardType) :
- InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources),
+ InputMapper(device), mSources(sources),
mKeyboardType(keyboardType) {
initializeLocked();
}
@@ -857,7 +761,7 @@
{ // acquire lock
AutoMutex _l(mLock);
dump.append(INDENT2 "Keyboard Input Mapper:\n");
- dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dumpParameters(dump);
dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mLocked.keyDowns.size());
dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mLocked.metaState);
@@ -865,6 +769,36 @@
} // release lock
}
+
+void KeyboardInputMapper::configure() {
+ InputMapper::configure();
+
+ // Configure basic parameters.
+ configureParameters();
+
+ // Reset LEDs.
+ {
+ AutoMutex _l(mLock);
+ resetLedStateLocked();
+ }
+}
+
+void KeyboardInputMapper::configureParameters() {
+ mParameters.orientationAware = false;
+ getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
+ mParameters.orientationAware);
+
+ mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1;
+}
+
+void KeyboardInputMapper::dumpParameters(String8& dump) {
+ dump.append(INDENT3 "Parameters:\n");
+ dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
+ mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+ toString(mParameters.orientationAware));
+}
+
void KeyboardInputMapper::reset() {
for (;;) {
int32_t keyCode, scanCode;
@@ -874,6 +808,7 @@
// Synthesize key up event on reset if keys are currently down.
if (mLocked.keyDowns.isEmpty()) {
initializeLocked();
+ resetLedStateLocked();
break; // done
}
@@ -921,10 +856,11 @@
if (down) {
// Rotate key codes according to orientation if needed.
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
- if (mAssociatedDisplayId >= 0) {
+ if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
int32_t orientation;
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
- return;
+ if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+ NULL, NULL, & orientation)) {
+ orientation = InputReaderPolicyInterface::ROTATION_0;
}
keyCode = rotateKeyCode(keyCode, orientation);
@@ -965,6 +901,7 @@
if (oldMetaState != newMetaState) {
mLocked.metaState = newMetaState;
metaStateChanged = true;
+ updateLedStateLocked(false);
}
downTime = mLocked.downTime;
@@ -974,6 +911,9 @@
getContext()->updateGlobalMetaState();
}
+ if (policyFlags & POLICY_FLAG_FUNCTION) {
+ newMetaState |= AMETA_FUNCTION_ON;
+ }
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
@@ -1009,11 +949,44 @@
} // release lock
}
+void KeyboardInputMapper::resetLedStateLocked() {
+ initializeLedStateLocked(mLocked.capsLockLedState, LED_CAPSL);
+ initializeLedStateLocked(mLocked.numLockLedState, LED_NUML);
+ initializeLedStateLocked(mLocked.scrollLockLedState, LED_SCROLLL);
+
+ updateLedStateLocked(true);
+}
+
+void KeyboardInputMapper::initializeLedStateLocked(LockedState::LedState& ledState, int32_t led) {
+ ledState.avail = getEventHub()->hasLed(getDeviceId(), led);
+ ledState.on = false;
+}
+
+void KeyboardInputMapper::updateLedStateLocked(bool reset) {
+ updateLedStateForModifierLocked(mLocked.capsLockLedState, LED_CAPSL,
+ AMETA_CAPS_LOCK_ON, reset);
+ updateLedStateForModifierLocked(mLocked.numLockLedState, LED_NUML,
+ AMETA_NUM_LOCK_ON, reset);
+ updateLedStateForModifierLocked(mLocked.scrollLockLedState, LED_SCROLLL,
+ AMETA_SCROLL_LOCK_ON, reset);
+}
+
+void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState& ledState,
+ int32_t led, int32_t modifier, bool reset) {
+ if (ledState.avail) {
+ bool desiredState = (mLocked.metaState & modifier) != 0;
+ if (reset || ledState.on != desiredState) {
+ getEventHub()->setLedState(getDeviceId(), led, desiredState);
+ ledState.on = desiredState;
+ }
+ }
+}
+
// --- TrackballInputMapper ---
-TrackballInputMapper::TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+TrackballInputMapper::TrackballInputMapper(InputDevice* device) :
+ InputMapper(device) {
mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
@@ -1040,7 +1013,7 @@
{ // acquire lock
AutoMutex _l(mLock);
dump.append(INDENT2 "Trackball Input Mapper:\n");
- dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dumpParameters(dump);
dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down));
@@ -1048,6 +1021,29 @@
} // release lock
}
+void TrackballInputMapper::configure() {
+ InputMapper::configure();
+
+ // Configure basic parameters.
+ configureParameters();
+}
+
+void TrackballInputMapper::configureParameters() {
+ mParameters.orientationAware = false;
+ getDevice()->getConfiguration().tryGetProperty(String8("trackball.orientationAware"),
+ mParameters.orientationAware);
+
+ mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1;
+}
+
+void TrackballInputMapper::dumpParameters(String8& dump) {
+ dump.append(INDENT3 "Parameters:\n");
+ dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
+ mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+ toString(mParameters.orientationAware));
+}
+
void TrackballInputMapper::initializeLocked() {
mAccumulator.clear();
@@ -1156,12 +1152,14 @@
pointerCoords.toolMinor = 0;
pointerCoords.orientation = 0;
- if (mAssociatedDisplayId >= 0 && (x != 0.0f || y != 0.0f)) {
+ if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0
+ && (x != 0.0f || y != 0.0f)) {
// Rotate motion based on display orientation if needed.
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
int32_t orientation;
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
- return;
+ if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+ NULL, NULL, & orientation)) {
+ orientation = InputReaderPolicyInterface::ROTATION_0;
}
float temp;
@@ -1206,8 +1204,8 @@
// --- TouchInputMapper ---
-TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+TouchInputMapper::TouchInputMapper(InputDevice* device) :
+ InputMapper(device) {
mLocked.surfaceOrientation = -1;
mLocked.surfaceWidth = -1;
mLocked.surfaceHeight = -1;
@@ -1219,7 +1217,15 @@
}
uint32_t TouchInputMapper::getSources() {
- return mAssociatedDisplayId >= 0 ? AINPUT_SOURCE_TOUCHSCREEN : AINPUT_SOURCE_TOUCHPAD;
+ switch (mParameters.deviceType) {
+ case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
+ return AINPUT_SOURCE_TOUCHSCREEN;
+ case Parameters::DEVICE_TYPE_TOUCH_PAD:
+ return AINPUT_SOURCE_TOUCHPAD;
+ default:
+ assert(false);
+ return AINPUT_SOURCE_UNKNOWN;
+ }
}
void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1270,13 +1276,12 @@
{ // acquire lock
AutoMutex _l(mLock);
dump.append(INDENT2 "Touch Input Mapper:\n");
- dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
dumpParameters(dump);
dumpVirtualKeysLocked(dump);
dumpRawAxes(dump);
dumpCalibration(dump);
dumpSurfaceLocked(dump);
- dump.appendFormat(INDENT3 "Translation and Scaling Factors:");
+ dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
dump.appendFormat(INDENT4 "XOrigin: %d\n", mLocked.xOrigin);
dump.appendFormat(INDENT4 "YOrigin: %d\n", mLocked.yOrigin);
dump.appendFormat(INDENT4 "XScale: %0.3f\n", mLocked.xScale);
@@ -1340,14 +1345,50 @@
mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
+
+ String8 deviceTypeString;
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
+ deviceTypeString)) {
+ if (deviceTypeString == "touchPad") {
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ } else if (deviceTypeString != "touchScreen") {
+ LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
+ }
+ }
+ bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+
+ mParameters.orientationAware = isTouchScreen;
+ getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
+ mParameters.orientationAware);
+
+ mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1;
}
void TouchInputMapper::dumpParameters(String8& dump) {
- dump.appendFormat(INDENT3 "UseBadTouchFilter: %s\n",
+ dump.append(INDENT3 "Parameters:\n");
+
+ switch (mParameters.deviceType) {
+ case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
+ dump.append(INDENT4 "DeviceType: touchScreen\n");
+ break;
+ case Parameters::DEVICE_TYPE_TOUCH_PAD:
+ dump.append(INDENT4 "DeviceType: touchPad\n");
+ break;
+ default:
+ assert(false);
+ }
+
+ dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
+ mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+ toString(mParameters.orientationAware));
+
+ dump.appendFormat(INDENT4 "UseBadTouchFilter: %s\n",
toString(mParameters.useBadTouchFilter));
- dump.appendFormat(INDENT3 "UseAveragingTouchFilter: %s\n",
+ dump.appendFormat(INDENT4 "UseAveragingTouchFilter: %s\n",
toString(mParameters.useAveragingTouchFilter));
- dump.appendFormat(INDENT3 "UseJumpyTouchFilter: %s\n",
+ dump.appendFormat(INDENT4 "UseJumpyTouchFilter: %s\n",
toString(mParameters.useJumpyTouchFilter));
}
@@ -1385,17 +1426,20 @@
bool TouchInputMapper::configureSurfaceLocked() {
// Update orientation and dimensions if needed.
- int32_t orientation;
- int32_t width, height;
- if (mAssociatedDisplayId >= 0) {
+ int32_t orientation = InputReaderPolicyInterface::ROTATION_0;
+ int32_t width = mRawAxes.x.getRange();
+ int32_t height = mRawAxes.y.getRange();
+
+ if (mParameters.associatedDisplayId >= 0) {
+ bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ bool wantOrientation = mParameters.orientationAware;
+
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) {
+ if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+ wantSize ? &width : NULL, wantSize ? &height : NULL,
+ wantOrientation ? &orientation : NULL)) {
return false;
}
- } else {
- orientation = InputReaderPolicyInterface::ROTATION_0;
- width = mRawAxes.x.getRange();
- height = mRawAxes.y.getRange();
}
bool orientationChanged = mLocked.surfaceOrientation != orientation;
@@ -1405,7 +1449,7 @@
bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
if (sizeChanged) {
- LOGI("Device reconfigured: id=0x%x, name=%s, display size is now %dx%d",
+ LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d",
getDeviceId(), getDeviceName().string(), width, height);
mLocked.surfaceWidth = width;
@@ -1413,10 +1457,18 @@
// Configure X and Y factors.
if (mRawAxes.x.valid && mRawAxes.y.valid) {
- mLocked.xOrigin = mRawAxes.x.minValue;
- mLocked.yOrigin = mRawAxes.y.minValue;
- mLocked.xScale = float(width) / mRawAxes.x.getRange();
- mLocked.yScale = float(height) / mRawAxes.y.getRange();
+ mLocked.xOrigin = mCalibration.haveXOrigin
+ ? mCalibration.xOrigin
+ : mRawAxes.x.minValue;
+ mLocked.yOrigin = mCalibration.haveYOrigin
+ ? mCalibration.yOrigin
+ : mRawAxes.y.minValue;
+ mLocked.xScale = mCalibration.haveXScale
+ ? mCalibration.xScale
+ : float(width) / mRawAxes.x.getRange();
+ mLocked.yScale = mCalibration.haveYScale
+ ? mCalibration.yScale
+ : float(height) / mRawAxes.y.getRange();
mLocked.xPrecision = 1.0f / mLocked.xScale;
mLocked.yPrecision = 1.0f / mLocked.yScale;
@@ -1609,9 +1661,8 @@
void TouchInputMapper::configureVirtualKeysLocked() {
assert(mRawAxes.x.valid && mRawAxes.y.valid);
- // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock.
Vector<VirtualKeyDefinition> virtualKeyDefinitions;
- getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);
+ getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
mLocked.virtualKeys.clear();
@@ -1679,9 +1730,15 @@
}
void TouchInputMapper::parseCalibration() {
- const InputDeviceCalibration& in = getDevice()->getCalibration();
+ const PropertyMap& in = getDevice()->getConfiguration();
Calibration& out = mCalibration;
+ // Position
+ out.haveXOrigin = in.tryGetProperty(String8("touch.position.xOrigin"), out.xOrigin);
+ out.haveYOrigin = in.tryGetProperty(String8("touch.position.yOrigin"), out.yOrigin);
+ out.haveXScale = in.tryGetProperty(String8("touch.position.xScale"), out.xScale);
+ out.haveYScale = in.tryGetProperty(String8("touch.position.yScale"), out.yScale);
+
// Touch Size
out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT;
String8 touchSizeCalibrationString;
@@ -1891,6 +1948,20 @@
void TouchInputMapper::dumpCalibration(String8& dump) {
dump.append(INDENT3 "Calibration:\n");
+ // Position
+ if (mCalibration.haveXOrigin) {
+ dump.appendFormat(INDENT4 "touch.position.xOrigin: %d\n", mCalibration.xOrigin);
+ }
+ if (mCalibration.haveYOrigin) {
+ dump.appendFormat(INDENT4 "touch.position.yOrigin: %d\n", mCalibration.yOrigin);
+ }
+ if (mCalibration.haveXScale) {
+ dump.appendFormat(INDENT4 "touch.position.xScale: %0.3f\n", mCalibration.xScale);
+ }
+ if (mCalibration.haveYScale) {
+ dump.appendFormat(INDENT4 "touch.position.yScale: %0.3f\n", mCalibration.yScale);
+ }
+
// Touch Size
switch (mCalibration.touchSizeCalibration) {
case Calibration::TOUCH_SIZE_CALIBRATION_NONE:
@@ -1945,8 +2016,8 @@
}
if (mCalibration.haveToolSizeIsSummed) {
- dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %d\n",
- mCalibration.toolSizeIsSummed);
+ dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %s\n",
+ toString(mCalibration.toolSizeIsSummed));
}
// Pressure
@@ -3130,8 +3201,8 @@
// --- SingleTouchInputMapper ---
-SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- TouchInputMapper(device, associatedDisplayId) {
+SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) :
+ TouchInputMapper(device) {
initialize();
}
@@ -3259,8 +3330,8 @@
// --- MultiTouchInputMapper ---
-MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- TouchInputMapper(device, associatedDisplayId) {
+MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
+ TouchInputMapper(device) {
initialize();
}
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 2c6346e..83d9556 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -35,8 +35,12 @@
static const char INPUT_SIGNAL_DISPATCH = 'D';
// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message.
-static const char INPUT_SIGNAL_FINISHED = 'f';
+// consuming the most recent message and it handled it.
+static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
+
+// Signal sent by the consumer to the producer to inform it that it has finished
+// consuming the most recent message but it did not handle it.
+static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
// --- InputChannel ---
@@ -497,7 +501,7 @@
return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
}
-status_t InputPublisher::receiveFinishedSignal() {
+status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
#if DEBUG_TRANSPORT_ACTIONS
LOGD("channel '%s' publisher ~ receiveFinishedSignal",
mChannel->getName().string());
@@ -506,9 +510,14 @@
char signal;
status_t result = mChannel->receiveSignal(& signal);
if (result) {
+ *outHandled = false;
return result;
}
- if (signal != INPUT_SIGNAL_FINISHED) {
+ if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
+ *outHandled = true;
+ } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
+ *outHandled = false;
+ } else {
LOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
mChannel->getName().string(), signal);
return UNKNOWN_ERROR;
@@ -626,13 +635,15 @@
return OK;
}
-status_t InputConsumer::sendFinishedSignal() {
+status_t InputConsumer::sendFinishedSignal(bool handled) {
#if DEBUG_TRANSPORT_ACTIONS
- LOGD("channel '%s' consumer ~ sendFinishedSignal",
- mChannel->getName().string());
+ LOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
+ mChannel->getName().string(), handled);
#endif
- return mChannel->sendSignal(INPUT_SIGNAL_FINISHED);
+ return mChannel->sendSignal(handled
+ ? INPUT_SIGNAL_FINISHED_HANDLED
+ : INPUT_SIGNAL_FINISHED_UNHANDLED);
}
status_t InputConsumer::receiveDispatchSignal() {
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
index e891181..9bfa8f6 100644
--- a/libs/ui/KeyCharacterMap.cpp
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -1,263 +1,847 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#define LOG_TAG "KeyCharacterMap"
-#include <ui/KeyCharacterMap.h>
-#include <cutils/properties.h>
-
-#include <utils/Log.h>
-#include <sys/types.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <fcntl.h>
-#include <limits.h>
#include <string.h>
+#include <android/keycodes.h>
+#include <ui/Keyboard.h>
+#include <ui/KeyCharacterMap.h>
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/Tokenizer.h>
+#include <utils/Timers.h>
-struct Header
-{
- char magic[8];
- unsigned int endian;
- unsigned int version;
- unsigned int keycount;
- unsigned char kbdtype;
- char padding[11];
+// Enables debug output for the parser.
+#define DEBUG_PARSER 0
+
+// Enables debug output for parser performance.
+#define DEBUG_PARSER_PERFORMANCE 0
+
+// Enables debug output for mapping.
+#define DEBUG_MAPPING 0
+
+
+namespace android {
+
+static const char* WHITESPACE = " \t\r";
+static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
+
+struct Modifier {
+ const char* label;
+ int32_t metaState;
+};
+static const Modifier modifiers[] = {
+ { "shift", AMETA_SHIFT_ON },
+ { "lshift", AMETA_SHIFT_LEFT_ON },
+ { "rshift", AMETA_SHIFT_RIGHT_ON },
+ { "alt", AMETA_ALT_ON },
+ { "lalt", AMETA_ALT_LEFT_ON },
+ { "ralt", AMETA_ALT_RIGHT_ON },
+ { "ctrl", AMETA_CTRL_ON },
+ { "lctrl", AMETA_CTRL_LEFT_ON },
+ { "rctrl", AMETA_CTRL_RIGHT_ON },
+ { "meta", AMETA_META_ON },
+ { "lmeta", AMETA_META_LEFT_ON },
+ { "rmeta", AMETA_META_RIGHT_ON },
+ { "sym", AMETA_SYM_ON },
+ { "fn", AMETA_FUNCTION_ON },
+ { "capslock", AMETA_CAPS_LOCK_ON },
+ { "numlock", AMETA_NUM_LOCK_ON },
+ { "scrolllock", AMETA_SCROLL_LOCK_ON },
};
-KeyCharacterMap::KeyCharacterMap()
-{
-}
-
-KeyCharacterMap::~KeyCharacterMap()
-{
- free(m_keys);
-}
-
-unsigned short
-KeyCharacterMap::get(int keycode, int meta)
-{
- Key* k = find_key(keycode);
- if (k != NULL) {
- return k->data[meta & META_MASK];
+#if DEBUG_MAPPING
+static String8 toString(const char16_t* chars, size_t numChars) {
+ String8 result;
+ for (size_t i = 0; i < numChars; i++) {
+ result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
}
- return 0;
+ return result;
+}
+#endif
+
+
+// --- KeyCharacterMap ---
+
+KeyCharacterMap::KeyCharacterMap() :
+ mType(KEYBOARD_TYPE_UNKNOWN) {
}
-unsigned short
-KeyCharacterMap::getNumber(int keycode)
-{
- Key* k = find_key(keycode);
- if (k != NULL) {
- return k->number;
+KeyCharacterMap::~KeyCharacterMap() {
+ for (size_t i = 0; i < mKeys.size(); i++) {
+ Key* key = mKeys.editValueAt(i);
+ delete key;
}
- return 0;
}
-unsigned short
-KeyCharacterMap::getMatch(int keycode, const unsigned short* chars,
- int charsize, uint32_t modifiers)
-{
- Key* k = find_key(keycode);
- modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it
- if (k != NULL) {
- const uint16_t* data = k->data;
- for (int j=0; j<charsize; j++) {
- uint16_t c = chars[j];
- for (int i=0; i<(META_MASK + 1); i++) {
- if ((modifiers == 0) || ((modifiers & i) != 0)) {
- if (c == data[i]) {
- return c;
+status_t KeyCharacterMap::load(const String8& filename, KeyCharacterMap** outMap) {
+ *outMap = NULL;
+
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(filename, &tokenizer);
+ if (status) {
+ LOGE("Error %d opening key character map file %s.", status, filename.string());
+ } else {
+ KeyCharacterMap* map = new KeyCharacterMap();
+ if (!map) {
+ LOGE("Error allocating key character 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;
+ LOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
+ tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ elapsedTime / 1000000.0);
+#endif
+ if (status) {
+ delete map;
+ } else {
+ *outMap = map;
+ }
+ }
+ delete tokenizer;
+ }
+ return status;
+}
+
+status_t KeyCharacterMap::loadByDeviceId(int32_t deviceId, KeyCharacterMap** outMap) {
+ *outMap = NULL;
+
+ String8 filename;
+ status_t result = getKeyCharacterMapFile(deviceId, filename);
+ if (!result) {
+ result = load(filename, outMap);
+ }
+ return result;
+}
+
+int32_t KeyCharacterMap::getKeyboardType() const {
+ return mType;
+}
+
+char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
+ char16_t result = 0;
+ const Key* key;
+ if (getKey(keyCode, &key)) {
+ result = key->label;
+ }
+#if DEBUG_MAPPING
+ LOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
+#endif
+ return result;
+}
+
+char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
+ char16_t result = 0;
+ const Key* key;
+ if (getKey(keyCode, &key)) {
+ result = key->number;
+ }
+#if DEBUG_MAPPING
+ LOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
+#endif
+ return result;
+}
+
+char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
+ char16_t result = 0;
+ const Key* key;
+ const Behavior* behavior;
+ if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+ result = behavior->character;
+ }
+#if DEBUG_MAPPING
+ LOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
+#endif
+ return result;
+}
+
+bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
+ FallbackAction* outFallbackAction) const {
+ outFallbackAction->keyCode = 0;
+ outFallbackAction->metaState = 0;
+
+ bool result = false;
+ const Key* key;
+ const Behavior* behavior;
+ if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+ outFallbackAction->keyCode = behavior->fallbackKeyCode;
+ outFallbackAction->metaState = metaState & ~behavior->metaState;
+ result = true;
+ }
+#if DEBUG_MAPPING
+ LOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
+ "fallback keyCode=%d, fallback metaState=0x%08x.",
+ keyCode, metaState, result ? "true" : "false",
+ outFallbackAction->keyCode, outFallbackAction->metaState);
+#endif
+ return result;
+}
+
+char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
+ int32_t metaState) const {
+ char16_t result = 0;
+ const Key* key;
+ if (getKey(keyCode, &key)) {
+ // Try to find the most general behavior that maps to this character.
+ // For example, the base key behavior will usually be last in the list.
+ // However, if we find a perfect meta state match for one behavior then use that one.
+ for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
+ if (behavior->character) {
+ for (size_t i = 0; i < numChars; i++) {
+ if (behavior->character == chars[i]) {
+ result = behavior->character;
+ if ((behavior->metaState & metaState) == behavior->metaState) {
+ goto ExactMatch;
+ }
+ break;
}
}
}
}
+ ExactMatch: ;
}
- return 0;
+#if DEBUG_MAPPING
+ LOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
+ keyCode, toString(chars, numChars).string(), metaState, result);
+#endif
+ return result;
}
-unsigned short
-KeyCharacterMap::getDisplayLabel(int keycode)
-{
- Key* k = find_key(keycode);
- if (k != NULL) {
- return k->display_label;
+bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
+ Vector<KeyEvent>& outEvents) const {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ for (size_t i = 0; i < numChars; i++) {
+ int32_t keyCode, metaState;
+ char16_t ch = chars[i];
+ if (!findKey(ch, &keyCode, &metaState)) {
+#if DEBUG_MAPPING
+ LOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
+ deviceId, toString(chars, numChars).string(), ch);
+#endif
+ return false;
+ }
+
+ int32_t currentMetaState = 0;
+ addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState);
+ addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
+ addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
+ addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState);
}
- return 0;
+#if DEBUG_MAPPING
+ LOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
+ deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
+ for (size_t i = 0; i < outEvents.size(); i++) {
+ LOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
+ outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
+ outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
+ }
+#endif
+ return true;
}
-bool
-KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel,
- unsigned short *number, unsigned short* results)
-{
- Key* k = find_key(keycode);
- if (k != NULL) {
- memcpy(results, k->data, sizeof(short)*(META_MASK + 1));
- *number = k->number;
- *displayLabel = k->display_label;
+bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
+ ssize_t index = mKeys.indexOfKey(keyCode);
+ if (index >= 0) {
+ *outKey = mKeys.valueAt(index);
return true;
- } else {
- return false;
}
+ return false;
}
-bool
-KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods)
-{
- uint32_t N = m_keyCount;
- for (int j=0; j<(META_MASK + 1); j++) {
- Key const* keys = m_keys;
- for (uint32_t i=0; i<N; i++) {
- if (keys->data[j] == c) {
- *key = keys->keycode;
- *mods = j;
+bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
+ const Key** outKey, const Behavior** outBehavior) const {
+ const Key* key;
+ if (getKey(keyCode, &key)) {
+ const Behavior* behavior = key->firstBehavior;
+ while (behavior) {
+ if ((behavior->metaState & metaState) == behavior->metaState) {
+ *outKey = key;
+ *outBehavior = behavior;
return true;
}
- keys++;
+ behavior = behavior->next;
}
}
return false;
}
-bool
-KeyCharacterMap::getEvents(uint16_t* chars, size_t len,
- Vector<int32_t>* keys, Vector<uint32_t>* modifiers)
-{
- for (size_t i=0; i<len; i++) {
- uint32_t k, mods;
- if (find_char(chars[i], &k, &mods)) {
- keys->add(k);
- modifiers->add(mods);
- } else {
- return false;
+bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
+ if (!ch) {
+ return false;
+ }
+
+ for (size_t i = 0; i < mKeys.size(); i++) {
+ const Key* key = mKeys.valueAt(i);
+
+ // Try to find the most general behavior that maps to this character.
+ // For example, the base key behavior will usually be last in the list.
+ const Behavior* found = NULL;
+ for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
+ if (behavior->character == ch) {
+ found = behavior;
+ }
+ }
+ if (found) {
+ *outKeyCode = mKeys.keyAt(i);
+ *outMetaState = found->metaState;
+ return true;
}
}
- return true;
+ return false;
}
-KeyCharacterMap::Key*
-KeyCharacterMap::find_key(int keycode)
-{
- Key* keys = m_keys;
- int low = 0;
- int high = m_keyCount - 1;
- int mid;
- int n;
- while (low <= high) {
- mid = (low + high) / 2;
- n = keys[mid].keycode;
- if (keycode < n) {
- high = mid - 1;
- } else if (keycode > n) {
- low = mid + 1;
- } else {
- return keys + mid;
- }
- }
- return NULL;
+void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
+ outEvents.push();
+ KeyEvent& event = outEvents.editTop();
+ event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
+ down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+ 0, keyCode, 0, metaState, 0, time, time);
}
-KeyCharacterMap*
-KeyCharacterMap::load(int id)
-{
- KeyCharacterMap* rv = NULL;
- char path[PATH_MAX];
- char propName[100];
- char dev[PROPERTY_VALUE_MAX];
- char tmpfn[PROPERTY_VALUE_MAX];
- int err;
- const char* root = getenv("ANDROID_ROOT");
+void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
+ int32_t* currentMetaState) {
+ // Add and remove meta keys symmetrically.
+ if (down) {
+ addLockedMetaKey(outEvents, deviceId, metaState, time,
+ AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
+ addLockedMetaKey(outEvents, deviceId, metaState, time,
+ AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
+ addLockedMetaKey(outEvents, deviceId, metaState, time,
+ AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
- sprintf(propName, "hw.keyboards.%u.devname", id);
- err = property_get(propName, dev, "");
- if (err > 0) {
- // replace all the spaces with underscores
- strcpy(tmpfn, dev);
- for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
- *p = '_';
- snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
- //LOGD("load: dev='%s' path='%s'\n", dev, path);
- rv = try_file(path);
- if (rv != NULL) {
- return rv;
- }
- LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
+ AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
+ AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
+ AMETA_SHIFT_ON, currentMetaState);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
+ AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
+ AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
+ AMETA_ALT_ON, currentMetaState);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
+ AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
+ AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
+ AMETA_CTRL_ON, currentMetaState);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
+ AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
+ AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
+ AMETA_META_ON, currentMetaState);
+
+ addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
+ AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
+ addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
+ AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
} else {
- LOGW("No keyboard for id %d", id);
- }
+ addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
+ AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
+ addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
+ AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
- snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
- rv = try_file(path);
- if (rv == NULL) {
- LOGE("Can't find any keycharmaps (also tried %s)", path);
- return NULL;
- }
- LOGW("Using default keymap: %s", path);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
+ AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
+ AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
+ AMETA_META_ON, currentMetaState);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
+ AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
+ AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
+ AMETA_CTRL_ON, currentMetaState);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
+ AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
+ AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
+ AMETA_ALT_ON, currentMetaState);
+ addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
+ AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
+ AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
+ AMETA_SHIFT_ON, currentMetaState);
- return rv;
+ addLockedMetaKey(outEvents, deviceId, metaState, time,
+ AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
+ addLockedMetaKey(outEvents, deviceId, metaState, time,
+ AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
+ addLockedMetaKey(outEvents, deviceId, metaState, time,
+ AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
+ }
}
-KeyCharacterMap*
-KeyCharacterMap::try_file(const char* filename)
-{
- KeyCharacterMap* rv = NULL;
- Key* keys;
- int fd;
- off_t filesize;
- Header header;
- int err;
-
- fd = open(filename, O_RDONLY);
- if (fd == -1) {
- LOGW("Can't open keycharmap file");
- return NULL;
+bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
+ int32_t keyCode, int32_t keyMetaState,
+ int32_t* currentMetaState) {
+ if ((metaState & keyMetaState) == keyMetaState) {
+ *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
+ addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
+ return true;
}
-
- filesize = lseek(fd, 0, SEEK_END);
- lseek(fd, 0, SEEK_SET);
-
- // validate the header
- if (filesize <= (off_t)sizeof(header)) {
- LOGW("Bad keycharmap - filesize=%d\n", (int)filesize);
- goto cleanup1;
- }
-
- err = read(fd, &header, sizeof(header));
- if (err == -1) {
- LOGW("Error reading keycharmap file");
- goto cleanup1;
- }
-
- if (0 != memcmp(header.magic, "keychar", 8)) {
- LOGW("Bad keycharmap magic token");
- goto cleanup1;
- }
- if (header.endian != 0x12345678) {
- LOGW("Bad keycharmap endians");
- goto cleanup1;
- }
- if ((header.version & 0xff) != 2) {
- LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version);
- goto cleanup1;
- }
- if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) {
- LOGW("Bad keycharmap file size\n");
- goto cleanup1;
- }
-
- // read the key data
- keys = (Key*)malloc(sizeof(Key)*header.keycount);
- err = read(fd, keys, sizeof(Key)*header.keycount);
- if (err == -1) {
- LOGW("Error reading keycharmap file");
- free(keys);
- goto cleanup1;
- }
-
- // return the object
- rv = new KeyCharacterMap;
- rv->m_keyCount = header.keycount;
- rv->m_keys = keys;
- rv->m_type = header.kbdtype;
-
-cleanup1:
- close(fd);
-
- return rv;
+ return false;
}
+
+void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
+ int32_t leftKeyCode, int32_t leftKeyMetaState,
+ int32_t rightKeyCode, int32_t rightKeyMetaState,
+ int32_t eitherKeyMetaState,
+ int32_t* currentMetaState) {
+ bool specific = false;
+ specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
+ leftKeyCode, leftKeyMetaState, currentMetaState);
+ specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
+ rightKeyCode, rightKeyMetaState, currentMetaState);
+
+ if (!specific) {
+ addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
+ leftKeyCode, eitherKeyMetaState, currentMetaState);
+ }
+}
+
+void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
+ int32_t deviceId, int32_t metaState, nsecs_t time,
+ int32_t keyCode, int32_t keyMetaState,
+ int32_t* currentMetaState) {
+ if ((metaState & keyMetaState) == keyMetaState) {
+ *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
+ addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
+ *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
+ addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
+ }
+}
+
+
+// --- KeyCharacterMap::Key ---
+
+KeyCharacterMap::Key::Key() :
+ label(0), number(0), firstBehavior(NULL) {
+}
+
+KeyCharacterMap::Key::~Key() {
+ Behavior* behavior = firstBehavior;
+ while (behavior) {
+ Behavior* next = behavior->next;
+ delete behavior;
+ behavior = next;
+ }
+}
+
+
+// --- KeyCharacterMap::Behavior ---
+
+KeyCharacterMap::Behavior::Behavior() :
+ next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
+}
+
+
+// --- KeyCharacterMap::Parser ---
+
+KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer) :
+ mMap(map), mTokenizer(tokenizer), mState(STATE_TOP) {
+}
+
+KeyCharacterMap::Parser::~Parser() {
+}
+
+status_t KeyCharacterMap::Parser::parse() {
+ while (!mTokenizer->isEof()) {
+#if DEBUG_PARSER
+ LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+#endif
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
+ switch (mState) {
+ case STATE_TOP: {
+ String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
+ if (keywordToken == "type") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ status_t status = parseType();
+ if (status) return status;
+ } else if (keywordToken == "key") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ status_t status = parseKey();
+ if (status) return status;
+ } else {
+ LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
+ keywordToken.string());
+ return BAD_VALUE;
+ }
+ break;
+ }
+
+ case STATE_KEY: {
+ status_t status = parseKeyProperty();
+ if (status) return status;
+ break;
+ }
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (!mTokenizer->isEol()) {
+ LOGE("%s: Expected end of line, got '%s'.",
+ mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+ return BAD_VALUE;
+ }
+ }
+
+ mTokenizer->nextLine();
+ }
+
+ if (mState != STATE_TOP) {
+ LOGE("%s: Unterminated key description at end of file.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
+ LOGE("%s: Missing required keyboard 'type' declaration.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
+status_t KeyCharacterMap::Parser::parseType() {
+ if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
+ LOGE("%s: Duplicate keyboard 'type' declaration.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ KeyboardType type;
+ String8 typeToken = mTokenizer->nextToken(WHITESPACE);
+ if (typeToken == "NUMERIC") {
+ type = KEYBOARD_TYPE_NUMERIC;
+ } else if (typeToken == "PREDICTIVE") {
+ type = KEYBOARD_TYPE_PREDICTIVE;
+ } else if (typeToken == "ALPHA") {
+ type = KEYBOARD_TYPE_ALPHA;
+ } else if (typeToken == "FULL") {
+ type = KEYBOARD_TYPE_FULL;
+ } else if (typeToken == "SPECIAL_FUNCTION") {
+ type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
+ } else {
+ LOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
+ typeToken.string());
+ return BAD_VALUE;
+ }
+
+#if DEBUG_PARSER
+ LOGD("Parsed type: type=%d.", type);
+#endif
+ mMap->mType = type;
+ return NO_ERROR;
+}
+
+status_t KeyCharacterMap::Parser::parseKey() {
+ String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
+ int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
+ if (!keyCode) {
+ LOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
+ keyCodeToken.string());
+ return BAD_VALUE;
+ }
+ if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
+ LOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
+ keyCodeToken.string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
+ if (openBraceToken != "{") {
+ LOGE("%s: Expected '{' after key code label, got '%s'.",
+ mTokenizer->getLocation().string(), openBraceToken.string());
+ return BAD_VALUE;
+ }
+
+#if DEBUG_PARSER
+ LOGD("Parsed beginning of key: keyCode=%d.", keyCode);
+#endif
+ mKeyCode = keyCode;
+ mMap->mKeys.add(keyCode, new Key());
+ mState = STATE_KEY;
+ return NO_ERROR;
+}
+
+status_t KeyCharacterMap::Parser::parseKeyProperty() {
+ String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
+ if (token == "}") {
+ mState = STATE_TOP;
+ return NO_ERROR;
+ }
+
+ Vector<Property> properties;
+
+ // Parse all comma-delimited property names up to the first colon.
+ for (;;) {
+ if (token == "label") {
+ properties.add(Property(PROPERTY_LABEL));
+ } else if (token == "number") {
+ properties.add(Property(PROPERTY_NUMBER));
+ } else {
+ int32_t metaState;
+ status_t status = parseModifier(token, &metaState);
+ if (status) {
+ LOGE("%s: Expected a property name or modifier, got '%s'.",
+ mTokenizer->getLocation().string(), token.string());
+ return status;
+ }
+ properties.add(Property(PROPERTY_META, metaState));
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (!mTokenizer->isEol()) {
+ char ch = mTokenizer->nextChar();
+ if (ch == ':') {
+ break;
+ } else if (ch == ',') {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
+ continue;
+ }
+ }
+
+ LOGE("%s: Expected ',' or ':' after property name.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ // Parse behavior after the colon.
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ Behavior behavior;
+ bool haveCharacter = false;
+ bool haveFallback = false;
+
+ do {
+ char ch = mTokenizer->peekChar();
+ if (ch == '\'') {
+ char16_t character;
+ status_t status = parseCharacterLiteral(&character);
+ if (status || !character) {
+ LOGE("%s: Invalid character literal for key.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ if (haveCharacter) {
+ LOGE("%s: Cannot combine multiple character literals or 'none'.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ behavior.character = character;
+ haveCharacter = true;
+ } else {
+ token = mTokenizer->nextToken(WHITESPACE);
+ if (token == "none") {
+ if (haveCharacter) {
+ LOGE("%s: Cannot combine multiple character literals or 'none'.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ haveCharacter = true;
+ } else if (token == "fallback") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ token = mTokenizer->nextToken(WHITESPACE);
+ int32_t keyCode = getKeyCodeByLabel(token.string());
+ if (!keyCode) {
+ LOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
+ mTokenizer->getLocation().string(),
+ token.string());
+ return BAD_VALUE;
+ }
+ if (haveFallback) {
+ LOGE("%s: Cannot combine multiple fallback key codes.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ behavior.fallbackKeyCode = keyCode;
+ haveFallback = true;
+ } else {
+ LOGE("%s: Expected a key behavior after ':'.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ } while (!mTokenizer->isEol());
+
+ // Add the behavior.
+ Key* key = mMap->mKeys.valueFor(mKeyCode);
+ for (size_t i = 0; i < properties.size(); i++) {
+ const Property& property = properties.itemAt(i);
+ switch (property.property) {
+ case PROPERTY_LABEL:
+ if (key->label) {
+ LOGE("%s: Duplicate label for key.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ key->label = behavior.character;
+#if DEBUG_PARSER
+ LOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
+#endif
+ break;
+ case PROPERTY_NUMBER:
+ if (key->number) {
+ LOGE("%s: Duplicate number for key.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ key->number = behavior.character;
+#if DEBUG_PARSER
+ LOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
+#endif
+ break;
+ case PROPERTY_META: {
+ for (Behavior* b = key->firstBehavior; b; b = b->next) {
+ if (b->metaState == property.metaState) {
+ LOGE("%s: Duplicate key behavior for modifier.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ }
+ Behavior* newBehavior = new Behavior(behavior);
+ newBehavior->metaState = property.metaState;
+ newBehavior->next = key->firstBehavior;
+ key->firstBehavior = newBehavior;
+#if DEBUG_PARSER
+ LOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
+ newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
+#endif
+ break;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
+ if (token == "base") {
+ *outMetaState = 0;
+ return NO_ERROR;
+ }
+
+ int32_t combinedMeta = 0;
+
+ const char* str = token.string();
+ const char* start = str;
+ for (const char* cur = str; ; cur++) {
+ char ch = *cur;
+ if (ch == '+' || ch == '\0') {
+ size_t len = cur - start;
+ int32_t metaState = 0;
+ for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
+ if (strlen(modifiers[i].label) == len
+ && strncmp(modifiers[i].label, start, len) == 0) {
+ metaState = modifiers[i].metaState;
+ break;
+ }
+ }
+ if (!metaState) {
+ return BAD_VALUE;
+ }
+ if (combinedMeta & metaState) {
+ LOGE("%s: Duplicate modifier combination '%s'.",
+ mTokenizer->getLocation().string(), token.string());
+ return BAD_VALUE;
+ }
+
+ combinedMeta |= metaState;
+ start = cur + 1;
+
+ if (ch == '\0') {
+ break;
+ }
+ }
+ }
+ *outMetaState = combinedMeta;
+ return NO_ERROR;
+}
+
+status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
+ char ch = mTokenizer->nextChar();
+ if (ch != '\'') {
+ goto Error;
+ }
+
+ ch = mTokenizer->nextChar();
+ if (ch == '\\') {
+ // Escape sequence.
+ ch = mTokenizer->nextChar();
+ if (ch == 'n') {
+ *outCharacter = '\n';
+ } else if (ch == 't') {
+ *outCharacter = '\t';
+ } else if (ch == '\\') {
+ *outCharacter = '\\';
+ } else if (ch == '\'') {
+ *outCharacter = '\'';
+ } else if (ch == '"') {
+ *outCharacter = '"';
+ } else if (ch == 'u') {
+ *outCharacter = 0;
+ for (int i = 0; i < 4; i++) {
+ ch = mTokenizer->nextChar();
+ int digit;
+ if (ch >= '0' && ch <= '9') {
+ digit = ch - '0';
+ } else if (ch >= 'A' && ch <= 'F') {
+ digit = ch - 'A' + 10;
+ } else if (ch >= 'a' && ch <= 'f') {
+ digit = ch - 'a' + 10;
+ } else {
+ goto Error;
+ }
+ *outCharacter = (*outCharacter << 4) | digit;
+ }
+ } else {
+ goto Error;
+ }
+ } else if (ch >= 32 && ch <= 126 && ch != '\'') {
+ // ASCII literal character.
+ *outCharacter = ch;
+ } else {
+ goto Error;
+ }
+
+ ch = mTokenizer->nextChar();
+ if (ch != '\'') {
+ goto Error;
+ }
+
+ // Ensure that we consumed the entire token.
+ if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
+ return NO_ERROR;
+ }
+
+Error:
+ LOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
+ return BAD_VALUE;
+}
+
+} // namespace android
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
index 15ae54c..56bc26f 100644
--- a/libs/ui/KeyLayoutMap.cpp
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -1,234 +1,213 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#define LOG_TAG "KeyLayoutMap"
-#include "KeyLayoutMap.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <utils/String8.h>
#include <stdlib.h>
-#include <ui/KeycodeLabels.h>
+#include <android/keycodes.h>
+#include <ui/Keyboard.h>
+#include <ui/KeyLayoutMap.h>
#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/Tokenizer.h>
+#include <utils/Timers.h>
+
+// Enables debug output for the parser.
+#define DEBUG_PARSER 0
+
+// Enables debug output for parser performance.
+#define DEBUG_PARSER_PERFORMANCE 0
+
+// Enables debug output for mapping.
+#define DEBUG_MAPPING 0
+
namespace android {
-KeyLayoutMap::KeyLayoutMap()
- :m_status(NO_INIT),
- m_keys()
-{
+static const char* WHITESPACE = " \t\r";
+
+// --- KeyLayoutMap ---
+
+KeyLayoutMap::KeyLayoutMap() {
}
-KeyLayoutMap::~KeyLayoutMap()
-{
+KeyLayoutMap::~KeyLayoutMap() {
}
-static String8
-next_token(char const** p, int *line)
-{
- bool begun = false;
- const char* begin = *p;
- const char* end = *p;
- while (true) {
- if (*end == '\n') {
- (*line)++;
+status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) {
+ *outMap = NULL;
+
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(filename, &tokenizer);
+ if (status) {
+ LOGE("Error %d opening key layout map file %s.", status, filename.string());
+ } else {
+ KeyLayoutMap* map = new KeyLayoutMap();
+ if (!map) {
+ LOGE("Error allocating key layout 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;
+ LOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
+ tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ elapsedTime / 1000000.0);
+#endif
+ if (status) {
+ delete map;
+ } else {
+ *outMap = map;
+ }
}
- switch (*end)
- {
- case '#':
- if (begun) {
- *p = end;
- return String8(begin, end-begin);
- } else {
- do {
- begin++;
- end++;
- } while (*begin != '\0' && *begin != '\n');
- }
- case '\0':
- case ' ':
- case '\n':
- case '\r':
- case '\t':
- if (begun || (*end == '\0')) {
- *p = end;
- return String8(begin, end-begin);
- } else {
- begin++;
- end++;
- break;
- }
- default:
- end++;
- begun = true;
- }
+ delete tokenizer;
}
+ return status;
}
-static int32_t
-token_to_value(const char *literal, const KeycodeLabel *list)
-{
- while (list->literal) {
- if (0 == strcmp(literal, list->literal)) {
- return list->value;
- }
- list++;
- }
- return list->value;
-}
-
-status_t
-KeyLayoutMap::load(const char* filename)
-{
- int fd = open(filename, O_RDONLY);
- if (fd < 0) {
- LOGE("error opening file=%s err=%s\n", filename, strerror(errno));
- m_status = errno;
- return errno;
- }
-
- off_t len = lseek(fd, 0, SEEK_END);
- off_t errlen = lseek(fd, 0, SEEK_SET);
- if (len < 0 || errlen < 0) {
- close(fd);
- LOGE("error seeking file=%s err=%s\n", filename, strerror(errno));
- m_status = errno;
- return errno;
- }
-
- char* buf = (char*)malloc(len+1);
- if (read(fd, buf, len) != len) {
- LOGE("error reading file=%s err=%s\n", filename, strerror(errno));
- m_status = errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
- return errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
- }
- errno = 0;
- buf[len] = '\0';
-
- int32_t scancode = -1;
- int32_t keycode = -1;
- uint32_t flags = 0;
- uint32_t tmp;
- char* end;
- status_t err = NO_ERROR;
- int line = 1;
- char const* p = buf;
- enum { BEGIN, SCANCODE, KEYCODE, FLAG } state = BEGIN;
- while (true) {
- String8 token = next_token(&p, &line);
- if (*p == '\0') {
- break;
- }
- switch (state)
- {
- case BEGIN:
- if (token == "key") {
- state = SCANCODE;
- } else {
- LOGE("%s:%d: expected key, got '%s'\n", filename, line,
- token.string());
- err = BAD_VALUE;
- goto done;
- }
- break;
- case SCANCODE:
- scancode = strtol(token.string(), &end, 0);
- if (*end != '\0') {
- LOGE("%s:%d: expected scancode (a number), got '%s'\n",
- filename, line, token.string());
- goto done;
- }
- //LOGI("%s:%d: got scancode %d\n", filename, line, scancode );
- state = KEYCODE;
- break;
- case KEYCODE:
- keycode = token_to_value(token.string(), KEYCODES);
- //LOGI("%s:%d: got keycode %d for %s\n", filename, line, keycode, token.string() );
- if (keycode == 0) {
- LOGE("%s:%d: expected keycode, got '%s'\n",
- filename, line, token.string());
- goto done;
- }
- state = FLAG;
- break;
- case FLAG:
- if (token == "key") {
- if (scancode != -1) {
- //LOGI("got key decl scancode=%d keycode=%d"
- // " flags=0x%08x\n", scancode, keycode, flags);
- Key k = { keycode, flags };
- m_keys.add(scancode, k);
- state = SCANCODE;
- scancode = -1;
- keycode = -1;
- flags = 0;
- break;
- }
- }
- tmp = token_to_value(token.string(), FLAGS);
- //LOGI("%s:%d: got flags %x for %s\n", filename, line, tmp, token.string() );
- if (tmp == 0) {
- LOGE("%s:%d: expected flag, got '%s'\n",
- filename, line, token.string());
- goto done;
- }
- flags |= tmp;
- break;
- }
- }
- if (state == FLAG && scancode != -1 ) {
- //LOGI("got key decl scancode=%d keycode=%d"
- // " flags=0x%08x\n", scancode, keycode, flags);
- Key k = { keycode, flags };
- m_keys.add(scancode, k);
- }
-
-done:
- free(buf);
- close(fd);
-
- m_status = err;
- return err;
-}
-
-status_t
-KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) const
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
-
- ssize_t index = m_keys.indexOfKey(scancode);
+status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
+ ssize_t index = mKeys.indexOfKey(scanCode);
if (index < 0) {
- //LOGW("couldn't map scancode=%d\n", scancode);
+#if DEBUG_MAPPING
+ LOGD("map: scanCode=%d ~ Failed.", scanCode);
+#endif
+ *keyCode = AKEYCODE_UNKNOWN;
+ *flags = 0;
return NAME_NOT_FOUND;
}
- const Key& k = m_keys.valueAt(index);
-
- *keycode = k.keycode;
+ const Key& k = mKeys.valueAt(index);
+ *keyCode = k.keyCode;
*flags = k.flags;
- //LOGD("mapped scancode=%d to keycode=%d flags=0x%08x\n", scancode,
- // keycode, flags);
-
+#if DEBUG_MAPPING
+ LOGD("map: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
+#endif
return NO_ERROR;
}
-status_t
-KeyLayoutMap::findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
-
- const size_t N = m_keys.size();
+status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
+ const size_t N = mKeys.size();
for (size_t i=0; i<N; i++) {
- if (m_keys.valueAt(i).keycode == keycode) {
- outScancodes->add(m_keys.keyAt(i));
+ if (mKeys.valueAt(i).keyCode == keyCode) {
+ outScanCodes->add(mKeys.keyAt(i));
}
}
-
+ return NO_ERROR;
+}
+
+// --- KeyLayoutMap::Parser ---
+
+KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
+ mMap(map), mTokenizer(tokenizer) {
+}
+
+KeyLayoutMap::Parser::~Parser() {
+}
+
+status_t KeyLayoutMap::Parser::parse() {
+ while (!mTokenizer->isEof()) {
+#if DEBUG_PARSER
+ LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+#endif
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
+ String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
+ if (keywordToken == "key") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ status_t status = parseKey();
+ if (status) return status;
+ } else {
+ LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
+ keywordToken.string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (!mTokenizer->isEol()) {
+ LOGE("%s: Expected end of line, got '%s'.",
+ mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+ return BAD_VALUE;
+ }
+ }
+
+ mTokenizer->nextLine();
+ }
+ return NO_ERROR;
+}
+
+status_t KeyLayoutMap::Parser::parseKey() {
+ String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
+ char* end;
+ int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
+ if (*end) {
+ LOGE("%s: Expected scan code number, got '%s'.", mTokenizer->getLocation().string(),
+ scanCodeToken.string());
+ return BAD_VALUE;
+ }
+ if (mMap->mKeys.indexOfKey(scanCode) >= 0) {
+ LOGE("%s: Duplicate entry for scan code '%s'.", mTokenizer->getLocation().string(),
+ scanCodeToken.string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
+ int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
+ if (!keyCode) {
+ LOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
+ keyCodeToken.string());
+ return BAD_VALUE;
+ }
+
+ uint32_t flags = 0;
+ for (;;) {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (mTokenizer->isEol()) break;
+
+ String8 flagToken = mTokenizer->nextToken(WHITESPACE);
+ uint32_t flag = getKeyFlagByLabel(flagToken.string());
+ if (!flag) {
+ LOGE("%s: Expected flag label, got '%s'.", mTokenizer->getLocation().string(),
+ flagToken.string());
+ return BAD_VALUE;
+ }
+ if (flags & flag) {
+ LOGE("%s: Duplicate flag '%s'.", mTokenizer->getLocation().string(),
+ flagToken.string());
+ return BAD_VALUE;
+ }
+ flags |= flag;
+ }
+
+#if DEBUG_PARSER
+ LOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
+#endif
+ Key key;
+ key.keyCode = keyCode;
+ key.flags = flags;
+ mMap->mKeys.add(scanCode, key);
return NO_ERROR;
}
diff --git a/libs/ui/KeyLayoutMap.h b/libs/ui/KeyLayoutMap.h
deleted file mode 100644
index 43f84ce..0000000
--- a/libs/ui/KeyLayoutMap.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef KEYLAYOUTMAP_H
-#define KEYLAYOUTMAP_H
-
-#include <utils/KeyedVector.h>
-
-namespace android {
-
-class KeyLayoutMap
-{
-public:
- KeyLayoutMap();
- ~KeyLayoutMap();
-
- status_t load(const char* filename);
-
- status_t map(int32_t scancode, int32_t *keycode, uint32_t *flags) const;
- status_t findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const;
-
-private:
- struct Key {
- int32_t keycode;
- uint32_t flags;
- };
-
- status_t m_status;
- KeyedVector<int32_t,Key> m_keys;
-};
-
-};
-
-#endif // KEYLAYOUTMAP_H
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
new file mode 100644
index 0000000..6faa600
--- /dev/null
+++ b/libs/ui/Keyboard.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Keyboard"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include <ui/Keyboard.h>
+#include <ui/KeycodeLabels.h>
+#include <ui/KeyLayoutMap.h>
+#include <ui/KeyCharacterMap.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+namespace android {
+
+// --- KeyMap ---
+
+KeyMap::KeyMap() :
+ keyLayoutMap(NULL), keyCharacterMap(NULL) {
+}
+
+KeyMap::~KeyMap() {
+ delete keyLayoutMap;
+ delete keyCharacterMap;
+}
+
+status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
+ const PropertyMap* deviceConfiguration) {
+ // Use the configured key layout if available.
+ if (deviceConfiguration) {
+ String8 keyLayoutName;
+ if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
+ keyLayoutName)) {
+ status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
+ if (status == NAME_NOT_FOUND) {
+ LOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
+ "it was not found.",
+ deviceIdenfifier.name.string(), keyLayoutName.string());
+ }
+ }
+
+ String8 keyCharacterMapName;
+ if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
+ keyCharacterMapName)) {
+ status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
+ if (status == NAME_NOT_FOUND) {
+ LOGE("Configuration for keyboard device '%s' requested keyboard character "
+ "map '%s' but it was not found.",
+ deviceIdenfifier.name.string(), keyLayoutName.string());
+ }
+ }
+
+ if (isComplete()) {
+ return OK;
+ }
+ }
+
+ // Try searching by device identifier.
+ if (probeKeyMap(deviceIdenfifier, String8::empty())) {
+ return OK;
+ }
+
+ // Fall back on the Generic key map.
+ // TODO Apply some additional heuristics here to figure out what kind of
+ // generic key map to use (US English, etc.) for typical external keyboards.
+ if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
+ return OK;
+ }
+
+ // Try the Virtual key map as a last resort.
+ if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
+ return OK;
+ }
+
+ // Give up!
+ LOGE("Could not determine key map for device '%s' and no default key maps were found!",
+ deviceIdenfifier.name.string());
+ return NAME_NOT_FOUND;
+}
+
+bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& keyMapName) {
+ if (!haveKeyLayout()) {
+ loadKeyLayout(deviceIdentifier, keyMapName);
+ }
+ if (!haveKeyCharacterMap()) {
+ loadKeyCharacterMap(deviceIdentifier, keyMapName);
+ }
+ return isComplete();
+}
+
+status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name) {
+ String8 path(getPath(deviceIdentifier, name,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
+ if (path.isEmpty()) {
+ return NAME_NOT_FOUND;
+ }
+
+ KeyLayoutMap* map;
+ status_t status = KeyLayoutMap::load(path, &map);
+ if (status) {
+ return status;
+ }
+
+ keyLayoutFile.setTo(path);
+ keyLayoutMap = map;
+ return OK;
+}
+
+status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name) {
+ String8 path(getPath(deviceIdentifier, name,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
+ if (path.isEmpty()) {
+ return NAME_NOT_FOUND;
+ }
+
+ KeyCharacterMap* map;
+ status_t status = KeyCharacterMap::load(path, &map);
+ if (status) {
+ return status;
+ }
+
+ keyCharacterMapFile.setTo(path);
+ keyCharacterMap = map;
+ return OK;
+}
+
+String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name, InputDeviceConfigurationFileType type) {
+ return name.isEmpty()
+ ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
+ : getInputDeviceConfigurationFilePathByName(name, type);
+}
+
+
+// --- Global functions ---
+
+bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
+ const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
+ if (!keyMap->haveKeyCharacterMap()
+ || keyMap->keyCharacterMap->getKeyboardType()
+ == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
+ return false;
+ }
+
+ if (deviceConfiguration) {
+ bool builtIn = false;
+ if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
+ && builtIn) {
+ return true;
+ }
+ }
+
+ return strstr(deviceIdentifier.name.string(), "-keypad");
+}
+
+void setKeyboardProperties(int32_t deviceId,
+ const InputDeviceIdentifier& deviceIdentifier,
+ const String8& keyLayoutFile, const String8& keyCharacterMapFile) {
+ char propName[PROPERTY_KEY_MAX];
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
+ property_set(propName, deviceIdentifier.name.string());
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
+ property_set(propName, keyLayoutFile.string());
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
+ property_set(propName, keyCharacterMapFile.string());
+}
+
+void clearKeyboardProperties(int32_t deviceId) {
+ char propName[PROPERTY_KEY_MAX];
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
+ property_set(propName, "");
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
+ property_set(propName, "");
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
+ property_set(propName, "");
+}
+
+status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) {
+ if (deviceId != DEVICE_ID_VIRTUAL_KEYBOARD) {
+ char propName[PROPERTY_KEY_MAX];
+ char fn[PROPERTY_VALUE_MAX];
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
+ if (property_get(propName, fn, "") > 0) {
+ outKeyCharacterMapFile.setTo(fn);
+ return OK;
+ }
+ }
+
+ // Default to Virtual since the keyboard does not appear to be installed.
+ outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePathByName(String8("Virtual"),
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
+ if (!outKeyCharacterMapFile.isEmpty()) {
+ return OK;
+ }
+
+ LOGE("Can't find any key character map files including the Virtual key map!");
+ return NAME_NOT_FOUND;
+}
+
+static int lookupLabel(const char* literal, const KeycodeLabel *list) {
+ while (list->literal) {
+ if (strcmp(literal, list->literal) == 0) {
+ return list->value;
+ }
+ list++;
+ }
+ return list->value;
+}
+
+int32_t getKeyCodeByLabel(const char* label) {
+ return int32_t(lookupLabel(label, KEYCODES));
+}
+
+uint32_t getKeyFlagByLabel(const char* label) {
+ return uint32_t(lookupLabel(label, FLAGS));
+}
+
+static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
+ int32_t newMetaState;
+ if (down) {
+ newMetaState = oldMetaState | mask;
+ } else {
+ newMetaState = oldMetaState &
+ ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
+ }
+
+ if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+ newMetaState |= AMETA_ALT_ON;
+ }
+
+ if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
+ newMetaState |= AMETA_SHIFT_ON;
+ }
+
+ if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
+ newMetaState |= AMETA_CTRL_ON;
+ }
+
+ if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
+ newMetaState |= AMETA_META_ON;
+ }
+ return newMetaState;
+}
+
+static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
+ if (down) {
+ return oldMetaState;
+ } else {
+ return oldMetaState ^ mask;
+ }
+}
+
+int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
+ int32_t mask;
+ switch (keyCode) {
+ case AKEYCODE_ALT_LEFT:
+ return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
+ case AKEYCODE_ALT_RIGHT:
+ return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
+ case AKEYCODE_SHIFT_LEFT:
+ return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
+ case AKEYCODE_SHIFT_RIGHT:
+ return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
+ case AKEYCODE_SYM:
+ return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
+ case AKEYCODE_FUNCTION:
+ return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
+ case AKEYCODE_CTRL_LEFT:
+ return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
+ case AKEYCODE_CTRL_RIGHT:
+ return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
+ case AKEYCODE_META_LEFT:
+ return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
+ case AKEYCODE_META_RIGHT:
+ return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
+ case AKEYCODE_CAPS_LOCK:
+ return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
+ case AKEYCODE_NUM_LOCK:
+ return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
+ case AKEYCODE_SCROLL_LOCK:
+ return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
+ default:
+ return oldMetaState;
+ }
+}
+
+
+} // namespace android
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
deleted file mode 100644
index b082c53..0000000
--- a/libs/ui/Overlay.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2007 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 <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-#include <binder/MemoryHeapBase.h>
-
-#include <ui/IOverlay.h>
-#include <ui/Overlay.h>
-
-#include <hardware/overlay.h>
-
-namespace android {
-
-Overlay::Overlay(const sp<OverlayRef>& overlayRef)
- : mOverlayRef(overlayRef), mOverlayData(0), mStatus(NO_INIT)
-{
- mOverlayData = NULL;
- hw_module_t const* module;
- if (overlayRef != 0) {
- if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
- if (overlay_data_open(module, &mOverlayData) == NO_ERROR) {
- mStatus = mOverlayData->initialize(mOverlayData,
- overlayRef->mOverlayHandle);
- }
- }
- }
-}
-
-Overlay::~Overlay() {
- if (mOverlayData) {
- overlay_data_close(mOverlayData);
- }
-}
-
-status_t Overlay::dequeueBuffer(overlay_buffer_t* buffer)
-{
- if (mStatus != NO_ERROR) return mStatus;
- return mOverlayData->dequeueBuffer(mOverlayData, buffer);
-}
-
-status_t Overlay::queueBuffer(overlay_buffer_t buffer)
-{
- if (mStatus != NO_ERROR) return mStatus;
- return mOverlayData->queueBuffer(mOverlayData, buffer);
-}
-
-status_t Overlay::resizeInput(uint32_t width, uint32_t height)
-{
- if (mStatus != NO_ERROR) return mStatus;
- return mOverlayData->resizeInput(mOverlayData, width, height);
-}
-
-status_t Overlay::setParameter(int param, int value)
-{
- if (mStatus != NO_ERROR) return mStatus;
- return mOverlayData->setParameter(mOverlayData, param, value);
-}
-
-status_t Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
-{
- if (mStatus != NO_ERROR) return mStatus;
- return mOverlayData->setCrop(mOverlayData, x, y, w, h);
-}
-
-status_t Overlay::getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
-{
- if (mStatus != NO_ERROR) return mStatus;
- return mOverlayData->getCrop(mOverlayData, x, y, w, h);
-}
-
-int32_t Overlay::getBufferCount() const
-{
- if (mStatus != NO_ERROR) return mStatus;
- return mOverlayData->getBufferCount(mOverlayData);
-}
-
-void* Overlay::getBufferAddress(overlay_buffer_t buffer)
-{
- if (mStatus != NO_ERROR) return NULL;
- return mOverlayData->getBufferAddress(mOverlayData, buffer);
-}
-
-void Overlay::destroy() {
-
- // Must delete the objects in reverse creation order, thus the
- // data side must be closed first and then the destroy send to
- // the control side.
- if (mOverlayData) {
- overlay_data_close(mOverlayData);
- mOverlayData = NULL;
- } else {
- LOGD("Overlay::destroy mOverlayData is NULL");
- }
-
- if (mOverlayRef != 0) {
- mOverlayRef->mOverlayChannel->destroy();
- } else {
- LOGD("Overlay::destroy mOverlayRef is NULL");
- }
-}
-
-status_t Overlay::getStatus() const {
- return mStatus;
-}
-
-overlay_handle_t Overlay::getHandleRef() const {
- if (mStatus != NO_ERROR) return NULL;
- return mOverlayRef->mOverlayHandle;
-}
-
-uint32_t Overlay::getWidth() const {
- if (mStatus != NO_ERROR) return 0;
- return mOverlayRef->mWidth;
-}
-
-uint32_t Overlay::getHeight() const {
- if (mStatus != NO_ERROR) return 0;
- return mOverlayRef->mHeight;
-}
-
-int32_t Overlay::getFormat() const {
- if (mStatus != NO_ERROR) return -1;
- return mOverlayRef->mFormat;
-}
-
-int32_t Overlay::getWidthStride() const {
- if (mStatus != NO_ERROR) return 0;
- return mOverlayRef->mWidthStride;
-}
-
-int32_t Overlay::getHeightStride() const {
- if (mStatus != NO_ERROR) return 0;
- return mOverlayRef->mHeightStride;
-}
-// ----------------------------------------------------------------------------
-
-OverlayRef::OverlayRef()
- : mOverlayHandle(0),
- mWidth(0), mHeight(0), mFormat(0), mWidthStride(0), mHeightStride(0),
- mOwnHandle(true)
-{
-}
-
-OverlayRef::OverlayRef(overlay_handle_t handle, const sp<IOverlay>& channel,
- uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs)
- : mOverlayHandle(handle), mOverlayChannel(channel),
- mWidth(w), mHeight(h), mFormat(f), mWidthStride(ws), mHeightStride(hs),
- mOwnHandle(false)
-{
-}
-
-OverlayRef::~OverlayRef()
-{
- if (mOwnHandle) {
- native_handle_close(mOverlayHandle);
- native_handle_delete(const_cast<native_handle*>(mOverlayHandle));
- }
-}
-
-sp<OverlayRef> OverlayRef::readFromParcel(const Parcel& data) {
- sp<OverlayRef> result;
- sp<IOverlay> overlay = IOverlay::asInterface(data.readStrongBinder());
- if (overlay != NULL) {
- uint32_t w = data.readInt32();
- uint32_t h = data.readInt32();
- uint32_t f = data.readInt32();
- uint32_t ws = data.readInt32();
- uint32_t hs = data.readInt32();
- native_handle* handle = data.readNativeHandle();
-
- result = new OverlayRef();
- result->mOverlayHandle = handle;
- result->mOverlayChannel = overlay;
- result->mWidth = w;
- result->mHeight = h;
- result->mFormat = f;
- result->mWidthStride = ws;
- result->mHeightStride = hs;
- }
- return result;
-}
-
-status_t OverlayRef::writeToParcel(Parcel* reply, const sp<OverlayRef>& o) {
- if (o != NULL) {
- reply->writeStrongBinder(o->mOverlayChannel->asBinder());
- reply->writeInt32(o->mWidth);
- reply->writeInt32(o->mHeight);
- reply->writeInt32(o->mFormat);
- reply->writeInt32(o->mWidthStride);
- reply->writeInt32(o->mHeightStride);
- reply->writeNativeHandle(o->mOverlayHandle);
- } else {
- reply->writeStrongBinder(NULL);
- }
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/ui/VirtualKeyMap.cpp b/libs/ui/VirtualKeyMap.cpp
new file mode 100644
index 0000000..e756cdd
--- /dev/null
+++ b/libs/ui/VirtualKeyMap.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VirtualKeyMap"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ui/VirtualKeyMap.h>
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/Tokenizer.h>
+#include <utils/Timers.h>
+
+// Enables debug output for the parser.
+#define DEBUG_PARSER 0
+
+// Enables debug output for parser performance.
+#define DEBUG_PARSER_PERFORMANCE 0
+
+
+namespace android {
+
+static const char* WHITESPACE = " \t\r";
+static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
+
+
+// --- VirtualKeyMap ---
+
+VirtualKeyMap::VirtualKeyMap() {
+}
+
+VirtualKeyMap::~VirtualKeyMap() {
+}
+
+status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
+ *outMap = NULL;
+
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(filename, &tokenizer);
+ if (status) {
+ LOGE("Error %d opening virtual key map file %s.", status, filename.string());
+ } else {
+ VirtualKeyMap* map = new VirtualKeyMap();
+ if (!map) {
+ LOGE("Error allocating virtual key map.");
+ status = NO_MEMORY;
+ } else {
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+ Parser parser(map, tokenizer);
+ status = parser.parse();
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
+ LOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
+ tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ elapsedTime / 1000000.0);
+#endif
+ if (status) {
+ delete map;
+ } else {
+ *outMap = map;
+ }
+ }
+ delete tokenizer;
+ }
+ return status;
+}
+
+
+// --- VirtualKeyMap::Parser ---
+
+VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
+ mMap(map), mTokenizer(tokenizer) {
+}
+
+VirtualKeyMap::Parser::~Parser() {
+}
+
+status_t VirtualKeyMap::Parser::parse() {
+ while (!mTokenizer->isEof()) {
+#if DEBUG_PARSER
+ LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+#endif
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
+ // Multiple keys can appear on one line or they can be broken up across multiple lines.
+ do {
+ String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
+ if (token != "0x01") {
+ LOGE("%s: Unknown virtual key type, expected 0x01.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ VirtualKeyDefinition defn;
+ bool success = parseNextIntField(&defn.scanCode)
+ && parseNextIntField(&defn.centerX)
+ && parseNextIntField(&defn.centerY)
+ && parseNextIntField(&defn.width)
+ && parseNextIntField(&defn.height);
+ if (!success) {
+ LOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+#if DEBUG_PARSER
+ LOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
+ "width=%d, height=%d",
+ defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
+#endif
+ mMap->mVirtualKeys.push(defn);
+ } while (consumeFieldDelimiterAndSkipWhitespace());
+
+ if (!mTokenizer->isEol()) {
+ LOGE("%s: Expected end of line, got '%s'.",
+ mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+ return BAD_VALUE;
+ }
+ }
+
+ mTokenizer->nextLine();
+ }
+
+ return NO_ERROR;
+}
+
+bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (mTokenizer->peekChar() == ':') {
+ mTokenizer->nextChar();
+ mTokenizer->skipDelimiters(WHITESPACE);
+ return true;
+ }
+ return false;
+}
+
+bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
+ if (!consumeFieldDelimiterAndSkipWhitespace()) {
+ return false;
+ }
+
+ String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
+ char* end;
+ *outValue = strtol(token.string(), &end, 0);
+ if (token.isEmpty() || *end != '\0') {
+ LOGE("Expected an integer, got '%s'.", token.string());
+ return false;
+ }
+ return true;
+}
+
+} // namespace android
diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp
index 8874dfe..7e17c57 100644
--- a/libs/ui/tests/InputDispatcher_test.cpp
+++ b/libs/ui/tests/InputDispatcher_test.cpp
@@ -54,9 +54,7 @@
return 60;
}
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags) {
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
}
virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
@@ -67,6 +65,11 @@
return false;
}
+ virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+ const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
+ return false;
+ }
+
virtual void notifySwitch(nsecs_t when,
int32_t switchCode, int32_t switchValue, uint32_t policyFlags) {
}
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 952b974..903fcaf 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -118,13 +118,16 @@
EXPECT_EQ(downTime, keyEvent->getDownTime());
EXPECT_EQ(eventTime, keyEvent->getEventTime());
- status = mConsumer->sendFinishedSignal();
+ status = mConsumer->sendFinishedSignal(true);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
- status = mPublisher->receiveFinishedSignal();
+ bool handled = false;
+ status = mPublisher->receiveFinishedSignal(&handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_TRUE(handled)
+ << "publisher receiveFinishedSignal should have set handled to consumer's reply";
status = mPublisher->reset();
ASSERT_EQ(OK, status)
@@ -279,13 +282,16 @@
EXPECT_EQ(samplePointerCoords[offset].orientation, motionEvent->getOrientation(i));
}
- status = mConsumer->sendFinishedSignal();
+ status = mConsumer->sendFinishedSignal(false);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
- status = mPublisher->receiveFinishedSignal();
+ bool handled = true;
+ status = mPublisher->receiveFinishedSignal(&handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_FALSE(handled)
+ << "publisher receiveFinishedSignal should have set handled to consumer's reply";
status = mPublisher->reset();
ASSERT_EQ(OK, status)
diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp
index de4b05a..97cbc25 100644
--- a/libs/ui/tests/InputReader_test.cpp
+++ b/libs/ui/tests/InputReader_test.cpp
@@ -42,8 +42,6 @@
KeyedVector<int32_t, DisplayInfo> mDisplayInfos;
bool mFilterTouchEvents;
bool mFilterJumpyTouchEvents;
- KeyedVector<String8, Vector<VirtualKeyDefinition> > mVirtualKeyDefinitions;
- KeyedVector<String8, InputDeviceCalibration> mInputDeviceCalibrations;
Vector<String8> mExcludedDeviceNames;
protected:
@@ -76,29 +74,6 @@
mFilterJumpyTouchEvents = enabled;
}
- void addInputDeviceCalibration(const String8& deviceName,
- const InputDeviceCalibration& calibration) {
- mInputDeviceCalibrations.add(deviceName, calibration);
- }
-
- void addInputDeviceCalibrationProperty(const String8& deviceName,
- const String8& key, const String8& value) {
- ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName);
- if (index < 0) {
- index = mInputDeviceCalibrations.add(deviceName, InputDeviceCalibration());
- }
- mInputDeviceCalibrations.editValueAt(index).addProperty(key, value);
- }
-
- void addVirtualKeyDefinition(const String8& deviceName,
- const VirtualKeyDefinition& definition) {
- if (mVirtualKeyDefinitions.indexOfKey(deviceName) < 0) {
- mVirtualKeyDefinitions.add(deviceName, Vector<VirtualKeyDefinition>());
- }
-
- mVirtualKeyDefinitions.editValueFor(deviceName).push(definition);
- }
-
void addExcludedDeviceName(const String8& deviceName) {
mExcludedDeviceNames.push(deviceName);
}
@@ -131,22 +106,6 @@
return mFilterJumpyTouchEvents;
}
- virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) {
- ssize_t index = mVirtualKeyDefinitions.indexOfKey(deviceName);
- if (index >= 0) {
- outVirtualKeyDefinitions.appendVector(mVirtualKeyDefinitions.valueAt(index));
- }
- }
-
- virtual void getInputDeviceCalibration(const String8& deviceName,
- InputDeviceCalibration& outCalibration) {
- ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName);
- if (index >= 0) {
- outCalibration = mInputDeviceCalibrations.valueAt(index);
- }
- }
-
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
outExcludedDeviceNames.appendVector(mExcludedDeviceNames);
}
@@ -342,6 +301,12 @@
ADD_FAILURE() << "Should never be called by input reader.";
}
+ virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel) {
+ ADD_FAILURE() << "Should never be called by input reader.";
+ return 0;
+ }
+
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) {
ADD_FAILURE() << "Should never be called by input reader.";
return 0;
@@ -365,11 +330,14 @@
struct Device {
String8 name;
uint32_t classes;
+ PropertyMap configuration;
KeyedVector<int, RawAbsoluteAxisInfo> axes;
KeyedVector<int32_t, int32_t> keyCodeStates;
KeyedVector<int32_t, int32_t> scanCodeStates;
KeyedVector<int32_t, int32_t> switchStates;
KeyedVector<int32_t, KeyInfo> keys;
+ KeyedVector<int32_t, bool> leds;
+ Vector<VirtualKeyDefinition> virtualKeys;
Device(const String8& name, uint32_t classes) :
name(name), classes(classes) {
@@ -408,6 +376,11 @@
enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0, 0, 0);
}
+ void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) {
+ Device* device = getDevice(deviceId);
+ device->configuration.addProperty(key, value);
+ }
+
void addAxis(int32_t deviceId, int axis,
int32_t minValue, int32_t maxValue, int flat, int fuzz) {
Device* device = getDevice(deviceId);
@@ -444,10 +417,25 @@
device->keys.add(scanCode, info);
}
+ void addLed(int32_t deviceId, int32_t led, bool initialState) {
+ Device* device = getDevice(deviceId);
+ device->leds.add(led, initialState);
+ }
+
+ bool getLedState(int32_t deviceId, int32_t led) {
+ Device* device = getDevice(deviceId);
+ return device->leds.valueFor(led);
+ }
+
Vector<String8>& getExcludedDevices() {
return mExcludedDevices;
}
+ void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
+ Device* device = getDevice(deviceId);
+ device->virtualKeys.push(definition);
+ }
+
void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type,
int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) {
RawEvent event;
@@ -482,6 +470,13 @@
return device ? device->name : String8("unknown");
}
+ virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ *outConfiguration = device->configuration;
+ }
+ }
+
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const {
Device* device = getDevice(deviceId);
@@ -577,6 +572,35 @@
return result;
}
+ virtual bool hasLed(int32_t deviceId, int32_t led) const {
+ Device* device = getDevice(deviceId);
+ return device && device->leds.indexOfKey(led) >= 0;
+ }
+
+ virtual void setLedState(int32_t deviceId, int32_t led, bool on) {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ ssize_t index = device->leds.indexOfKey(led);
+ if (index >= 0) {
+ device->leds.replaceValueAt(led, on);
+ } else {
+ ADD_FAILURE()
+ << "Attempted to set the state of an LED that the EventHub declared "
+ "was not present. led=" << led;
+ }
+ }
+ }
+
+ virtual void getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+ outVirtualKeys.clear();
+
+ Device* device = getDevice(deviceId);
+ if (device) {
+ outVirtualKeys.appendVector(device->virtualKeys);
+ }
+ }
+
virtual void dump(String8& dump) {
}
};
@@ -1113,6 +1137,7 @@
mFakeDispatcher = new FakeInputDispatcher();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeDispatcher);
+ mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME));
}
@@ -1172,9 +1197,7 @@
TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) {
// Configuration.
- InputDeviceCalibration calibration;
- calibration.addProperty(String8("key"), String8("value"));
- mFakePolicy->addInputDeviceCalibration(String8(DEVICE_NAME), calibration);
+ mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value"));
FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD);
mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
@@ -1195,8 +1218,8 @@
mDevice->configure();
String8 propertyValue;
- ASSERT_TRUE(mDevice->getCalibration().tryGetProperty(String8("key"), propertyValue))
- << "Device should have read calibration during configuration phase.";
+ ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue))
+ << "Device should have read configuration during configuration phase.";
ASSERT_STREQ("value", propertyValue.string());
ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled());
@@ -1293,9 +1316,8 @@
mFakeEventHub.clear();
}
- void prepareCalibration(const char* key, const char* value) {
- mFakePolicy->addInputDeviceCalibrationProperty(String8(DEVICE_NAME),
- String8(key), String8(value));
+ void addConfigurationProperty(const char* key, const char* value) {
+ mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value));
}
void addMapperAndConfigure(InputMapper* mapper) {
@@ -1412,7 +1434,7 @@
TEST_F(KeyboardInputMapperTest, GetSources) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1420,7 +1442,7 @@
}
TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1457,7 +1479,7 @@
}
TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1477,7 +1499,7 @@
}
TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1522,7 +1544,7 @@
}
TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1561,11 +1583,14 @@
ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled());
}
-TEST_F(KeyboardInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateDPad) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) {
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
+ mFakePolicy->setDisplayInfo(DISPLAY_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ InputReaderPolicyInterface::ROTATION_90);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1576,9 +1601,10 @@
KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
}
-TEST_F(KeyboardInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateDPad) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, DISPLAY_ID,
+TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ addConfigurationProperty("keyboard.orientationAware", "1");
addMapperAndConfigure(mapper);
mFakePolicy->setDisplayInfo(DISPLAY_ID,
@@ -1653,7 +1679,7 @@
}
TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1665,7 +1691,7 @@
}
TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1677,7 +1703,7 @@
}
TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1690,6 +1716,81 @@
ASSERT_FALSE(flags[1]);
}
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) {
+ mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/);
+
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
+ AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ addMapperAndConfigure(mapper);
+
+ // Initialization should have turned all of the lights off.
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+
+ // Toggle caps lock on.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState());
+
+ // Toggle num lock on.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState());
+
+ // Toggle caps lock off.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState());
+
+ // Toggle scroll lock on.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
+
+ // Toggle num lock off.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
+
+ // Toggle scroll lock off.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
+}
+
// --- TrackballInputMapperTest ---
@@ -1719,14 +1820,14 @@
}
TEST_F(TrackballInputMapperTest, GetSources) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources());
}
TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
InputDeviceInfo info;
@@ -1739,7 +1840,7 @@
}
TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -1787,7 +1888,7 @@
}
TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1811,7 +1912,7 @@
}
TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1832,7 +1933,7 @@
}
TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1867,7 +1968,7 @@
}
TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1887,7 +1988,7 @@
}
TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1905,10 +2006,13 @@
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
}
-TEST_F(TrackballInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateMotions) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+TEST_F(TrackballInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) {
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
+ mFakePolicy->setDisplayInfo(DISPLAY_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ InputReaderPolicyInterface::ROTATION_90);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0));
@@ -1919,8 +2023,9 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
}
-TEST_F(TrackballInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateMotions) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, DISPLAY_ID);
+TEST_F(TrackballInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) {
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
+ addConfigurationProperty("trackball.orientationAware", "1");
addMapperAndConfigure(mapper);
mFakePolicy->setDisplayInfo(DISPLAY_ID,
@@ -2041,8 +2146,8 @@
}
void TouchInputMapperTest::prepareVirtualKeys() {
- mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[0]);
- mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[1]);
+ mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]);
+ mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]);
mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, AKEYCODE_HOME, POLICY_FLAG_WAKE);
mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, AKEYCODE_MENU, POLICY_FLAG_WAKE);
}
@@ -2121,24 +2226,26 @@
}
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenNotAttachedToADisplay_ReturnsTouchPad) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, -1);
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchPad");
addMapperAndConfigure(mapper);
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
}
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenAttachedToADisplay_ReturnsTouchScreen) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
addMapperAndConfigure(mapper);
ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());
}
TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2165,7 +2272,7 @@
}
TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2192,7 +2299,7 @@
}
TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2208,7 +2315,7 @@
TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) {
// Note: Ideally we should send cancels but the implementation is more straightforward
// with up and this will only happen if a device is forcibly removed.
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2241,7 +2348,7 @@
}
TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2267,7 +2374,7 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2316,7 +2423,7 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2430,7 +2537,7 @@
}
TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2498,7 +2605,7 @@
}
TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2580,8 +2687,30 @@
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled());
}
-TEST_F(SingleTouchInputMapperTest, Process_Rotation) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "0");
+ addMapperAndConfigure(mapper);
+
+ FakeInputDispatcher::NotifyMotionArgs args;
+
+ // Rotation 90.
+ prepareDisplay(InputReaderPolicyInterface::ROTATION_90);
+ processDown(mapper, toRawX(50), toRawY(75));
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
+ ASSERT_NEAR(50, args.pointerCoords[0].x, 1);
+ ASSERT_NEAR(75, args.pointerCoords[0].y, 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
@@ -2641,7 +2770,7 @@
}
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | PRESSURE | TOOL);
addMapperAndConfigure(mapper);
@@ -2773,7 +2902,7 @@
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -3024,7 +3153,7 @@
}
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | ID);
prepareVirtualKeys();
@@ -3184,7 +3313,7 @@
}
TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR);
addMapperAndConfigure(mapper);
@@ -3229,11 +3358,11 @@
}
TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | MINOR);
- prepareCalibration("touch.touchSize.calibration", "geometric");
- prepareCalibration("touch.toolSize.calibration", "geometric");
+ addConfigurationProperty("touch.touchSize.calibration", "geometric");
+ addConfigurationProperty("touch.toolSize.calibration", "geometric");
addMapperAndConfigure(mapper);
// These calculations are based on the input device calibration documentation.
@@ -3270,17 +3399,17 @@
}
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinearCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
- prepareCalibration("touch.touchSize.calibration", "pressure");
- prepareCalibration("touch.toolSize.calibration", "linear");
- prepareCalibration("touch.toolSize.linearScale", "10");
- prepareCalibration("touch.toolSize.linearBias", "160");
- prepareCalibration("touch.toolSize.isSummed", "1");
- prepareCalibration("touch.pressure.calibration", "amplitude");
- prepareCalibration("touch.pressure.source", "touch");
- prepareCalibration("touch.pressure.scale", "0.01");
+ addConfigurationProperty("touch.touchSize.calibration", "pressure");
+ addConfigurationProperty("touch.toolSize.calibration", "linear");
+ addConfigurationProperty("touch.toolSize.linearScale", "10");
+ addConfigurationProperty("touch.toolSize.linearBias", "160");
+ addConfigurationProperty("touch.toolSize.isSummed", "1");
+ addConfigurationProperty("touch.pressure.calibration", "amplitude");
+ addConfigurationProperty("touch.pressure.source", "touch");
+ addConfigurationProperty("touch.pressure.scale", "0.01");
addMapperAndConfigure(mapper);
// These calculations are based on the input device calibration documentation.
@@ -3326,18 +3455,18 @@
}
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_AreaCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
- prepareCalibration("touch.touchSize.calibration", "pressure");
- prepareCalibration("touch.toolSize.calibration", "area");
- prepareCalibration("touch.toolSize.areaScale", "22");
- prepareCalibration("touch.toolSize.areaBias", "1");
- prepareCalibration("touch.toolSize.linearScale", "9.2");
- prepareCalibration("touch.toolSize.linearBias", "3");
- prepareCalibration("touch.pressure.calibration", "amplitude");
- prepareCalibration("touch.pressure.source", "touch");
- prepareCalibration("touch.pressure.scale", "0.01");
+ addConfigurationProperty("touch.touchSize.calibration", "pressure");
+ addConfigurationProperty("touch.toolSize.calibration", "area");
+ addConfigurationProperty("touch.toolSize.areaScale", "22");
+ addConfigurationProperty("touch.toolSize.areaBias", "1");
+ addConfigurationProperty("touch.toolSize.linearScale", "9.2");
+ addConfigurationProperty("touch.toolSize.linearBias", "3");
+ addConfigurationProperty("touch.pressure.calibration", "amplitude");
+ addConfigurationProperty("touch.pressure.source", "touch");
+ addConfigurationProperty("touch.pressure.scale", "0.01");
addMapperAndConfigure(mapper);
// These calculations are based on the input device calibration documentation.
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index eb75ed8..e8d40ba 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -28,6 +28,7 @@
Flattenable.cpp \
ObbFile.cpp \
Pool.cpp \
+ PropertyMap.cpp \
RefBase.cpp \
ResourceTypes.cpp \
SharedBuffer.cpp \
@@ -41,6 +42,8 @@
TextOutput.cpp \
Threads.cpp \
Timers.cpp \
+ Tokenizer.cpp \
+ Unicode.cpp \
VectorImpl.cpp \
ZipFileCRO.cpp \
ZipFileRO.cpp \
@@ -67,11 +70,6 @@
endif
endif
-ifeq ($(HOST_OS),darwin)
-# MacOS doesn't have lseek64. However, off_t is 64-bit anyway.
-LOCAL_CFLAGS += -DOFF_T_IS_64_BIT
-endif
-
include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
index cef7db4..a18294b 100644
--- a/libs/utils/Asset.cpp
+++ b/libs/utils/Asset.cpp
@@ -35,6 +35,9 @@
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
using namespace android;
@@ -62,7 +65,7 @@
if (cur->isAllocated()) {
res.append(" ");
res.append(cur->getAssetSource());
- off_t size = (cur->getLength()+512)/1024;
+ off64_t size = (cur->getLength()+512)/1024;
char buf[64];
sprintf(buf, ": %dK\n", (int)size);
res.append(buf);
@@ -119,7 +122,7 @@
{
_FileAsset* pAsset;
status_t result;
- off_t length;
+ off64_t length;
int fd;
fd = open(fileName, O_RDONLY | O_BINARY);
@@ -132,12 +135,26 @@
* always open things read-only it doesn't really matter, so there's
* no value in incurring the extra overhead of an fstat() call.
*/
- length = lseek(fd, 0, SEEK_END);
+ // TODO(kroot): replace this with fstat despite the plea above.
+#if 1
+ length = lseek64(fd, 0, SEEK_END);
if (length < 0) {
::close(fd);
return NULL;
}
- (void) lseek(fd, 0, SEEK_SET);
+ (void) lseek64(fd, 0, SEEK_SET);
+#else
+ struct stat st;
+ if (fstat(fd, &st) < 0) {
+ ::close(fd);
+ return NULL;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ ::close(fd);
+ return NULL;
+ }
+#endif
pAsset = new _FileAsset;
result = pAsset->openChunk(fileName, fd, 0, length);
@@ -162,7 +179,7 @@
{
_CompressedAsset* pAsset;
status_t result;
- off_t fileLen;
+ off64_t fileLen;
bool scanResult;
long offset;
int method;
@@ -215,7 +232,7 @@
/*
* Create a new Asset from part of an open file.
*/
-/*static*/ Asset* Asset::createFromFileSegment(int fd, off_t offset,
+/*static*/ Asset* Asset::createFromFileSegment(int fd, off64_t offset,
size_t length, AccessMode mode)
{
_FileAsset* pAsset;
@@ -233,7 +250,7 @@
/*
* Create a new Asset from compressed data in an open file.
*/
-/*static*/ Asset* Asset::createFromCompressedData(int fd, off_t offset,
+/*static*/ Asset* Asset::createFromCompressedData(int fd, off64_t offset,
int compressionMethod, size_t uncompressedLen, size_t compressedLen,
AccessMode mode)
{
@@ -295,9 +312,9 @@
*
* Returns the new chunk offset, or -1 if the seek is illegal.
*/
-off_t Asset::handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn)
+off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn)
{
- off_t newOffset;
+ off64_t newOffset;
switch (whence) {
case SEEK_SET:
@@ -311,15 +328,15 @@
break;
default:
LOGW("unexpected whence %d\n", whence);
- // this was happening due to an off_t size mismatch
+ // this was happening due to an off64_t size mismatch
assert(false);
- return (off_t) -1;
+ return (off64_t) -1;
}
if (newOffset < 0 || newOffset > maxPosn) {
LOGW("seek out of range: want %ld, end=%ld\n",
(long) newOffset, (long) maxPosn);
- return (off_t) -1;
+ return (off64_t) -1;
}
return newOffset;
@@ -353,7 +370,7 @@
*
* Zero-length chunks are allowed.
*/
-status_t _FileAsset::openChunk(const char* fileName, int fd, off_t offset, size_t length)
+status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
{
assert(mFp == NULL); // no reopen
assert(mMap == NULL);
@@ -363,15 +380,15 @@
/*
* Seek to end to get file length.
*/
- off_t fileLength;
- fileLength = lseek(fd, 0, SEEK_END);
- if (fileLength == (off_t) -1) {
+ off64_t fileLength;
+ fileLength = lseek64(fd, 0, SEEK_END);
+ if (fileLength == (off64_t) -1) {
// probably a bad file descriptor
LOGD("failed lseek (errno=%d)\n", errno);
return UNKNOWN_ERROR;
}
- if ((off_t) (offset + length) > fileLength) {
+ if ((off64_t) (offset + length) > fileLength) {
LOGD("start (%ld) + len (%ld) > end (%ld)\n",
(long) offset, (long) length, (long) fileLength);
return BAD_INDEX;
@@ -482,21 +499,21 @@
/*
* Seek to a new position.
*/
-off_t _FileAsset::seek(off_t offset, int whence)
+off64_t _FileAsset::seek(off64_t offset, int whence)
{
- off_t newPosn;
- long actualOffset;
+ off64_t newPosn;
+ off64_t actualOffset;
// compute new position within chunk
newPosn = handleSeek(offset, whence, mOffset, mLength);
- if (newPosn == (off_t) -1)
+ if (newPosn == (off64_t) -1)
return newPosn;
- actualOffset = (long) (mStart + newPosn);
+ actualOffset = mStart + newPosn;
if (mFp != NULL) {
if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
- return (off_t) -1;
+ return (off64_t) -1;
}
mOffset = actualOffset - mStart;
@@ -603,7 +620,7 @@
}
}
-int _FileAsset::openFileDescriptor(off_t* outStart, off_t* outLength) const
+int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
{
if (mMap != NULL) {
const char* fname = mMap->getFileName();
@@ -678,7 +695,7 @@
* This currently just sets up some values and returns. On the first
* read, we expand the entire file into a buffer and return data from it.
*/
-status_t _CompressedAsset::openChunk(int fd, off_t offset,
+status_t _CompressedAsset::openChunk(int fd, off64_t offset,
int compressionMethod, size_t uncompressedLen, size_t compressedLen)
{
assert(mFd < 0); // no re-open
@@ -782,13 +799,13 @@
* expensive, because it requires plowing through a bunch of compressed
* data.
*/
-off_t _CompressedAsset::seek(off_t offset, int whence)
+off64_t _CompressedAsset::seek(off64_t offset, int whence)
{
- off_t newPosn;
+ off64_t newPosn;
// compute new position within chunk
newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen);
- if (newPosn == (off_t) -1)
+ if (newPosn == (off64_t) -1)
return newPosn;
if (mZipInflater) {
diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp
index e1ba9b2..c220a90 100644
--- a/libs/utils/FileMap.cpp
+++ b/libs/utils/FileMap.cpp
@@ -63,16 +63,18 @@
free(mFileName);
}
#ifdef HAVE_POSIX_FILEMAP
- if (munmap(mBasePtr, mBaseLength) != 0) {
+ if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
}
#endif
#ifdef HAVE_WIN32_FILEMAP
- if ( UnmapViewOfFile(mBasePtr) == 0) {
+ if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
GetLastError() );
}
- CloseHandle(mFileMapping);
+ if (mFileMapping != INVALID_HANDLE_VALUE) {
+ CloseHandle(mFileMapping);
+ }
CloseHandle(mFileHandle);
#endif
}
@@ -86,11 +88,12 @@
*
* Returns "false" on failure.
*/
-bool FileMap::create(const char* origFileName, int fd, off_t offset, size_t length, bool readOnly)
+bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
+ bool readOnly)
{
#ifdef HAVE_WIN32_FILEMAP
int adjust;
- off_t adjOffset;
+ off64_t adjOffset;
size_t adjLength;
if (mPageSize == -1) {
@@ -129,7 +132,7 @@
#endif
#ifdef HAVE_POSIX_FILEMAP
int prot, flags, adjust;
- off_t adjOffset;
+ off64_t adjOffset;
size_t adjLength;
void* ptr;
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
index 2c3724c..2907b56 100644
--- a/libs/utils/ObbFile.cpp
+++ b/libs/utils/ObbFile.cpp
@@ -22,6 +22,8 @@
#include <unistd.h>
#define LOG_TAG "ObbFile"
+
+#include <utils/Compat.h>
#include <utils/Log.h>
#include <utils/ObbFile.h>
@@ -67,17 +69,6 @@
_rc; })
#endif
-/*
- * Work around situations where off_t is 64-bit and use off64_t in
- * situations where it's 32-bit.
- */
-#ifdef OFF_T_IS_64_BIT
-#define my_lseek64 lseek
-typedef off_t my_off64_t;
-#else
-#define my_lseek64 lseek64
-typedef off64_t my_off64_t;
-#endif
namespace android {
@@ -125,7 +116,7 @@
bool ObbFile::parseObbFile(int fd)
{
- my_off64_t fileLength = my_lseek64(fd, 0, SEEK_END);
+ off64_t fileLength = lseek64(fd, 0, SEEK_END);
if (fileLength < kFooterMinSize) {
if (fileLength < 0) {
@@ -140,7 +131,7 @@
size_t footerSize;
{
- my_lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
+ lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
char *footer = new char[kFooterTagSize];
actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
@@ -171,8 +162,8 @@
}
}
- my_off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
- if (my_lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
+ off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
+ if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
return false;
}
@@ -211,10 +202,10 @@
memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
- uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
- if (packageNameLen <= 0
+ size_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
+ if (packageNameLen == 0
|| packageNameLen > (footerSize - kPackageNameOffset)) {
- LOGW("bad ObbFile package name length (0x%04x; 0x%04x possible)\n",
+ LOGW("bad ObbFile package name length (0x%04zx; 0x%04zx possible)\n",
packageNameLen, footerSize - kPackageNameOffset);
free(scanBuf);
return false;
@@ -257,7 +248,7 @@
return false;
}
- my_lseek64(fd, 0, SEEK_END);
+ lseek64(fd, 0, SEEK_END);
if (mPackageName.size() == 0 || mVersion == -1) {
LOGW("tried to write uninitialized ObbFile data\n");
diff --git a/libs/utils/PropertyMap.cpp b/libs/utils/PropertyMap.cpp
new file mode 100644
index 0000000..fd7edec
--- /dev/null
+++ b/libs/utils/PropertyMap.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <utils/PropertyMap.h>
+#include <utils/Log.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') {
+ LOGW("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') {
+ LOGW("Property key '%s' has invalid value '%s'. Expected a float.",
+ key.string(), stringValue.string());
+ return false;
+ }
+ outValue = value;
+ return true;
+}
+
+status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
+ *outMap = NULL;
+
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(filename, &tokenizer);
+ if (status) {
+ LOGE("Error %d opening property file %s.", status, filename.string());
+ } else {
+ PropertyMap* map = new PropertyMap();
+ if (!map) {
+ LOGE("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;
+ LOGD("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
+ LOGD("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()) {
+ LOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ if (mTokenizer->nextChar() != '=') {
+ LOGE("%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) {
+ LOGE("%s: Found reserved character '\\' or '\"' in property value.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (!mTokenizer->isEol()) {
+ LOGE("%s: Expected end of line, got '%s'.",
+ mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+ return BAD_VALUE;
+ }
+
+ if (mMap->hasProperty(keyToken)) {
+ LOGE("%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/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 8345cc3..bbf5093 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -317,6 +317,12 @@
mStringPoolSize =
(mHeader->header.size-mHeader->stringsStart)/charSize;
} else {
+ // check invariant: styles starts before end of data
+ if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) {
+ LOGW("Bad style block: style block starts at %d past data size of %d\n",
+ (int)mHeader->stylesStart, (int)mHeader->header.size);
+ return (mError=BAD_TYPE);
+ }
// check invariant: styles follow the strings
if (mHeader->stylesStart <= mHeader->stringsStart) {
LOGW("Bad style block: style block starts at %d, before strings at %d\n",
@@ -438,15 +444,51 @@
}
}
-#define DECODE_LENGTH(str, chrsz, len) \
- len = *(str); \
- if (*(str)&(1<<(chrsz*8-1))) { \
- (str)++; \
- len = (((len)&((1<<(chrsz*8-1))-1))<<(chrsz*8)) + *(str); \
- } \
- (str)++;
+/**
+ * Strings in UTF-16 format have length indicated by a length encoded in the
+ * stored data. It is either 1 or 2 characters of length data. This allows a
+ * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that
+ * much data in a string, you're abusing them.
+ *
+ * If the high bit is set, then there are two characters or 4 bytes of length
+ * data encoded. In that case, drop the high bit of the first character and
+ * add it together with the next character.
+ */
+static inline size_t
+decodeLength(const char16_t** str)
+{
+ size_t len = **str;
+ if ((len & 0x8000) != 0) {
+ (*str)++;
+ len = ((len & 0x7FFF) << 16) | **str;
+ }
+ (*str)++;
+ return len;
+}
-const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
+/**
+ * Strings in UTF-8 format have length indicated by a length encoded in the
+ * stored data. It is either 1 or 2 characters of length data. This allows a
+ * maximum length of 0x7FFF (32767 bytes), but you should consider storing
+ * text in another way if you're using that much data in a single string.
+ *
+ * If the high bit is set, then there are two characters or 2 bytes of length
+ * data encoded. In that case, drop the high bit of the first character and
+ * add it together with the next character.
+ */
+static inline size_t
+decodeLength(const uint8_t** str)
+{
+ size_t len = **str;
+ if ((len & 0x80) != 0) {
+ (*str)++;
+ len = ((len & 0x7F) << 8) | **str;
+ }
+ (*str)++;
+ return len;
+}
+
+const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
@@ -455,37 +497,51 @@
if (!isUTF8) {
const char16_t* strings = (char16_t*)mStrings;
const char16_t* str = strings+off;
- DECODE_LENGTH(str, sizeof(char16_t), *outLen)
- if ((uint32_t)(str+*outLen-strings) < mStringPoolSize) {
+
+ *u16len = decodeLength(&str);
+ if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
return str;
} else {
LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+*outLen-strings), (int)mStringPoolSize);
+ (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
}
} else {
const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* str = strings+off;
- DECODE_LENGTH(str, sizeof(uint8_t), *outLen)
- size_t encLen;
- DECODE_LENGTH(str, sizeof(uint8_t), encLen)
- if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
+ const uint8_t* u8str = strings+off;
+
+ *u16len = decodeLength(&u8str);
+ size_t u8len = decodeLength(&u8str);
+
+ // encLen must be less than 0x7FFF due to encoding.
+ if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
AutoMutex lock(mDecodeLock);
+
if (mCache[idx] != NULL) {
return mCache[idx];
}
- char16_t *u16str = (char16_t *)calloc(*outLen+1, sizeof(char16_t));
+
+ ssize_t actualLen = utf8_to_utf16_length(u8str, u8len);
+ if (actualLen < 0 || (size_t)actualLen != *u16len) {
+ LOGW("Bad string block: string #%lld decoded length is not correct "
+ "%lld vs %llu\n",
+ (long long)idx, (long long)actualLen, (long long)*u16len);
+ return NULL;
+ }
+
+ char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
if (!u16str) {
LOGW("No memory when trying to allocate decode cache for string #%d\n",
(int)idx);
return NULL;
}
- const unsigned char *u8src = reinterpret_cast<const unsigned char *>(str);
- utf8_to_utf16(u8src, encLen, u16str, *outLen);
+
+ utf8_to_utf16(u8str, u8len, u16str);
mCache[idx] = u16str;
return u16str;
} else {
- LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
+ LOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
+ (long long)idx, (long long)(u8str+u8len-strings),
+ (long long)mStringPoolSize);
}
}
} else {
@@ -506,9 +562,8 @@
if (isUTF8) {
const uint8_t* strings = (uint8_t*)mStrings;
const uint8_t* str = strings+off;
- DECODE_LENGTH(str, sizeof(uint8_t), *outLen)
- size_t encLen;
- DECODE_LENGTH(str, sizeof(uint8_t), encLen)
+ *outLen = decodeLength(&str);
+ size_t encLen = decodeLength(&str);
if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
return (const char*)str;
} else {
@@ -1878,13 +1933,19 @@
outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
outName->name = grp->basePackage->keyStrings.stringAt(
dtohl(entry->key.index), &outName->nameLen);
+
+ // If we have a bad index for some reason, we should abort.
+ if (outName->type == NULL || outName->name == NULL) {
+ return false;
+ }
+
return true;
}
return false;
}
-ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
+ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
uint32_t* outSpecFlags, ResTable_config* outConfig) const
{
if (mError != NO_ERROR) {
@@ -1914,7 +1975,7 @@
memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
if (outSpecFlags != NULL) *outSpecFlags = 0;
-
+
// Look through all resource packages, starting with the most
// recently added.
const PackageGroup* const grp = mPackageGroups[p];
@@ -1922,6 +1983,22 @@
LOGW("Bad identifier when getting value for resource number 0x%08x", resID);
return BAD_INDEX;
}
+
+ // Allow overriding density
+ const ResTable_config* desiredConfig = &mParams;
+ ResTable_config* overrideConfig = NULL;
+ if (density > 0) {
+ overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config));
+ if (overrideConfig == NULL) {
+ LOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno));
+ return BAD_INDEX;
+ }
+ memcpy(overrideConfig, &mParams, sizeof(ResTable_config));
+ overrideConfig->density = density;
+ desiredConfig = overrideConfig;
+ }
+
+ ssize_t rc = BAD_VALUE;
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
@@ -1931,12 +2008,13 @@
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ ssize_t offset = getEntry(package, t, e, desiredConfig, &type, &entry, &typeClass);
if (offset <= 0) {
if (offset < 0) {
LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
resID, t, e, ip, (int)offset);
- return offset;
+ rc = offset;
+ goto out;
}
continue;
}
@@ -1951,13 +2029,14 @@
TABLE_NOISY(aout << "Resource type data: "
<< HexDump(type, dtohl(type->header.size)) << endl);
-
+
if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
LOGW("ResTable_item at %d is beyond type chunk data %d",
(int)offset, dtohl(type->header.size));
- return BAD_TYPE;
+ rc = BAD_TYPE;
+ goto out;
}
-
+
const Res_value* item =
(const Res_value*)(((const uint8_t*)type) + offset);
ResTable_config thisConfig;
@@ -1999,10 +2078,16 @@
outValue->data, &len)).string()
: "",
outValue->data));
- return bestPackage->header->index;
+ rc = bestPackage->header->index;
+ goto out;
}
- return BAD_VALUE;
+out:
+ if (overrideConfig != NULL) {
+ free(overrideConfig);
+ }
+
+ return rc;
}
ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
@@ -2015,7 +2100,7 @@
if (outLastRef) *outLastRef = value->data;
uint32_t lastRef = value->data;
uint32_t newFlags = 0;
- const ssize_t newIndex = getResource(value->data, value, true, &newFlags,
+ const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
outConfig);
if (newIndex == BAD_INDEX) {
return BAD_INDEX;
@@ -2609,6 +2694,24 @@
*outType = *defType;
}
*outName = String16(p, end-p);
+ if(**outPackage == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource package cannot be an empty string";
+ }
+ return false;
+ }
+ if(**outType == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource type cannot be an empty string";
+ }
+ return false;
+ }
+ if(**outName == 0) {
+ if(outErrorMsg) {
+ *outErrorMsg = "Resource id cannot be an empty string";
+ }
+ return false;
+ }
return true;
}
@@ -4127,13 +4230,16 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- this->getResourceName(resID, &resName);
- printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
- resID,
- CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen),
- dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ if (this->getResourceName(resID, &resName)) {
+ printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
+ resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen),
+ dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ } else {
+ printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
+ }
}
}
for (size_t configIndex=0; configIndex<NTC; configIndex++) {
@@ -4340,11 +4446,14 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- this->getResourceName(resID, &resName);
- printf(" resource 0x%08x %s:%s/%s: ", resID,
- CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ if (this->getResourceName(resID, &resName)) {
+ printf(" resource 0x%08x %s:%s/%s: ", resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ } else {
+ printf(" INVALID RESOURCE 0x%08x: ", resID);
+ }
if ((thisOffset&0x3) != 0) {
printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
continue;
@@ -4402,18 +4511,19 @@
print_value(pkg, value);
} else if (bagPtr != NULL) {
const int N = dtohl(bagPtr->count);
- const ResTable_map* mapPtr = (const ResTable_map*)
- (((const uint8_t*)ent) + esize);
+ const uint8_t* baseMapPtr = (const uint8_t*)ent;
+ size_t mapOffset = esize;
+ const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
printf(" Parent=0x%08x, Count=%d\n",
dtohl(bagPtr->parent.ident), N);
- for (int i=0; i<N; i++) {
+ for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
printf(" #%i (Key=0x%08x): ",
i, dtohl(mapPtr->name.ident));
value.copyFrom_dtoh(mapPtr->value);
print_value(pkg, value);
const size_t size = dtohs(mapPtr->value.size);
- mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr)
- + size + sizeof(*mapPtr)-sizeof(mapPtr->value));
+ mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
+ mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
}
}
}
diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/utils/StreamingZipInflater.cpp
index 1f62ac5..5a162cc 100644
--- a/libs/utils/StreamingZipInflater.cpp
+++ b/libs/utils/StreamingZipInflater.cpp
@@ -31,7 +31,7 @@
/*
* Streaming access to compressed asset data in an open fd
*/
-StreamingZipInflater::StreamingZipInflater(int fd, off_t compDataStart,
+StreamingZipInflater::StreamingZipInflater(int fd, off64_t compDataStart,
size_t uncompSize, size_t compSize) {
mFd = fd;
mDataMap = NULL;
@@ -210,7 +210,7 @@
// seeking backwards requires uncompressing fom the beginning, so is very
// expensive. seeking forwards only requires uncompressing from the current
// position to the destination.
-off_t StreamingZipInflater::seekAbsolute(off_t absoluteInputPosition) {
+off64_t StreamingZipInflater::seekAbsolute(off64_t absoluteInputPosition) {
if (absoluteInputPosition < mOutCurPosition) {
// rewind and reprocess the data from the beginning
if (!mStreamNeedsInit) {
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index eab7b2b..4ce1664 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -18,228 +18,17 @@
#include <utils/Debug.h>
#include <utils/Log.h>
+#include <utils/Unicode.h>
#include <utils/String8.h>
#include <utils/TextOutput.h>
#include <utils/threads.h>
#include <private/utils/Static.h>
-#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 <netinet/in.h>
-#endif
-
#include <memory.h>
#include <stdio.h>
#include <ctype.h>
-// ---------------------------------------------------------------------------
-
-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);
-}
-
-static inline size_t
-utf8_char_len(uint8_t ch)
-{
- return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
-}
-
-#define UTF8_SHIFT_AND_MASK(unicode, byte) (unicode)<<=6; (unicode) |= (0x3f & (byte));
-
-static inline uint32_t
-utf8_to_utf32(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);
-}
-
-void
-utf8_to_utf16(const uint8_t *src, size_t srcLen,
- char16_t* dst, const size_t dstLen)
-{
- const uint8_t* const end = src + srcLen;
- const char16_t* const dstEnd = dst + dstLen;
- while (src < end && dst < dstEnd) {
- size_t len = utf8_char_len(*src);
- uint32_t codepoint = utf8_to_utf32((const uint8_t*)src, len);
-
- // Convert the UTF32 codepoint to one or more UTF16 codepoints
- if (codepoint <= 0xFFFF) {
- // Single UTF16 character
- *dst++ = (char16_t) codepoint;
- } else {
- // Multiple UTF16 characters with surrogates
- codepoint = codepoint - 0x10000;
- *dst++ = (char16_t) ((codepoint >> 10) + 0xD800);
- *dst++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
- }
-
- src += len;
- }
- if (dst < dstEnd) {
- *dst = 0;
- }
-}
-
-// ---------------------------------------------------------------------------
namespace android {
@@ -270,37 +59,33 @@
// ---------------------------------------------------------------------------
-static char16_t* allocFromUTF8(const char* in, size_t len)
+static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
{
- if (len == 0) return getEmptyString();
-
- size_t chars = 0;
- const char* end = in+len;
- const char* p = in;
-
- while (p < end) {
- chars++;
- int utf8len = utf8_char_len(*p);
- uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, utf8len);
- if (codepoint > 0xFFFF) chars++; // this will be a surrogate pair in utf16
- p += utf8len;
+ if (u8len == 0) return getEmptyString();
+
+ const uint8_t* u8cur = (const uint8_t*) u8str;
+
+ const ssize_t u16len = utf8_to_utf16_length(u8cur, u8len);
+ if (u16len < 0) {
+ return getEmptyString();
}
-
- size_t bufSize = (chars+1)*sizeof(char16_t);
- SharedBuffer* buf = SharedBuffer::alloc(bufSize);
+
+ const uint8_t* const u8end = u8cur + u8len;
+
+ SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
if (buf) {
- p = in;
- char16_t* str = (char16_t*)buf->data();
-
- utf8_to_utf16((const uint8_t*)p, len, str, bufSize);
+ u8cur = (const uint8_t*) u8str;
+ char16_t* u16str = (char16_t*)buf->data();
+
+ utf8_to_utf16(u8cur, u8len, u16str);
//printf("Created UTF-16 string from UTF-8 \"%s\":", in);
//printHexData(1, str, buf->size(), 16, 1);
//printf("\n");
- return str;
+ return u16str;
}
-
+
return getEmptyString();
}
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index 1c4f80c..0bc5aff 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -17,6 +17,8 @@
#include <utils/String8.h>
#include <utils/Log.h>
+#include <utils/Unicode.h>
+#include <utils/SharedBuffer.h>
#include <utils/String16.h>
#include <utils/TextOutput.h>
#include <utils/threads.h>
@@ -34,94 +36,10 @@
namespace android {
-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
-};
-
// Separator used by resource paths. This is not platform dependent contrary
// to OS_PATH_SEPARATOR.
#define RES_PATH_SEPARATOR '/'
-// Return number of utf8 bytes required for the character.
-static size_t utf32_to_utf8_bytes(char32_t srcChar)
-{
- size_t bytesToWrite;
-
- // Figure out how many bytes the result will require.
- if (srcChar < 0x00000080)
- {
- bytesToWrite = 1;
- }
- else if (srcChar < 0x00000800)
- {
- bytesToWrite = 2;
- }
- else if (srcChar < 0x00010000)
- {
- if ((srcChar < kUnicodeSurrogateStart)
- || (srcChar > kUnicodeSurrogateEnd))
- {
- bytesToWrite = 3;
- }
- else
- {
- // Surrogates are invalid UTF-32 characters.
- return 0;
- }
- }
- // Max code point for Unicode is 0x0010FFFF.
- else if (srcChar <= kUnicodeMaxCodepoint)
- {
- bytesToWrite = 4;
- }
- else
- {
- // Invalid UTF-32 character.
- return 0;
- }
-
- return bytesToWrite;
-}
-
-// Write out the source character to <dstP>.
-
-static void utf32_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]);
- }
-}
-
-// ---------------------------------------------------------------------------
-
static SharedBuffer* gEmptyStringBuf = NULL;
static char* gEmptyString = NULL;
@@ -175,62 +93,47 @@
return getEmptyString();
}
-template<typename T, typename L>
-static char* allocFromUTF16OrUTF32(const T* in, L len)
-{
- if (len == 0) return getEmptyString();
-
- size_t bytes = 0;
- const T* end = in+len;
- const T* p = in;
-
- while (p < end) {
- bytes += utf32_to_utf8_bytes(*p);
- p++;
- }
-
- SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
- LOG_ASSERT(buf, "Unable to allocate shared buffer");
- if (buf) {
- p = in;
- char* str = (char*)buf->data();
- char* d = str;
- while (p < end) {
- const T c = *p++;
- size_t len = utf32_to_utf8_bytes(c);
- utf32_to_utf8((uint8_t*)d, c, len);
- d += len;
- }
- *d = 0;
-
- return str;
- }
-
- return getEmptyString();
-}
-
static char* allocFromUTF16(const char16_t* in, size_t len)
{
if (len == 0) return getEmptyString();
- const size_t bytes = utf8_length_from_utf16(in, len);
+ const ssize_t bytes = utf16_to_utf8_length(in, len);
+ if (bytes < 0) {
+ return getEmptyString();
+ }
SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
LOG_ASSERT(buf, "Unable to allocate shared buffer");
- if (buf) {
- char* str = (char*)buf->data();
-
- utf16_to_utf8(in, len, str, bytes+1);
-
- return str;
+ if (!buf) {
+ return getEmptyString();
}
- 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)
{
- return allocFromUTF16OrUTF32<char32_t, size_t>(in, 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);
+ LOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (!buf) {
+ return getEmptyString();
+ }
+
+ char* str = (char*) buf->data();
+ utf32_to_utf8(in, len, str);
+
+ return str;
}
// ---------------------------------------------------------------------------
@@ -292,6 +195,29 @@
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();
@@ -374,22 +300,28 @@
status_t String8::appendFormat(const char* fmt, ...)
{
- va_list ap;
- va_start(ap, 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, ap);
+ 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, ap);
+ vsnprintf(buf + oldLength, n + 1, fmt, args);
} else {
result = NO_MEMORY;
}
}
-
- va_end(ap);
return result;
}
@@ -505,17 +437,17 @@
size_t String8::getUtf32Length() const
{
- return utf32_length(mString, length());
+ return utf8_to_utf32_length(mString, length());
}
int32_t String8::getUtf32At(size_t index, size_t *next_index) const
{
- return utf32_at(mString, length(), index, next_index);
+ return utf32_from_utf8_at(mString, length(), index, next_index);
}
-size_t String8::getUtf32(char32_t* dst, size_t dst_len) const
+void String8::getUtf32(char32_t* dst) const
{
- return utf8_to_utf32(mString, length(), dst, dst_len);
+ utf8_to_utf32(mString, length(), dst);
}
TextOutput& operator<<(TextOutput& to, const String8& val)
@@ -700,241 +632,3 @@
}
}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-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;
-}
-
-size_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 0;
- }
-
- 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 0;
- }
- // 0x3F == 00111111
- utf32 = (utf32 << 6) + (*cur++ & 0x3F);
- }
- // "first_char" must be (110xxxxx - 11110xxx)
- if (num_to_read == 5) {
- return 0;
- }
- to_ignore_mask |= mask;
- utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
- if (utf32 > android::kUnicodeMaxCodepoint) {
- return 0;
- }
-
- ret += num_to_read;
- }
- return ret;
-}
-
-size_t 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;
-}
-
-size_t utf8_length_from_utf32(const char32_t *src, size_t src_len)
-{
- if (src == NULL || src_len == 0) {
- return 0;
- }
- size_t ret = 0;
- const char32_t *end = src + src_len;
- while (src < end) {
- ret += android::utf32_to_utf8_bytes(*src++);
- }
- return ret;
-}
-
-size_t utf8_length_from_utf16(const char16_t *src, size_t src_len)
-{
- if (src == NULL || src_len == 0) {
- return 0;
- }
- 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 += android::utf32_to_utf8_bytes((char32_t) *src++);
- }
- }
- return ret;
-}
-
-static 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<int32_t>(utf32);
-}
-
-int32_t utf32_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;
-}
-
-size_t utf8_to_utf32(const char* src, size_t src_len,
- char32_t* dst, size_t dst_len)
-{
- if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
- return 0;
- }
-
- const char* cur = src;
- const char* end = src + src_len;
- char32_t* cur_utf32 = dst;
- const char32_t* end_utf32 = dst + dst_len;
- while (cur_utf32 < end_utf32 && cur < end) {
- size_t num_read;
- *cur_utf32++ =
- static_cast<char32_t>(utf32_at_internal(cur, &num_read));
- cur += num_read;
- }
- if (cur_utf32 < end_utf32) {
- *cur_utf32 = 0;
- }
- return static_cast<size_t>(cur_utf32 - dst);
-}
-
-size_t utf32_to_utf8(const char32_t* src, size_t src_len,
- char* dst, size_t dst_len)
-{
- if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
- return 0;
- }
- const char32_t *cur_utf32 = src;
- const char32_t *end_utf32 = src + src_len;
- char *cur = dst;
- const char *end = dst + dst_len;
- while (cur_utf32 < end_utf32 && cur < end) {
- size_t len = android::utf32_to_utf8_bytes(*cur_utf32);
- android::utf32_to_utf8((uint8_t *)cur, *cur_utf32++, len);
- cur += len;
- }
- if (cur < end) {
- *cur = '\0';
- }
- return cur - dst;
-}
-
-size_t utf16_to_utf8(const char16_t* src, size_t src_len,
- char* dst, size_t dst_len)
-{
- if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
- return 0;
- }
- const char16_t* cur_utf16 = src;
- const char16_t* const end_utf16 = src + src_len;
- char *cur = dst;
- const char* const end = dst + dst_len;
- while (cur_utf16 < end_utf16 && cur < end) {
- char32_t utf32;
- // surrogate pairs
- if ((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16) {
- utf32 = (*cur_utf16++ - 0xD800) << 10;
- utf32 |= *cur_utf16++ - 0xDC00;
- utf32 += 0x10000;
- } else {
- utf32 = (char32_t) *cur_utf16++;
- }
- size_t len = android::utf32_to_utf8_bytes(utf32);
- android::utf32_to_utf8((uint8_t*)cur, utf32, len);
- cur += len;
- }
- if (cur < end) {
- *cur = '\0';
- }
- return cur - dst;
-}
diff --git a/libs/utils/Tokenizer.cpp b/libs/utils/Tokenizer.cpp
new file mode 100644
index 0000000..b3445b7
--- /dev/null
+++ b/libs/utils/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 <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utils/Log.h>
+#include <utils/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;
+ LOGE("Error opening file '%s', %s.", filename.string(), strerror(errno));
+ } else {
+ struct stat stat;
+ if (fstat(fd, &stat)) {
+ result = -errno;
+ LOGE("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<char*>(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;
+ LOGE("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
+ LOGD("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
+ LOGD("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
+ LOGD("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/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp
new file mode 100644
index 0000000..78c61b4
--- /dev/null
+++ b/libs/utils/Unicode.cpp
@@ -0,0 +1,575 @@
+/*
+ * 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 <utils/Unicode.h>
+
+#include <stddef.h>
+
+#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 <netinet/in.h>
+#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 <dstP>.
+
+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<int32_t>(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<char32_t>(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;
+}
+
+/**
+ * Convert a UTF-8 string to UTF-16. The destination UTF-16 buffer must have
+ * space for NULL at the end.
+ */
+void utf8_to_utf16(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;
+ }
+ *u16cur = 0;
+}
+
+}
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp
index 16b219c..55dfd9f 100644
--- a/libs/utils/ZipFileCRO.cpp
+++ b/libs/utils/ZipFileCRO.cpp
@@ -40,7 +40,7 @@
bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken,
int* pMethod, size_t* pUncompLen,
- size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {
+ size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) {
ZipFileRO* zip = (ZipFileRO*)zipToken;
ZipEntryRO entry = (ZipEntryRO)entryToken;
return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset,
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index 4261196..b18c383 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -146,7 +146,7 @@
return NAME_NOT_FOUND;
}
- mFileLength = lseek(fd, 0, SEEK_END);
+ mFileLength = lseek64(fd, 0, SEEK_END);
if (mFileLength < kEOCDLen) {
TEMP_FAILURE_RETRY(close(fd));
return UNKNOWN_ERROR;
@@ -202,7 +202,7 @@
/*
* Make sure this is a Zip archive.
*/
- if (lseek(mFd, 0, SEEK_SET) != 0) {
+ if (lseek64(mFd, 0, SEEK_SET) != 0) {
LOGW("seek to start failed: %s", strerror(errno));
free(scanBuf);
return false;
@@ -240,9 +240,9 @@
*
* We start by pulling in the last part of the file.
*/
- off_t searchStart = mFileLength - readAmount;
+ off64_t searchStart = mFileLength - readAmount;
- if (lseek(mFd, searchStart, SEEK_SET) != searchStart) {
+ if (lseek64(mFd, searchStart, SEEK_SET) != searchStart) {
LOGW("seek %ld failed: %s\n", (long) searchStart, strerror(errno));
free(scanBuf);
return false;
@@ -274,7 +274,7 @@
return false;
}
- off_t eocdOffset = searchStart + i;
+ off64_t eocdOffset = searchStart + i;
const unsigned char* eocdPtr = scanBuf + i;
assert(eocdOffset < mFileLength);
@@ -473,7 +473,7 @@
* appear to be bogus.
*/
bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
- size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const
+ size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const
{
bool ret = false;
@@ -489,7 +489,7 @@
* so we can just subtract back from that.
*/
const unsigned char* ptr = (const unsigned char*) hashEntry.name;
- off_t cdOffset = mDirectoryOffset;
+ off64_t cdOffset = mDirectoryOffset;
ptr -= kCDELen;
@@ -536,12 +536,12 @@
#ifdef HAVE_PREAD
/*
* This file descriptor might be from zygote's preloaded assets,
- * so we need to do an pread() instead of a lseek() + read() to
+ * so we need to do an pread64() instead of a lseek64() + read() to
* guarantee atomicity across the processes with the shared file
* descriptors.
*/
ssize_t actual =
- TEMP_FAILURE_RETRY(pread(mFd, lfhBuf, sizeof(lfhBuf), localHdrOffset));
+ TEMP_FAILURE_RETRY(pread64(mFd, lfhBuf, sizeof(lfhBuf), localHdrOffset));
if (actual != sizeof(lfhBuf)) {
LOGW("failed reading lfh from offset %ld\n", localHdrOffset);
@@ -556,17 +556,17 @@
}
#else /* HAVE_PREAD */
/*
- * For hosts don't have pread() we cannot guarantee atomic reads from
+ * For hosts don't have pread64() we cannot guarantee atomic reads from
* an offset in a file. Android should never run on those platforms.
* File descriptors inherited from a fork() share file offsets and
* there would be nothing to protect from two different processes
- * calling lseek() concurrently.
+ * calling lseek64() concurrently.
*/
{
AutoMutex _l(mFdLock);
- if (lseek(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
+ if (lseek64(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
LOGW("failed seeking to lfh at offset %ld\n", localHdrOffset);
return false;
}
@@ -579,7 +579,7 @@
}
if (get4LE(lfhBuf) != kLFHSignature) {
- off_t actualOffset = lseek(mFd, 0, SEEK_CUR);
+ off64_t actualOffset = lseek64(mFd, 0, SEEK_CUR);
LOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
"got: offset=" ZD " data=0x%08lx\n",
localHdrOffset, kLFHSignature, (ZD_TYPE) actualOffset, get4LE(lfhBuf));
@@ -588,7 +588,7 @@
}
#endif /* HAVE_PREAD */
- off_t dataOffset = localHdrOffset + kLFHLen
+ off64_t dataOffset = localHdrOffset + kLFHLen
+ get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
if (dataOffset >= cdOffset) {
LOGW("bad data offset %ld in zip\n", (long) dataOffset);
@@ -596,14 +596,14 @@
}
/* check lengths */
- if ((off_t)(dataOffset + compLen) > cdOffset) {
+ if ((off64_t)(dataOffset + compLen) > cdOffset) {
LOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n",
(long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset);
return false;
}
if (method == kCompressStored &&
- (off_t)(dataOffset + uncompLen) > cdOffset)
+ (off64_t)(dataOffset + uncompLen) > cdOffset)
{
LOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
(long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
@@ -649,7 +649,7 @@
FileMap* newMap;
size_t compLen;
- off_t offset;
+ off64_t offset;
if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))
return NULL;
@@ -679,7 +679,7 @@
int method;
size_t uncompLen, compLen;
- off_t offset;
+ off64_t offset;
const unsigned char* ptr;
getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
@@ -739,7 +739,7 @@
int method;
size_t uncompLen, compLen;
- off_t offset;
+ off64_t offset;
const unsigned char* ptr;
getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 00077ee..72d4876 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -8,7 +8,8 @@
test_src_files := \
ObbFile_test.cpp \
Looper_test.cpp \
- String8_test.cpp
+ String8_test.cpp \
+ Unicode_test.cpp
shared_libraries := \
libz \
diff --git a/libs/utils/tests/Unicode_test.cpp b/libs/utils/tests/Unicode_test.cpp
new file mode 100644
index 0000000..18c130c
--- /dev/null
+++ b/libs/utils/tests/Unicode_test.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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 "Unicode_test"
+#include <utils/Log.h>
+#include <utils/Unicode.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class UnicodeTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) {
+ ssize_t measured;
+
+ const uint8_t str[] = { };
+
+ measured = utf8_to_utf16_length(str, 0);
+ EXPECT_EQ(0, measured)
+ << "Zero length input should return zero length output.";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16ASCIILength) {
+ ssize_t measured;
+
+ // U+0030 or ASCII '0'
+ const uint8_t str[] = { 0x30 };
+
+ measured = utf8_to_utf16_length(str, sizeof(str));
+ EXPECT_EQ(1, measured)
+ << "ASCII glyphs should have a length of 1 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Plane1Length) {
+ ssize_t measured;
+
+ // U+2323 SMILE
+ const uint8_t str[] = { 0xE2, 0x8C, 0xA3 };
+
+ measured = utf8_to_utf16_length(str, sizeof(str));
+ EXPECT_EQ(1, measured)
+ << "Plane 1 glyphs should have a length of 1 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16SurrogateLength) {
+ ssize_t measured;
+
+ // U+10000
+ const uint8_t str[] = { 0xF0, 0x90, 0x80, 0x80 };
+
+ measured = utf8_to_utf16_length(str, sizeof(str));
+ EXPECT_EQ(2, measured)
+ << "Surrogate pairs should have a length of 2 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16TruncatedUTF8) {
+ ssize_t measured;
+
+ // Truncated U+2323 SMILE
+ // U+2323 SMILE
+ const uint8_t str[] = { 0xE2, 0x8C };
+
+ measured = utf8_to_utf16_length(str, sizeof(str));
+ EXPECT_EQ(-1, measured)
+ << "Truncated UTF-8 should return -1 to indicate invalid";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Normal) {
+ const uint8_t str[] = {
+ 0x30, // U+0030, 1 UTF-16 character
+ 0xC4, 0x80, // U+0100, 1 UTF-16 character
+ 0xE2, 0x8C, 0xA3, // U+2323, 1 UTF-16 character
+ 0xF0, 0x90, 0x80, 0x80, // U+10000, 2 UTF-16 character
+ };
+
+ char16_t output[1 + 1 + 1 + 2 + 1]; // Room for NULL
+
+ utf8_to_utf16(str, sizeof(str), output);
+
+ EXPECT_EQ(0x0030, output[0])
+ << "should be U+0030";
+ EXPECT_EQ(0x0100, output[1])
+ << "should be U+0100";
+ EXPECT_EQ(0x2323, output[2])
+ << "should be U+2323";
+ EXPECT_EQ(0xD800, output[3])
+ << "should be first half of surrogate U+10000";
+ EXPECT_EQ(0xDC00, output[4])
+ << "should be second half of surrogate U+10000";
+ EXPECT_EQ(NULL, output[5])
+ << "should be NULL terminated";
+}
+
+}
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 5c09dcc..7ac6f92 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -40,7 +40,6 @@
#include <pixelflinger/pixelflinger.h>
#include <private/ui/android_natives_priv.h>
-#include <private/ui/sw_gralloc_handle.h>
#include <hardware/copybit.h>
@@ -446,15 +445,10 @@
android_native_buffer_t* buf, int usage, void** vaddr)
{
int err;
- if (sw_gralloc_handle_t::validate(buf->handle) < 0) {
- err = module->lock(module, buf->handle,
- usage, 0, 0, buf->width, buf->height, vaddr);
- } else {
- sw_gralloc_handle_t const* hnd =
- reinterpret_cast<sw_gralloc_handle_t const*>(buf->handle);
- *vaddr = (void*)hnd->base;
- err = NO_ERROR;
- }
+
+ err = module->lock(module, buf->handle,
+ usage, 0, 0, buf->width, buf->height, vaddr);
+
return err;
}
@@ -462,9 +456,9 @@
{
if (!buf) return BAD_VALUE;
int err = NO_ERROR;
- if (sw_gralloc_handle_t::validate(buf->handle) < 0) {
- err = module->unlock(module, buf->handle);
- }
+
+ err = module->unlock(module, buf->handle);
+
return err;
}
@@ -546,7 +540,9 @@
if (!dirtyRegion.isEmpty()) {
dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
if (previousBuffer) {
- const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
+ // This was const Region copyBack, but that causes an
+ // internal compile error on simulator builds
+ /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
if (!copyBack.isEmpty()) {
void* prevBits;
if (lock(previousBuffer,
@@ -1980,7 +1976,7 @@
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
// TODO: eglSwapInterval()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return EGL_TRUE;
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index ae924cd..c8041fc 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -8,6 +8,7 @@
LOCAL_SRC_FILES:= \
EGL/egl.cpp \
+ EGL/trace.cpp \
EGL/getProcAddress.cpp.arm \
EGL/hooks.cpp \
EGL/Loader.cpp \
@@ -33,6 +34,7 @@
LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_CFLAGS += -DEGL_TRACE=1
ifeq ($(TARGET_BOARD_PLATFORM),msm7k)
LOCAL_CFLAGS += -DADRENO130=1
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index ebe2193..7acce02 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -61,6 +61,8 @@
"EGL_KHR_image "
"EGL_KHR_image_base "
"EGL_KHR_image_pixmap "
+ "EGL_KHR_gl_texture_2D_image "
+ "EGL_KHR_fence_sync "
"EGL_ANDROID_image_native_buffer "
"EGL_ANDROID_swap_rectangle "
;
@@ -246,9 +248,23 @@
EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
};
+struct egl_sync_t : public egl_object_t
+{
+ typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref;
+
+ egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync)
+ : dpy(dpy), context(context), sync(sync)
+ {
+ }
+ EGLDisplay dpy;
+ EGLContext context;
+ EGLSyncKHR sync;
+};
+
typedef egl_surface_t::Ref SurfaceRef;
typedef egl_context_t::Ref ContextRef;
typedef egl_image_t::Ref ImageRef;
+typedef egl_sync_t::Ref SyncRef;
struct tls_t
{
@@ -272,6 +288,58 @@
EGLAPI gl_hooks_t gHooksNoContext;
EGLAPI pthread_key_t gGLWrapperKey = -1;
+#if EGL_TRACE
+
+EGLAPI pthread_key_t gGLTraceKey = -1;
+
+// ----------------------------------------------------------------------------
+
+static int gEGLTraceLevel;
+static int gEGLApplicationTraceLevel;
+extern EGLAPI gl_hooks_t gHooksTrace;
+
+static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) {
+ pthread_setspecific(gGLTraceKey, value);
+}
+
+gl_hooks_t const* getGLTraceThreadSpecific() {
+ return static_cast<gl_hooks_t*>(pthread_getspecific(gGLTraceKey));
+}
+
+static void initEglTraceLevel() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.trace", value, "0");
+ int propertyLevel = atoi(value);
+ int applicationLevel = gEGLApplicationTraceLevel;
+ gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
+}
+
+static void setGLHooksThreadSpecific(gl_hooks_t const *value) {
+ if (gEGLTraceLevel > 0) {
+ setGlTraceThreadSpecific(value);
+ setGlThreadSpecific(&gHooksTrace);
+ } else {
+ setGlThreadSpecific(value);
+ }
+}
+
+/*
+ * Global entry point to allow applications to modify their own trace level.
+ * The effective trace level is the max of this level and the value of debug.egl.trace.
+ */
+extern "C"
+void setGLTraceLevel(int level) {
+ gEGLApplicationTraceLevel = level;
+}
+
+#else
+
+static inline void setGLHooksThreadSpecific(gl_hooks_t const *value) {
+ setGlThreadSpecific(value);
+}
+
+#endif
+
// ----------------------------------------------------------------------------
static __attribute__((noinline))
@@ -410,10 +478,6 @@
(__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
{ "eglSetSwapRectangleANDROID",
(__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
- { "glEGLImageTargetTexture2DOES",
- (__eglMustCastToProperFunctionPointerType)NULL },
- { "glEGLImageTargetRenderbufferStorageOES",
- (__eglMustCastToProperFunctionPointerType)NULL },
};
extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
@@ -450,13 +514,17 @@
#if !USE_FAST_TLS_KEY
pthread_key_create(&gGLWrapperKey, NULL);
#endif
+#if EGL_TRACE
+ pthread_key_create(&gGLTraceKey, NULL);
+ initEglTraceLevel();
+#endif
uint32_t addr = (uint32_t)((void*)gl_no_context);
android_memset32(
(uint32_t*)(void*)&gHooksNoContext,
addr,
sizeof(gHooksNoContext));
- setGlThreadSpecific(&gHooksNoContext);
+ setGLHooksThreadSpecific(&gHooksNoContext);
}
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
@@ -490,6 +558,11 @@
return egl_to_native_cast<egl_image_t>(image);
}
+static inline
+egl_sync_t* get_sync(EGLSyncKHR sync) {
+ return egl_to_native_cast<egl_sync_t>(sync);
+}
+
static egl_connection_t* validate_display_config(
EGLDisplay dpy, EGLConfig config,
egl_display_t const*& dp)
@@ -663,9 +736,17 @@
dp->refs++;
return EGL_TRUE;
}
-
- setGlThreadSpecific(&gHooksNoContext);
-
+
+#if EGL_TRACE
+
+ // Called both at early_init time and at this time. (Early_init is pre-zygote, so
+ // the information from that call may be stale.)
+ initEglTraceLevel();
+
+#endif
+
+ setGLHooksThreadSpecific(&gHooksNoContext);
+
// initialize each EGL and
// build our own extension string first, based on the extension we know
// and the extension supported by our client implementation
@@ -1238,11 +1319,11 @@
// cur_c has to be valid here (but could be terminated)
if (ctx != EGL_NO_CONTEXT) {
- setGlThreadSpecific(c->cnx->hooks[c->version]);
+ setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
setContext(ctx);
_c.acquire();
} else {
- setGlThreadSpecific(&gHooksNoContext);
+ setGLHooksThreadSpecific(&gHooksNoContext);
setContext(EGL_NO_CONTEXT);
}
_cur_c.release();
@@ -1434,6 +1515,9 @@
// Extensions are independent of the bound context
cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
+#if EGL_TRACE
+ gHooksTrace.ext.extensions[slot] =
+#endif
cnx->egl.eglGetProcAddress(procname);
}
}
@@ -1811,6 +1895,111 @@
return EGL_TRUE;
}
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 5
+// ----------------------------------------------------------------------------
+
+
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
+{
+ EGLContext ctx = eglGetCurrentContext();
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_NO_SYNC_KHR;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_context_t * const c = get_context(ctx);
+ EGLSyncKHR result = EGL_NO_SYNC_KHR;
+ if (c->cnx->egl.eglCreateSyncKHR) {
+ EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
+ dp->disp[c->impl].dpy, type, attrib_list);
+ if (sync == EGL_NO_SYNC_KHR)
+ return sync;
+ result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
+ }
+ return (EGLSyncKHR)result;
+}
+
+EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_context_t * const c = get_context(ctx);
+
+ if (c->cnx->egl.eglDestroySyncKHR) {
+ return c->cnx->egl.eglDestroySyncKHR(
+ dp->disp[c->impl].dpy, syncObject->sync);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_context_t * const c = get_context(ctx);
+
+ if (c->cnx->egl.eglClientWaitSyncKHR) {
+ return c->cnx->egl.eglClientWaitSyncKHR(
+ dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_context_t * const c = get_context(ctx);
+
+ if (c->cnx->egl.eglGetSyncAttribKHR) {
+ return c->cnx->egl.eglGetSyncAttribKHR(
+ dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
+ }
+
+ return EGL_FALSE;
+}
// ----------------------------------------------------------------------------
// ANDROID extensions
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 5d89287..63c3c19 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -51,6 +51,13 @@
EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
+/* EGL_EGLEXT_VERSION 5 */
+
+EGL_ENTRY(EGLSyncKHR, eglCreateSyncKHR, EGLDisplay, EGLenum, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroySyncKHR, EGLDisplay, EGLSyncKHR)
+EGL_ENTRY(EGLint, eglClientWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR)
+EGL_ENTRY(EGLBoolean, eglGetSyncAttribKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLint *)
+
/* ANDROID extensions */
EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp
new file mode 100644
index 0000000..d3e96ba
--- /dev/null
+++ b/opengl/libs/EGL/trace.cpp
@@ -0,0 +1,355 @@
+/*
+ ** Copyright 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.
+ */
+
+#if EGL_TRACE
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <cutils/log.h>
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct GLenumString {
+ GLenum e;
+ const char* s;
+};
+
+#undef GL_ENUM
+#define GL_ENUM(VAL,NAME) {VAL, #NAME},
+
+static GLenumString g_enumnames[] = {
+#include "enums.in"
+};
+#undef GL_ENUM
+
+static int compareGLEnum(const void* a, const void* b) {
+ return ((const GLenumString*) a)->e - ((const GLenumString*) b)->e;
+}
+
+static const char* GLEnumToString(GLenum e) {
+ GLenumString key = {e, ""};
+ const GLenumString* result = (const GLenumString*) bsearch(
+ &key, g_enumnames,
+ sizeof(g_enumnames) / sizeof(g_enumnames[0]),
+ sizeof(g_enumnames[0]), compareGLEnum);
+ if (result) {
+ return result->s;
+ }
+ return NULL;
+}
+
+static const char* GLbooleanToString(GLboolean arg) {
+ return arg ? "GL_TRUE" : "GL_FALSE";
+}
+
+static GLenumString g_bitfieldNames[] = {
+ {0x00004000, "GL_COLOR_BUFFER_BIT"},
+ {0x00000400, "GL_STENCIL_BUFFER_BIT"},
+ {0x00000100, "GL_DEPTH_BUFFER_BIT"}
+};
+
+class StringBuilder {
+ static const int lineSize = 500;
+ char line[lineSize];
+ int line_index;
+public:
+ StringBuilder() {
+ line_index = 0;
+ line[0] = '\0';
+ }
+ void append(const char* fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ line_index += vsnprintf(line + line_index, lineSize-line_index, fmt, argp);
+ va_end(argp);
+ }
+ const char* getString() {
+ line_index = 0;
+ line[lineSize-1] = '\0';
+ return line;
+ }
+};
+
+
+static void TraceGLShaderSource(GLuint shader, GLsizei count,
+ const GLchar** string, const GLint* length) {
+ LOGD("const char* shaderSrc[] = {");
+ for (GLsizei i = 0; i < count; i++) {
+ const char* comma = i < count-1 ? "," : "";
+ const GLchar* s = string[i];
+ if (length) {
+ GLint len = length[i];
+ LOGD(" \"%*s\"%s", len, s, comma);
+ } else {
+ LOGD(" \"%s\"%s", s, comma);
+ }
+ }
+ LOGD("};");
+ if (length) {
+ LOGD("const GLint* shaderLength[] = {");
+ for (GLsizei i = 0; i < count; i++) {
+ const char* comma = i < count-1 ? "," : "";
+ GLint len = length[i];
+ LOGD(" \"%d\"%s", len, comma);
+ }
+ LOGD("};");
+ LOGD("glShaderSource(%u, %u, shaderSrc, shaderLength);",
+ shader, count);
+ } else {
+ LOGD("glShaderSource(%u, %u, shaderSrc, (const GLint*) 0);",
+ shader, count);
+ }
+}
+
+static void TraceValue(int elementCount, char type,
+ GLsizei chunkCount, GLsizei chunkSize, const void* value) {
+ StringBuilder stringBuilder;
+ GLsizei count = chunkCount * chunkSize;
+ bool isFloat = type == 'f';
+ const char* typeString = isFloat ? "GLfloat" : "GLint";
+ LOGD("const %s value[] = {", typeString);
+ for (GLsizei i = 0; i < count; i++) {
+ StringBuilder builder;
+ builder.append(" ");
+ for (int e = 0; e < elementCount; e++) {
+ const char* comma = ", ";
+ if (e == elementCount-1) {
+ if (i == count - 1) {
+ comma = "";
+ } else {
+ comma = ",";
+ }
+ }
+ if (isFloat) {
+ builder.append("%g%s", * (GLfloat*) value, comma);
+ value = (void*) (((GLfloat*) value) + 1);
+ } else {
+ builder.append("%d%s", * (GLint*) value, comma);
+ value = (void*) (((GLint*) value) + 1);
+ }
+ }
+ LOGD("%s", builder.getString());
+ if (chunkSize > 1 && i < count-1
+ && (i % chunkSize) == (chunkSize-1)) {
+ LOGD("%s", ""); // Print a blank line.
+ }
+ }
+ LOGD("};");
+}
+
+static void TraceUniformv(int elementCount, char type,
+ GLuint location, GLsizei count, const void* value) {
+ TraceValue(elementCount, type, count, 1, value);
+ LOGD("glUniform%d%c(%u, %u, value);", elementCount, type, location, count);
+}
+
+static void TraceUniformMatrix(int matrixSideLength,
+ GLuint location, GLsizei count, GLboolean transpose, const void* value) {
+ TraceValue(matrixSideLength, 'f', count, matrixSideLength, value);
+ LOGD("glUniformMatrix%dfv(%u, %u, %s, value);", matrixSideLength, location, count,
+ GLbooleanToString(transpose));
+}
+
+static void TraceGL(const char* name, int numArgs, ...) {
+ va_list argp;
+ va_start(argp, numArgs);
+ int nameLen = strlen(name);
+
+ // glShaderSource
+ if (nameLen == 14 && strcmp(name, "glShaderSource") == 0) {
+ va_arg(argp, const char*);
+ GLuint shader = va_arg(argp, GLuint);
+ va_arg(argp, const char*);
+ GLsizei count = va_arg(argp, GLsizei);
+ va_arg(argp, const char*);
+ const GLchar** string = (const GLchar**) va_arg(argp, void*);
+ va_arg(argp, const char*);
+ const GLint* length = (const GLint*) va_arg(argp, void*);
+ va_end(argp);
+ TraceGLShaderSource(shader, count, string, length);
+ return;
+ }
+
+ // glUniformXXv
+
+ if (nameLen == 12 && strncmp(name, "glUniform", 9) == 0 && name[11] == 'v') {
+ int elementCount = name[9] - '0'; // 1..4
+ char type = name[10]; // 'f' or 'i'
+ va_arg(argp, const char*);
+ GLuint location = va_arg(argp, GLuint);
+ va_arg(argp, const char*);
+ GLsizei count = va_arg(argp, GLsizei);
+ va_arg(argp, const char*);
+ const void* value = (const void*) va_arg(argp, void*);
+ va_end(argp);
+ TraceUniformv(elementCount, type, location, count, value);
+ return;
+ }
+
+ // glUniformMatrixXfv
+
+ if (nameLen == 18 && strncmp(name, "glUniformMatrix", 15) == 0
+ && name[16] == 'f' && name[17] == 'v') {
+ int matrixSideLength = name[15] - '0'; // 2..4
+ va_arg(argp, const char*);
+ GLuint location = va_arg(argp, GLuint);
+ va_arg(argp, const char*);
+ GLsizei count = va_arg(argp, GLsizei);
+ va_arg(argp, const char*);
+ GLboolean transpose = (GLboolean) va_arg(argp, int);
+ va_arg(argp, const char*);
+ const void* value = (const void*) va_arg(argp, void*);
+ va_end(argp);
+ TraceUniformMatrix(matrixSideLength, location, count, transpose, value);
+ return;
+ }
+
+ StringBuilder builder;
+ builder.append("%s(", name);
+ for (int i = 0; i < numArgs; i++) {
+ if (i > 0) {
+ builder.append(", ");
+ }
+ const char* type = va_arg(argp, const char*);
+ bool isPtr = type[strlen(type)-1] == '*'
+ || strcmp(type, "GLeglImageOES") == 0;
+ if (isPtr) {
+ const void* arg = va_arg(argp, const void*);
+ builder.append("(%s) 0x%08x", type, (size_t) arg);
+ } else if (strcmp(type, "GLbitfield") == 0) {
+ size_t arg = va_arg(argp, size_t);
+ bool first = true;
+ for (size_t i = 0; i < sizeof(g_bitfieldNames) / sizeof(g_bitfieldNames[0]); i++) {
+ const GLenumString* b = &g_bitfieldNames[i];
+ if (b->e & arg) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(" | ");
+ }
+ builder.append("%s", b->s);
+ arg &= ~b->e;
+ }
+ }
+ if (first || arg != 0) {
+ if (!first) {
+ builder.append(" | ");
+ }
+ builder.append("0x%08x", arg);
+ }
+ } else if (strcmp(type, "GLboolean") == 0) {
+ GLboolean arg = va_arg(argp, int);
+ builder.append("%s", GLbooleanToString(arg));
+ } else if (strcmp(type, "GLclampf") == 0) {
+ double arg = va_arg(argp, double);
+ builder.append("%g", arg);
+ } else if (strcmp(type, "GLenum") == 0) {
+ GLenum arg = va_arg(argp, int);
+ const char* s = GLEnumToString(arg);
+ if (s) {
+ builder.append("%s", s);
+ } else {
+ builder.append("0x%x", arg);
+ }
+ } else if (strcmp(type, "GLfixed") == 0) {
+ int arg = va_arg(argp, int);
+ builder.append("0x%08x", arg);
+ } else if (strcmp(type, "GLfloat") == 0) {
+ double arg = va_arg(argp, double);
+ builder.append("%g", arg);
+ } else if (strcmp(type, "GLint") == 0) {
+ int arg = va_arg(argp, int);
+ const char* s = NULL;
+ if (strcmp(name, "glTexParameteri") == 0) {
+ s = GLEnumToString(arg);
+ }
+ if (s) {
+ builder.append("%s", s);
+ } else {
+ builder.append("%d", arg);
+ }
+ } else if (strcmp(type, "GLintptr") == 0) {
+ int arg = va_arg(argp, unsigned int);
+ builder.append("%u", arg);
+ } else if (strcmp(type, "GLsizei") == 0) {
+ int arg = va_arg(argp, size_t);
+ builder.append("%u", arg);
+ } else if (strcmp(type, "GLsizeiptr") == 0) {
+ int arg = va_arg(argp, size_t);
+ builder.append("%u", arg);
+ } else if (strcmp(type, "GLuint") == 0) {
+ int arg = va_arg(argp, unsigned int);
+ builder.append("%u", arg);
+ } else {
+ builder.append("/* ??? %s */", type);
+ break;
+ }
+ }
+ builder.append(");");
+ LOGD("%s", builder.getString());
+ va_end(argp);
+}
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define TRACE_GL_VOID(_api, _args, _argList, ...) \
+static void Tracing_ ## _api _args { \
+ TraceGL(#_api, __VA_ARGS__); \
+ gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
+ _c->_api _argList; \
+}
+
+#define TRACE_GL(_type, _api, _args, _argList, ...) \
+static _type Tracing_ ## _api _args { \
+ TraceGL(#_api, __VA_ARGS__); \
+ gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
+ return _c->_api _argList; \
+}
+
+extern "C" {
+#include "../trace.in"
+}
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+#define GL_ENTRY(_r, _api, ...) Tracing_ ## _api,
+
+EGLAPI gl_hooks_t gHooksTrace = {
+ {
+ #include "entries.in"
+ },
+ {
+ {0}
+ }
+};
+#undef GL_ENTRY
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif // EGL_TRACE
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index 18dd483..fee4609 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -39,6 +39,8 @@
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
+#define DEBUG_CALL_GL_API 0
+
#if USE_FAST_TLS_KEY
#ifdef HAVE_ARM_TLS_REGISTER
@@ -74,10 +76,24 @@
#define API_ENTRY(_api) _api
+#if DEBUG_CALL_GL_API
+
#define CALL_GL_API(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
- _c->_api(__VA_ARGS__)
-
+ _c->_api(__VA_ARGS__); \
+ GLenum status = GL_NO_ERROR; \
+ while ((status = glGetError()) != GL_NO_ERROR) { \
+ LOGD("[" #_api "] 0x%x", status); \
+ }
+
+#else
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ _c->_api(__VA_ARGS__);
+
+#endif
+
#define CALL_GL_API_RETURN(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
return _c->_api(__VA_ARGS__)
diff --git a/opengl/libs/enums.in b/opengl/libs/enums.in
new file mode 100644
index 0000000..f9752c2
--- /dev/null
+++ b/opengl/libs/enums.in
@@ -0,0 +1,594 @@
+GL_ENUM(0x0000,GL_POINTS)
+GL_ENUM(0x0001,GL_LINES)
+GL_ENUM(0x0002,GL_LINE_LOOP)
+GL_ENUM(0x0003,GL_LINE_STRIP)
+GL_ENUM(0x0004,GL_TRIANGLES)
+GL_ENUM(0x0005,GL_TRIANGLE_STRIP)
+GL_ENUM(0x0006,GL_TRIANGLE_FAN)
+GL_ENUM(0x0104,GL_ADD)
+GL_ENUM(0x0200,GL_NEVER)
+GL_ENUM(0x0201,GL_LESS)
+GL_ENUM(0x0202,GL_EQUAL)
+GL_ENUM(0x0203,GL_LEQUAL)
+GL_ENUM(0x0204,GL_GREATER)
+GL_ENUM(0x0205,GL_NOTEQUAL)
+GL_ENUM(0x0206,GL_GEQUAL)
+GL_ENUM(0x0207,GL_ALWAYS)
+GL_ENUM(0x0300,GL_SRC_COLOR)
+GL_ENUM(0x0301,GL_ONE_MINUS_SRC_COLOR)
+GL_ENUM(0x0302,GL_SRC_ALPHA)
+GL_ENUM(0x0303,GL_ONE_MINUS_SRC_ALPHA)
+GL_ENUM(0x0304,GL_DST_ALPHA)
+GL_ENUM(0x0305,GL_ONE_MINUS_DST_ALPHA)
+GL_ENUM(0x0306,GL_DST_COLOR)
+GL_ENUM(0x0307,GL_ONE_MINUS_DST_COLOR)
+GL_ENUM(0x0308,GL_SRC_ALPHA_SATURATE)
+GL_ENUM(0x0404,GL_FRONT)
+GL_ENUM(0x0405,GL_BACK)
+GL_ENUM(0x0408,GL_FRONT_AND_BACK)
+GL_ENUM(0x0500,GL_INVALID_ENUM)
+GL_ENUM(0x0501,GL_INVALID_VALUE)
+GL_ENUM(0x0502,GL_INVALID_OPERATION)
+GL_ENUM(0x0503,GL_STACK_OVERFLOW)
+GL_ENUM(0x0504,GL_STACK_UNDERFLOW)
+GL_ENUM(0x0505,GL_OUT_OF_MEMORY)
+GL_ENUM(0x0506,GL_INVALID_FRAMEBUFFER_OPERATION_OES)
+GL_ENUM(0x0800,GL_EXP)
+GL_ENUM(0x0801,GL_EXP2)
+GL_ENUM(0x0900,GL_CW)
+GL_ENUM(0x0901,GL_CCW)
+GL_ENUM(0x0B00,GL_CURRENT_COLOR)
+GL_ENUM(0x0B02,GL_CURRENT_NORMAL)
+GL_ENUM(0x0B03,GL_CURRENT_TEXTURE_COORDS)
+GL_ENUM(0x0B10,GL_POINT_SMOOTH)
+GL_ENUM(0x0B11,GL_POINT_SIZE)
+GL_ENUM(0x0B12,GL_SMOOTH_POINT_SIZE_RANGE)
+GL_ENUM(0x0B20,GL_LINE_SMOOTH)
+GL_ENUM(0x0B21,GL_LINE_WIDTH)
+GL_ENUM(0x0B22,GL_SMOOTH_LINE_WIDTH_RANGE)
+GL_ENUM(0x0B44,GL_CULL_FACE)
+GL_ENUM(0x0B45,GL_CULL_FACE_MODE)
+GL_ENUM(0x0B46,GL_FRONT_FACE)
+GL_ENUM(0x0B50,GL_LIGHTING)
+GL_ENUM(0x0B52,GL_LIGHT_MODEL_TWO_SIDE)
+GL_ENUM(0x0B53,GL_LIGHT_MODEL_AMBIENT)
+GL_ENUM(0x0B54,GL_SHADE_MODEL)
+GL_ENUM(0x0B57,GL_COLOR_MATERIAL)
+GL_ENUM(0x0B60,GL_FOG)
+GL_ENUM(0x0B62,GL_FOG_DENSITY)
+GL_ENUM(0x0B63,GL_FOG_START)
+GL_ENUM(0x0B64,GL_FOG_END)
+GL_ENUM(0x0B65,GL_FOG_MODE)
+GL_ENUM(0x0B66,GL_FOG_COLOR)
+GL_ENUM(0x0B70,GL_DEPTH_RANGE)
+GL_ENUM(0x0B71,GL_DEPTH_TEST)
+GL_ENUM(0x0B72,GL_DEPTH_WRITEMASK)
+GL_ENUM(0x0B73,GL_DEPTH_CLEAR_VALUE)
+GL_ENUM(0x0B74,GL_DEPTH_FUNC)
+GL_ENUM(0x0B90,GL_STENCIL_TEST)
+GL_ENUM(0x0B91,GL_STENCIL_CLEAR_VALUE)
+GL_ENUM(0x0B92,GL_STENCIL_FUNC)
+GL_ENUM(0x0B93,GL_STENCIL_VALUE_MASK)
+GL_ENUM(0x0B94,GL_STENCIL_FAIL)
+GL_ENUM(0x0B95,GL_STENCIL_PASS_DEPTH_FAIL)
+GL_ENUM(0x0B96,GL_STENCIL_PASS_DEPTH_PASS)
+GL_ENUM(0x0B97,GL_STENCIL_REF)
+GL_ENUM(0x0B98,GL_STENCIL_WRITEMASK)
+GL_ENUM(0x0BA0,GL_MATRIX_MODE)
+GL_ENUM(0x0BA1,GL_NORMALIZE)
+GL_ENUM(0x0BA2,GL_VIEWPORT)
+GL_ENUM(0x0BA3,GL_MODELVIEW_STACK_DEPTH)
+GL_ENUM(0x0BA4,GL_PROJECTION_STACK_DEPTH)
+GL_ENUM(0x0BA5,GL_TEXTURE_STACK_DEPTH)
+GL_ENUM(0x0BA6,GL_MODELVIEW_MATRIX)
+GL_ENUM(0x0BA7,GL_PROJECTION_MATRIX)
+GL_ENUM(0x0BA8,GL_TEXTURE_MATRIX)
+GL_ENUM(0x0BC0,GL_ALPHA_TEST)
+GL_ENUM(0x0BC1,GL_ALPHA_TEST_FUNC)
+GL_ENUM(0x0BC2,GL_ALPHA_TEST_REF)
+GL_ENUM(0x0BD0,GL_DITHER)
+GL_ENUM(0x0BE0,GL_BLEND_DST)
+GL_ENUM(0x0BE1,GL_BLEND_SRC)
+GL_ENUM(0x0BE2,GL_BLEND)
+GL_ENUM(0x0BF0,GL_LOGIC_OP_MODE)
+GL_ENUM(0x0BF2,GL_COLOR_LOGIC_OP)
+GL_ENUM(0x0C10,GL_SCISSOR_BOX)
+GL_ENUM(0x0C11,GL_SCISSOR_TEST)
+GL_ENUM(0x0C22,GL_COLOR_CLEAR_VALUE)
+GL_ENUM(0x0C23,GL_COLOR_WRITEMASK)
+GL_ENUM(0x0C50,GL_PERSPECTIVE_CORRECTION_HINT)
+GL_ENUM(0x0C51,GL_POINT_SMOOTH_HINT)
+GL_ENUM(0x0C52,GL_LINE_SMOOTH_HINT)
+GL_ENUM(0x0C54,GL_FOG_HINT)
+GL_ENUM(0x0CF5,GL_UNPACK_ALIGNMENT)
+GL_ENUM(0x0D05,GL_PACK_ALIGNMENT)
+GL_ENUM(0x0D1C,GL_ALPHA_SCALE)
+GL_ENUM(0x0D31,GL_MAX_LIGHTS)
+GL_ENUM(0x0D32,GL_MAX_CLIP_PLANES)
+GL_ENUM(0x0D33,GL_MAX_TEXTURE_SIZE)
+GL_ENUM(0x0D36,GL_MAX_MODELVIEW_STACK_DEPTH)
+GL_ENUM(0x0D38,GL_MAX_PROJECTION_STACK_DEPTH)
+GL_ENUM(0x0D39,GL_MAX_TEXTURE_STACK_DEPTH)
+GL_ENUM(0x0D3A,GL_MAX_VIEWPORT_DIMS)
+GL_ENUM(0x0D50,GL_SUBPIXEL_BITS)
+GL_ENUM(0x0D52,GL_RED_BITS)
+GL_ENUM(0x0D53,GL_GREEN_BITS)
+GL_ENUM(0x0D54,GL_BLUE_BITS)
+GL_ENUM(0x0D55,GL_ALPHA_BITS)
+GL_ENUM(0x0D56,GL_DEPTH_BITS)
+GL_ENUM(0x0D57,GL_STENCIL_BITS)
+GL_ENUM(0x0DE1,GL_TEXTURE_2D)
+GL_ENUM(0x1100,GL_DONT_CARE)
+GL_ENUM(0x1101,GL_FASTEST)
+GL_ENUM(0x1102,GL_NICEST)
+GL_ENUM(0x1200,GL_AMBIENT)
+GL_ENUM(0x1201,GL_DIFFUSE)
+GL_ENUM(0x1202,GL_SPECULAR)
+GL_ENUM(0x1203,GL_POSITION)
+GL_ENUM(0x1204,GL_SPOT_DIRECTION)
+GL_ENUM(0x1205,GL_SPOT_EXPONENT)
+GL_ENUM(0x1206,GL_SPOT_CUTOFF)
+GL_ENUM(0x1207,GL_CONSTANT_ATTENUATION)
+GL_ENUM(0x1208,GL_LINEAR_ATTENUATION)
+GL_ENUM(0x1209,GL_QUADRATIC_ATTENUATION)
+GL_ENUM(0x1400,GL_BYTE)
+GL_ENUM(0x1401,GL_UNSIGNED_BYTE)
+GL_ENUM(0x1402,GL_SHORT)
+GL_ENUM(0x1403,GL_UNSIGNED_SHORT)
+GL_ENUM(0x1404,GL_INT)
+GL_ENUM(0x1405,GL_UNSIGNED_INT)
+GL_ENUM(0x1406,GL_FLOAT)
+GL_ENUM(0x140C,GL_FIXED)
+GL_ENUM(0x1500,GL_CLEAR)
+GL_ENUM(0x1501,GL_AND)
+GL_ENUM(0x1502,GL_AND_REVERSE)
+GL_ENUM(0x1503,GL_COPY)
+GL_ENUM(0x1504,GL_AND_INVERTED)
+GL_ENUM(0x1505,GL_NOOP)
+GL_ENUM(0x1506,GL_XOR)
+GL_ENUM(0x1507,GL_OR)
+GL_ENUM(0x1508,GL_NOR)
+GL_ENUM(0x1509,GL_EQUIV)
+GL_ENUM(0x150A,GL_INVERT)
+GL_ENUM(0x150B,GL_OR_REVERSE)
+GL_ENUM(0x150C,GL_COPY_INVERTED)
+GL_ENUM(0x150D,GL_OR_INVERTED)
+GL_ENUM(0x150E,GL_NAND)
+GL_ENUM(0x150F,GL_SET)
+GL_ENUM(0x1600,GL_EMISSION)
+GL_ENUM(0x1601,GL_SHININESS)
+GL_ENUM(0x1602,GL_AMBIENT_AND_DIFFUSE)
+GL_ENUM(0x1700,GL_MODELVIEW)
+GL_ENUM(0x1701,GL_PROJECTION)
+GL_ENUM(0x1702,GL_TEXTURE)
+GL_ENUM(0x1800,GL_COLOR_EXT)
+GL_ENUM(0x1801,GL_DEPTH_EXT)
+GL_ENUM(0x1802,GL_STENCIL_EXT)
+GL_ENUM(0x1901,GL_STENCIL_INDEX)
+GL_ENUM(0x1902,GL_DEPTH_COMPONENT)
+GL_ENUM(0x1906,GL_ALPHA)
+GL_ENUM(0x1907,GL_RGB)
+GL_ENUM(0x1908,GL_RGBA)
+GL_ENUM(0x1909,GL_LUMINANCE)
+GL_ENUM(0x190A,GL_LUMINANCE_ALPHA)
+GL_ENUM(0x1D00,GL_FLAT)
+GL_ENUM(0x1D01,GL_SMOOTH)
+GL_ENUM(0x1E00,GL_KEEP)
+GL_ENUM(0x1E01,GL_REPLACE)
+GL_ENUM(0x1E02,GL_INCR)
+GL_ENUM(0x1E03,GL_DECR)
+GL_ENUM(0x1F00,GL_VENDOR)
+GL_ENUM(0x1F01,GL_RENDERER)
+GL_ENUM(0x1F02,GL_VERSION)
+GL_ENUM(0x1F03,GL_EXTENSIONS)
+GL_ENUM(0x2100,GL_MODULATE)
+GL_ENUM(0x2101,GL_DECAL)
+GL_ENUM(0x2200,GL_TEXTURE_ENV_MODE)
+GL_ENUM(0x2201,GL_TEXTURE_ENV_COLOR)
+GL_ENUM(0x2300,GL_TEXTURE_ENV)
+GL_ENUM(0x2500,GL_TEXTURE_GEN_MODE_OES)
+GL_ENUM(0x2600,GL_NEAREST)
+GL_ENUM(0x2601,GL_LINEAR)
+GL_ENUM(0x2700,GL_NEAREST_MIPMAP_NEAREST)
+GL_ENUM(0x2701,GL_LINEAR_MIPMAP_NEAREST)
+GL_ENUM(0x2702,GL_NEAREST_MIPMAP_LINEAR)
+GL_ENUM(0x2703,GL_LINEAR_MIPMAP_LINEAR)
+GL_ENUM(0x2800,GL_TEXTURE_MAG_FILTER)
+GL_ENUM(0x2801,GL_TEXTURE_MIN_FILTER)
+GL_ENUM(0x2802,GL_TEXTURE_WRAP_S)
+GL_ENUM(0x2803,GL_TEXTURE_WRAP_T)
+GL_ENUM(0x2901,GL_REPEAT)
+GL_ENUM(0x2A00,GL_POLYGON_OFFSET_UNITS)
+GL_ENUM(0x3000,GL_CLIP_PLANE0)
+GL_ENUM(0x3001,GL_CLIP_PLANE1)
+GL_ENUM(0x3002,GL_CLIP_PLANE2)
+GL_ENUM(0x3003,GL_CLIP_PLANE3)
+GL_ENUM(0x3004,GL_CLIP_PLANE4)
+GL_ENUM(0x3005,GL_CLIP_PLANE5)
+GL_ENUM(0x4000,GL_LIGHT0)
+GL_ENUM(0x4001,GL_LIGHT1)
+GL_ENUM(0x4002,GL_LIGHT2)
+GL_ENUM(0x4003,GL_LIGHT3)
+GL_ENUM(0x4004,GL_LIGHT4)
+GL_ENUM(0x4005,GL_LIGHT5)
+GL_ENUM(0x4006,GL_LIGHT6)
+GL_ENUM(0x4007,GL_LIGHT7)
+GL_ENUM(0x8000,GL_COVERAGE_BUFFER_BIT_NV)
+GL_ENUM(0x8001,GL_CONSTANT_COLOR)
+GL_ENUM(0x8002,GL_ONE_MINUS_CONSTANT_COLOR)
+GL_ENUM(0x8003,GL_CONSTANT_ALPHA)
+GL_ENUM(0x8004,GL_ONE_MINUS_CONSTANT_ALPHA)
+GL_ENUM(0x8005,GL_BLEND_COLOR)
+GL_ENUM(0x8006,GL_FUNC_ADD_OES)
+GL_ENUM(0x8007,GL_MIN_EXT)
+GL_ENUM(0x8008,GL_MAX_EXT)
+GL_ENUM(0x8009,GL_BLEND_EQUATION_RGB_OES)
+GL_ENUM(0x800A,GL_FUNC_SUBTRACT_OES)
+GL_ENUM(0x800B,GL_FUNC_REVERSE_SUBTRACT_OES)
+GL_ENUM(0x8033,GL_UNSIGNED_SHORT_4_4_4_4)
+GL_ENUM(0x8034,GL_UNSIGNED_SHORT_5_5_5_1)
+GL_ENUM(0x8037,GL_POLYGON_OFFSET_FILL)
+GL_ENUM(0x8038,GL_POLYGON_OFFSET_FACTOR)
+GL_ENUM(0x803A,GL_RESCALE_NORMAL)
+GL_ENUM(0x8051,GL_RGB8_OES)
+GL_ENUM(0x8056,GL_RGBA4_OES)
+GL_ENUM(0x8057,GL_RGB5_A1_OES)
+GL_ENUM(0x8058,GL_RGBA8_OES)
+GL_ENUM(0x8069,GL_TEXTURE_BINDING_2D)
+GL_ENUM(0x806A,GL_TEXTURE_BINDING_3D_OES)
+GL_ENUM(0x806F,GL_TEXTURE_3D_OES)
+GL_ENUM(0x8072,GL_TEXTURE_WRAP_R_OES)
+GL_ENUM(0x8073,GL_MAX_3D_TEXTURE_SIZE_OES)
+GL_ENUM(0x8074,GL_VERTEX_ARRAY)
+GL_ENUM(0x8075,GL_NORMAL_ARRAY)
+GL_ENUM(0x8076,GL_COLOR_ARRAY)
+GL_ENUM(0x8078,GL_TEXTURE_COORD_ARRAY)
+GL_ENUM(0x807A,GL_VERTEX_ARRAY_SIZE)
+GL_ENUM(0x807B,GL_VERTEX_ARRAY_TYPE)
+GL_ENUM(0x807C,GL_VERTEX_ARRAY_STRIDE)
+GL_ENUM(0x807E,GL_NORMAL_ARRAY_TYPE)
+GL_ENUM(0x807F,GL_NORMAL_ARRAY_STRIDE)
+GL_ENUM(0x8081,GL_COLOR_ARRAY_SIZE)
+GL_ENUM(0x8082,GL_COLOR_ARRAY_TYPE)
+GL_ENUM(0x8083,GL_COLOR_ARRAY_STRIDE)
+GL_ENUM(0x8088,GL_TEXTURE_COORD_ARRAY_SIZE)
+GL_ENUM(0x8089,GL_TEXTURE_COORD_ARRAY_TYPE)
+GL_ENUM(0x808A,GL_TEXTURE_COORD_ARRAY_STRIDE)
+GL_ENUM(0x808E,GL_VERTEX_ARRAY_POINTER)
+GL_ENUM(0x808F,GL_NORMAL_ARRAY_POINTER)
+GL_ENUM(0x8090,GL_COLOR_ARRAY_POINTER)
+GL_ENUM(0x8092,GL_TEXTURE_COORD_ARRAY_POINTER)
+GL_ENUM(0x809D,GL_MULTISAMPLE)
+GL_ENUM(0x809E,GL_SAMPLE_ALPHA_TO_COVERAGE)
+GL_ENUM(0x809F,GL_SAMPLE_ALPHA_TO_ONE)
+GL_ENUM(0x80A0,GL_SAMPLE_COVERAGE)
+GL_ENUM(0x80A8,GL_SAMPLE_BUFFERS)
+GL_ENUM(0x80A9,GL_SAMPLES)
+GL_ENUM(0x80AA,GL_SAMPLE_COVERAGE_VALUE)
+GL_ENUM(0x80AB,GL_SAMPLE_COVERAGE_INVERT)
+GL_ENUM(0x80C8,GL_BLEND_DST_RGB_OES)
+GL_ENUM(0x80C9,GL_BLEND_SRC_RGB_OES)
+GL_ENUM(0x80CA,GL_BLEND_DST_ALPHA_OES)
+GL_ENUM(0x80CB,GL_BLEND_SRC_ALPHA_OES)
+GL_ENUM(0x80E1,GL_BGRA_EXT)
+GL_ENUM(0x8126,GL_POINT_SIZE_MIN)
+GL_ENUM(0x8127,GL_POINT_SIZE_MAX)
+GL_ENUM(0x8128,GL_POINT_FADE_THRESHOLD_SIZE)
+GL_ENUM(0x8129,GL_POINT_DISTANCE_ATTENUATION)
+GL_ENUM(0x812F,GL_CLAMP_TO_EDGE)
+GL_ENUM(0x8191,GL_GENERATE_MIPMAP)
+GL_ENUM(0x8192,GL_GENERATE_MIPMAP_HINT)
+GL_ENUM(0x81A5,GL_DEPTH_COMPONENT16_OES)
+GL_ENUM(0x81A6,GL_DEPTH_COMPONENT24_OES)
+GL_ENUM(0x81A7,GL_DEPTH_COMPONENT32_OES)
+GL_ENUM(0x8363,GL_UNSIGNED_SHORT_5_6_5)
+GL_ENUM(0x8365,GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT)
+GL_ENUM(0x8366,GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)
+GL_ENUM(0x8368,GL_UNSIGNED_INT_2_10_10_10_REV_EXT)
+GL_ENUM(0x8370,GL_MIRRORED_REPEAT_OES)
+GL_ENUM(0x83F0,GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
+GL_ENUM(0x83F1,GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+GL_ENUM(0x846D,GL_ALIASED_POINT_SIZE_RANGE)
+GL_ENUM(0x846E,GL_ALIASED_LINE_WIDTH_RANGE)
+GL_ENUM(0x84C0,GL_TEXTURE0)
+GL_ENUM(0x84C1,GL_TEXTURE1)
+GL_ENUM(0x84C2,GL_TEXTURE2)
+GL_ENUM(0x84C3,GL_TEXTURE3)
+GL_ENUM(0x84C4,GL_TEXTURE4)
+GL_ENUM(0x84C5,GL_TEXTURE5)
+GL_ENUM(0x84C6,GL_TEXTURE6)
+GL_ENUM(0x84C7,GL_TEXTURE7)
+GL_ENUM(0x84C8,GL_TEXTURE8)
+GL_ENUM(0x84C9,GL_TEXTURE9)
+GL_ENUM(0x84CA,GL_TEXTURE10)
+GL_ENUM(0x84CB,GL_TEXTURE11)
+GL_ENUM(0x84CC,GL_TEXTURE12)
+GL_ENUM(0x84CD,GL_TEXTURE13)
+GL_ENUM(0x84CE,GL_TEXTURE14)
+GL_ENUM(0x84CF,GL_TEXTURE15)
+GL_ENUM(0x84D0,GL_TEXTURE16)
+GL_ENUM(0x84D1,GL_TEXTURE17)
+GL_ENUM(0x84D2,GL_TEXTURE18)
+GL_ENUM(0x84D3,GL_TEXTURE19)
+GL_ENUM(0x84D4,GL_TEXTURE20)
+GL_ENUM(0x84D5,GL_TEXTURE21)
+GL_ENUM(0x84D6,GL_TEXTURE22)
+GL_ENUM(0x84D7,GL_TEXTURE23)
+GL_ENUM(0x84D8,GL_TEXTURE24)
+GL_ENUM(0x84D9,GL_TEXTURE25)
+GL_ENUM(0x84DA,GL_TEXTURE26)
+GL_ENUM(0x84DB,GL_TEXTURE27)
+GL_ENUM(0x84DC,GL_TEXTURE28)
+GL_ENUM(0x84DD,GL_TEXTURE29)
+GL_ENUM(0x84DE,GL_TEXTURE30)
+GL_ENUM(0x84DF,GL_TEXTURE31)
+GL_ENUM(0x84E0,GL_ACTIVE_TEXTURE)
+GL_ENUM(0x84E1,GL_CLIENT_ACTIVE_TEXTURE)
+GL_ENUM(0x84E2,GL_MAX_TEXTURE_UNITS)
+GL_ENUM(0x84E7,GL_SUBTRACT)
+GL_ENUM(0x84E8,GL_MAX_RENDERBUFFER_SIZE_OES)
+GL_ENUM(0x84F2,GL_ALL_COMPLETED_NV)
+GL_ENUM(0x84F3,GL_FENCE_STATUS_NV)
+GL_ENUM(0x84F4,GL_FENCE_CONDITION_NV)
+GL_ENUM(0x84F9,GL_DEPTH_STENCIL_OES)
+GL_ENUM(0x84FA,GL_UNSIGNED_INT_24_8_OES)
+GL_ENUM(0x84FD,GL_MAX_TEXTURE_LOD_BIAS_EXT)
+GL_ENUM(0x84FE,GL_TEXTURE_MAX_ANISOTROPY_EXT)
+GL_ENUM(0x84FF,GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)
+GL_ENUM(0x8500,GL_TEXTURE_FILTER_CONTROL_EXT)
+GL_ENUM(0x8501,GL_TEXTURE_LOD_BIAS_EXT)
+GL_ENUM(0x8507,GL_INCR_WRAP_OES)
+GL_ENUM(0x8508,GL_DECR_WRAP_OES)
+GL_ENUM(0x8511,GL_NORMAL_MAP_OES)
+GL_ENUM(0x8512,GL_REFLECTION_MAP_OES)
+GL_ENUM(0x8513,GL_TEXTURE_CUBE_MAP_OES)
+GL_ENUM(0x8514,GL_TEXTURE_BINDING_CUBE_MAP_OES)
+GL_ENUM(0x8515,GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES)
+GL_ENUM(0x8516,GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES)
+GL_ENUM(0x8517,GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES)
+GL_ENUM(0x8518,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES)
+GL_ENUM(0x8519,GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES)
+GL_ENUM(0x851A,GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES)
+GL_ENUM(0x851C,GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES)
+GL_ENUM(0x8570,GL_COMBINE)
+GL_ENUM(0x8571,GL_COMBINE_RGB)
+GL_ENUM(0x8572,GL_COMBINE_ALPHA)
+GL_ENUM(0x8573,GL_RGB_SCALE)
+GL_ENUM(0x8574,GL_ADD_SIGNED)
+GL_ENUM(0x8575,GL_INTERPOLATE)
+GL_ENUM(0x8576,GL_CONSTANT)
+GL_ENUM(0x8577,GL_PRIMARY_COLOR)
+GL_ENUM(0x8578,GL_PREVIOUS)
+GL_ENUM(0x8580,GL_SRC0_RGB)
+GL_ENUM(0x8581,GL_SRC1_RGB)
+GL_ENUM(0x8582,GL_SRC2_RGB)
+GL_ENUM(0x8588,GL_SRC0_ALPHA)
+GL_ENUM(0x8589,GL_SRC1_ALPHA)
+GL_ENUM(0x858A,GL_SRC2_ALPHA)
+GL_ENUM(0x8590,GL_OPERAND0_RGB)
+GL_ENUM(0x8591,GL_OPERAND1_RGB)
+GL_ENUM(0x8592,GL_OPERAND2_RGB)
+GL_ENUM(0x8598,GL_OPERAND0_ALPHA)
+GL_ENUM(0x8599,GL_OPERAND1_ALPHA)
+GL_ENUM(0x859A,GL_OPERAND2_ALPHA)
+GL_ENUM(0x85B5,GL_VERTEX_ARRAY_BINDING_OES)
+GL_ENUM(0x8622,GL_VERTEX_ATTRIB_ARRAY_ENABLED)
+GL_ENUM(0x8623,GL_VERTEX_ATTRIB_ARRAY_SIZE)
+GL_ENUM(0x8624,GL_VERTEX_ATTRIB_ARRAY_STRIDE)
+GL_ENUM(0x8625,GL_VERTEX_ATTRIB_ARRAY_TYPE)
+GL_ENUM(0x8626,GL_CURRENT_VERTEX_ATTRIB)
+GL_ENUM(0x8645,GL_VERTEX_ATTRIB_ARRAY_POINTER)
+GL_ENUM(0x86A2,GL_NUM_COMPRESSED_TEXTURE_FORMATS)
+GL_ENUM(0x86A3,GL_COMPRESSED_TEXTURE_FORMATS)
+GL_ENUM(0x86A4,GL_MAX_VERTEX_UNITS_OES)
+GL_ENUM(0x86A9,GL_WEIGHT_ARRAY_TYPE_OES)
+GL_ENUM(0x86AA,GL_WEIGHT_ARRAY_STRIDE_OES)
+GL_ENUM(0x86AB,GL_WEIGHT_ARRAY_SIZE_OES)
+GL_ENUM(0x86AC,GL_WEIGHT_ARRAY_POINTER_OES)
+GL_ENUM(0x86AD,GL_WEIGHT_ARRAY_OES)
+GL_ENUM(0x86AE,GL_DOT3_RGB)
+GL_ENUM(0x86AF,GL_DOT3_RGBA)
+GL_ENUM(0x8740,GL_Z400_BINARY_AMD)
+GL_ENUM(0x8741,GL_PROGRAM_BINARY_LENGTH_OES)
+GL_ENUM(0x8764,GL_BUFFER_SIZE)
+GL_ENUM(0x8765,GL_BUFFER_USAGE)
+GL_ENUM(0x87EE,GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD)
+GL_ENUM(0x87F9,GL_3DC_X_AMD)
+GL_ENUM(0x87FA,GL_3DC_XY_AMD)
+GL_ENUM(0x87FE,GL_NUM_PROGRAM_BINARY_FORMATS_OES)
+GL_ENUM(0x87FF,GL_PROGRAM_BINARY_FORMATS_OES)
+GL_ENUM(0x8800,GL_STENCIL_BACK_FUNC)
+GL_ENUM(0x8801,GL_STENCIL_BACK_FAIL)
+GL_ENUM(0x8802,GL_STENCIL_BACK_PASS_DEPTH_FAIL)
+GL_ENUM(0x8803,GL_STENCIL_BACK_PASS_DEPTH_PASS)
+GL_ENUM(0x8823,GL_WRITEONLY_RENDERING_QCOM)
+GL_ENUM(0x883D,GL_BLEND_EQUATION_ALPHA_OES)
+GL_ENUM(0x8840,GL_MATRIX_PALETTE_OES)
+GL_ENUM(0x8842,GL_MAX_PALETTE_MATRICES_OES)
+GL_ENUM(0x8843,GL_CURRENT_PALETTE_MATRIX_OES)
+GL_ENUM(0x8844,GL_MATRIX_INDEX_ARRAY_OES)
+GL_ENUM(0x8846,GL_MATRIX_INDEX_ARRAY_SIZE_OES)
+GL_ENUM(0x8847,GL_MATRIX_INDEX_ARRAY_TYPE_OES)
+GL_ENUM(0x8848,GL_MATRIX_INDEX_ARRAY_STRIDE_OES)
+GL_ENUM(0x8849,GL_MATRIX_INDEX_ARRAY_POINTER_OES)
+GL_ENUM(0x8861,GL_POINT_SPRITE_OES)
+GL_ENUM(0x8862,GL_COORD_REPLACE_OES)
+GL_ENUM(0x8869,GL_MAX_VERTEX_ATTRIBS)
+GL_ENUM(0x886A,GL_VERTEX_ATTRIB_ARRAY_NORMALIZED)
+GL_ENUM(0x8872,GL_MAX_TEXTURE_IMAGE_UNITS)
+GL_ENUM(0x8892,GL_ARRAY_BUFFER)
+GL_ENUM(0x8893,GL_ELEMENT_ARRAY_BUFFER)
+GL_ENUM(0x8894,GL_ARRAY_BUFFER_BINDING)
+GL_ENUM(0x8895,GL_ELEMENT_ARRAY_BUFFER_BINDING)
+GL_ENUM(0x8896,GL_VERTEX_ARRAY_BUFFER_BINDING)
+GL_ENUM(0x8897,GL_NORMAL_ARRAY_BUFFER_BINDING)
+GL_ENUM(0x8898,GL_COLOR_ARRAY_BUFFER_BINDING)
+GL_ENUM(0x889A,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING)
+GL_ENUM(0x889E,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES)
+GL_ENUM(0x889F,GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)
+GL_ENUM(0x88B9,GL_WRITE_ONLY_OES)
+GL_ENUM(0x88BB,GL_BUFFER_ACCESS_OES)
+GL_ENUM(0x88BC,GL_BUFFER_MAPPED_OES)
+GL_ENUM(0x88BD,GL_BUFFER_MAP_POINTER_OES)
+GL_ENUM(0x88E0,GL_STREAM_DRAW)
+GL_ENUM(0x88E4,GL_STATIC_DRAW)
+GL_ENUM(0x88E8,GL_DYNAMIC_DRAW)
+GL_ENUM(0x88F0,GL_DEPTH24_STENCIL8_OES)
+GL_ENUM(0x898A,GL_POINT_SIZE_ARRAY_TYPE_OES)
+GL_ENUM(0x898B,GL_POINT_SIZE_ARRAY_STRIDE_OES)
+GL_ENUM(0x898C,GL_POINT_SIZE_ARRAY_POINTER_OES)
+GL_ENUM(0x898D,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES)
+GL_ENUM(0x898E,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES)
+GL_ENUM(0x898F,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES)
+GL_ENUM(0x8B30,GL_FRAGMENT_SHADER)
+GL_ENUM(0x8B31,GL_VERTEX_SHADER)
+GL_ENUM(0x8B4C,GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+GL_ENUM(0x8B4D,GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+GL_ENUM(0x8B4F,GL_SHADER_TYPE)
+GL_ENUM(0x8B50,GL_FLOAT_VEC2)
+GL_ENUM(0x8B51,GL_FLOAT_VEC3)
+GL_ENUM(0x8B52,GL_FLOAT_VEC4)
+GL_ENUM(0x8B53,GL_INT_VEC2)
+GL_ENUM(0x8B54,GL_INT_VEC3)
+GL_ENUM(0x8B55,GL_INT_VEC4)
+GL_ENUM(0x8B56,GL_BOOL)
+GL_ENUM(0x8B57,GL_BOOL_VEC2)
+GL_ENUM(0x8B58,GL_BOOL_VEC3)
+GL_ENUM(0x8B59,GL_BOOL_VEC4)
+GL_ENUM(0x8B5A,GL_FLOAT_MAT2)
+GL_ENUM(0x8B5B,GL_FLOAT_MAT3)
+GL_ENUM(0x8B5C,GL_FLOAT_MAT4)
+GL_ENUM(0x8B5E,GL_SAMPLER_2D)
+GL_ENUM(0x8B5F,GL_SAMPLER_3D_OES)
+GL_ENUM(0x8B60,GL_SAMPLER_CUBE)
+GL_ENUM(0x8B80,GL_DELETE_STATUS)
+GL_ENUM(0x8B81,GL_COMPILE_STATUS)
+GL_ENUM(0x8B82,GL_LINK_STATUS)
+GL_ENUM(0x8B83,GL_VALIDATE_STATUS)
+GL_ENUM(0x8B84,GL_INFO_LOG_LENGTH)
+GL_ENUM(0x8B85,GL_ATTACHED_SHADERS)
+GL_ENUM(0x8B86,GL_ACTIVE_UNIFORMS)
+GL_ENUM(0x8B87,GL_ACTIVE_UNIFORM_MAX_LENGTH)
+GL_ENUM(0x8B88,GL_SHADER_SOURCE_LENGTH)
+GL_ENUM(0x8B89,GL_ACTIVE_ATTRIBUTES)
+GL_ENUM(0x8B8A,GL_ACTIVE_ATTRIBUTE_MAX_LENGTH)
+GL_ENUM(0x8B8B,GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES)
+GL_ENUM(0x8B8C,GL_SHADING_LANGUAGE_VERSION)
+GL_ENUM(0x8B8D,GL_CURRENT_PROGRAM)
+GL_ENUM(0x8B90,GL_PALETTE4_RGB8_OES)
+GL_ENUM(0x8B91,GL_PALETTE4_RGBA8_OES)
+GL_ENUM(0x8B92,GL_PALETTE4_R5_G6_B5_OES)
+GL_ENUM(0x8B93,GL_PALETTE4_RGBA4_OES)
+GL_ENUM(0x8B94,GL_PALETTE4_RGB5_A1_OES)
+GL_ENUM(0x8B95,GL_PALETTE8_RGB8_OES)
+GL_ENUM(0x8B96,GL_PALETTE8_RGBA8_OES)
+GL_ENUM(0x8B97,GL_PALETTE8_R5_G6_B5_OES)
+GL_ENUM(0x8B98,GL_PALETTE8_RGBA4_OES)
+GL_ENUM(0x8B99,GL_PALETTE8_RGB5_A1_OES)
+GL_ENUM(0x8B9A,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES)
+GL_ENUM(0x8B9B,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES)
+GL_ENUM(0x8B9C,GL_POINT_SIZE_ARRAY_OES)
+GL_ENUM(0x8B9D,GL_TEXTURE_CROP_RECT_OES)
+GL_ENUM(0x8B9E,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES)
+GL_ENUM(0x8B9F,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES)
+GL_ENUM(0x8BC0,GL_COUNTER_TYPE_AMD)
+GL_ENUM(0x8BC1,GL_COUNTER_RANGE_AMD)
+GL_ENUM(0x8BC2,GL_UNSIGNED_INT64_AMD)
+GL_ENUM(0x8BC3,GL_PERCENTAGE_AMD)
+GL_ENUM(0x8BC4,GL_PERFMON_RESULT_AVAILABLE_AMD)
+GL_ENUM(0x8BC5,GL_PERFMON_RESULT_SIZE_AMD)
+GL_ENUM(0x8BC6,GL_PERFMON_RESULT_AMD)
+GL_ENUM(0x8BD2,GL_TEXTURE_WIDTH_QCOM)
+GL_ENUM(0x8BD3,GL_TEXTURE_HEIGHT_QCOM)
+GL_ENUM(0x8BD4,GL_TEXTURE_DEPTH_QCOM)
+GL_ENUM(0x8BD5,GL_TEXTURE_INTERNAL_FORMAT_QCOM)
+GL_ENUM(0x8BD6,GL_TEXTURE_FORMAT_QCOM)
+GL_ENUM(0x8BD7,GL_TEXTURE_TYPE_QCOM)
+GL_ENUM(0x8BD8,GL_TEXTURE_IMAGE_VALID_QCOM)
+GL_ENUM(0x8BD9,GL_TEXTURE_NUM_LEVELS_QCOM)
+GL_ENUM(0x8BDA,GL_TEXTURE_TARGET_QCOM)
+GL_ENUM(0x8BDB,GL_TEXTURE_OBJECT_VALID_QCOM)
+GL_ENUM(0x8BDC,GL_STATE_RESTORE)
+GL_ENUM(0x8C00,GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG)
+GL_ENUM(0x8C01,GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG)
+GL_ENUM(0x8C02,GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG)
+GL_ENUM(0x8C03,GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG)
+GL_ENUM(0x8C04,GL_MODULATE_COLOR_IMG)
+GL_ENUM(0x8C05,GL_RECIP_ADD_SIGNED_ALPHA_IMG)
+GL_ENUM(0x8C06,GL_TEXTURE_ALPHA_MODULATE_IMG)
+GL_ENUM(0x8C07,GL_FACTOR_ALPHA_MODULATE_IMG)
+GL_ENUM(0x8C08,GL_FRAGMENT_ALPHA_MODULATE_IMG)
+GL_ENUM(0x8C09,GL_ADD_BLEND_IMG)
+GL_ENUM(0x8C0A,GL_SGX_BINARY_IMG)
+GL_ENUM(0x8C92,GL_ATC_RGB_AMD)
+GL_ENUM(0x8C93,GL_ATC_RGBA_EXPLICIT_ALPHA_AMD)
+GL_ENUM(0x8CA3,GL_STENCIL_BACK_REF)
+GL_ENUM(0x8CA4,GL_STENCIL_BACK_VALUE_MASK)
+GL_ENUM(0x8CA5,GL_STENCIL_BACK_WRITEMASK)
+GL_ENUM(0x8CA6,GL_FRAMEBUFFER_BINDING_OES)
+GL_ENUM(0x8CA7,GL_RENDERBUFFER_BINDING_OES)
+GL_ENUM(0x8CD0,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES)
+GL_ENUM(0x8CD1,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES)
+GL_ENUM(0x8CD2,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES)
+GL_ENUM(0x8CD3,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES)
+GL_ENUM(0x8CD4,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES)
+GL_ENUM(0x8CD5,GL_FRAMEBUFFER_COMPLETE_OES)
+GL_ENUM(0x8CD6,GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES)
+GL_ENUM(0x8CD7,GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES)
+GL_ENUM(0x8CD9,GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES)
+GL_ENUM(0x8CDA,GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES)
+GL_ENUM(0x8CDD,GL_FRAMEBUFFER_UNSUPPORTED_OES)
+GL_ENUM(0x8CE0,GL_COLOR_ATTACHMENT0_OES)
+GL_ENUM(0x8D00,GL_DEPTH_ATTACHMENT_OES)
+GL_ENUM(0x8D20,GL_STENCIL_ATTACHMENT_OES)
+GL_ENUM(0x8D40,GL_FRAMEBUFFER_OES)
+GL_ENUM(0x8D41,GL_RENDERBUFFER_OES)
+GL_ENUM(0x8D42,GL_RENDERBUFFER_WIDTH_OES)
+GL_ENUM(0x8D43,GL_RENDERBUFFER_HEIGHT_OES)
+GL_ENUM(0x8D44,GL_RENDERBUFFER_INTERNAL_FORMAT_OES)
+GL_ENUM(0x8D46,GL_STENCIL_INDEX1_OES)
+GL_ENUM(0x8D47,GL_STENCIL_INDEX4_OES)
+GL_ENUM(0x8D48,GL_STENCIL_INDEX8_OES)
+GL_ENUM(0x8D50,GL_RENDERBUFFER_RED_SIZE_OES)
+GL_ENUM(0x8D51,GL_RENDERBUFFER_GREEN_SIZE_OES)
+GL_ENUM(0x8D52,GL_RENDERBUFFER_BLUE_SIZE_OES)
+GL_ENUM(0x8D53,GL_RENDERBUFFER_ALPHA_SIZE_OES)
+GL_ENUM(0x8D54,GL_RENDERBUFFER_DEPTH_SIZE_OES)
+GL_ENUM(0x8D55,GL_RENDERBUFFER_STENCIL_SIZE_OES)
+GL_ENUM(0x8D60,GL_TEXTURE_GEN_STR_OES)
+GL_ENUM(0x8D61,GL_HALF_FLOAT_OES)
+GL_ENUM(0x8D62,GL_RGB565_OES)
+GL_ENUM(0x8D64,GL_ETC1_RGB8_OES)
+GL_ENUM(0x8D65,GL_TEXTURE_EXTERNAL_OES)
+GL_ENUM(0x8D66,GL_SAMPLER_EXTERNAL_OES)
+GL_ENUM(0x8D67,GL_TEXTURE_BINDING_EXTERNAL_OES)
+GL_ENUM(0x8D68,GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES)
+GL_ENUM(0x8DF0,GL_LOW_FLOAT)
+GL_ENUM(0x8DF1,GL_MEDIUM_FLOAT)
+GL_ENUM(0x8DF2,GL_HIGH_FLOAT)
+GL_ENUM(0x8DF3,GL_LOW_INT)
+GL_ENUM(0x8DF4,GL_MEDIUM_INT)
+GL_ENUM(0x8DF5,GL_HIGH_INT)
+GL_ENUM(0x8DF6,GL_UNSIGNED_INT_10_10_10_2_OES)
+GL_ENUM(0x8DF7,GL_INT_10_10_10_2_OES)
+GL_ENUM(0x8DF8,GL_SHADER_BINARY_FORMATS)
+GL_ENUM(0x8DF9,GL_NUM_SHADER_BINARY_FORMATS)
+GL_ENUM(0x8DFA,GL_SHADER_COMPILER)
+GL_ENUM(0x8DFB,GL_MAX_VERTEX_UNIFORM_VECTORS)
+GL_ENUM(0x8DFC,GL_MAX_VARYING_VECTORS)
+GL_ENUM(0x8DFD,GL_MAX_FRAGMENT_UNIFORM_VECTORS)
+GL_ENUM(0x8E2C,GL_DEPTH_COMPONENT16_NONLINEAR_NV)
+GL_ENUM(0x8ED0,GL_COVERAGE_COMPONENT_NV)
+GL_ENUM(0x8ED1,GL_COVERAGE_COMPONENT4_NV)
+GL_ENUM(0x8ED2,GL_COVERAGE_ATTACHMENT_NV)
+GL_ENUM(0x8ED3,GL_COVERAGE_BUFFERS_NV)
+GL_ENUM(0x8ED4,GL_COVERAGE_SAMPLES_NV)
+GL_ENUM(0x8ED5,GL_COVERAGE_ALL_FRAGMENTS_NV)
+GL_ENUM(0x8ED6,GL_COVERAGE_EDGE_FRAGMENTS_NV)
+GL_ENUM(0x8ED7,GL_COVERAGE_AUTOMATIC_NV)
+GL_ENUM(0x8FA0,GL_PERFMON_GLOBAL_MODE_QCOM)
+GL_ENUM(0x9130,GL_SGX_PROGRAM_BINARY_IMG)
+GL_ENUM(0x9133,GL_RENDERBUFFER_SAMPLES_IMG)
+GL_ENUM(0x9134,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG)
+GL_ENUM(0x9135,GL_MAX_SAMPLES_IMG)
+GL_ENUM(0x9136,GL_TEXTURE_SAMPLES_IMG)
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 1ab58cc..812e26d 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -141,6 +141,11 @@
#endif
+#if EGL_TRACE
+
+extern gl_hooks_t const* getGLTraceThreadSpecific();
+
+#endif
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles
index 120cb4b..50bbf08 100755
--- a/opengl/libs/tools/genfiles
+++ b/opengl/libs/tools/genfiles
@@ -31,3 +31,14 @@
| sort -t, -k2 \
| awk -F, '!_[$2]++' \
> ../entries.in
+
+./gltracegen ../entries.in >../trace.in
+
+cat ../../include/GLES/gl.h \
+ ../../include/GLES/glext.h \
+ ../../include/GLES2/gl2.h \
+ ../../include/GLES2/gl2ext.h \
+ | ./glenumsgen \
+ | sort \
+ > ../enums.in
+
diff --git a/opengl/libs/tools/glenumsgen b/opengl/libs/tools/glenumsgen
new file mode 100755
index 0000000..2ae5fbf
--- /dev/null
+++ b/opengl/libs/tools/glenumsgen
@@ -0,0 +1,38 @@
+#! /usr/bin/perl
+#
+# Copyright (C) 2010 Google Inc.
+#
+# 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.
+
+use strict;
+
+my %enumHash = ();
+
+while (my $line = <STDIN>) {
+ next if $line =~ /^\//;
+ # Skip bitfield definitions.
+ next if $line =~ /_BIT(\d+_|\s+)/;
+ if ($line !~ /^#define\s+(\S+)\s+(0x\S+)/) {
+ next;
+ }
+ my $enumName = $1;
+ my $enumValue = $2;
+ next if exists($enumHash { $enumValue });
+ $enumHash { $enumValue } = $enumName;
+ printf("GL_ENUM(%s,%s)\n", $enumValue, $enumName);
+}
+
+
+
+
+
diff --git a/opengl/libs/tools/gltracegen b/opengl/libs/tools/gltracegen
new file mode 100755
index 0000000..da42653
--- /dev/null
+++ b/opengl/libs/tools/gltracegen
@@ -0,0 +1,95 @@
+#! /usr/bin/perl
+#
+# Copyright (C) 2010 Google Inc.
+#
+# 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.
+
+use strict;
+
+sub rtrim($)
+{
+ my $string = shift;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
+while (my $line = <>) {
+ next if $line =~ /^\//;
+ next if $line =~ /^#/;
+ next if $line =~ /^\s*$/;
+ if ($line !~ /^GL_ENTRY\(([^,]+), ([^,]+), ([^\)]+)\)/) {
+ next;
+ }
+ my $type = $1;
+ my $name = $2;
+ my $args = $3;
+
+ my @args = split ',', $args;
+ my $len = scalar(@args);
+ my $nonVoidArgLen = 0;
+ for (my $num = 0; $num < $len; $num++) {
+ if ($args[$num] ne "void") {
+ $nonVoidArgLen++;
+ }
+ }
+ if ($type eq "void") {
+ printf("TRACE_GL_VOID(");
+ } else {
+ printf("TRACE_GL(%s, ", $type);
+ }
+
+ printf("%s, (%s), (", $name, $args);
+ for (my $num = 0; $num < $len; $num++) {
+ if ($args[$num] ne "void") {
+ if ($num > 0) {
+ print ", ";
+ }
+ #
+ # extract the name from the parameter
+ # type name
+ # const type *name
+ # type *name
+ # type name[4]
+ #
+ if ($args[$num] =~ /(\S+\s)+\**\s*([\w]+)/) {
+ printf("%s", $2);
+ }
+ }
+ }
+ printf("), %d", $nonVoidArgLen);
+ for (my $num = 0; $num < $len; $num++) {
+ if ($args[$num] ne "void") {
+ #
+ # extract the name from the parameter
+ # type name
+ # const type *name
+ # type *name
+ # type name[4]
+ #
+ my $arg = $args[$num];
+ if ($arg =~ /(\S+\s)+\**\s*([\w]+)/) {
+ my $name = $2;
+ if ($arg =~ /((const )*(\S+\s)+\**)\s*([\w]+)/) {
+ my $type = rtrim($1);
+ printf(", \"%s\", %s", $type, $name);
+ }
+ }
+ }
+ }
+ printf(")\n");
+}
+
+
+
+
+
diff --git a/opengl/libs/trace.in b/opengl/libs/trace.in
new file mode 100644
index 0000000..3d492af
--- /dev/null
+++ b/opengl/libs/trace.in
@@ -0,0 +1,376 @@
+TRACE_GL_VOID(glActiveTexture, (GLenum texture), (texture), 1, "GLenum", texture)
+TRACE_GL_VOID(glAlphaFunc, (GLenum func, GLclampf ref), (func, ref), 2, "GLenum", func, "GLclampf", ref)
+TRACE_GL_VOID(glAlphaFuncx, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
+TRACE_GL_VOID(glAlphaFuncxOES, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
+TRACE_GL_VOID(glAttachShader, (GLuint program, GLuint shader), (program, shader), 2, "GLuint", program, "GLuint", shader)
+TRACE_GL_VOID(glBeginPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glBindAttribLocation, (GLuint program, GLuint index, const GLchar* name), (program, index, name), 3, "GLuint", program, "GLuint", index, "const GLchar*", name)
+TRACE_GL_VOID(glBindBuffer, (GLenum target, GLuint buffer), (target, buffer), 2, "GLenum", target, "GLuint", buffer)
+TRACE_GL_VOID(glBindFramebuffer, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer)
+TRACE_GL_VOID(glBindFramebufferOES, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer)
+TRACE_GL_VOID(glBindRenderbuffer, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer)
+TRACE_GL_VOID(glBindRenderbufferOES, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer)
+TRACE_GL_VOID(glBindTexture, (GLenum target, GLuint texture), (target, texture), 2, "GLenum", target, "GLuint", texture)
+TRACE_GL_VOID(glBindVertexArrayOES, (GLuint array), (array), 1, "GLuint", array)
+TRACE_GL_VOID(glBlendColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha), (red, green, blue, alpha), 4, "GLclampf", red, "GLclampf", green, "GLclampf", blue, "GLclampf", alpha)
+TRACE_GL_VOID(glBlendEquation, ( GLenum mode ), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glBlendEquationOES, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glBlendEquationSeparate, (GLenum modeRGB, GLenum modeAlpha), (modeRGB, modeAlpha), 2, "GLenum", modeRGB, "GLenum", modeAlpha)
+TRACE_GL_VOID(glBlendEquationSeparateOES, (GLenum modeRGB, GLenum modeAlpha), (modeRGB, modeAlpha), 2, "GLenum", modeRGB, "GLenum", modeAlpha)
+TRACE_GL_VOID(glBlendFunc, (GLenum sfactor, GLenum dfactor), (sfactor, dfactor), 2, "GLenum", sfactor, "GLenum", dfactor)
+TRACE_GL_VOID(glBlendFuncSeparate, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha)
+TRACE_GL_VOID(glBlendFuncSeparateOES, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha)
+TRACE_GL_VOID(glBufferData, (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage), (target, size, data, usage), 4, "GLenum", target, "GLsizeiptr", size, "const GLvoid *", data, "GLenum", usage)
+TRACE_GL_VOID(glBufferSubData, (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data), (target, offset, size, data), 4, "GLenum", target, "GLintptr", offset, "GLsizeiptr", size, "const GLvoid *", data)
+TRACE_GL(GLenum, glCheckFramebufferStatus, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL(GLenum, glCheckFramebufferStatusOES, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL_VOID(glClear, (GLbitfield mask), (mask), 1, "GLbitfield", mask)
+TRACE_GL_VOID(glClearColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha), (red, green, blue, alpha), 4, "GLclampf", red, "GLclampf", green, "GLclampf", blue, "GLclampf", alpha)
+TRACE_GL_VOID(glClearColorx, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha), (red, green, blue, alpha), 4, "GLclampx", red, "GLclampx", green, "GLclampx", blue, "GLclampx", alpha)
+TRACE_GL_VOID(glClearColorxOES, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha), (red, green, blue, alpha), 4, "GLclampx", red, "GLclampx", green, "GLclampx", blue, "GLclampx", alpha)
+TRACE_GL_VOID(glClearDepthf, (GLclampf depth), (depth), 1, "GLclampf", depth)
+TRACE_GL_VOID(glClearDepthfOES, (GLclampf depth), (depth), 1, "GLclampf", depth)
+TRACE_GL_VOID(glClearDepthx, (GLclampx depth), (depth), 1, "GLclampx", depth)
+TRACE_GL_VOID(glClearDepthxOES, (GLclampx depth), (depth), 1, "GLclampx", depth)
+TRACE_GL_VOID(glClearStencil, (GLint s), (s), 1, "GLint", s)
+TRACE_GL_VOID(glClientActiveTexture, (GLenum texture), (texture), 1, "GLenum", texture)
+TRACE_GL_VOID(glClipPlanef, (GLenum plane, const GLfloat *equation), (plane, equation), 2, "GLenum", plane, "const GLfloat *", equation)
+TRACE_GL_VOID(glClipPlanefIMG, (GLenum p, const GLfloat *eqn), (p, eqn), 2, "GLenum", p, "const GLfloat *", eqn)
+TRACE_GL_VOID(glClipPlanefOES, (GLenum plane, const GLfloat *equation), (plane, equation), 2, "GLenum", plane, "const GLfloat *", equation)
+TRACE_GL_VOID(glClipPlanex, (GLenum plane, const GLfixed *equation), (plane, equation), 2, "GLenum", plane, "const GLfixed *", equation)
+TRACE_GL_VOID(glClipPlanexIMG, (GLenum p, const GLfixed *eqn), (p, eqn), 2, "GLenum", p, "const GLfixed *", eqn)
+TRACE_GL_VOID(glClipPlanexOES, (GLenum plane, const GLfixed *equation), (plane, equation), 2, "GLenum", plane, "const GLfixed *", equation)
+TRACE_GL_VOID(glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha), (red, green, blue, alpha), 4, "GLfloat", red, "GLfloat", green, "GLfloat", blue, "GLfloat", alpha)
+TRACE_GL_VOID(glColor4ub, (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha), (red, green, blue, alpha), 4, "GLubyte", red, "GLubyte", green, "GLubyte", blue, "GLubyte", alpha)
+TRACE_GL_VOID(glColor4x, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha), (red, green, blue, alpha), 4, "GLfixed", red, "GLfixed", green, "GLfixed", blue, "GLfixed", alpha)
+TRACE_GL_VOID(glColor4xOES, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha), (red, green, blue, alpha), 4, "GLfixed", red, "GLfixed", green, "GLfixed", blue, "GLfixed", alpha)
+TRACE_GL_VOID(glColorMask, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha), (red, green, blue, alpha), 4, "GLboolean", red, "GLboolean", green, "GLboolean", blue, "GLboolean", alpha)
+TRACE_GL_VOID(glColorPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glCompileShader, (GLuint shader), (shader), 1, "GLuint", shader)
+TRACE_GL_VOID(glCompressedTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data), (target, level, internalformat, width, height, border, imageSize, data), 8, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLint", border, "GLsizei", imageSize, "const GLvoid *", data)
+TRACE_GL_VOID(glCompressedTexImage3DOES, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data), (target, level, internalformat, width, height, depth, border, imageSize, data), 9, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLint", border, "GLsizei", imageSize, "const GLvoid*", data)
+TRACE_GL_VOID(glCompressedTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data), (target, level, xoffset, yoffset, width, height, format, imageSize, data), 9, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLsizei", imageSize, "const GLvoid *", data)
+TRACE_GL_VOID(glCompressedTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLsizei", imageSize, "const GLvoid*", data)
+TRACE_GL_VOID(glCopyTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border), (target, level, internalformat, x, y, width, height, border), 8, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height, "GLint", border)
+TRACE_GL_VOID(glCopyTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height), (target, level, xoffset, yoffset, x, y, width, height), 8, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glCopyTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height), (target, level, xoffset, yoffset, zoffset, x, y, width, height), 9, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glCoverageMaskNV, (GLboolean mask), (mask), 1, "GLboolean", mask)
+TRACE_GL_VOID(glCoverageOperationNV, (GLenum operation), (operation), 1, "GLenum", operation)
+TRACE_GL(GLuint, glCreateProgram, (void), (), 0)
+TRACE_GL(GLuint, glCreateShader, (GLenum type), (type), 1, "GLenum", type)
+TRACE_GL_VOID(glCullFace, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glCurrentPaletteMatrixOES, (GLuint matrixpaletteindex), (matrixpaletteindex), 1, "GLuint", matrixpaletteindex)
+TRACE_GL_VOID(glDeleteBuffers, (GLsizei n, const GLuint *buffers), (n, buffers), 2, "GLsizei", n, "const GLuint *", buffers)
+TRACE_GL_VOID(glDeleteFencesNV, (GLsizei n, const GLuint *fences), (n, fences), 2, "GLsizei", n, "const GLuint *", fences)
+TRACE_GL_VOID(glDeleteFramebuffers, (GLsizei n, const GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "const GLuint*", framebuffers)
+TRACE_GL_VOID(glDeleteFramebuffersOES, (GLsizei n, const GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "const GLuint*", framebuffers)
+TRACE_GL_VOID(glDeletePerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
+TRACE_GL_VOID(glDeleteProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glDeleteRenderbuffers, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers)
+TRACE_GL_VOID(glDeleteRenderbuffersOES, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers)
+TRACE_GL_VOID(glDeleteShader, (GLuint shader), (shader), 1, "GLuint", shader)
+TRACE_GL_VOID(glDeleteTextures, (GLsizei n, const GLuint *textures), (n, textures), 2, "GLsizei", n, "const GLuint *", textures)
+TRACE_GL_VOID(glDeleteVertexArraysOES, (GLsizei n, const GLuint *arrays), (n, arrays), 2, "GLsizei", n, "const GLuint *", arrays)
+TRACE_GL_VOID(glDepthFunc, (GLenum func), (func), 1, "GLenum", func)
+TRACE_GL_VOID(glDepthMask, (GLboolean flag), (flag), 1, "GLboolean", flag)
+TRACE_GL_VOID(glDepthRangef, (GLclampf zNear, GLclampf zFar), (zNear, zFar), 2, "GLclampf", zNear, "GLclampf", zFar)
+TRACE_GL_VOID(glDepthRangefOES, (GLclampf zNear, GLclampf zFar), (zNear, zFar), 2, "GLclampf", zNear, "GLclampf", zFar)
+TRACE_GL_VOID(glDepthRangex, (GLclampx zNear, GLclampx zFar), (zNear, zFar), 2, "GLclampx", zNear, "GLclampx", zFar)
+TRACE_GL_VOID(glDepthRangexOES, (GLclampx zNear, GLclampx zFar), (zNear, zFar), 2, "GLclampx", zNear, "GLclampx", zFar)
+TRACE_GL_VOID(glDetachShader, (GLuint program, GLuint shader), (program, shader), 2, "GLuint", program, "GLuint", shader)
+TRACE_GL_VOID(glDisable, (GLenum cap), (cap), 1, "GLenum", cap)
+TRACE_GL_VOID(glDisableClientState, (GLenum array), (array), 1, "GLenum", array)
+TRACE_GL_VOID(glDisableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl)
+TRACE_GL_VOID(glDisableVertexAttribArray, (GLuint index), (index), 1, "GLuint", index)
+TRACE_GL_VOID(glDiscardFramebufferEXT, (GLenum target, GLsizei numAttachments, const GLenum *attachments), (target, numAttachments, attachments), 3, "GLenum", target, "GLsizei", numAttachments, "const GLenum *", attachments)
+TRACE_GL_VOID(glDrawArrays, (GLenum mode, GLint first, GLsizei count), (mode, first, count), 3, "GLenum", mode, "GLint", first, "GLsizei", count)
+TRACE_GL_VOID(glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices), (mode, count, type, indices), 4, "GLenum", mode, "GLsizei", count, "GLenum", type, "const GLvoid *", indices)
+TRACE_GL_VOID(glDrawTexfOES, (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height), (x, y, z, width, height), 5, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", width, "GLfloat", height)
+TRACE_GL_VOID(glDrawTexfvOES, (const GLfloat *coords), (coords), 1, "const GLfloat *", coords)
+TRACE_GL_VOID(glDrawTexiOES, (GLint x, GLint y, GLint z, GLint width, GLint height), (x, y, z, width, height), 5, "GLint", x, "GLint", y, "GLint", z, "GLint", width, "GLint", height)
+TRACE_GL_VOID(glDrawTexivOES, (const GLint *coords), (coords), 1, "const GLint *", coords)
+TRACE_GL_VOID(glDrawTexsOES, (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height), (x, y, z, width, height), 5, "GLshort", x, "GLshort", y, "GLshort", z, "GLshort", width, "GLshort", height)
+TRACE_GL_VOID(glDrawTexsvOES, (const GLshort *coords), (coords), 1, "const GLshort *", coords)
+TRACE_GL_VOID(glDrawTexxOES, (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height), (x, y, z, width, height), 5, "GLfixed", x, "GLfixed", y, "GLfixed", z, "GLfixed", width, "GLfixed", height)
+TRACE_GL_VOID(glDrawTexxvOES, (const GLfixed *coords), (coords), 1, "const GLfixed *", coords)
+TRACE_GL_VOID(glEGLImageTargetRenderbufferStorageOES, (GLenum target, GLeglImageOES image), (target, image), 2, "GLenum", target, "GLeglImageOES", image)
+TRACE_GL_VOID(glEGLImageTargetTexture2DOES, (GLenum target, GLeglImageOES image), (target, image), 2, "GLenum", target, "GLeglImageOES", image)
+TRACE_GL_VOID(glEnable, (GLenum cap), (cap), 1, "GLenum", cap)
+TRACE_GL_VOID(glEnableClientState, (GLenum array), (array), 1, "GLenum", array)
+TRACE_GL_VOID(glEnableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl)
+TRACE_GL_VOID(glEnableVertexAttribArray, (GLuint index), (index), 1, "GLuint", index)
+TRACE_GL_VOID(glEndPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glEndTilingQCOM, (GLbitfield preserveMask), (preserveMask), 1, "GLbitfield", preserveMask)
+TRACE_GL_VOID(glExtGetBufferPointervQCOM, (GLenum target, GLvoid **params), (target, params), 2, "GLenum", target, "GLvoid **", params)
+TRACE_GL_VOID(glExtGetBuffersQCOM, (GLuint *buffers, GLint maxBuffers, GLint *numBuffers), (buffers, maxBuffers, numBuffers), 3, "GLuint *", buffers, "GLint", maxBuffers, "GLint *", numBuffers)
+TRACE_GL_VOID(glExtGetFramebuffersQCOM, (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers), (framebuffers, maxFramebuffers, numFramebuffers), 3, "GLuint *", framebuffers, "GLint", maxFramebuffers, "GLint *", numFramebuffers)
+TRACE_GL_VOID(glExtGetProgramBinarySourceQCOM, (GLuint program, GLenum shadertype, GLchar *source, GLint *length), (program, shadertype, source, length), 4, "GLuint", program, "GLenum", shadertype, "GLchar *", source, "GLint *", length)
+TRACE_GL_VOID(glExtGetProgramsQCOM, (GLuint *programs, GLint maxPrograms, GLint *numPrograms), (programs, maxPrograms, numPrograms), 3, "GLuint *", programs, "GLint", maxPrograms, "GLint *", numPrograms)
+TRACE_GL_VOID(glExtGetRenderbuffersQCOM, (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers), (renderbuffers, maxRenderbuffers, numRenderbuffers), 3, "GLuint *", renderbuffers, "GLint", maxRenderbuffers, "GLint *", numRenderbuffers)
+TRACE_GL_VOID(glExtGetShadersQCOM, (GLuint *shaders, GLint maxShaders, GLint *numShaders), (shaders, maxShaders, numShaders), 3, "GLuint *", shaders, "GLint", maxShaders, "GLint *", numShaders)
+TRACE_GL_VOID(glExtGetTexLevelParameterivQCOM, (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params), (texture, face, level, pname, params), 5, "GLuint", texture, "GLenum", face, "GLint", level, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glExtGetTexSubImageQCOM, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "GLvoid *", texels)
+TRACE_GL_VOID(glExtGetTexturesQCOM, (GLuint *textures, GLint maxTextures, GLint *numTextures), (textures, maxTextures, numTextures), 3, "GLuint *", textures, "GLint", maxTextures, "GLint *", numTextures)
+TRACE_GL(GLboolean, glExtIsProgramBinaryQCOM, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glExtTexObjectStateOverrideiQCOM, (GLenum target, GLenum pname, GLint param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glFinish, (void), (), 0)
+TRACE_GL_VOID(glFinishFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
+TRACE_GL_VOID(glFlush, (void), (), 0)
+TRACE_GL_VOID(glFogf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glFogfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glFogx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glFogxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glFogxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glFogxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glFramebufferRenderbuffer, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer)
+TRACE_GL_VOID(glFramebufferRenderbufferOES, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer)
+TRACE_GL_VOID(glFramebufferTexture2D, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level)
+TRACE_GL_VOID(glFramebufferTexture2DMultisampleIMG, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples), (target, attachment, textarget, texture, level, samples), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLsizei", samples)
+TRACE_GL_VOID(glFramebufferTexture2DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level)
+TRACE_GL_VOID(glFramebufferTexture3DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset), (target, attachment, textarget, texture, level, zoffset), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLint", zoffset)
+TRACE_GL_VOID(glFrontFace, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glFrustumf, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glFrustumfOES, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glFrustumx, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glFrustumxOES, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glGenBuffers, (GLsizei n, GLuint *buffers), (n, buffers), 2, "GLsizei", n, "GLuint *", buffers)
+TRACE_GL_VOID(glGenFencesNV, (GLsizei n, GLuint *fences), (n, fences), 2, "GLsizei", n, "GLuint *", fences)
+TRACE_GL_VOID(glGenFramebuffers, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers)
+TRACE_GL_VOID(glGenFramebuffersOES, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers)
+TRACE_GL_VOID(glGenPerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
+TRACE_GL_VOID(glGenRenderbuffers, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers)
+TRACE_GL_VOID(glGenRenderbuffersOES, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers)
+TRACE_GL_VOID(glGenTextures, (GLsizei n, GLuint *textures), (n, textures), 2, "GLsizei", n, "GLuint *", textures)
+TRACE_GL_VOID(glGenVertexArraysOES, (GLsizei n, GLuint *arrays), (n, arrays), 2, "GLsizei", n, "GLuint *", arrays)
+TRACE_GL_VOID(glGenerateMipmap, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL_VOID(glGenerateMipmapOES, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL_VOID(glGetActiveAttrib, (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name), (program, index, bufsize, length, size, type, name), 7, "GLuint", program, "GLuint", index, "GLsizei", bufsize, "GLsizei*", length, "GLint*", size, "GLenum*", type, "GLchar*", name)
+TRACE_GL_VOID(glGetActiveUniform, (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name), (program, index, bufsize, length, size, type, name), 7, "GLuint", program, "GLuint", index, "GLsizei", bufsize, "GLsizei*", length, "GLint*", size, "GLenum*", type, "GLchar*", name)
+TRACE_GL_VOID(glGetAttachedShaders, (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders), (program, maxcount, count, shaders), 4, "GLuint", program, "GLsizei", maxcount, "GLsizei*", count, "GLuint*", shaders)
+TRACE_GL(int, glGetAttribLocation, (GLuint program, const GLchar* name), (program, name), 2, "GLuint", program, "const GLchar*", name)
+TRACE_GL_VOID(glGetBooleanv, (GLenum pname, GLboolean *params), (pname, params), 2, "GLenum", pname, "GLboolean *", params)
+TRACE_GL_VOID(glGetBufferParameteriv, (GLenum target, GLenum pname, GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetBufferPointervOES, (GLenum target, GLenum pname, GLvoid ** params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLvoid **", params)
+TRACE_GL_VOID(glGetClipPlanef, (GLenum pname, GLfloat eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfloat", eqn)
+TRACE_GL_VOID(glGetClipPlanefOES, (GLenum pname, GLfloat eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfloat", eqn)
+TRACE_GL_VOID(glGetClipPlanex, (GLenum pname, GLfixed eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfixed", eqn)
+TRACE_GL_VOID(glGetClipPlanexOES, (GLenum pname, GLfixed eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfixed", eqn)
+TRACE_GL_VOID(glGetDriverControlStringQCOM, (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString), (driverControl, bufSize, length, driverControlString), 4, "GLuint", driverControl, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", driverControlString)
+TRACE_GL_VOID(glGetDriverControlsQCOM, (GLint *num, GLsizei size, GLuint *driverControls), (num, size, driverControls), 3, "GLint *", num, "GLsizei", size, "GLuint *", driverControls)
+TRACE_GL(GLenum, glGetError, (void), (), 0)
+TRACE_GL_VOID(glGetFenceivNV, (GLuint fence, GLenum pname, GLint *params), (fence, pname, params), 3, "GLuint", fence, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetFixedv, (GLenum pname, GLfixed *params), (pname, params), 2, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetFixedvOES, (GLenum pname, GLfixed *params), (pname, params), 2, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetFloatv, (GLenum pname, GLfloat *params), (pname, params), 2, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetFramebufferAttachmentParameteriv, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetFramebufferAttachmentParameterivOES, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetIntegerv, (GLenum pname, GLint *params), (pname, params), 2, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetLightfv, (GLenum light, GLenum pname, GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetLightxv, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetLightxvOES, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetMaterialfv, (GLenum face, GLenum pname, GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetMaterialxv, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetMaterialxvOES, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetPerfMonitorCounterDataAMD, (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten), (monitor, pname, dataSize, data, bytesWritten), 5, "GLuint", monitor, "GLenum", pname, "GLsizei", dataSize, "GLuint *", data, "GLint *", bytesWritten)
+TRACE_GL_VOID(glGetPerfMonitorCounterInfoAMD, (GLuint group, GLuint counter, GLenum pname, GLvoid *data), (group, counter, pname, data), 4, "GLuint", group, "GLuint", counter, "GLenum", pname, "GLvoid *", data)
+TRACE_GL_VOID(glGetPerfMonitorCounterStringAMD, (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString), (group, counter, bufSize, length, counterString), 5, "GLuint", group, "GLuint", counter, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", counterString)
+TRACE_GL_VOID(glGetPerfMonitorCountersAMD, (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters), (group, numCounters, maxActiveCounters, counterSize, counters), 5, "GLuint", group, "GLint *", numCounters, "GLint *", maxActiveCounters, "GLsizei", counterSize, "GLuint *", counters)
+TRACE_GL_VOID(glGetPerfMonitorGroupStringAMD, (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString), (group, bufSize, length, groupString), 4, "GLuint", group, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", groupString)
+TRACE_GL_VOID(glGetPerfMonitorGroupsAMD, (GLint *numGroups, GLsizei groupsSize, GLuint *groups), (numGroups, groupsSize, groups), 3, "GLint *", numGroups, "GLsizei", groupsSize, "GLuint *", groups)
+TRACE_GL_VOID(glGetPointerv, (GLenum pname, GLvoid **params), (pname, params), 2, "GLenum", pname, "GLvoid **", params)
+TRACE_GL_VOID(glGetProgramBinaryOES, (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary), (program, bufSize, length, binaryFormat, binary), 5, "GLuint", program, "GLsizei", bufSize, "GLsizei *", length, "GLenum *", binaryFormat, "GLvoid *", binary)
+TRACE_GL_VOID(glGetProgramInfoLog, (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog), (program, bufsize, length, infolog), 4, "GLuint", program, "GLsizei", bufsize, "GLsizei*", length, "GLchar*", infolog)
+TRACE_GL_VOID(glGetProgramiv, (GLuint program, GLenum pname, GLint* params), (program, pname, params), 3, "GLuint", program, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetRenderbufferParameteriv, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetRenderbufferParameterivOES, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetShaderInfoLog, (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog), (shader, bufsize, length, infolog), 4, "GLuint", shader, "GLsizei", bufsize, "GLsizei*", length, "GLchar*", infolog)
+TRACE_GL_VOID(glGetShaderPrecisionFormat, (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision), (shadertype, precisiontype, range, precision), 4, "GLenum", shadertype, "GLenum", precisiontype, "GLint*", range, "GLint*", precision)
+TRACE_GL_VOID(glGetShaderSource, (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source), (shader, bufsize, length, source), 4, "GLuint", shader, "GLsizei", bufsize, "GLsizei*", length, "GLchar*", source)
+TRACE_GL_VOID(glGetShaderiv, (GLuint shader, GLenum pname, GLint* params), (shader, pname, params), 3, "GLuint", shader, "GLenum", pname, "GLint*", params)
+TRACE_GL(const GLubyte *, glGetString, (GLenum name), (name), 1, "GLenum", name)
+TRACE_GL_VOID(glGetTexEnvfv, (GLenum env, GLenum pname, GLfloat *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetTexEnviv, (GLenum env, GLenum pname, GLint *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetTexEnvxv, (GLenum env, GLenum pname, GLfixed *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexEnvxvOES, (GLenum env, GLenum pname, GLfixed *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexGenfvOES, (GLenum coord, GLenum pname, GLfloat *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetTexGenivOES, (GLenum coord, GLenum pname, GLint *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetTexGenxvOES, (GLenum coord, GLenum pname, GLfixed *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexParameterfv, (GLenum target, GLenum pname, GLfloat *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetTexParameteriv, (GLenum target, GLenum pname, GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetTexParameterxv, (GLenum target, GLenum pname, GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexParameterxvOES, (GLenum target, GLenum pname, GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLfixed *", params)
+TRACE_GL(int, glGetUniformLocation, (GLuint program, const GLchar* name), (program, name), 2, "GLuint", program, "const GLchar*", name)
+TRACE_GL_VOID(glGetUniformfv, (GLuint program, GLint location, GLfloat* params), (program, location, params), 3, "GLuint", program, "GLint", location, "GLfloat*", params)
+TRACE_GL_VOID(glGetUniformiv, (GLuint program, GLint location, GLint* params), (program, location, params), 3, "GLuint", program, "GLint", location, "GLint*", params)
+TRACE_GL_VOID(glGetVertexAttribPointerv, (GLuint index, GLenum pname, GLvoid** pointer), (index, pname, pointer), 3, "GLuint", index, "GLenum", pname, "GLvoid**", pointer)
+TRACE_GL_VOID(glGetVertexAttribfv, (GLuint index, GLenum pname, GLfloat* params), (index, pname, params), 3, "GLuint", index, "GLenum", pname, "GLfloat*", params)
+TRACE_GL_VOID(glGetVertexAttribiv, (GLuint index, GLenum pname, GLint* params), (index, pname, params), 3, "GLuint", index, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glHint, (GLenum target, GLenum mode), (target, mode), 2, "GLenum", target, "GLenum", mode)
+TRACE_GL(GLboolean, glIsBuffer, (GLuint buffer), (buffer), 1, "GLuint", buffer)
+TRACE_GL(GLboolean, glIsEnabled, (GLenum cap), (cap), 1, "GLenum", cap)
+TRACE_GL(GLboolean, glIsFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
+TRACE_GL(GLboolean, glIsFramebuffer, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer)
+TRACE_GL(GLboolean, glIsFramebufferOES, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer)
+TRACE_GL(GLboolean, glIsProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL(GLboolean, glIsRenderbuffer, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer)
+TRACE_GL(GLboolean, glIsRenderbufferOES, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer)
+TRACE_GL(GLboolean, glIsShader, (GLuint shader), (shader), 1, "GLuint", shader)
+TRACE_GL(GLboolean, glIsTexture, (GLuint texture), (texture), 1, "GLuint", texture)
+TRACE_GL(GLboolean, glIsVertexArrayOES, (GLuint array), (array), 1, "GLuint", array)
+TRACE_GL_VOID(glLightModelf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glLightModelfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glLightModelx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightModelxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightModelxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLightModelxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLightf, (GLenum light, GLenum pname, GLfloat param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glLightfv, (GLenum light, GLenum pname, const GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glLightx, (GLenum light, GLenum pname, GLfixed param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightxOES, (GLenum light, GLenum pname, GLfixed param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightxv, (GLenum light, GLenum pname, const GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLightxvOES, (GLenum light, GLenum pname, const GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLineWidth, (GLfloat width), (width), 1, "GLfloat", width)
+TRACE_GL_VOID(glLineWidthx, (GLfixed width), (width), 1, "GLfixed", width)
+TRACE_GL_VOID(glLineWidthxOES, (GLfixed width), (width), 1, "GLfixed", width)
+TRACE_GL_VOID(glLinkProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glLoadIdentity, (void), (), 0)
+TRACE_GL_VOID(glLoadMatrixf, (const GLfloat *m), (m), 1, "const GLfloat *", m)
+TRACE_GL_VOID(glLoadMatrixx, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glLoadMatrixxOES, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glLoadPaletteFromModelViewMatrixOES, (void), (), 0)
+TRACE_GL_VOID(glLogicOp, (GLenum opcode), (opcode), 1, "GLenum", opcode)
+TRACE_GL(void*, glMapBufferOES, (GLenum target, GLenum access), (target, access), 2, "GLenum", target, "GLenum", access)
+TRACE_GL_VOID(glMaterialf, (GLenum face, GLenum pname, GLfloat param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glMaterialfv, (GLenum face, GLenum pname, const GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glMaterialx, (GLenum face, GLenum pname, GLfixed param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glMaterialxOES, (GLenum face, GLenum pname, GLfixed param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glMaterialxv, (GLenum face, GLenum pname, const GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glMaterialxvOES, (GLenum face, GLenum pname, const GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glMatrixIndexPointerOES, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glMatrixMode, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glMultMatrixf, (const GLfloat *m), (m), 1, "const GLfloat *", m)
+TRACE_GL_VOID(glMultMatrixx, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glMultMatrixxOES, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glMultiDrawArraysEXT, (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount), (mode, first, count, primcount), 4, "GLenum", mode, "GLint *", first, "GLsizei *", count, "GLsizei", primcount)
+TRACE_GL_VOID(glMultiDrawElementsEXT, (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount), (mode, count, type, indices, primcount), 5, "GLenum", mode, "const GLsizei *", count, "GLenum", type, "const GLvoid* *", indices, "GLsizei", primcount)
+TRACE_GL_VOID(glMultiTexCoord4f, (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q), (target, s, t, r, q), 5, "GLenum", target, "GLfloat", s, "GLfloat", t, "GLfloat", r, "GLfloat", q)
+TRACE_GL_VOID(glMultiTexCoord4x, (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q), (target, s, t, r, q), 5, "GLenum", target, "GLfixed", s, "GLfixed", t, "GLfixed", r, "GLfixed", q)
+TRACE_GL_VOID(glMultiTexCoord4xOES, (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q), (target, s, t, r, q), 5, "GLenum", target, "GLfixed", s, "GLfixed", t, "GLfixed", r, "GLfixed", q)
+TRACE_GL_VOID(glNormal3f, (GLfloat nx, GLfloat ny, GLfloat nz), (nx, ny, nz), 3, "GLfloat", nx, "GLfloat", ny, "GLfloat", nz)
+TRACE_GL_VOID(glNormal3x, (GLfixed nx, GLfixed ny, GLfixed nz), (nx, ny, nz), 3, "GLfixed", nx, "GLfixed", ny, "GLfixed", nz)
+TRACE_GL_VOID(glNormal3xOES, (GLfixed nx, GLfixed ny, GLfixed nz), (nx, ny, nz), 3, "GLfixed", nx, "GLfixed", ny, "GLfixed", nz)
+TRACE_GL_VOID(glNormalPointer, (GLenum type, GLsizei stride, const GLvoid *pointer), (type, stride, pointer), 3, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glOrthof, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glOrthofOES, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glOrthox, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glOrthoxOES, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glPixelStorei, (GLenum pname, GLint param), (pname, param), 2, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glPointParameterf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glPointParameterfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glPointParameterx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glPointParameterxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glPointParameterxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glPointParameterxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glPointSize, (GLfloat size), (size), 1, "GLfloat", size)
+TRACE_GL_VOID(glPointSizePointerOES, (GLenum type, GLsizei stride, const GLvoid *pointer), (type, stride, pointer), 3, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glPointSizex, (GLfixed size), (size), 1, "GLfixed", size)
+TRACE_GL_VOID(glPointSizexOES, (GLfixed size), (size), 1, "GLfixed", size)
+TRACE_GL_VOID(glPolygonOffset, (GLfloat factor, GLfloat units), (factor, units), 2, "GLfloat", factor, "GLfloat", units)
+TRACE_GL_VOID(glPolygonOffsetx, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
+TRACE_GL_VOID(glPolygonOffsetxOES, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
+TRACE_GL_VOID(glPopMatrix, (void), (), 0)
+TRACE_GL_VOID(glProgramBinaryOES, (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length), (program, binaryFormat, binary, length), 4, "GLuint", program, "GLenum", binaryFormat, "const GLvoid *", binary, "GLint", length)
+TRACE_GL_VOID(glPushMatrix, (void), (), 0)
+TRACE_GL(GLbitfield, glQueryMatrixxOES, (GLfixed mantissa[16], GLint exponent[16]), (mantissa, exponent), 2, "GLfixed", mantissa, "GLint", exponent)
+TRACE_GL_VOID(glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels), (x, y, width, height, format, type, pixels), 7, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "GLvoid *", pixels)
+TRACE_GL_VOID(glReleaseShaderCompiler, (void), (), 0)
+TRACE_GL_VOID(glRenderbufferStorage, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleIMG, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageOES, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRotatef, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z), (angle, x, y, z), 4, "GLfloat", angle, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glRotatex, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glRotatexOES, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glSampleCoverage, (GLclampf value, GLboolean invert), (value, invert), 2, "GLclampf", value, "GLboolean", invert)
+TRACE_GL_VOID(glSampleCoveragex, (GLclampx value, GLboolean invert), (value, invert), 2, "GLclampx", value, "GLboolean", invert)
+TRACE_GL_VOID(glSampleCoveragexOES, (GLclampx value, GLboolean invert), (value, invert), 2, "GLclampx", value, "GLboolean", invert)
+TRACE_GL_VOID(glScalef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glScalex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glScalexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glScissor, (GLint x, GLint y, GLsizei width, GLsizei height), (x, y, width, height), 4, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glSelectPerfMonitorCountersAMD, (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList), (monitor, enable, group, numCounters, countersList), 5, "GLuint", monitor, "GLboolean", enable, "GLuint", group, "GLint", numCounters, "GLuint *", countersList)
+TRACE_GL_VOID(glSetFenceNV, (GLuint fence, GLenum condition), (fence, condition), 2, "GLuint", fence, "GLenum", condition)
+TRACE_GL_VOID(glShadeModel, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glShaderBinary, (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length), (n, shaders, binaryformat, binary, length), 5, "GLsizei", n, "const GLuint*", shaders, "GLenum", binaryformat, "const GLvoid*", binary, "GLsizei", length)
+TRACE_GL_VOID(glShaderSource, (GLuint shader, GLsizei count, const GLchar** string, const GLint* length), (shader, count, string, length), 4, "GLuint", shader, "GLsizei", count, "const GLchar**", string, "const GLint*", length)
+TRACE_GL_VOID(glStartTilingQCOM, (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask), (x, y, width, height, preserveMask), 5, "GLuint", x, "GLuint", y, "GLuint", width, "GLuint", height, "GLbitfield", preserveMask)
+TRACE_GL_VOID(glStencilFunc, (GLenum func, GLint ref, GLuint mask), (func, ref, mask), 3, "GLenum", func, "GLint", ref, "GLuint", mask)
+TRACE_GL_VOID(glStencilFuncSeparate, (GLenum face, GLenum func, GLint ref, GLuint mask), (face, func, ref, mask), 4, "GLenum", face, "GLenum", func, "GLint", ref, "GLuint", mask)
+TRACE_GL_VOID(glStencilMask, (GLuint mask), (mask), 1, "GLuint", mask)
+TRACE_GL_VOID(glStencilMaskSeparate, (GLenum face, GLuint mask), (face, mask), 2, "GLenum", face, "GLuint", mask)
+TRACE_GL_VOID(glStencilOp, (GLenum fail, GLenum zfail, GLenum zpass), (fail, zfail, zpass), 3, "GLenum", fail, "GLenum", zfail, "GLenum", zpass)
+TRACE_GL_VOID(glStencilOpSeparate, (GLenum face, GLenum fail, GLenum zfail, GLenum zpass), (face, fail, zfail, zpass), 4, "GLenum", face, "GLenum", fail, "GLenum", zfail, "GLenum", zpass)
+TRACE_GL(GLboolean, glTestFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
+TRACE_GL_VOID(glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glTexEnvf, (GLenum target, GLenum pname, GLfloat param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glTexEnvfv, (GLenum target, GLenum pname, const GLfloat *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glTexEnvi, (GLenum target, GLenum pname, GLint param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glTexEnviv, (GLenum target, GLenum pname, const GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLint *", params)
+TRACE_GL_VOID(glTexEnvx, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexEnvxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexEnvxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexEnvxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexGenfOES, (GLenum coord, GLenum pname, GLfloat param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glTexGenfvOES, (GLenum coord, GLenum pname, const GLfloat *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glTexGeniOES, (GLenum coord, GLenum pname, GLint param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glTexGenivOES, (GLenum coord, GLenum pname, const GLint *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLint *", params)
+TRACE_GL_VOID(glTexGenxOES, (GLenum coord, GLenum pname, GLfixed param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexGenxvOES, (GLenum coord, GLenum pname, const GLfixed *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexImage2D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels), (target, level, internalformat, width, height, border, format, type, pixels), 9, "GLenum", target, "GLint", level, "GLint", internalformat, "GLsizei", width, "GLsizei", height, "GLint", border, "GLenum", format, "GLenum", type, "const GLvoid *", pixels)
+TRACE_GL_VOID(glTexImage3DOES, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels), (target, level, internalformat, width, height, depth, border, format, type, pixels), 10, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLint", border, "GLenum", format, "GLenum", type, "const GLvoid*", pixels)
+TRACE_GL_VOID(glTexParameterf, (GLenum target, GLenum pname, GLfloat param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glTexParameterfv, (GLenum target, GLenum pname, const GLfloat *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glTexParameteri, (GLenum target, GLenum pname, GLint param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glTexParameteriv, (GLenum target, GLenum pname, const GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLint *", params)
+TRACE_GL_VOID(glTexParameterx, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexParameterxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexParameterxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexParameterxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels), (target, level, xoffset, yoffset, width, height, format, type, pixels), 9, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "const GLvoid *", pixels)
+TRACE_GL_VOID(glTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "const GLvoid*", pixels)
+TRACE_GL_VOID(glTranslatef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glTranslatex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glTranslatexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glUniform1f, (GLint location, GLfloat x), (location, x), 2, "GLint", location, "GLfloat", x)
+TRACE_GL_VOID(glUniform1fv, (GLint location, GLsizei count, const GLfloat* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLfloat*", v)
+TRACE_GL_VOID(glUniform1i, (GLint location, GLint x), (location, x), 2, "GLint", location, "GLint", x)
+TRACE_GL_VOID(glUniform1iv, (GLint location, GLsizei count, const GLint* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLint*", v)
+TRACE_GL_VOID(glUniform2f, (GLint location, GLfloat x, GLfloat y), (location, x, y), 3, "GLint", location, "GLfloat", x, "GLfloat", y)
+TRACE_GL_VOID(glUniform2fv, (GLint location, GLsizei count, const GLfloat* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLfloat*", v)
+TRACE_GL_VOID(glUniform2i, (GLint location, GLint x, GLint y), (location, x, y), 3, "GLint", location, "GLint", x, "GLint", y)
+TRACE_GL_VOID(glUniform2iv, (GLint location, GLsizei count, const GLint* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLint*", v)
+TRACE_GL_VOID(glUniform3f, (GLint location, GLfloat x, GLfloat y, GLfloat z), (location, x, y, z), 4, "GLint", location, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glUniform3fv, (GLint location, GLsizei count, const GLfloat* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLfloat*", v)
+TRACE_GL_VOID(glUniform3i, (GLint location, GLint x, GLint y, GLint z), (location, x, y, z), 4, "GLint", location, "GLint", x, "GLint", y, "GLint", z)
+TRACE_GL_VOID(glUniform3iv, (GLint location, GLsizei count, const GLint* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLint*", v)
+TRACE_GL_VOID(glUniform4f, (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w), (location, x, y, z, w), 5, "GLint", location, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", w)
+TRACE_GL_VOID(glUniform4fv, (GLint location, GLsizei count, const GLfloat* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLfloat*", v)
+TRACE_GL_VOID(glUniform4i, (GLint location, GLint x, GLint y, GLint z, GLint w), (location, x, y, z, w), 5, "GLint", location, "GLint", x, "GLint", y, "GLint", z, "GLint", w)
+TRACE_GL_VOID(glUniform4iv, (GLint location, GLsizei count, const GLint* v), (location, count, v), 3, "GLint", location, "GLsizei", count, "const GLint*", v)
+TRACE_GL_VOID(glUniformMatrix2fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), (location, count, transpose, value), 4, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat*", value)
+TRACE_GL_VOID(glUniformMatrix3fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), (location, count, transpose, value), 4, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat*", value)
+TRACE_GL_VOID(glUniformMatrix4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), (location, count, transpose, value), 4, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat*", value)
+TRACE_GL(GLboolean, glUnmapBufferOES, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL_VOID(glUseProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glValidateProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glVertexAttrib1f, (GLuint indx, GLfloat x), (indx, x), 2, "GLuint", indx, "GLfloat", x)
+TRACE_GL_VOID(glVertexAttrib1fv, (GLuint indx, const GLfloat* values), (indx, values), 2, "GLuint", indx, "const GLfloat*", values)
+TRACE_GL_VOID(glVertexAttrib2f, (GLuint indx, GLfloat x, GLfloat y), (indx, x, y), 3, "GLuint", indx, "GLfloat", x, "GLfloat", y)
+TRACE_GL_VOID(glVertexAttrib2fv, (GLuint indx, const GLfloat* values), (indx, values), 2, "GLuint", indx, "const GLfloat*", values)
+TRACE_GL_VOID(glVertexAttrib3f, (GLuint indx, GLfloat x, GLfloat y, GLfloat z), (indx, x, y, z), 4, "GLuint", indx, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glVertexAttrib3fv, (GLuint indx, const GLfloat* values), (indx, values), 2, "GLuint", indx, "const GLfloat*", values)
+TRACE_GL_VOID(glVertexAttrib4f, (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w), (indx, x, y, z, w), 5, "GLuint", indx, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", w)
+TRACE_GL_VOID(glVertexAttrib4fv, (GLuint indx, const GLfloat* values), (indx, values), 2, "GLuint", indx, "const GLfloat*", values)
+TRACE_GL_VOID(glVertexAttribPointer, (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr), (indx, size, type, normalized, stride, ptr), 6, "GLuint", indx, "GLint", size, "GLenum", type, "GLboolean", normalized, "GLsizei", stride, "const GLvoid*", ptr)
+TRACE_GL_VOID(glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glViewport, (GLint x, GLint y, GLsizei width, GLsizei height), (x, y, width, height), 4, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glWeightPointerOES, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
diff --git a/opengl/tests/gl2_java/AndroidManifest.xml b/opengl/tests/gl2_java/AndroidManifest.xml
index 585b63f..8bb6840 100644
--- a/opengl/tests/gl2_java/AndroidManifest.xml
+++ b/opengl/tests/gl2_java/AndroidManifest.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/opengl/tests/gl2_java/res/values/strings.xml b/opengl/tests/gl2_java/res/values/strings.xml
index d718b1d..06bd23c 100644
--- a/opengl/tests/gl2_java/res/values/strings.xml
+++ b/opengl/tests/gl2_java/res/values/strings.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<!-- This file contains resource definitions for displayed strings, allowing
diff --git a/opengl/tests/gl2_jni/AndroidManifest.xml b/opengl/tests/gl2_jni/AndroidManifest.xml
index a72a6a5..1827e5f 100644
--- a/opengl/tests/gl2_jni/AndroidManifest.xml
+++ b/opengl/tests/gl2_jni/AndroidManifest.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/opengl/tests/gl2_jni/res/values/strings.xml b/opengl/tests/gl2_jni/res/values/strings.xml
index e3f7331..a29c74b 100644
--- a/opengl/tests/gl2_jni/res/values/strings.xml
+++ b/opengl/tests/gl2_jni/res/values/strings.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<!-- This file contains resource definitions for displayed strings, allowing
diff --git a/opengl/tests/gl2_yuvtex/Android.mk b/opengl/tests/gl2_yuvtex/Android.mk
new file mode 100644
index 0000000..6304700
--- /dev/null
+++ b/opengl/tests/gl2_yuvtex/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gl2_yuvtex.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv2 \
+ libui
+
+LOCAL_MODULE:= test-opengl-gl2_yuvtex
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
new file mode 100644
index 0000000..602ea1a
--- /dev/null
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+static void printGLString(const char *name, GLenum s) {
+ // fprintf(stderr, "printGLString %s, %d\n", name, s);
+ const char *v = (const char *) glGetString(s);
+ // int error = glGetError();
+ // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+ // (unsigned int) v);
+ // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+ // fprintf(stderr, "GL %s = %s\n", name, v);
+ // else
+ // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+ fprintf(stderr, "GL %s = %s\n", name, v);
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+ "varying vec2 yuvTexCoords;\n"
+ "void main() {\n"
+ " yuvTexCoords = vPosition.xy + vec2(0.5, 0.5);\n"
+ " gl_Position = vPosition;\n"
+ "}\n";
+
+static const char gFragmentShader[] = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "uniform samplerExternalOES yuvTexSampler;\n"
+ "varying vec2 yuvTexCoords;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(yuvTexSampler, yuvTexCoords);\n"
+ "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+ GLuint shader = glCreateShader(shaderType);
+ if (shader) {
+ glShaderSource(shader, 1, &pSource, NULL);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ fprintf(stderr, "Could not compile shader %d:\n%s\n",
+ shaderType, buf);
+ free(buf);
+ }
+ } else {
+ fprintf(stderr, "Guessing at GL_INFO_LOG_LENGTH size\n");
+ char* buf = (char*) malloc(0x1000);
+ if (buf) {
+ glGetShaderInfoLog(shader, 0x1000, NULL, buf);
+ fprintf(stderr, "Could not compile shader %d:\n%s\n",
+ shaderType, buf);
+ free(buf);
+ }
+ }
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+ if (!vertexShader) {
+ return 0;
+ }
+
+ GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+ if (!pixelShader) {
+ return 0;
+ }
+
+ GLuint program = glCreateProgram();
+ if (program) {
+ glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader");
+ glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader");
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = (char*) malloc(bufLength);
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, NULL, buf);
+ fprintf(stderr, "Could not link program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+}
+
+GLuint gProgram;
+GLint gvPositionHandle;
+GLint gYuvTexSamplerHandle;
+
+bool setupGraphics(int w, int h) {
+ gProgram = createProgram(gVertexShader, gFragmentShader);
+ if (!gProgram) {
+ return false;
+ }
+ gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+ checkGlError("glGetAttribLocation");
+ fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n",
+ gvPositionHandle);
+ gYuvTexSamplerHandle = glGetUniformLocation(gProgram, "yuvTexSampler");
+ checkGlError("glGetUniformLocation");
+ fprintf(stderr, "glGetUniformLocation(\"yuvTexSampler\") = %d\n",
+ gYuvTexSamplerHandle);
+
+ glViewport(0, 0, w, h);
+ checkGlError("glViewport");
+ return true;
+}
+
+int align(int x, int a) {
+ return (x + (a-1)) & (~(a-1));
+}
+
+const int yuvTexWidth = 608;
+const int yuvTexHeight = 480;
+const int yuvTexUsage = GraphicBuffer::USAGE_HW_TEXTURE |
+ GraphicBuffer::USAGE_SW_WRITE_RARELY;
+const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12;
+const int yuvTexOffsetY = 0;
+const int yuvTexStrideY = (yuvTexWidth + 0xf) & ~0xf;
+const int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight;
+const int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+const int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2;
+const int yuvTexStrideU = yuvTexStrideV;
+const bool yuvTexSameUV = false;
+static sp<GraphicBuffer> yuvTexBuffer;
+static GLuint yuvTex;
+
+bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) {
+ int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1;
+ int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
+ yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
+ yuvTexUsage);
+ char* buf = NULL;
+ status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+ if (err != 0) {
+ fprintf(stderr, "yuvTexBuffer->lock(...) failed: %d\n", err);
+ return false;
+ }
+ for (int x = 0; x < yuvTexWidth; x++) {
+ for (int y = 0; y < yuvTexHeight; y++) {
+ int parityX = (x / blockWidth) & 1;
+ int parityY = (y / blockHeight) & 1;
+ unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
+ buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
+ if (x < yuvTexWidth / 2 && y < yuvTexHeight / 2) {
+ buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
+ if (yuvTexSameUV) {
+ buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = intensity;
+ } else if (x < yuvTexWidth / 4 && y < yuvTexHeight / 4) {
+ buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
+ buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
+ buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
+ buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = intensity;
+ }
+ }
+ }
+ }
+
+ err = yuvTexBuffer->unlock();
+ if (err != 0) {
+ fprintf(stderr, "yuvTexBuffer->unlock() failed: %d\n", err);
+ return false;
+ }
+
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)yuvTexBuffer->getNativeBuffer();
+ EGLImageKHR img = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ clientBuffer, 0);
+ checkEglError("eglCreateImageKHR");
+ if (img == EGL_NO_IMAGE_KHR) {
+ return false;
+ }
+
+ glGenTextures(1, &yuvTex);
+ checkGlError("glGenTextures");
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex);
+ checkGlError("glBindTexture");
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img);
+ checkGlError("glEGLImageTargetTexture2DOES");
+
+ return true;
+}
+
+const GLfloat gTriangleVertices[] = {
+ -0.5f, 0.5f,
+ -0.5f, -0.5f,
+ 0.5f, -0.5f,
+ 0.5f, 0.5f,
+};
+
+void renderFrame() {
+ glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+ checkGlError("glClearColor");
+ glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ checkGlError("glClear");
+
+ glUseProgram(gProgram);
+ checkGlError("glUseProgram");
+
+ glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+ checkGlError("glVertexAttribPointer");
+ glEnableVertexAttribArray(gvPositionHandle);
+ checkGlError("glEnableVertexAttribArray");
+
+ glUniform1i(gYuvTexSamplerHandle, 0);
+ checkGlError("glUniform1i");
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex);
+ checkGlError("glBindTexture");
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ checkGlError("glDrawArrays");
+}
+
+void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ printf(" %s: ", names[j].name);
+ printf("%d (0x%x)", value, value);
+ }
+ }
+ printf("\n");
+}
+
+int main(int argc, char** argv) {
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+
+ EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLSurface surface;
+ EGLint w, h;
+
+ EGLDisplay dpy;
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+ return 0;
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+ if (returnValue != EGL_TRUE) {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
+ if (returnValue) {
+ printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
+ return 1;
+ }
+
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ printf("Chose this configuration:\n");
+ printEGLConfiguration(dpy, myConfig);
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ printf("gelCreateWindowSurface failed.\n");
+ return 1;
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ printf("eglCreateContext failed\n");
+ return 1;
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ return 1;
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ checkEglError("eglQuerySurface");
+ GLint dim = w < h ? w : h;
+
+ fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ if(!setupYuvTexSurface(dpy, context)) {
+ fprintf(stderr, "Could not set up texture surface.\n");
+ return 1;
+ }
+
+ if(!setupGraphics(w, h)) {
+ fprintf(stderr, "Could not set up graphics.\n");
+ return 1;
+ }
+
+ for (;;) {
+ renderFrame();
+ eglSwapBuffers(dpy, surface);
+ checkEglError("eglSwapBuffers");
+ }
+
+ return 0;
+}
diff --git a/opengl/tests/gl_jni/AndroidManifest.xml b/opengl/tests/gl_jni/AndroidManifest.xml
index 64bd6bf..5d0ec96 100644
--- a/opengl/tests/gl_jni/AndroidManifest.xml
+++ b/opengl/tests/gl_jni/AndroidManifest.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/opengl/tests/gl_jni/res/values/strings.xml b/opengl/tests/gl_jni/res/values/strings.xml
index 880f5c9..aee9fa0 100644
--- a/opengl/tests/gl_jni/res/values/strings.xml
+++ b/opengl/tests/gl_jni/res/values/strings.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<!-- This file contains resource definitions for displayed strings, allowing
diff --git a/opengl/tests/gl_perf/Android.mk b/opengl/tests/gl_perf/Android.mk
new file mode 100644
index 0000000..37647ca
--- /dev/null
+++ b/opengl/tests/gl_perf/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gl2_perf.cpp \
+ filltest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv2 \
+ libui
+
+LOCAL_MODULE:= test-opengl-gl2_perf
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_perf/fill_common.cpp b/opengl/tests/gl_perf/fill_common.cpp
new file mode 100644
index 0000000..a069f67
--- /dev/null
+++ b/opengl/tests/gl_perf/fill_common.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2007 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 "fragment_shaders.cpp"
+
+FILE * fOut = NULL;
+void ptSwap();
+
+static char gCurrentTestName[1024];
+static uint32_t gWidth = 0;
+static uint32_t gHeight = 0;
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ LOGE("after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+ GLuint shader = glCreateShader(shaderType);
+ if (shader) {
+ glShaderSource(shader, 1, &pSource, NULL);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ LOGE("Could not compile shader %d:\n%s\n", shaderType, buf);
+ free(buf);
+ }
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ }
+ return shader;
+}
+
+enum {
+ A_POS,
+ A_COLOR,
+ A_TEX0,
+ A_TEX1
+};
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+ if (!vertexShader) {
+ return 0;
+ }
+
+ GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+ if (!pixelShader) {
+ return 0;
+ }
+
+ GLuint program = glCreateProgram();
+ if (program) {
+ glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader v");
+ glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader p");
+
+ glBindAttribLocation(program, A_POS, "a_pos");
+ glBindAttribLocation(program, A_COLOR, "a_color");
+ glBindAttribLocation(program, A_TEX0, "a_tex0");
+ glBindAttribLocation(program, A_TEX1, "a_tex1");
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = (char*) malloc(bufLength);
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, NULL, buf);
+ LOGE("Could not link program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ checkGlError("createProgram");
+ glUseProgram(program);
+ return program;
+}
+
+uint64_t getTime() {
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
+}
+
+uint64_t gTime;
+void startTimer() {
+ gTime = getTime();
+}
+
+
+static void endTimer(int count) {
+ uint64_t t2 = getTime();
+ double delta = ((double)(t2 - gTime)) / 1000000000;
+ double pixels = (gWidth * gHeight) * count;
+ double mpps = pixels / delta / 1000000;
+ double dc60 = ((double)count) / delta / 60;
+
+ if (fOut) {
+ fprintf(fOut, "%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
+ fflush(fOut);
+ } else {
+ printf("%s, %f, %f\n", gCurrentTestName, mpps, dc60);
+ }
+ LOGI("%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
+}
+
+
+static const char gVertexShader[] =
+ "attribute vec4 a_pos;\n"
+ "attribute vec4 a_color;\n"
+ "attribute vec2 a_tex0;\n"
+ "attribute vec2 a_tex1;\n"
+ "varying vec4 v_color;\n"
+ "varying vec2 v_tex0;\n"
+ "varying vec2 v_tex1;\n"
+ "uniform vec2 u_texOff;\n"
+
+ "void main() {\n"
+ " v_color = a_color;\n"
+ " v_tex0 = a_tex0;\n"
+ " v_tex1 = a_tex1;\n"
+ " v_tex0.x += u_texOff.x;\n"
+ " v_tex1.y += u_texOff.y;\n"
+ " gl_Position = a_pos;\n"
+ "}\n";
+
+static void setupVA() {
+ static const float vtx[] = {
+ -1.0f,-1.0f,
+ 1.0f,-1.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f };
+ static const float color[] = {
+ 1.0f,0.0f,1.0f,1.0f,
+ 0.0f,0.0f,1.0f,1.0f,
+ 1.0f,1.0f,0.0f,1.0f,
+ 1.0f,1.0f,1.0f,1.0f };
+ static const float tex0[] = {
+ 0.0f,0.0f,
+ 1.0f,0.0f,
+ 0.0f,1.0f,
+ 1.0f,1.0f };
+ static const float tex1[] = {
+ 1.0f,0.0f,
+ 1.0f,1.0f,
+ 0.0f,1.0f,
+ 0.0f,0.0f };
+
+ glEnableVertexAttribArray(A_POS);
+ glEnableVertexAttribArray(A_COLOR);
+ glEnableVertexAttribArray(A_TEX0);
+ glEnableVertexAttribArray(A_TEX1);
+
+ glVertexAttribPointer(A_POS, 2, GL_FLOAT, false, 8, vtx);
+ glVertexAttribPointer(A_COLOR, 4, GL_FLOAT, false, 16, color);
+ glVertexAttribPointer(A_TEX0, 2, GL_FLOAT, false, 8, tex0);
+ glVertexAttribPointer(A_TEX1, 2, GL_FLOAT, false, 8, tex1);
+}
+
+static void randUniform(int pgm, const char *var) {
+ int loc = glGetUniformLocation(pgm, var);
+ if (loc >= 0) {
+ float x = ((float)rand()) / RAND_MAX;
+ float y = ((float)rand()) / RAND_MAX;
+ float z = ((float)rand()) / RAND_MAX;
+ float w = ((float)rand()) / RAND_MAX;
+ glUniform4f(loc, x, y, z, w);
+ }
+}
+
+static void doLoop(bool warmup, int pgm, uint32_t passCount) {
+ if (warmup) {
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ ptSwap();
+ glFinish();
+ return;
+ }
+
+ startTimer();
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ for (uint32_t ct=0; ct < passCount; ct++) {
+ int loc = glGetUniformLocation(pgm, "u_texOff");
+ glUniform2f(loc, ((float)ct) / passCount, ((float)ct) / 2.f / passCount);
+
+ randUniform(pgm, "u_color");
+ randUniform(pgm, "u_0");
+ randUniform(pgm, "u_1");
+ randUniform(pgm, "u_2");
+ randUniform(pgm, "u_3");
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ ptSwap();
+ glFinish();
+ endTimer(passCount);
+}
+
+
+static uint32_t rgb(uint32_t r, uint32_t g, uint32_t b)
+{
+ uint32_t ret = 0xff000000;
+ ret |= r & 0xff;
+ ret |= (g & 0xff) << 8;
+ ret |= (b & 0xff) << 16;
+ return ret;
+}
+
+void genTextures() {
+ uint32_t *m = (uint32_t *)malloc(1024*1024*4);
+ for (int y=0; y < 1024; y++){
+ for (int x=0; x < 1024; x++){
+ m[y*1024 + x] = rgb(x, (((x+y) & 0xff) == 0x7f) * 0xff, y);
+ }
+ }
+ glBindTexture(GL_TEXTURE_2D, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ for (int y=0; y < 16; y++){
+ for (int x=0; x < 16; x++){
+ m[y*16 + x] = rgb(x << 4, (((x+y) & 0xf) == 0x7) * 0xff, y << 4);
+ }
+ }
+ glBindTexture(GL_TEXTURE_2D, 2);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ free(m);
+}
+
+static void doSingleTest(uint32_t pgmNum, int tex) {
+ const char *pgmTxt = gFragmentTests[pgmNum]->txt;
+ int pgm = createProgram(gVertexShader, pgmTxt);
+ if (!pgm) {
+ printf("error running test\n");
+ return;
+ }
+ int loc = glGetUniformLocation(pgm, "u_tex0");
+ if (loc >= 0) glUniform1i(loc, 0);
+ loc = glGetUniformLocation(pgm, "u_tex1");
+ if (loc >= 0) glUniform1i(loc, 1);
+
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glActiveTexture(GL_TEXTURE0);
+
+ glBlendFunc(GL_ONE, GL_ONE);
+ glDisable(GL_BLEND);
+ //sprintf(str2, "%i, %i, %i, %i, %i, 0",
+ //useVarColor, texCount, modulateFirstTex, extraMath, tex0);
+ //doLoop(true, pgm, w, h, str2);
+ //doLoop(false, pgm, w, h, str2);
+
+ glEnable(GL_BLEND);
+ sprintf(gCurrentTestName, "%s, %i, %i, 1", gFragmentTests[pgmNum]->name, pgmNum, tex);
+ doLoop(true, pgm, 100);
+ doLoop(false, pgm, 100);
+}
+
diff --git a/opengl/tests/gl_perf/filltest.cpp b/opengl/tests/gl_perf/filltest.cpp
new file mode 100644
index 0000000..3f8faca
--- /dev/null
+++ b/opengl/tests/gl_perf/filltest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 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 <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <string.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <utils/Timers.h>
+#include <EGL/egl.h>
+#include <utils/Log.h>
+
+
+using namespace android;
+
+
+#include "fill_common.cpp"
+
+
+bool doTest(uint32_t w, uint32_t h) {
+ gWidth = w;
+ gHeight = h;
+ setupVA();
+ genTextures();
+
+ printf("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
+
+ for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+ doSingleTest(num, 2);
+ if (gFragmentTests[num]->texCount) {
+ doSingleTest(num, 1);
+ }
+ }
+
+ exit(0);
+ return true;
+}
diff --git a/opengl/tests/gl_perf/fragment_shaders.cpp b/opengl/tests/gl_perf/fragment_shaders.cpp
new file mode 100644
index 0000000..79d5ead
--- /dev/null
+++ b/opengl/tests/gl_perf/fragment_shaders.cpp
@@ -0,0 +1,139 @@
+
+typedef struct FragmentTestRec {
+ const char * name;
+ uint32_t texCount;
+ const char * txt;
+} FragmentTest;
+
+static FragmentTest fpFill = {
+ "Solid color", 0,
+
+ "precision mediump float;\n"
+ "uniform vec4 u_color;\n"
+ "void main() {\n"
+ " gl_FragColor = u_color;\n"
+ "}\n"
+};
+
+static FragmentTest fpGradient = {
+ "Solid gradient", 0,
+
+ "precision mediump float;\n"
+ "varying lowp vec4 v_color;\n"
+ "void main() {\n"
+ " gl_FragColor = v_color;\n"
+ "}\n"
+};
+
+static FragmentTest fpCopyTex = {
+ "Texture copy", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(u_tex0, v_tex0);\n"
+ "}\n"
+};
+
+static FragmentTest fpCopyTexGamma = {
+ "Texture copy with gamma", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " vec4 t = texture2D(u_tex0, v_tex0);\n"
+ " t.rgb = pow(t.rgb, vec3(1.4, 1.4, 1.4));\n"
+ " gl_FragColor = t;\n"
+ "}\n"
+};
+
+static FragmentTest fpTexSpec = {
+ "Texture spec", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " vec4 t = texture2D(u_tex0, v_tex0);\n"
+ " float simSpec = dot(gl_FragCoord.xyz, gl_FragCoord.xyz);\n"
+ " simSpec = pow(clamp(simSpec, 0.1, 1.0), 40.0);\n"
+ " gl_FragColor = t + vec4(simSpec, simSpec, simSpec, simSpec);\n"
+ "}\n"
+};
+
+static FragmentTest fpDepTex = {
+ "Dependent Lookup", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "void main() {\n"
+ " vec4 t = texture2D(u_tex0, v_tex0);\n"
+ " t += texture2D(u_tex0, t.xy);\n"
+ " gl_FragColor = t;\n"
+ "}\n"
+};
+
+static FragmentTest fpModulateConstantTex = {
+ "Texture modulate constant", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "uniform sampler2D u_tex0;\n"
+ "uniform vec4 u_color;\n"
+
+ "void main() {\n"
+ " lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+ " c *= u_color;\n"
+ " gl_FragColor = c;\n"
+ "}\n"
+};
+
+static FragmentTest fpModulateVaryingTex = {
+ "Texture modulate gradient", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "varying lowp vec4 v_color;\n"
+ "uniform sampler2D u_tex0;\n"
+
+ "void main() {\n"
+ " lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+ " c *= v_color;\n"
+ " gl_FragColor = c;\n"
+ "}\n"
+};
+
+static FragmentTest fpModulateVaryingConstantTex = {
+ "Texture modulate gradient constant", 1,
+
+ "precision mediump float;\n"
+ "varying vec2 v_tex0;\n"
+ "varying lowp vec4 v_color;\n"
+ "uniform sampler2D u_tex0;\n"
+ "uniform vec4 u_color;\n"
+
+ "void main() {\n"
+ " lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+ " c *= v_color;\n"
+ " c *= u_color;\n"
+ " gl_FragColor = c;\n"
+ "}\n"
+};
+
+static FragmentTest *gFragmentTests[] = {
+ &fpFill,
+ &fpGradient,
+ &fpCopyTex,
+ &fpCopyTexGamma,
+ &fpTexSpec,
+ &fpDepTex,
+ &fpModulateConstantTex,
+ &fpModulateVaryingTex,
+ &fpModulateVaryingConstantTex,
+
+};
+
+static const size_t gFragmentTestCount = sizeof(gFragmentTests) / sizeof(gFragmentTests[0]);
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
new file mode 100644
index 0000000..9dfcf1c
--- /dev/null
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2007 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 <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+bool doTest(uint32_t w, uint32_t h);
+
+static EGLDisplay dpy;
+static EGLSurface surface;
+
+int main(int argc, char** argv) {
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+
+ EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLint w, h;
+
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+ return 0;
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ if (returnValue != EGL_TRUE) {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
+ if (returnValue) {
+ printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
+ return 0;
+ }
+
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ printf("gelCreateWindowSurface failed.\n");
+ return 0;
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ return 0;
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ checkEglError("eglQuerySurface");
+ GLint dim = w < h ? w : h;
+
+ glViewport(0, 0, w, h);
+
+ for (;;) {
+ doTest(w, h);
+ eglSwapBuffers(dpy, surface);
+ checkEglError("eglSwapBuffers");
+ }
+
+ return 0;
+}
+
+void ptSwap() {
+ eglSwapBuffers(dpy, surface);
+}
+
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
new file mode 100644
index 0000000..dd75a74
--- /dev/null
+++ b/opengl/tests/gl_perfapp/Android.mk
@@ -0,0 +1,54 @@
+#########################################################################
+# OpenGL ES Perf App
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GLPerf
+
+LOCAL_JNI_SHARED_LIBRARIES := libglperf
+
+# Run on Eclair
+LOCAL_SDK_VERSION := 7
+
+include $(BUILD_PACKAGE)
+
+#########################################################################
+# Build JNI Shared Library
+#########################################################################
+
+LOCAL_PATH:= $(LOCAL_PATH)/jni
+
+include $(CLEAR_VARS)
+
+# Optional tag would mean it doesn't get installed by default
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -Werror
+
+LOCAL_SRC_FILES:= \
+ gl_code.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libEGL \
+ libGLESv2
+
+LOCAL_MODULE := libglperf
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gl_perfapp/AndroidManifest.xml b/opengl/tests/gl_perfapp/AndroidManifest.xml
new file mode 100644
index 0000000..ee4bd98
--- /dev/null
+++ b/opengl/tests/gl_perfapp/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.glperf"
+ android:versionName="1.0.0" android:versionCode="10000" >
+ <uses-sdk android:targetSdkVersion="7" android:minSdkVersion="7" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:label="@string/glperf_activity">
+ <activity android:name="GLPerfActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
new file mode 100644
index 0000000..f993371
--- /dev/null
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -0,0 +1,103 @@
+// OpenGL ES 2.0 code
+
+#include <nativehelper/jni.h>
+#define LOG_TAG "GLPerf gl_code.cpp"
+#include <utils/Log.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <utils/Timers.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "../../gl_perf/fill_common.cpp"
+
+
+//////////////////////////
+
+// Width and height of the screen
+
+uint32_t w;
+uint32_t h;
+
+// The stateClock starts at zero and increments by 1 every time we draw a frame. It is used to control which phase of the test we are in.
+
+int stateClock;
+const int doLoopStates = 2;
+const int doSingleTestStates = 2;
+bool done;
+
+// Saves the parameters of the test (so we can print them out when we finish the timing.)
+
+
+int pgm;
+
+void ptSwap() {
+}
+
+void doTest() {
+ uint32_t testNum = stateClock >> 2;
+ int texSize = ((stateClock >> 1) & 0x1) + 1;
+
+ if (testNum >= gFragmentTestCount) {
+ LOGI("done\n");
+ if (fOut) {
+ fclose(fOut);
+ fOut = NULL;
+ }
+ done = true;
+ return;
+ }
+
+ // LOGI("doTest %d %d %d\n", texCount, extraMath, testSubState);
+
+// for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+ doSingleTest(testNum, texSize);
+}
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height);
+ JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj);
+};
+
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+ gWidth = width;
+ gHeight = height;
+ if (!done) {
+ stateClock = 0;
+ done = false;
+ setupVA();
+ genTextures();
+ const char* fileName = "/sdcard/glperf.csv";
+ if (fOut != NULL) {
+ LOGI("Closing partially written output.n");
+ fclose(fOut);
+ fOut = NULL;
+ }
+ LOGI("Writing to: %s\n",fileName);
+ fOut = fopen(fileName, "w");
+ if (fOut == NULL) {
+ LOGE("Could not open: %s\n", fileName);
+ }
+
+ LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
+ if (fOut) fprintf(fOut,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
+ }
+}
+
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj)
+{
+ if (! done) {
+ if (stateClock > 0 && ((stateClock & 1) == 0)) {
+ //endTimer(100);
+ }
+ doTest();
+ stateClock++;
+ } else {
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ }
+}
diff --git a/opengl/tests/gl_perfapp/res/values/strings.xml b/opengl/tests/gl_perfapp/res/values/strings.xml
new file mode 100644
index 0000000..52cd961
--- /dev/null
+++ b/opengl/tests/gl_perfapp/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="glperf_activity">GLPerf</string>
+
+</resources>
+
diff --git a/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfActivity.java b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfActivity.java
new file mode 100644
index 0000000..e3f3abf
--- /dev/null
+++ b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.glperf;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class GLPerfActivity extends Activity {
+
+ GLPerfView mView;
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ mView = new GLPerfView(getApplication());
+ setContentView(mView);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfLib.java b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfLib.java
new file mode 100644
index 0000000..89a0e54
--- /dev/null
+++ b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfLib.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.glperf;
+
+// Wrapper for native library
+
+public class GLPerfLib {
+
+ static {
+ System.loadLibrary("glperf");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+ public static native void init(int width, int height);
+ public static native void step();
+}
diff --git a/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfView.java b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfView.java
new file mode 100644
index 0000000..4ce4a4d
--- /dev/null
+++ b/opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfView.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.glperf;
+/*
+ * 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.
+ */
+
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class GLPerfView extends GLSurfaceView {
+ private static String TAG = "GLPerfView";
+
+ public GLPerfView(Context context) {
+ super(context);
+ init(false, 0, 0);
+ }
+
+ public GLPerfView(Context context, boolean translucent, int depth, int stencil) {
+ super(context);
+ init(translucent, depth, stencil);
+ }
+
+ private void init(boolean translucent, int depth, int stencil) {
+ setEGLContextFactory(new ContextFactory());
+ setEGLConfigChooser( translucent ?
+ new ConfigChooser(8,8,8,8, depth, stencil) :
+ new ConfigChooser(5,6,5,0, depth, stencil));
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ Log.w(TAG, "creating OpenGL ES 2.0 context");
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
+ // printConfigs(egl, display, configs);
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ EGLConfig closestConfig = null;
+ int closestDistance = 1000;
+ for(EGLConfig config : configs) {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+ if (d >= mDepthSize && s>= mStencilSize) {
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+ int distance = Math.abs(r - mRedSize)
+ + Math.abs(g - mGreenSize)
+ + Math.abs(b - mBlueSize)
+ + Math.abs(a - mAlphaSize);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestConfig = config;
+ }
+ }
+ }
+ return closestConfig;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++) {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig config) {
+ int[] attributes = {
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE,
+ EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE,
+ EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = {
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++) {
+ int attribute = attributes[i];
+ String name = names[i];
+ if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+ public void onDrawFrame(GL10 gl) {
+ GLPerfLib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLPerfLib.init(width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing.
+ }
+ }
+}
+
diff --git a/opengl/tests/gl_yuvtex/Android.mk b/opengl/tests/gl_yuvtex/Android.mk
new file mode 100644
index 0000000..a78db25
--- /dev/null
+++ b/opengl/tests/gl_yuvtex/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gl_yuvtex.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-gl_yuvtex
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
new file mode 100644
index 0000000..fbe65f1
--- /dev/null
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+static void printGLString(const char *name, GLenum s) {
+ // fprintf(stderr, "printGLString %s, %d\n", name, s);
+ const char *v = (const char *) glGetString(s);
+ // int error = glGetError();
+ // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+ // (unsigned int) v);
+ // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+ // fprintf(stderr, "GL %s = %s\n", name, v);
+ // else
+ // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+ fprintf(stderr, "GL %s = %s\n", name, v);
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+bool setupGraphics(int w, int h) {
+ glViewport(0, 0, w, h);
+ checkGlError("glViewport");
+ return true;
+}
+
+int align(int x, int a) {
+ return (x + (a-1)) & (~(a-1));
+}
+
+const int yuvTexWidth = 600;
+const int yuvTexHeight = 480;
+const int yuvTexUsage = GraphicBuffer::USAGE_HW_TEXTURE |
+ GraphicBuffer::USAGE_SW_WRITE_RARELY;
+const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12;
+const int yuvTexOffsetY = 0;
+const int yuvTexStrideY = (yuvTexWidth + 0xf) & ~0xf;
+const int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight;
+const int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+const int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2;
+const int yuvTexStrideU = yuvTexStrideV;
+const bool yuvTexSameUV = false;
+static sp<GraphicBuffer> yuvTexBuffer;
+static GLuint yuvTex;
+
+bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) {
+ int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1;
+ int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
+ yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
+ yuvTexUsage);
+ char* buf = NULL;
+ status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+ if (err != 0) {
+ fprintf(stderr, "yuvTexBuffer->lock(...) failed: %d\n", err);
+ return false;
+ }
+ for (int x = 0; x < yuvTexWidth; x++) {
+ for (int y = 0; y < yuvTexHeight; y++) {
+ int parityX = (x / blockWidth) & 1;
+ int parityY = (y / blockHeight) & 1;
+ unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
+ buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
+ if (x < yuvTexWidth / 2 && y < yuvTexHeight / 2) {
+ buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
+ if (yuvTexSameUV) {
+ buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = intensity;
+ } else if (x < yuvTexWidth / 4 && y < yuvTexHeight / 4) {
+ buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
+ buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
+ buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
+ buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = intensity;
+ }
+ }
+ }
+ }
+
+ err = yuvTexBuffer->unlock();
+ if (err != 0) {
+ fprintf(stderr, "yuvTexBuffer->unlock() failed: %d\n", err);
+ return false;
+ }
+
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)yuvTexBuffer->getNativeBuffer();
+ EGLImageKHR img = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ clientBuffer, 0);
+ checkEglError("eglCreateImageKHR");
+ if (img == EGL_NO_IMAGE_KHR) {
+ return false;
+ }
+
+ glGenTextures(1, &yuvTex);
+ checkGlError("glGenTextures");
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex);
+ checkGlError("glBindTexture");
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img);
+ checkGlError("glEGLImageTargetTexture2DOES");
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ checkGlError("glTexParameteri");
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ checkGlError("glTexParameteri");
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ checkGlError("glTexEnvx");
+
+ GLint crop[4] = { 0, 0, yuvTexWidth, yuvTexHeight };
+ glTexParameteriv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_CROP_RECT_OES, crop);
+ checkGlError("glTexParameteriv");
+
+ return true;
+}
+
+void renderFrame(int w, int h) {
+ glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+ checkGlError("glClearColor");
+ glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ checkGlError("glClear");
+
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex);
+ checkGlError("glBindTexture");
+ glEnable(GL_TEXTURE_EXTERNAL_OES);
+ checkGlError("glEnable");
+
+ glDrawTexiOES(0, 0, 0, w, h);
+ checkGlError("glDrawTexiOES");
+}
+
+void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ printf(" %s: ", names[j].name);
+ printf("%d (0x%x)", value, value);
+ }
+ }
+ printf("\n");
+}
+
+int main(int argc, char** argv) {
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+
+ EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE };
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
+ EGL_NONE };
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLSurface surface;
+ EGLint w, h;
+
+ EGLDisplay dpy;
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+ return 0;
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+ if (returnValue != EGL_TRUE) {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
+ if (returnValue) {
+ printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
+ return 1;
+ }
+
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ printf("Chose this configuration:\n");
+ printEGLConfiguration(dpy, myConfig);
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ printf("gelCreateWindowSurface failed.\n");
+ return 1;
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ printf("eglCreateContext failed\n");
+ return 1;
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ return 1;
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ checkEglError("eglQuerySurface");
+ GLint dim = w < h ? w : h;
+
+ fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ if(!setupYuvTexSurface(dpy, context)) {
+ fprintf(stderr, "Could not set up texture surface.\n");
+ return 1;
+ }
+
+ if(!setupGraphics(w, h)) {
+ fprintf(stderr, "Could not set up graphics.\n");
+ return 1;
+ }
+
+ for (;;) {
+ static int dir = -1;
+
+ renderFrame(w, h);
+ eglSwapBuffers(dpy, surface);
+ checkEglError("eglSwapBuffers");
+
+ if (w <= 10 || h <= 10)
+ {
+ dir = -dir;
+ }
+
+ if (w >= 1300 || h >= 900)
+ {
+ dir = -dir;
+ }
+
+
+ w += dir;
+ h += dir;
+ }
+
+ return 0;
+}
diff --git a/opengl/tests/gldual/AndroidManifest.xml b/opengl/tests/gldual/AndroidManifest.xml
index 06f4c4d..a36f4f7 100644
--- a/opengl/tests/gldual/AndroidManifest.xml
+++ b/opengl/tests/gldual/AndroidManifest.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/opengl/tests/gldual/res/values/strings.xml b/opengl/tests/gldual/res/values/strings.xml
index 4267dff..b1f535d 100644
--- a/opengl/tests/gldual/res/values/strings.xml
+++ b/opengl/tests/gldual/res/values/strings.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<!-- This file contains resource definitions for displayed strings, allowing
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
new file mode 100644
index 0000000..743dbf1
--- /dev/null
+++ b/opengl/tests/hwc/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= hwc_stress.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv2 \
+ libui \
+ libhardware \
+
+LOCAL_STATIC_LIBRARIES := \
+ libtestUtil \
+
+LOCAL_C_INCLUDES += \
+ system/extras/tests/include \
+ hardware/libhardware/include \
+
+LOCAL_MODULE:= hwc_stress
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativestresstest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+include $(BUILD_NATIVE_TEST)
diff --git a/opengl/tests/hwc/hwc_stress.cpp b/opengl/tests/hwc/hwc_stress.cpp
new file mode 100644
index 0000000..580eb83
--- /dev/null
+++ b/opengl/tests/hwc/hwc_stress.cpp
@@ -0,0 +1,1262 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Hardware Composer stress test
+ *
+ * Performs a pseudo-random (prandom) sequence of operations to the
+ * Hardware Composer (HWC), for a specified number of passes or for
+ * a specified period of time. By default the period of time is FLT_MAX,
+ * so that the number of passes will take precedence.
+ *
+ * The passes are grouped together, where (pass / passesPerGroup) specifies
+ * which group a particular pass is in. This causes every passesPerGroup
+ * worth of sequential passes to be within the same group. Computationally
+ * intensive operations are performed just once at the beginning of a group
+ * of passes and then used by all the passes in that group. This is done
+ * so as to increase both the average and peak rate of graphic operations,
+ * by moving computationally intensive operations to the beginning of a group.
+ * In particular, at the start of each group of passes a set of
+ * graphic buffers are created, then used by the first and remaining
+ * passes of that group of passes.
+ *
+ * The per-group initialization of the graphic buffers is performed
+ * by a function called initFrames. This function creates an array
+ * of smart pointers to the graphic buffers, in the form of a vector
+ * of vectors. The array is accessed in row major order, so each
+ * row is a vector of smart pointers. All the pointers of a single
+ * row point to graphic buffers which use the same pixel format and
+ * have the same dimension, although it is likely that each one is
+ * filled with a different color. This is done so that after doing
+ * the first HWC prepare then set call, subsequent set calls can
+ * be made with each of the layer handles changed to a different
+ * graphic buffer within the same row. Since the graphic buffers
+ * in a particular row have the same pixel format and dimension,
+ * additional HWC set calls can be made, without having to perform
+ * an HWC prepare call.
+ *
+ * This test supports the following command-line options:
+ *
+ * -v Verbose
+ * -s num Starting pass
+ * -e num Ending pass
+ * -p num Execute the single pass specified by num
+ * -n num Number of set operations to perform after each prepare operation
+ * -t float Maximum time in seconds to execute the test
+ * -d float Delay in seconds performed after each set operation
+ * -D float Delay in seconds performed after the last pass is executed
+ *
+ * Typically the test is executed for a large range of passes. By default
+ * passes 0 through 99999 (100,000 passes) are executed. Although this test
+ * does not validate the generated image, at times it is useful to reexecute
+ * a particular pass and leave the displayed image on the screen for an
+ * extended period of time. This can be done either by setting the -s
+ * and -e options to the desired pass, along with a large value for -D.
+ * This can also be done via the -p option, again with a large value for
+ * the -D options.
+ *
+ * So far this test only contains code to create graphic buffers with
+ * a continuous solid color. Although this test is unable to validate the
+ * image produced, any image that contains other than rectangles of a solid
+ * color are incorrect. Note that the rectangles may use a transparent
+ * color and have a blending operation that causes the color in overlapping
+ * rectangles to be mixed. In such cases the overlapping portions may have
+ * a different color from the rest of the rectangle.
+ */
+
+#include <algorithm>
+#include <assert.h>
+#include <cerrno>
+#include <cmath>
+#include <cstdlib>
+#include <ctime>
+#include <libgen.h>
+#include <sched.h>
+#include <sstream>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <vector>
+
+#include <arpa/inet.h> // For ntohl() and htonl()
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+#define LOG_TAG "hwcStressTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#include <hardware/hwcomposer.h>
+
+using namespace std;
+using namespace android;
+
+const float maxSizeRatio = 1.3; // Graphic buffers can be upto this munch
+ // larger than the default screen size
+const unsigned int passesPerGroup = 10; // A group of passes all use the same
+ // graphic buffers
+
+// Ratios at which rare and frequent conditions should be produced
+const float rareRatio = 0.1;
+const float freqRatio = 0.9;
+
+// Defaults for command-line options
+const bool defaultVerbose = false;
+const unsigned int defaultStartPass = 0;
+const unsigned int defaultEndPass = 99999;
+const unsigned int defaultPerPassNumSet = 10;
+const float defaultPerSetDelay = 0.0; // Default delay after each set
+ // operation. Default delay of
+ // zero used so as to perform the
+ // the set operations as quickly
+ // as possible.
+const float defaultEndDelay = 2.0; // Default delay between completion of
+ // final pass and restart of framework
+const float defaultDuration = FLT_MAX; // A fairly long time, so that
+ // range of passes will have
+ // precedence
+
+// Command-line option settings
+static bool verbose = defaultVerbose;
+static unsigned int startPass = defaultStartPass;
+static unsigned int endPass = defaultEndPass;
+static unsigned int numSet = defaultPerPassNumSet;
+static float perSetDelay = defaultPerSetDelay;
+static float endDelay = defaultEndDelay;
+static float duration = defaultDuration;
+
+// Command-line mutual exclusion detection flags.
+// Corresponding flag set true once an option is used.
+bool eFlag, sFlag, pFlag;
+
+#define MAXSTR 100
+#define MAXCMD 200
+#define BITSPERBYTE 8 // TODO: Obtain from <values.h>, once
+ // it has been added
+
+#define CMD_STOP_FRAMEWORK "stop 2>&1"
+#define CMD_START_FRAMEWORK "start 2>&1"
+
+#define NUMA(a) (sizeof(a) / sizeof(a [0]))
+#define MEMCLR(addr, size) do { \
+ memset((addr), 0, (size)); \
+ } while (0)
+
+// Represent RGB color as fraction of color components.
+// Each of the color components are expected in the range [0.0, 1.0]
+class RGBColor {
+ public:
+ RGBColor(): _r(0.0), _g(0.0), _b(0.0) {};
+ RGBColor(float f): _r(f), _g(f), _b(f) {}; // Gray
+ RGBColor(float r, float g, float b): _r(r), _g(g), _b(b) {};
+ float r(void) const { return _r; }
+ float g(void) const { return _g; }
+ float b(void) const { return _b; }
+
+ private:
+ float _r;
+ float _g;
+ float _b;
+};
+
+// Represent YUV color as fraction of color components.
+// Each of the color components are expected in the range [0.0, 1.0]
+class YUVColor {
+ public:
+ YUVColor(): _y(0.0), _u(0.0), _v(0.0) {};
+ YUVColor(float f): _y(f), _u(0.0), _v(0.0) {}; // Gray
+ YUVColor(float y, float u, float v): _y(y), _u(u), _v(v) {};
+ float y(void) const { return _y; }
+ float u(void) const { return _u; }
+ float v(void) const { return _v; }
+
+ private:
+ float _y;
+ float _u;
+ float _v;
+};
+
+// File scope constants
+static const struct graphicFormat {
+ unsigned int format;
+ const char *desc;
+ unsigned int wMod, hMod; // Width/height mod this value must equal zero
+} graphicFormat[] = {
+ {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888", 1, 1},
+ {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888", 1, 1},
+ {HAL_PIXEL_FORMAT_RGB_888, "RGB888", 1, 1},
+ {HAL_PIXEL_FORMAT_RGB_565, "RGB565", 1, 1},
+ {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888", 1, 1},
+ {HAL_PIXEL_FORMAT_RGBA_5551, "RGBA5551", 1, 1},
+ {HAL_PIXEL_FORMAT_RGBA_4444, "RGBA4444", 1, 1},
+ {HAL_PIXEL_FORMAT_YV12, "YV12", 2, 2},
+};
+const unsigned int blendingOps[] = {
+ HWC_BLENDING_NONE,
+ HWC_BLENDING_PREMULT,
+ HWC_BLENDING_COVERAGE,
+};
+const unsigned int layerFlags[] = {
+ HWC_SKIP_LAYER,
+};
+const vector<unsigned int> vecLayerFlags(layerFlags,
+ layerFlags + NUMA(layerFlags));
+
+const unsigned int transformFlags[] = {
+ HWC_TRANSFORM_FLIP_H,
+ HWC_TRANSFORM_FLIP_V,
+ HWC_TRANSFORM_ROT_90,
+ // ROT_180 & ROT_270 intentionally not listed, because they
+ // they are formed from combinations of the flags already listed.
+};
+const vector<unsigned int> vecTransformFlags(transformFlags,
+ transformFlags + NUMA(transformFlags));
+
+// File scope globals
+static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
+ GraphicBuffer::USAGE_SW_WRITE_RARELY;
+static hw_module_t const *hwcModule;
+static hwc_composer_device_t *hwcDevice;
+static vector <vector <sp<GraphicBuffer> > > frames;
+static EGLDisplay dpy;
+static EGLContext context;
+static EGLSurface surface;
+static EGLint width, height;
+
+// File scope prototypes
+static void execCmd(const char *cmd);
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE);
+static void checkGlError(const char* op);
+static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
+static void printGLString(const char *name, GLenum s);
+static hwc_layer_list_t *createLayerList(size_t numLayers);
+static void freeLayerList(hwc_layer_list_t *list);
+static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans);
+static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans);
+void init(void);
+void initFrames(unsigned int seed);
+void displayList(hwc_layer_list_t *list);
+void displayListPrepareModifiable(hwc_layer_list_t *list);
+void displayListHandles(hwc_layer_list_t *list);
+const char *graphicFormat2str(unsigned int format);
+template <class T> vector<T> vectorRandSelect(const vector<T>& vec, size_t num);
+template <class T> T vectorOr(const vector<T>& vec);
+
+/*
+ * Main
+ *
+ * Performs the following high-level sequence of operations:
+ *
+ * 1. Command-line parsing
+ *
+ * 2. Initialization
+ *
+ * 3. For each pass:
+ *
+ * a. If pass is first pass or in a different group from the
+ * previous pass, initialize the array of graphic buffers.
+ *
+ * b. Create a HWC list with room to specify a prandomly
+ * selected number of layers.
+ *
+ * c. Select a subset of the rows from the graphic buffer array,
+ * such that there is a unique row to be used for each
+ * of the layers in the HWC list.
+ *
+ * d. Prandomly fill in the HWC list with handles
+ * selected from any of the columns of the selected row.
+ *
+ * e. Pass the populated list to the HWC prepare call.
+ *
+ * f. Pass the populated list to the HWC set call.
+ *
+ * g. If additional set calls are to be made, then for each
+ * additional set call, select a new set of handles and
+ * perform the set call.
+ */
+int
+main(int argc, char *argv[])
+{
+ int rv, opt;
+ char *chptr;
+ unsigned int pass;
+ char cmd[MAXCMD];
+ struct timeval startTime, currentTime, delta;
+
+ testSetLogCatTag(LOG_TAG);
+
+ // Parse command line arguments
+ while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) {
+ switch (opt) {
+ case 'd': // Delay after each set operation
+ perSetDelay = strtod(optarg, &chptr);
+ if ((*chptr != '\0') || (perSetDelay < 0.0)) {
+ testPrintE("Invalid command-line specified per pass delay of: "
+ "%s", optarg);
+ exit(1);
+ }
+ break;
+
+ case 'D': // End of test delay
+ // Delay between completion of final pass and restart
+ // of framework
+ endDelay = strtod(optarg, &chptr);
+ if ((*chptr != '\0') || (endDelay < 0.0)) {
+ testPrintE("Invalid command-line specified end of test delay "
+ "of: %s", optarg);
+ exit(2);
+ }
+ break;
+
+ case 't': // Duration
+ duration = strtod(optarg, &chptr);
+ if ((*chptr != '\0') || (duration < 0.0)) {
+ testPrintE("Invalid command-line specified duration of: %s",
+ optarg);
+ exit(3);
+ }
+ break;
+
+ case 'n': // Num set operations per pass
+ numSet = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified num set per pass "
+ "of: %s", optarg);
+ exit(4);
+ }
+ break;
+
+ case 's': // Starting Pass
+ sFlag = true;
+ if (pFlag) {
+ testPrintE("Invalid combination of command-line options.");
+ testPrintE(" The -p option is mutually exclusive from the");
+ testPrintE(" -s and -e options.");
+ exit(5);
+ }
+ startPass = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified starting pass "
+ "of: %s", optarg);
+ exit(6);
+ }
+ break;
+
+ case 'e': // Ending Pass
+ eFlag = true;
+ if (pFlag) {
+ testPrintE("Invalid combination of command-line options.");
+ testPrintE(" The -p option is mutually exclusive from the");
+ testPrintE(" -s and -e options.");
+ exit(7);
+ }
+ endPass = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified ending pass "
+ "of: %s", optarg);
+ exit(8);
+ }
+ break;
+
+ case 'p': // Run a single specified pass
+ pFlag = true;
+ if (sFlag || eFlag) {
+ testPrintE("Invalid combination of command-line options.");
+ testPrintE(" The -p option is mutually exclusive from the");
+ testPrintE(" -s and -e options.");
+ exit(9);
+ }
+ startPass = endPass = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified pass of: %s",
+ optarg);
+ exit(10);
+ }
+ break;
+
+ case 'v': // Verbose
+ verbose = true;
+ break;
+
+ case 'h': // Help
+ case '?':
+ default:
+ testPrintE(" %s [options]", basename(argv[0]));
+ testPrintE(" options:");
+ testPrintE(" -p Execute specified pass");
+ testPrintE(" -s Starting pass");
+ testPrintE(" -e Ending pass");
+ testPrintE(" -t Duration");
+ testPrintE(" -d Delay after each set operation");
+ testPrintE(" -D End of test delay");
+ testPrintE(" -n Num set operations per pass");
+ testPrintE(" -v Verbose");
+ exit(((optopt == 0) || (optopt == '?')) ? 0 : 11);
+ }
+ }
+ if (endPass < startPass) {
+ testPrintE("Unexpected ending pass before starting pass");
+ testPrintE(" startPass: %u endPass: %u", startPass, endPass);
+ exit(12);
+ }
+ if (argc != optind) {
+ testPrintE("Unexpected command-line postional argument");
+ testPrintE(" %s [-s start_pass] [-e end_pass] [-t duration]",
+ basename(argv[0]));
+ exit(13);
+ }
+ testPrintI("duration: %g", duration);
+ testPrintI("startPass: %u", startPass);
+ testPrintI("endPass: %u", endPass);
+ testPrintI("numSet: %u", numSet);
+
+ // Stop framework
+ rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
+ if (rv >= (signed) sizeof(cmd) - 1) {
+ testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
+ exit(14);
+ }
+ execCmd(cmd);
+ testDelay(1.0); // TODO - needs means to query whether asyncronous stop
+ // framework operation has completed. For now, just wait
+ // a long time.
+
+ init();
+
+ // For each pass
+ gettimeofday(&startTime, NULL);
+ for (pass = startPass; pass <= endPass; pass++) {
+ // Stop if duration of work has already been performed
+ gettimeofday(¤tTime, NULL);
+ delta = tvDelta(&startTime, ¤tTime);
+ if (tv2double(&delta) > duration) { break; }
+
+ // Regenerate a new set of test frames when this pass is
+ // either the first pass or is in a different group then
+ // the previous pass. A group of passes are passes that
+ // all have the same quotient when their pass number is
+ // divided by passesPerGroup.
+ if ((pass == startPass)
+ || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) {
+ initFrames(pass / passesPerGroup);
+ }
+
+ testPrintI("==== Starting pass: %u", pass);
+
+ // Cause deterministic sequence of prandom numbers to be
+ // generated for this pass.
+ srand48(pass);
+
+ hwc_layer_list_t *list;
+ list = createLayerList(testRandMod(frames.size()) + 1);
+ if (list == NULL) {
+ testPrintE("createLayerList failed");
+ exit(20);
+ }
+
+ // Prandomly select a subset of frames to be used by this pass.
+ vector <vector <sp<GraphicBuffer> > > selectedFrames;
+ selectedFrames = vectorRandSelect(frames, list->numHwLayers);
+
+ // Any transform tends to create a layer that the hardware
+ // composer is unable to support and thus has to leave for
+ // SurfaceFlinger. Place heavy bias on specifying no transforms.
+ bool noTransform = testRandFract() > rareRatio;
+
+ for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
+ unsigned int idx = testRandMod(selectedFrames[n1].size());
+ sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
+ hwc_layer_t *layer = &list->hwLayers[n1];
+ layer->handle = gBuf->handle;
+
+ layer->blending = blendingOps[testRandMod(NUMA(blendingOps))];
+ layer->flags = (testRandFract() > rareRatio) ? 0
+ : vectorOr(vectorRandSelect(vecLayerFlags,
+ testRandMod(vecLayerFlags.size() + 1)));
+ layer->transform = (noTransform || testRandFract() > rareRatio) ? 0
+ : vectorOr(vectorRandSelect(vecTransformFlags,
+ testRandMod(vecTransformFlags.size() + 1)));
+ layer->sourceCrop.left = testRandMod(gBuf->getWidth());
+ layer->sourceCrop.top = testRandMod(gBuf->getHeight());
+ layer->sourceCrop.right = layer->sourceCrop.left
+ + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1;
+ layer->sourceCrop.bottom = layer->sourceCrop.top
+ + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1;
+ layer->displayFrame.left = testRandMod(width);
+ layer->displayFrame.top = testRandMod(height);
+ layer->displayFrame.right = layer->displayFrame.left
+ + testRandMod(width - layer->displayFrame.left) + 1;
+ layer->displayFrame.bottom = layer->displayFrame.top
+ + testRandMod(height - layer->displayFrame.top) + 1;
+
+ // Increase the frequency that a scale factor of 1.0 from
+ // the sourceCrop to displayFrame occurs. This is the
+ // most common scale factor used by applications and would
+ // be rarely produced by this stress test without this
+ // logic.
+ if (testRandFract() <= freqRatio) {
+ // Only change to scale factor to 1.0 if both the
+ // width and height will fit.
+ int sourceWidth = layer->sourceCrop.right
+ - layer->sourceCrop.left;
+ int sourceHeight = layer->sourceCrop.bottom
+ - layer->sourceCrop.top;
+ if (((layer->displayFrame.left + sourceWidth) <= width)
+ && ((layer->displayFrame.top + sourceHeight) <= height)) {
+ layer->displayFrame.right = layer->displayFrame.left
+ + sourceWidth;
+ layer->displayFrame.bottom = layer->displayFrame.top
+ + sourceHeight;
+ }
+ }
+
+ layer->visibleRegionScreen.numRects = 1;
+ layer->visibleRegionScreen.rects = &layer->displayFrame;
+ }
+
+ // Perform prepare operation
+ if (verbose) { testPrintI("Prepare:"); displayList(list); }
+ hwcDevice->prepare(hwcDevice, list);
+ if (verbose) {
+ testPrintI("Post Prepare:");
+ displayListPrepareModifiable(list);
+ }
+
+ // Turn off the geometry changed flag
+ list->flags &= ~HWC_GEOMETRY_CHANGED;
+
+ // Perform the set operation(s)
+ if (verbose) {testPrintI("Set:"); }
+ for (unsigned int n1 = 0; n1 < numSet; n1++) {
+ if (verbose) {displayListHandles(list); }
+ hwcDevice->set(hwcDevice, dpy, surface, list);
+
+ // Prandomly select a new set of handles
+ for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
+ unsigned int idx = testRandMod(selectedFrames[n1].size());
+ sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
+ hwc_layer_t *layer = &list->hwLayers[n1];
+ layer->handle = (native_handle_t *) gBuf->handle;
+ }
+
+ testDelay(perSetDelay);
+ }
+
+
+ freeLayerList(list);
+ testPrintI("==== Completed pass: %u", pass);
+ }
+
+ testDelay(endDelay);
+
+ // Start framework
+ rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
+ if (rv >= (signed) sizeof(cmd) - 1) {
+ testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
+ exit(21);
+ }
+ execCmd(cmd);
+
+ testPrintI("Successfully completed %u passes", pass - startPass);
+
+ return 0;
+}
+
+/*
+ * Execute Command
+ *
+ * Executes the command pointed to by cmd. Output from the
+ * executed command is captured and sent to LogCat Info. Once
+ * the command has finished execution, it's exit status is captured
+ * and checked for an exit status of zero. Any other exit status
+ * causes diagnostic information to be printed and an immediate
+ * testcase failure.
+ */
+static void execCmd(const char *cmd)
+{
+ FILE *fp;
+ int rv;
+ int status;
+ char str[MAXSTR];
+
+ // Display command to be executed
+ testPrintI("cmd: %s", cmd);
+
+ // Execute the command
+ fflush(stdout);
+ if ((fp = popen(cmd, "r")) == NULL) {
+ testPrintE("execCmd popen failed, errno: %i", errno);
+ exit(30);
+ }
+
+ // Obtain and display each line of output from the executed command
+ while (fgets(str, sizeof(str), fp) != NULL) {
+ if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
+ str[strlen(str) - 1] = '\0';
+ }
+ testPrintI(" out: %s", str);
+ }
+
+ // Obtain and check return status of executed command.
+ // Fail on non-zero exit status
+ status = pclose(fp);
+ if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
+ testPrintE("Unexpected command failure");
+ testPrintE(" status: %#x", status);
+ if (WIFEXITED(status)) {
+ testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
+ }
+ if (WIFSIGNALED(status)) {
+ testPrintE("WTERMSIG: %i", WTERMSIG(status));
+ }
+ exit(31);
+ }
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal) {
+ if (returnVal != EGL_TRUE) {
+ testPrintE("%s() returned %d", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ testPrintE("after %s() eglError %s (0x%x)",
+ op, EGLUtils::strerror(error), error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ testPrintE("after %s() glError (0x%x)", op, error);
+ }
+}
+
+static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ testPrintI(" %s: %d (%#x)", names[j].name, value, value);
+ }
+ }
+ testPrintI("");
+}
+
+static void printGLString(const char *name, GLenum s)
+{
+ const char *v = (const char *) glGetString(s);
+
+ if (v == NULL) {
+ testPrintI("GL %s unknown", name);
+ } else {
+ testPrintI("GL %s = %s", name, v);
+ }
+}
+
+/*
+ * createLayerList
+ * dynamically creates layer list with numLayers worth
+ * of hwLayers entries.
+ */
+static hwc_layer_list_t *createLayerList(size_t numLayers)
+{
+ hwc_layer_list_t *list;
+
+ size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t);
+ if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
+ return NULL;
+ }
+ list->flags = HWC_GEOMETRY_CHANGED;
+ list->numHwLayers = numLayers;
+
+ return list;
+}
+
+/*
+ * freeLayerList
+ * Frees memory previous allocated via createLayerList().
+ */
+static void freeLayerList(hwc_layer_list_t *list)
+{
+ free(list);
+}
+
+static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans)
+{
+ unsigned char* buf = NULL;
+ status_t err;
+ uint32_t pixel;
+
+ // RGB 2 YUV conversion ratios
+ const struct rgb2yuvRatios {
+ int format;
+ float weightRed;
+ float weightBlu;
+ float weightGrn;
+ } rgb2yuvRatios[] = {
+ { HAL_PIXEL_FORMAT_YV12, 0.299, 0.114, 0.587 },
+ };
+
+ const struct rgbAttrib {
+ int format;
+ bool hostByteOrder;
+ size_t bytes;
+ size_t rOffset;
+ size_t rSize;
+ size_t gOffset;
+ size_t gSize;
+ size_t bOffset;
+ size_t bSize;
+ size_t aOffset;
+ size_t aSize;
+ } rgbAttributes[] = {
+ {HAL_PIXEL_FORMAT_RGBA_8888, false, 4, 0, 8, 8, 8, 16, 8, 24, 8},
+ {HAL_PIXEL_FORMAT_RGBX_8888, false, 4, 0, 8, 8, 8, 16, 8, 0, 0},
+ {HAL_PIXEL_FORMAT_RGB_888, false, 3, 0, 8, 8, 8, 16, 8, 0, 0},
+ {HAL_PIXEL_FORMAT_RGB_565, true, 2, 0, 5, 5, 6, 11, 5, 0, 0},
+ {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8, 8, 8, 0, 8, 24, 8},
+ {HAL_PIXEL_FORMAT_RGBA_5551, true , 2, 0, 5, 5, 5, 10, 5, 15, 1},
+ {HAL_PIXEL_FORMAT_RGBA_4444, false, 2, 12, 4, 0, 4, 4, 4, 8, 4},
+ };
+
+ // If YUV format, convert color and pass work to YUV color fill
+ for (unsigned int n1 = 0; n1 < NUMA(rgb2yuvRatios); n1++) {
+ if (gBuf->getPixelFormat() == rgb2yuvRatios[n1].format) {
+ float wr = rgb2yuvRatios[n1].weightRed;
+ float wb = rgb2yuvRatios[n1].weightBlu;
+ float wg = rgb2yuvRatios[n1].weightGrn;
+ float y = wr * color.r() + wb * color.b() + wg * color.g();
+ float u = 0.5 * ((color.b() - y) / (1 - wb)) + 0.5;
+ float v = 0.5 * ((color.r() - y) / (1 - wr)) + 0.5;
+ YUVColor yuvColor(y, u, v);
+ fillColor(gBuf, yuvColor, trans);
+ return;
+ }
+ }
+
+ const struct rgbAttrib *attrib;
+ for (attrib = rgbAttributes; attrib < rgbAttributes + NUMA(rgbAttributes);
+ attrib++) {
+ if (attrib->format == gBuf->getPixelFormat()) { break; }
+ }
+ if (attrib >= rgbAttributes + NUMA(rgbAttributes)) {
+ testPrintE("fillColor rgb unsupported format of: %u",
+ gBuf->getPixelFormat());
+ exit(50);
+ }
+
+ pixel = htonl((uint32_t) (((1 << attrib->rSize) - 1) * color.r())
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->rOffset + attrib->rSize)));
+ pixel |= htonl((uint32_t) (((1 << attrib->gSize) - 1) * color.g())
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->gOffset + attrib->gSize)));
+ pixel |= htonl((uint32_t) (((1 << attrib->bSize) - 1) * color.b())
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->bOffset + attrib->bSize)));
+ if (attrib->aSize) {
+ pixel |= htonl((uint32_t) (((1 << attrib->aSize) - 1) * trans)
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->aOffset + attrib->aSize)));
+ }
+ if (attrib->hostByteOrder) {
+ pixel = ntohl(pixel);
+ pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE;
+ }
+
+ err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+ if (err != 0) {
+ testPrintE("fillColor rgb lock failed: %d", err);
+ exit(51);
+ }
+
+ for (unsigned int row = 0; row < gBuf->getHeight(); row++) {
+ for (unsigned int col = 0; col < gBuf->getWidth(); col++) {
+ memmove(buf, &pixel, attrib->bytes);
+ buf += attrib->bytes;
+ }
+ for (unsigned int pad = 0;
+ pad < (gBuf->getStride() - gBuf->getWidth()) * attrib->bytes;
+ pad++) {
+ *buf++ = testRandMod(256);
+ }
+ }
+
+ err = gBuf->unlock();
+ if (err != 0) {
+ testPrintE("fillColor rgb unlock failed: %d", err);
+ exit(52);
+ }
+}
+
+static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans)
+{
+ unsigned char* buf = NULL;
+ status_t err;
+ unsigned int width = gBuf->getWidth();
+ unsigned int height = gBuf->getHeight();
+
+ const struct yuvAttrib {
+ int format;
+ bool planar;
+ unsigned int uSubSampX;
+ unsigned int uSubSampY;
+ unsigned int vSubSampX;
+ unsigned int vSubSampY;
+ } yuvAttributes[] = {
+ { HAL_PIXEL_FORMAT_YV12, true, 2, 2, 2, 2},
+ };
+
+ const struct yuvAttrib *attrib;
+ for (attrib = yuvAttributes; attrib < yuvAttributes + NUMA(yuvAttributes);
+ attrib++) {
+ if (attrib->format == gBuf->getPixelFormat()) { break; }
+ }
+ if (attrib >= yuvAttributes + NUMA(yuvAttributes)) {
+ testPrintE("fillColor yuv unsupported format of: %u",
+ gBuf->getPixelFormat());
+ exit(60);
+ }
+
+ assert(attrib->planar == true); // So far, only know how to handle planar
+
+ err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+ if (err != 0) {
+ testPrintE("fillColor lock failed: %d", err);
+ exit(61);
+ }
+
+ // Fill in Y component
+ for (unsigned int row = 0; row < height; row++) {
+ for (unsigned int col = 0; col < width; col++) {
+ *buf++ = 255 * color.y();
+ }
+ for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth();
+ pad++) {
+ *buf++ = testRandMod(256);
+ }
+ }
+
+ // Fill in U component
+ for (unsigned int row = 0; row < height; row += attrib->uSubSampY) {
+ for (unsigned int col = 0; col < width; col += attrib->uSubSampX) {
+ *buf++ = 255 * color.u();
+ }
+ for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth();
+ pad += attrib->uSubSampX) {
+ *buf++ = testRandMod(256);
+ }
+ }
+
+ // Fill in V component
+ for (unsigned int row = 0; row < height; row += attrib->vSubSampY) {
+ for (unsigned int col = 0; col < width; col += attrib->vSubSampX) {
+ *buf++ = 255 * color.v();
+ }
+ for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth();
+ pad += attrib->vSubSampX) {
+ *buf++ = testRandMod(256);
+ }
+ }
+
+ err = gBuf->unlock();
+ if (err != 0) {
+ testPrintE("fillColor unlock failed: %d", err);
+ exit(62);
+ }
+}
+
+void init(void)
+{
+ int rv;
+
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+ EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint sConfigAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+ EGLint majorVersion, minorVersion;
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ testPrintE("eglGetDisplay returned EGL_NO_DISPLAY");
+ exit(70);
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ testPrintI("EGL version %d.%d", majorVersion, minorVersion);
+ if (returnValue != EGL_TRUE) {
+ testPrintE("eglInitialize failed");
+ exit(71);
+ }
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ if (window == NULL) {
+ testPrintE("android_createDisplaySurface failed");
+ exit(72);
+ }
+ returnValue = EGLUtils::selectConfigForNativeWindow(dpy,
+ sConfigAttribs, window, &myConfig);
+ if (returnValue) {
+ testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d",
+ returnValue);
+ exit(73);
+ }
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ testPrintI("Chose this configuration:");
+ printEGLConfiguration(dpy, myConfig);
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ testPrintE("gelCreateWindowSurface failed.");
+ exit(74);
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, contextAttribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ testPrintE("eglCreateContext failed");
+ exit(75);
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ testPrintE("eglMakeCurrent failed");
+ exit(76);
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &width);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &height);
+ checkEglError("eglQuerySurface");
+
+ testPrintI("Window dimensions: %d x %d", width, height);
+
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) {
+ testPrintE("hw_get_module failed, rv: %i", rv);
+ errno = -rv;
+ perror(NULL);
+ exit(77);
+ }
+ if ((rv = hwc_open(hwcModule, &hwcDevice)) != 0) {
+ testPrintE("hwc_open failed, rv: %i", rv);
+ errno = -rv;
+ perror(NULL);
+ exit(78);
+ }
+
+ testPrintI("");
+}
+
+/*
+ * Initialize Frames
+ *
+ * Creates an array of graphic buffers, within the global variable
+ * named frames. The graphic buffers are contained within a vector of
+ * vectors. All the graphic buffers in a particular row are of the same
+ * format and dimension. Each graphic buffer is uniformly filled with a
+ * prandomly selected color. It is likely that each buffer, even
+ * in the same row, will be filled with a unique color.
+ */
+void initFrames(unsigned int seed)
+{
+ int rv;
+ const size_t maxRows = 5;
+ const size_t minCols = 2; // Need at least double buffering
+ const size_t maxCols = 4; // One more than triple buffering
+
+ if (verbose) { testPrintI("initFrames seed: %u", seed); }
+ srand48(seed);
+ size_t rows = testRandMod(maxRows) + 1;
+
+ frames.clear();
+ frames.resize(rows);
+
+ for (unsigned int row = 0; row < rows; row++) {
+ // All frames within a row have to have the same format and
+ // dimensions. Width and height need to be >= 1.
+ unsigned int formatIdx = testRandMod(NUMA(graphicFormat));
+ const struct graphicFormat *formatPtr = &graphicFormat[formatIdx];
+ int format = formatPtr->format;
+
+ // Pick width and height, which must be >= 1 and the size
+ // mod the wMod/hMod value must be equal to 0.
+ size_t w = (width * maxSizeRatio) * testRandFract();
+ size_t h = (height * maxSizeRatio) * testRandFract();
+ w = max(1u, w);
+ h = max(1u, h);
+ if ((w % formatPtr->wMod) != 0) {
+ w += formatPtr->wMod - (w % formatPtr->wMod);
+ }
+ if ((h % formatPtr->hMod) != 0) {
+ h += formatPtr->hMod - (h % formatPtr->hMod);
+ }
+ if (verbose) {
+ testPrintI(" frame %u width: %u height: %u format: %u %s",
+ row, w, h, format, graphicFormat2str(format));
+ }
+
+ size_t cols = testRandMod((maxCols + 1) - minCols) + minCols;
+ frames[row].resize(cols);
+ for (unsigned int col = 0; col < cols; col++) {
+ RGBColor color(testRandFract(), testRandFract(), testRandFract());
+ float transp = testRandFract();
+
+ frames[row][col] = new GraphicBuffer(w, h, format, texUsage);
+ if ((rv = frames[row][col]->initCheck()) != NO_ERROR) {
+ testPrintE("GraphicBuffer initCheck failed, rv: %i", rv);
+ testPrintE(" frame %u width: %u height: %u format: %u %s",
+ row, w, h, format, graphicFormat2str(format));
+ exit(80);
+ }
+
+ fillColor(frames[row][col].get(), color, transp);
+ if (verbose) {
+ testPrintI(" buf: %p handle: %p color: <%f, %f, %f> "
+ "transp: %f",
+ frames[row][col].get(), frames[row][col]->handle,
+ color.r(), color.g(), color.b(), transp);
+ }
+ }
+ }
+}
+
+void displayList(hwc_layer_list_t *list)
+{
+ testPrintI(" flags: %#x%s", list->flags,
+ (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : "");
+ testPrintI(" numHwLayers: %u", list->numHwLayers);
+
+ for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+ testPrintI(" layer %u compositionType: %#x%s%s", layer,
+ list->hwLayers[layer].compositionType,
+ (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
+ ? " FRAMEBUFFER" : "",
+ (list->hwLayers[layer].compositionType == HWC_OVERLAY)
+ ? " OVERLAY" : "");
+
+ testPrintI(" hints: %#x",
+ list->hwLayers[layer].hints,
+ (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
+ ? " TRIPLE_BUFFER" : "",
+ (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
+ ? " CLEAR_FB" : "");
+
+ testPrintI(" flags: %#x%s",
+ list->hwLayers[layer].flags,
+ (list->hwLayers[layer].flags & HWC_SKIP_LAYER)
+ ? " SKIP_LAYER" : "");
+
+ testPrintI(" handle: %p",
+ list->hwLayers[layer].handle);
+
+ // Intentionally skipped display of ROT_180 & ROT_270,
+ // which are formed from combinations of the other flags.
+ testPrintI(" transform: %#x%s%s%s",
+ list->hwLayers[layer].transform,
+ (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H)
+ ? " FLIP_H" : "",
+ (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V)
+ ? " FLIP_V" : "",
+ (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90)
+ ? " ROT_90" : "");
+
+ testPrintI(" blending: %#x",
+ list->hwLayers[layer].blending,
+ (list->hwLayers[layer].blending == HWC_BLENDING_NONE)
+ ? " NONE" : "",
+ (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT)
+ ? " PREMULT" : "",
+ (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE)
+ ? " COVERAGE" : "");
+
+ testPrintI(" sourceCrop: [%i, %i, %i, %i]",
+ list->hwLayers[layer].sourceCrop.left,
+ list->hwLayers[layer].sourceCrop.top,
+ list->hwLayers[layer].sourceCrop.right,
+ list->hwLayers[layer].sourceCrop.bottom);
+
+ testPrintI(" displayFrame: [%i, %i, %i, %i]",
+ list->hwLayers[layer].displayFrame.left,
+ list->hwLayers[layer].displayFrame.top,
+ list->hwLayers[layer].displayFrame.right,
+ list->hwLayers[layer].displayFrame.bottom);
+ testPrintI(" scaleFactor: [%f %f]",
+ (float) (list->hwLayers[layer].displayFrame.right
+ - list->hwLayers[layer].displayFrame.left)
+ / (float) (list->hwLayers[layer].sourceCrop.right
+ - list->hwLayers[layer].sourceCrop.left),
+ (float) (list->hwLayers[layer].displayFrame.bottom
+ - list->hwLayers[layer].displayFrame.top)
+ / (float) (list->hwLayers[layer].sourceCrop.bottom
+ - list->hwLayers[layer].sourceCrop.top));
+ }
+}
+
+/*
+ * Display List Prepare Modifiable
+ *
+ * Displays the portions of a list that are meant to be modified by
+ * a prepare call.
+ */
+void displayListPrepareModifiable(hwc_layer_list_t *list)
+{
+ for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+ testPrintI(" layer %u compositionType: %#x%s%s", layer,
+ list->hwLayers[layer].compositionType,
+ (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
+ ? " FRAMEBUFFER" : "",
+ (list->hwLayers[layer].compositionType == HWC_OVERLAY)
+ ? " OVERLAY" : "");
+ testPrintI(" hints: %#x%s%s",
+ list->hwLayers[layer].hints,
+ (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
+ ? " TRIPLE_BUFFER" : "",
+ (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
+ ? " CLEAR_FB" : "");
+ }
+}
+
+/*
+ * Display List Handles
+ *
+ * Displays the handles of all the graphic buffers in the list.
+ */
+void displayListHandles(hwc_layer_list_t *list)
+{
+ const unsigned int maxLayersPerLine = 6;
+
+ ostringstream str(" layers:");
+ for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+ str << ' ' << list->hwLayers[layer].handle;
+ if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1))
+ && (layer != list->numHwLayers - 1)) {
+ testPrintI("%s", str.str().c_str());
+ str.str(" ");
+ }
+ }
+ testPrintI("%s", str.str().c_str());
+}
+
+const char *graphicFormat2str(unsigned int format)
+{
+ const static char *unknown = "unknown";
+
+ for (unsigned int n1 = 0; n1 < NUMA(graphicFormat); n1++) {
+ if (format == graphicFormat[n1].format) {
+ return graphicFormat[n1].desc;
+ }
+ }
+
+ return unknown;
+}
+
+/*
+ * Vector Random Select
+ *
+ * Prandomly selects and returns num elements from vec.
+ */
+template <class T>
+vector<T> vectorRandSelect(const vector<T>& vec, size_t num)
+{
+ vector<T> rv = vec;
+
+ while (rv.size() > num) {
+ rv.erase(rv.begin() + testRandMod(rv.size()));
+ }
+
+ return rv;
+}
+
+/*
+ * Vector Or
+ *
+ * Or's togethen the values of each element of vec and returns the result.
+ */
+template <class T>
+T vectorOr(const vector<T>& vec)
+{
+ T rv = 0;
+
+ for (size_t n1 = 0; n1 < vec.size(); n1++) {
+ rv |= vec[n1];
+ }
+
+ return rv;
+}
diff --git a/opengl/tests/testFramerate/Android.mk b/opengl/tests/testFramerate/Android.mk
new file mode 100644
index 0000000..500abf3
--- /dev/null
+++ b/opengl/tests/testFramerate/Android.mk
@@ -0,0 +1,19 @@
+#########################################################################
+# Test framerate and look for hiccups
+#########################################################################
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestFramerate
+
+include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testFramerate/AndroidManifest.xml b/opengl/tests/testFramerate/AndroidManifest.xml
new file mode 100644
index 0000000..85617f4
--- /dev/null
+++ b/opengl/tests/testFramerate/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testframerate">
+ <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" />
+
+ <application
+ android:label="@string/testFramerate_activity">
+ <activity android:name="TestFramerateActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/testFramerate/res/values/strings.xml b/opengl/tests/testFramerate/res/values/strings.xml
new file mode 100644
index 0000000..baadf0e
--- /dev/null
+++ b/opengl/tests/testFramerate/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="testFramerate_activity">TestFramerate</string>
+
+</resources>
+
diff --git a/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java
new file mode 100644
index 0000000..cbe279b
--- /dev/null
+++ b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testframerate;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class TestFramerateActivity extends Activity {
+
+ TestFramerateView mView;
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new TestFramerateView(getApplication());
+ setContentView(mView);
+ mView.setFocusableInTouchMode(true);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java
new file mode 100644
index 0000000..f3fb5de
--- /dev/null
+++ b/opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testframerate;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.SystemProperties;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+
+class TestFramerateView extends GLSurfaceView {
+ private static String TAG = "TestFramerateView";
+
+ public TestFramerateView(Context context) {
+ super(context);
+ setEGLContextClientVersion(2);
+ setRenderer(new Renderer());
+ }
+
+ private long mLastTime_us = 0;
+ private long mNumShortFramesElapsed = 0;
+ private void registerTime(long now_us) {
+ long longFrameTime_ms = Integer.parseInt(SystemProperties.get("debug.longframe_ms", "16"));
+ long elapsedTime_us = now_us - mLastTime_us;
+ float fps = 1000000.f / elapsedTime_us;
+ if (mLastTime_us > 0 && elapsedTime_us > longFrameTime_ms*1000) {
+ Log.v(TAG, "Long frame: " + elapsedTime_us/1000.f + " ms (" + fps + " fps)");
+ if (mNumShortFramesElapsed > 0) {
+ Log.v(TAG, " Short frames since last long frame: " + mNumShortFramesElapsed);
+ mNumShortFramesElapsed = 0;
+ }
+ } else {
+ ++mNumShortFramesElapsed;
+ }
+
+ mLastTime_us = now_us;
+ }
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ public Renderer() {
+ }
+
+
+ public void onDrawFrame(GL10 gl) {
+ long now_us = System.nanoTime() / 1000;
+ registerTime(now_us);
+
+ float red = (now_us % 1000000) / 1000000.f;
+ float green = (now_us % 2000000) / 2000000.f;
+ float blue = (now_us % 3000000) / 3000000.f;
+ GLES20.glClearColor(red, green, blue, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ }
+
+ }
+}
diff --git a/opengl/tests/testLatency/Android.mk b/opengl/tests/testLatency/Android.mk
new file mode 100644
index 0000000..96417c7
--- /dev/null
+++ b/opengl/tests/testLatency/Android.mk
@@ -0,0 +1,20 @@
+#########################################################################
+# Test end-to-end latency.
+#########################################################################
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SDK_VERSION := 8
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestLatency
+
+include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testLatency/AndroidManifest.xml b/opengl/tests/testLatency/AndroidManifest.xml
new file mode 100644
index 0000000..59f2643
--- /dev/null
+++ b/opengl/tests/testLatency/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testlatency">
+ <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" />
+
+ <application
+ android:label="@string/testLatency_activity">
+ <activity android:name="TestLatencyActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/testLatency/res/values/strings.xml b/opengl/tests/testLatency/res/values/strings.xml
new file mode 100644
index 0000000..d80b77c
--- /dev/null
+++ b/opengl/tests/testLatency/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="testLatency_activity">TestLatency</string>
+
+</resources>
+
diff --git a/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java
new file mode 100644
index 0000000..ed993cb
--- /dev/null
+++ b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testlatency;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class TestLatencyActivity extends Activity {
+
+ TestLatencyView mView;
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new TestLatencyView(getApplication());
+ setContentView(mView);
+ mView.setFocusableInTouchMode(true);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java
new file mode 100644
index 0000000..d62bf17
--- /dev/null
+++ b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testlatency;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class TestLatencyView extends GLSurfaceView {
+ private static String TAG = "TestLatencyiew";
+ private float mX;
+ private float mY;
+ private float mDX;
+ private float mDY;
+ private long mT;
+ private long mDT;
+
+ public TestLatencyView(Context context) {
+ super(context);
+ setEGLContextClientVersion(2);
+ setRenderer(new Renderer());
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_MOVE:
+ float x = event.getX();
+ float y = event.getY();
+ long t = event.getEventTime();
+ synchronized(this) {
+ mDT = t - mT;
+ mT = t;
+ mDX = x - mX;
+ mX = x;
+ mDY = y - mY;
+ mY = y;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ private float mScaleX, mScaleY, mOffsetX, mOffsetY;
+ private final float MS_PER_FRAME = 1000 / 60;
+ public Renderer() {
+ mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4)
+ .order(ByteOrder.nativeOrder()).asFloatBuffer();
+ }
+
+
+ public void onDrawFrame(GL10 gl) {
+ GLES20.glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
+ GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+ GLES20.glUseProgram(mProgram);
+ checkGlError("glUseProgram");
+
+ float x, y, dx, dy;
+ long t, dt;
+ synchronized(TestLatencyView.this) {
+ x = mX;
+ y = mY;
+ dx = mDX;
+ dy = mDY;
+ dt = mDT;
+ }
+
+ if (dt > 0) {
+ dx = dx * MS_PER_FRAME / dt;
+ dy = dy * MS_PER_FRAME / dt;
+ }
+
+ GLES20.glEnableVertexAttribArray(mvPositionHandle);
+ checkGlError("glEnableVertexAttribArray");
+ GLES20.glEnableVertexAttribArray(mvColorHandle);
+ checkGlError("glEnableVertexAttribArray");
+ for(int step = 0; step < 8; step++) {
+ float sx = (x + dx * step) * mScaleX + mOffsetX;
+ float sy = (y + dy * step) * mScaleY + mOffsetY;
+ int cbase = step * 4;
+
+ for (int i = 0; i < mTriangleVerticesData.length; i += 6) {
+ mTriangleVerticesData2[i] = sx + mTriangleVerticesData[i];
+ mTriangleVerticesData2[i+1] = -sy + mTriangleVerticesData[i+1];
+ mTriangleVerticesData2[i+2] = mColors[cbase];
+ mTriangleVerticesData2[i+3] = mColors[cbase+1];
+ mTriangleVerticesData2[i+4] = mColors[cbase+2];
+ mTriangleVerticesData2[i+5] = mColors[cbase+3];
+ }
+ mTriangleVertices.position(0);
+ mTriangleVertices.put(mTriangleVerticesData2).position(0);
+
+ GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices);
+ checkGlError("glVertexAttribPointer mvPosition");
+ mTriangleVertices.put(mTriangleVerticesData2).position(2);
+ GLES20.glVertexAttribPointer(mvColorHandle, 4, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices);
+ checkGlError("glVertexAttribPointer mvColor");
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
+ checkGlError("glDrawArrays");
+ }
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ mScaleX = 2.0f / width;
+ mScaleY = 2.0f / height;
+ mOffsetX = -1f;
+ mOffsetY = -1f;
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ mProgram = createProgram(mVertexShader, mFragmentShader);
+ if (mProgram == 0) {
+ return;
+ }
+ mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
+ checkGlError("glGetAttribLocation");
+ if (mvPositionHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for vPosition");
+ }
+ mvColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
+ checkGlError("glGetAttribLocation");
+ if (mvColorHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for vColor");
+ }
+ }
+
+ private int loadShader(int shaderType, String source) {
+ int shader = GLES20.glCreateShader(shaderType);
+ if (shader != 0) {
+ GLES20.glShaderSource(shader, source);
+ GLES20.glCompileShader(shader);
+ int[] compiled = new int[1];
+ GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+ if (compiled[0] == 0) {
+ Log.e(TAG, "Could not compile shader " + shaderType + ":");
+ Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+ }
+
+ private int createProgram(String vertexSource, String fragmentSource) {
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+ if (vertexShader == 0) {
+ return 0;
+ }
+
+ int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+ if (pixelShader == 0) {
+ return 0;
+ }
+
+ int program = GLES20.glCreateProgram();
+ if (program != 0) {
+ GLES20.glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader vertexShader");
+ GLES20.glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader pixelShader");
+ GLES20.glLinkProgram(program);
+ int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: ");
+ Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+ GLES20.glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+ }
+
+ private void checkGlError(String op) {
+ int error;
+ while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+ Log.e(TAG, op + ": glError " + error);
+ throw new RuntimeException(op + ": glError " + error);
+ }
+ }
+
+ // X, Y, R G B A
+ private final float[] mTriangleVerticesData = {
+ -0.025f, 0.3f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f , 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.025f, 0.3f, 1.0f, 1.0f, 255.0f, 1.0f
+ };
+
+ // Color cascade:
+ private final float[] mColors = {
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ 0.5f, 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.5f, 0.0f, 1.0f,
+ 0.5f, 0.5f, 0.0f, 1.0f,
+
+ 0.0f, 0.0f, 0.5f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f
+ };
+
+ private float[] mTriangleVerticesData2 = new float[mTriangleVerticesData.length];
+ private FloatBuffer mTriangleVertices;
+
+ private final String mVertexShader = "attribute vec4 aPosition;\n"
+ + "attribute vec4 aColor;\n"
+ + "varying vec4 vColor;\n"
+ + "void main() {\n"
+ + " gl_Position = aPosition;\n"
+ + " vColor = aColor;\n"
+ + "}\n";
+
+ private final String mFragmentShader = "precision mediump float;\n"
+ + "varying vec4 vColor;\n"
+ + "void main() {\n"
+ + " gl_FragColor = vColor;\n"
+ + "}\n";
+
+ private int mProgram;
+ private int mvPositionHandle;
+ private int mvColorHandle;
+
+ }
+}
+
diff --git a/opengl/tests/testPauseResume/AndroidManifest.xml b/opengl/tests/testPauseResume/AndroidManifest.xml
index 3e8e7e7..1879bc3 100644
--- a/opengl/tests/testPauseResume/AndroidManifest.xml
+++ b/opengl/tests/testPauseResume/AndroidManifest.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/opengl/tests/testPauseResume/res/values/strings.xml b/opengl/tests/testPauseResume/res/values/strings.xml
index 208fe15..b4c98fe 100644
--- a/opengl/tests/testPauseResume/res/values/strings.xml
+++ b/opengl/tests/testPauseResume/res/values/strings.xml
@@ -1,21 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<!-- This file contains resource definitions for displayed strings, allowing
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
new file mode 100644
index 0000000..ab37809
--- /dev/null
+++ b/opengl/tests/testViewport/Android.mk
@@ -0,0 +1,26 @@
+#########################################################################
+# OpenGL ES JNI sample
+# This makefile builds both an activity and a shared library.
+#########################################################################
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TestViewport
+
+# Set a specific SDK version so we can run on Froyo.
+
+LOCAL_SDK_VERSION := 8
+
+include $(BUILD_PACKAGE)
+
+endif # TARGET_SIMULATOR
diff --git a/opengl/tests/testViewport/AndroidManifest.xml b/opengl/tests/testViewport/AndroidManifest.xml
new file mode 100644
index 0000000..ba178bb
--- /dev/null
+++ b/opengl/tests/testViewport/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test">
+ <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:label="@string/test_activity">
+ <activity android:name="TestActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/testViewport/README b/opengl/tests/testViewport/README
new file mode 100644
index 0000000..c06abc9
--- /dev/null
+++ b/opengl/tests/testViewport/README
@@ -0,0 +1,28 @@
+Repro steps:
+
+build, install and run the attached test program TestViewport.apk
+
+Run on Sapphire with Froyo.
+
+The program clears the screen to blue, then draws a full screen white quad that
+is alligned to the screen.
+(Therefore the whole screen should appear to be white.)
+
+
+Note that screen is all white.
+
+Rotate screen 90 degrees.
+
+Expected: screen is still all white.
+
+Actual: screen is blue with offset white rectangle.
+
+This bug only happens on Sapphire, it works correctly on Passion.
+
+What happens:
+
+I think the bug is that the gl.glViewport() call in onSurfaceChanged() is
+being ignored by the OpenGL driver.
+
+NOTE: If a gl.glViewport call is added at the beginning of the onDrawFrame()
+call (which means it is called before every draw), the program runs correctly.
diff --git a/opengl/tests/testViewport/res/values/strings.xml b/opengl/tests/testViewport/res/values/strings.xml
new file mode 100644
index 0000000..c037a7c
--- /dev/null
+++ b/opengl/tests/testViewport/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+ them to be changed based on the locale and options. -->
+
+<resources>
+ <!-- Simple strings. -->
+ <string name="test_activity">Test Viewport</string>
+
+</resources>
+
diff --git a/opengl/tests/testViewport/src/com/android/test/TestActivity.java b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
new file mode 100644
index 0000000..cc7e450
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+ private final static String TAG = "TestActivity";
+ TestView mView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mView = new TestView(getApplication());
+ mView.setFocusableInTouchMode(true);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+}
diff --git a/opengl/tests/testViewport/src/com/android/test/TestView.java b/opengl/tests/testViewport/src/com/android/test/TestView.java
new file mode 100644
index 0000000..23cc37d
--- /dev/null
+++ b/opengl/tests/testViewport/src/com/android/test/TestView.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test;
+/*
+ * 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.
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.FloatBuffer;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation. This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class TestView extends GLSurfaceView {
+ TestView(Context context) {
+ super(context);
+ init();
+ }
+
+ public TestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setRenderer(new Renderer());
+ setRenderMode(RENDERMODE_WHEN_DIRTY);
+ }
+
+ /** A grid is a topologically rectangular array of vertices.
+ *
+ * The vertex and index data are held in VBO objects because on most
+ * GPUs VBO objects are the fastest way of rendering static vertex
+ * and index data.
+ *
+ */
+
+ private static class Grid {
+ // Size of vertex data elements in bytes:
+ final static int FLOAT_SIZE = 4;
+ final static int CHAR_SIZE = 2;
+
+ // Vertex structure:
+ // float x, y, z;
+
+ final static int VERTEX_SIZE = 3 * FLOAT_SIZE;
+
+ private int mVertexBufferObjectId;
+ private int mElementBufferObjectId;
+
+ // These buffers are used to hold the vertex and index data while
+ // constructing the grid. Once createBufferObjects() is called
+ // the buffers are nulled out to save memory.
+
+ private ByteBuffer mVertexByteBuffer;
+ private FloatBuffer mVertexBuffer;
+ private CharBuffer mIndexBuffer;
+
+ private int mW;
+ private int mH;
+ private int mIndexCount;
+
+ public Grid(int w, int h) {
+ if (w < 0 || w >= 65536) {
+ throw new IllegalArgumentException("w");
+ }
+ if (h < 0 || h >= 65536) {
+ throw new IllegalArgumentException("h");
+ }
+ if (w * h >= 65536) {
+ throw new IllegalArgumentException("w * h >= 65536");
+ }
+
+ mW = w;
+ mH = h;
+ int size = w * h;
+
+ mVertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_SIZE * size)
+ .order(ByteOrder.nativeOrder());
+ mVertexBuffer = mVertexByteBuffer.asFloatBuffer();
+
+ int quadW = mW - 1;
+ int quadH = mH - 1;
+ int quadCount = quadW * quadH;
+ int indexCount = quadCount * 6;
+ mIndexCount = indexCount;
+ mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount)
+ .order(ByteOrder.nativeOrder()).asCharBuffer();
+
+ /*
+ * Initialize triangle list mesh.
+ *
+ * [0]-----[ 1] ...
+ * | / |
+ * | / |
+ * | / |
+ * [w]-----[w+1] ...
+ * | |
+ *
+ */
+
+ {
+ int i = 0;
+ for (int y = 0; y < quadH; y++) {
+ for (int x = 0; x < quadW; x++) {
+ char a = (char) (y * mW + x);
+ char b = (char) (y * mW + x + 1);
+ char c = (char) ((y + 1) * mW + x);
+ char d = (char) ((y + 1) * mW + x + 1);
+
+ mIndexBuffer.put(i++, a);
+ mIndexBuffer.put(i++, c);
+ mIndexBuffer.put(i++, b);
+
+ mIndexBuffer.put(i++, b);
+ mIndexBuffer.put(i++, c);
+ mIndexBuffer.put(i++, d);
+ }
+ }
+ }
+
+ }
+
+ public void set(int i, int j, float x, float y, float z) {
+ if (i < 0 || i >= mW) {
+ throw new IllegalArgumentException("i");
+ }
+ if (j < 0 || j >= mH) {
+ throw new IllegalArgumentException("j");
+ }
+
+ int index = mW * j + i;
+
+ mVertexBuffer.position(index * VERTEX_SIZE / FLOAT_SIZE);
+ mVertexBuffer.put(x);
+ mVertexBuffer.put(y);
+ mVertexBuffer.put(z);
+ }
+
+ public void createBufferObjects(GL gl) {
+ // Generate a the vertex and element buffer IDs
+ int[] vboIds = new int[2];
+ GL11 gl11 = (GL11) gl;
+ gl11.glGenBuffers(2, vboIds, 0);
+ mVertexBufferObjectId = vboIds[0];
+ mElementBufferObjectId = vboIds[1];
+
+ // Upload the vertex data
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+ mVertexByteBuffer.position(0);
+ gl11.glBufferData(GL11.GL_ARRAY_BUFFER, mVertexByteBuffer.capacity(), mVertexByteBuffer, GL11.GL_STATIC_DRAW);
+
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+ mIndexBuffer.position(0);
+ gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.capacity() * CHAR_SIZE, mIndexBuffer, GL11.GL_STATIC_DRAW);
+
+ // We don't need the in-memory data any more
+ mVertexBuffer = null;
+ mVertexByteBuffer = null;
+ mIndexBuffer = null;
+ }
+
+ public void draw(GL10 gl) {
+ GL11 gl11 = (GL11) gl;
+
+ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId);
+ gl11.glVertexPointer(3, GL10.GL_FLOAT, VERTEX_SIZE, 0);
+
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId);
+ gl11.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, 0);
+ gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
+ gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
+ gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
+
+
+ private class Renderer implements GLSurfaceView.Renderer {
+ private static final String TAG = "Renderer";
+ private Grid mGrid;
+
+ public void onDrawFrame(GL10 gl) {
+ gl.glClearColor(0,0,1,1);
+ gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
+ mGrid.draw(gl);
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ gl.glViewport(0, 0, width, height);
+ gl.glMatrixMode(GL11.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glOrthof(0, width, height, 0, -1, 1);
+ gl.glMatrixMode(GL11.GL_MODELVIEW);
+ createGrid(gl, width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ }
+
+ private void createGrid(GL10 gl, float w, float h) {
+ mGrid = new Grid(2, 2);
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 2; i++) {
+ float x = w * i;
+ float y = h * j;
+ float z = 0.0f;
+ mGrid.set(i,j, x, y, z);
+ }
+ }
+ mGrid.createBufferObjects(gl);
+ }
+ }
+}
+
diff --git a/opengl/tools/glgen/stubs/gles11/glGetString.java b/opengl/tools/glgen/stubs/gles11/glGetString.java
index d44a6dd..b02a0d1 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetString.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetString.java
@@ -1,21 +1,21 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- // C function const GLubyte * glGetString ( GLenum name )
-
- public static native String glGetString(
- int name
- );
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ // C function const GLubyte * glGetString ( GLenum name )
+
+ public static native String glGetString(
+ int name
+ );
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 41562f6..8a00a2e 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -5,12 +5,10 @@
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
- BlurFilter.cpp.arm \
+ DisplayHardware/HWComposer.cpp \
GLExtensions.cpp \
Layer.cpp \
LayerBase.cpp \
- LayerBuffer.cpp \
- LayerBlur.cpp \
LayerDim.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \
@@ -25,7 +23,6 @@
endif
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
- LOCAL_CFLAGS += -DUSE_COMPOSITION_BYPASS
endif
@@ -38,7 +35,6 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libpixelflinger \
libhardware \
libutils \
libEGL \
diff --git a/services/surfaceflinger/BlurFilter.cpp b/services/surfaceflinger/BlurFilter.cpp
deleted file mode 100644
index 1ffbd5b..0000000
--- a/services/surfaceflinger/BlurFilter.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <utils/Errors.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "clz.h"
-
-#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
-#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
-
-namespace android {
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
- return v;
-}
-inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
- return v;
-}
-#else
-inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
- return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
-}
-inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
- return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
-}
-#endif
-
-const int BLUR_DITHER_BITS = 6; // dither weights stored on 6 bits
-const int BLUR_DITHER_ORDER_SHIFT= 3;
-const int BLUR_DITHER_ORDER = (1<<BLUR_DITHER_ORDER_SHIFT);
-const int BLUR_DITHER_SIZE = BLUR_DITHER_ORDER * BLUR_DITHER_ORDER;
-const int BLUR_DITHER_MASK = BLUR_DITHER_ORDER-1;
-
-static const uint8_t gDitherMatrix[BLUR_DITHER_SIZE] = {
- 0, 32, 8, 40, 2, 34, 10, 42,
- 48, 16, 56, 24, 50, 18, 58, 26,
- 12, 44, 4, 36, 14, 46, 6, 38,
- 60, 28, 52, 20, 62, 30, 54, 22,
- 3, 35, 11, 43, 1, 33, 9, 41,
- 51, 19, 59, 27, 49, 17, 57, 25,
- 15, 47, 7, 39, 13, 45, 5, 37,
- 63, 31, 55, 23, 61, 29, 53, 21
-};
-
-
-template <int FACTOR = 0>
-struct BlurColor565
-{
- typedef uint16_t type;
- int r, g, b;
- inline BlurColor565() { }
- inline BlurColor565(uint16_t v) {
- r = v >> 11;
- g = (v >> 5) & 0x3E;
- b = v & 0x1F;
- }
- inline void clear() { r=g=b=0; }
- inline uint16_t to(int shift, int last, int dither) const {
- int R = r;
- int G = g;
- int B = b;
- if (UNLIKELY(last)) {
- if (FACTOR>0) {
- int L = (R+G+B)>>1;
- R += (((L>>1) - R) * FACTOR) >> 8;
- G += (((L ) - G) * FACTOR) >> 8;
- B += (((L>>1) - B) * FACTOR) >> 8;
- }
- R += (dither << shift) >> BLUR_DITHER_BITS;
- G += (dither << shift) >> BLUR_DITHER_BITS;
- B += (dither << shift) >> BLUR_DITHER_BITS;
- }
- R >>= shift;
- G >>= shift;
- B >>= shift;
- return (R<<11) | (G<<5) | B;
- }
- inline BlurColor565& operator += (const BlurColor565& rhs) {
- r += rhs.r;
- g += rhs.g;
- b += rhs.b;
- return *this;
- }
- inline BlurColor565& operator -= (const BlurColor565& rhs) {
- r -= rhs.r;
- g -= rhs.g;
- b -= rhs.b;
- return *this;
- }
-};
-
-template <int FACTOR = 0>
-struct BlurColor888X
-{
- typedef uint32_t type;
- int r, g, b;
- inline BlurColor888X() { }
- inline BlurColor888X(uint32_t v) {
- v = BLUR_RGBA_TO_HOST(v);
- r = v & 0xFF;
- g = (v >> 8) & 0xFF;
- b = (v >> 16) & 0xFF;
- }
- inline void clear() { r=g=b=0; }
- inline uint32_t to(int shift, int last, int dither) const {
- int R = r;
- int G = g;
- int B = b;
- if (UNLIKELY(last)) {
- if (FACTOR>0) {
- int L = (R+G+G+B)>>2;
- R += ((L - R) * FACTOR) >> 8;
- G += ((L - G) * FACTOR) >> 8;
- B += ((L - B) * FACTOR) >> 8;
- }
- }
- R >>= shift;
- G >>= shift;
- B >>= shift;
- return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R);
- }
- inline BlurColor888X& operator += (const BlurColor888X& rhs) {
- r += rhs.r;
- g += rhs.g;
- b += rhs.b;
- return *this;
- }
- inline BlurColor888X& operator -= (const BlurColor888X& rhs) {
- r -= rhs.r;
- g -= rhs.g;
- b -= rhs.b;
- return *this;
- }
-};
-
-struct BlurGray565
-{
- typedef uint16_t type;
- int l;
- inline BlurGray565() { }
- inline BlurGray565(uint16_t v) {
- int r = v >> 11;
- int g = (v >> 5) & 0x3F;
- int b = v & 0x1F;
- l = (r + g + b + 1)>>1;
- }
- inline void clear() { l=0; }
- inline uint16_t to(int shift, int last, int dither) const {
- int L = l;
- if (UNLIKELY(last)) {
- L += (dither << shift) >> BLUR_DITHER_BITS;
- }
- L >>= shift;
- return ((L>>1)<<11) | (L<<5) | (L>>1);
- }
- inline BlurGray565& operator += (const BlurGray565& rhs) {
- l += rhs.l;
- return *this;
- }
- inline BlurGray565& operator -= (const BlurGray565& rhs) {
- l -= rhs.l;
- return *this;
- }
-};
-
-struct BlurGray8888
-{
- typedef uint32_t type;
- int l, a;
- inline BlurGray8888() { }
- inline BlurGray8888(uint32_t v) {
- v = BLUR_RGBA_TO_HOST(v);
- int r = v & 0xFF;
- int g = (v >> 8) & 0xFF;
- int b = (v >> 16) & 0xFF;
- a = v >> 24;
- l = r + g + g + b;
- }
- inline void clear() { l=a=0; }
- inline uint32_t to(int shift, int last, int dither) const {
- int L = l;
- int A = a;
- if (UNLIKELY(last)) {
- L += (dither << (shift+2)) >> BLUR_DITHER_BITS;
- A += (dither << shift) >> BLUR_DITHER_BITS;
- }
- L >>= (shift+2);
- A >>= shift;
- return BLUR_HOST_TO_RGBA((A<<24) | (L<<16) | (L<<8) | L);
- }
- inline BlurGray8888& operator += (const BlurGray8888& rhs) {
- l += rhs.l;
- a += rhs.a;
- return *this;
- }
- inline BlurGray8888& operator -= (const BlurGray8888& rhs) {
- l -= rhs.l;
- a -= rhs.a;
- return *this;
- }
-};
-
-
-template<typename PIXEL>
-static status_t blurFilter(
- GGLSurface const* dst,
- GGLSurface const* src,
- int kernelSizeUser,
- int repeat)
-{
- typedef typename PIXEL::type TYPE;
-
- const int shift = 31 - clz(kernelSizeUser);
- const int areaShift = shift*2;
- const int kernelSize = 1<<shift;
- const int kernelHalfSize = kernelSize/2;
- const int mask = kernelSize-1;
- const int w = src->width;
- const int h = src->height;
- const uint8_t* ditherMatrix = gDitherMatrix;
-
- // we need a temporary buffer to store one line of blurred columns
- // as well as kernelSize lines of source pixels organized as a ring buffer.
- void* const temporary_buffer = malloc(
- (w + kernelSize) * sizeof(PIXEL) +
- (src->stride * kernelSize) * sizeof(TYPE));
- if (!temporary_buffer)
- return NO_MEMORY;
-
- PIXEL* const sums = (PIXEL*)temporary_buffer;
- TYPE* const scratch = (TYPE*)(sums + w + kernelSize);
-
- // Apply the blur 'repeat' times, this is used to approximate
- // gaussian blurs. 3 times gives good results.
- for (int k=0 ; k<repeat ; k++) {
-
- // Clear the columns sums for this round
- memset(sums, 0, (w + kernelSize) * sizeof(PIXEL));
- TYPE* head;
- TYPE pixel;
- PIXEL current;
-
- // Since we're going to override the source data we need
- // to copy it in a temporary buffer. Only kernelSize lines are
- // required. But since we start in the center of the kernel,
- // we only copy half of the data, and fill the rest with zeros
- // (assuming black/transparent pixels).
- memcpy( scratch + src->stride*kernelHalfSize,
- src->data,
- src->stride*kernelHalfSize*sizeof(TYPE));
-
- // sum half of each column, because we assume the first half is
- // zeros (black/transparent).
- for (int y=0 ; y<kernelHalfSize ; y++) {
- head = (TYPE*)src->data + y*src->stride;
- for (int x=0 ; x<w ; x++)
- sums[x] += PIXEL( *head++ );
- }
-
- for (int y=0 ; y<h ; y++) {
- TYPE* fb = (TYPE*)dst->data + y*dst->stride;
-
- // compute the dither matrix line
- uint8_t const * ditherY = ditherMatrix
- + (y & BLUR_DITHER_MASK)*BLUR_DITHER_ORDER;
-
- // Horizontal blur pass on the columns sums
- int count, dither, x=0;
- PIXEL const * out= sums;
- PIXEL const * in = sums;
- current.clear();
-
- count = kernelHalfSize;
- do {
- current += *in;
- in++;
- } while (--count);
-
- count = kernelHalfSize;
- do {
- current += *in;
- dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
- *fb++ = current.to(areaShift, k==repeat-1, dither);
- in++;
- } while (--count);
-
- count = w-kernelSize;
- do {
- current += *in;
- current -= *out;
- dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
- *fb++ = current.to(areaShift, k==repeat-1, dither);
- in++, out++;
- } while (--count);
-
- count = kernelHalfSize;
- do {
- current -= *out;
- dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
- *fb++ = current.to(areaShift, k==repeat-1, dither);
- out++;
- } while (--count);
-
- // vertical blur pass, subtract the oldest line from each columns
- // and add a new line. Subtract or add zeros at the top
- // and bottom edges.
- TYPE* const tail = scratch + (y & mask) * src->stride;
- if (y >= kernelHalfSize) {
- for (int x=0 ; x<w ; x++)
- sums[x] -= PIXEL( tail[x] );
- }
- if (y < h-kernelSize) {
- memcpy( tail,
- (TYPE*)src->data + (y+kernelHalfSize)*src->stride,
- src->stride*sizeof(TYPE));
- for (int x=0 ; x<w ; x++)
- sums[x] += PIXEL( tail[x] );
- }
- }
-
- // The subsequent passes are always done in-place.
- src = dst;
- }
-
- free(temporary_buffer);
-
- return NO_ERROR;
-}
-
-template status_t blurFilter< BlurColor565<0x80> >(
- GGLSurface const* dst,
- GGLSurface const* src,
- int kernelSizeUser,
- int repeat);
-
-status_t blurFilter(
- GGLSurface const* image,
- int kernelSizeUser,
- int repeat)
-{
- status_t err = BAD_VALUE;
- if (image->format == GGL_PIXEL_FORMAT_RGB_565) {
- err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
- } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) {
- err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat);
- }
- return err;
-}
-
-} // namespace android
-
-//err = blur< BlurColor565<0x80> >(dst, src, kernelSizeUser, repeat);
-//err = blur<BlurGray565>(dst, src, kernelSizeUser, repeat);
-//err = blur<BlurGray8888>(dst, src, kernelSizeUser, repeat);
diff --git a/services/surfaceflinger/BlurFilter.h b/services/surfaceflinger/BlurFilter.h
deleted file mode 100644
index 294db43..0000000
--- a/services/surfaceflinger/BlurFilter.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_BLUR_FILTER_H
-#define ANDROID_BLUR_FILTER_H
-
-#include <stdint.h>
-#include <utils/Errors.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-namespace android {
-
-status_t blurFilter(
- GGLSurface const* image,
- int kernelSizeUser,
- int repeat);
-
-} // namespace android
-
-#endif // ANDROID_BLUR_FILTER_H
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 818774d..64cff96 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -36,11 +36,10 @@
#include "DisplayHardware/DisplayHardware.h"
-#include <hardware/copybit.h>
-#include <hardware/overlay.h>
#include <hardware/gralloc.h>
#include "GLExtensions.h"
+#include "HWComposer.h"
using namespace android;
@@ -76,7 +75,7 @@
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy),
- mFlags(0)
+ mFlags(0), mHwc(0)
{
init(dpy);
}
@@ -104,12 +103,6 @@
mDpiY = mNativeWindow->ydpi;
mRefreshRate = fbDev->fps;
- mOverlayEngine = NULL;
- hw_module_t const* module;
- if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
- overlay_control_open(module, &mOverlayEngine);
- }
-
EGLint w, h, dummy;
EGLint numConfigs=0;
EGLSurface surface;
@@ -272,6 +265,17 @@
// Unbind the context from this thread
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+
+ // initialize the H/W composer
+ mHwc = new HWComposer();
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->setFrameBuffer(mDisplay, mSurface);
+ }
+}
+
+HWComposer& DisplayHardware::getHwComposer() const {
+ return *mHwc;
}
/*
@@ -285,12 +289,14 @@
{
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
- overlay_control_close(mOverlayEngine);
}
void DisplayHardware::releaseScreen() const
{
DisplayHardwareBase::releaseScreen();
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->release();
+ }
}
void DisplayHardware::acquireScreen() const
@@ -331,7 +337,12 @@
}
mPageFlipCount++;
- eglSwapBuffers(dpy, surface);
+
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->commit();
+ } else {
+ eglSwapBuffers(dpy, surface);
+ }
checkEGLErrors("eglSwapBuffers");
// for debugging
@@ -339,12 +350,6 @@
//glClear(GL_COLOR_BUFFER_BIT);
}
-status_t DisplayHardware::postBypassBuffer(const native_handle_t* handle) const
-{
- framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
- return fbDev->post(fbDev, handle);
-}
-
uint32_t DisplayHardware::getFlags() const
{
return mFlags;
@@ -354,3 +359,8 @@
{
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
}
+
+void DisplayHardware::dump(String8& res) const
+{
+ mNativeWindow->dump(res);
+}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 79ef2a7..ee7a2af 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -33,13 +33,10 @@
#include "DisplayHardware/DisplayHardwareBase.h"
-struct overlay_control_device_t;
-struct framebuffer_device_t;
-struct copybit_image_t;
-
namespace android {
class FramebufferNativeWindow;
+class HWComposer;
class DisplayHardware : public DisplayHardwareBase
{
@@ -64,7 +61,6 @@
// Flip the front and back buffers if the back buffer is "dirty". Might
// be instantaneous, might involve copying the frame buffer around.
void flip(const Region& dirty) const;
- status_t postBypassBuffer(const native_handle_t* handle) const;
float getDpiX() const;
float getDpiY() const;
@@ -80,7 +76,11 @@
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
- overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+
+ void dump(String8& res) const;
+
+ // Hardware Composer
+ HWComposer& getHwComposer() const;
status_t compositionComplete() const;
@@ -111,8 +111,9 @@
GLint mMaxViewportDims;
GLint mMaxTextureSize;
+ HWComposer* mHwc;
+
sp<FramebufferNativeWindow> mNativeWindow;
- overlay_control_device_t* mOverlayEngine;
};
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
new file mode 100644
index 0000000..4a3b20d
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+#include <hardware/hardware.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "HWComposer.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+HWComposer::HWComposer()
+ : mModule(0), mHwc(0), mList(0), mCapacity(0),
+ mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
+{
+ int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
+ LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ err = hwc_open(mModule, &mHwc);
+ LOGE_IF(err, "%s device failed to initialize (%s)",
+ HWC_HARDWARE_COMPOSER, strerror(-err));
+ }
+}
+
+HWComposer::~HWComposer() {
+ free(mList);
+ if (mHwc) {
+ hwc_close(mHwc);
+ }
+}
+
+status_t HWComposer::initCheck() const {
+ return mHwc ? NO_ERROR : NO_INIT;
+}
+
+void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
+ mDpy = (hwc_display_t)dpy;
+ mSur = (hwc_surface_t)sur;
+}
+
+status_t HWComposer::createWorkList(size_t numLayers) {
+ if (mHwc) {
+ if (!mList || mCapacity < numLayers) {
+ free(mList);
+ size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t);
+ mList = (hwc_layer_list_t*)malloc(size);
+ mCapacity = numLayers;
+ }
+ mList->flags = HWC_GEOMETRY_CHANGED;
+ mList->numHwLayers = numLayers;
+ }
+ return NO_ERROR;
+}
+
+status_t HWComposer::prepare() const {
+ int err = mHwc->prepare(mHwc, mList);
+ return (status_t)err;
+}
+
+status_t HWComposer::commit() const {
+ int err = mHwc->set(mHwc, mDpy, mSur, mList);
+ if (mList) {
+ mList->flags &= ~HWC_GEOMETRY_CHANGED;
+ }
+ return (status_t)err;
+}
+
+status_t HWComposer::release() const {
+ int err = mHwc->set(mHwc, NULL, NULL, NULL);
+ return (status_t)err;
+}
+
+size_t HWComposer::getNumLayers() const {
+ return mList ? mList->numHwLayers : 0;
+}
+
+hwc_layer_t* HWComposer::getLayers() const {
+ return mList ? mList->hwLayers : 0;
+}
+
+void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const {
+ if (mHwc && mList) {
+ result.append("Hardware Composer state:\n");
+
+ snprintf(buffer, SIZE, " numHwLayers=%u, flags=%08x\n",
+ mList->numHwLayers, mList->flags);
+ result.append(buffer);
+
+ for (size_t i=0 ; i<mList->numHwLayers ; i++) {
+ const hwc_layer_t& l(mList->hwLayers[i]);
+ snprintf(buffer, SIZE, " %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d]\n",
+ l.compositionType ? "OVERLAY" : "FB",
+ l.hints, l.flags, l.transform, l.blending,
+ l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom);
+ result.append(buffer);
+ }
+
+ }
+ if (mHwc && mHwc->common.version >= 1 && mHwc->dump) {
+ mHwc->dump(mHwc, buffer, SIZE);
+ result.append(buffer);
+ }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
new file mode 100644
index 0000000..5a9e9eb
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -0,0 +1,75 @@
+/*
+ * 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_SF_HWCOMPOSER_H
+#define ANDROID_SF_HWCOMPOSER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <hardware/hwcomposer.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+class HWComposer
+{
+public:
+
+ HWComposer();
+ ~HWComposer();
+
+ status_t initCheck() const;
+
+ // tells the HAL what the framebuffer is
+ void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
+
+ // create a work list for numLayers layer
+ status_t createWorkList(size_t numLayers);
+
+ // Asks the HAL what it can do
+ status_t prepare() const;
+
+ // commits the list
+ status_t commit() const;
+
+ // release hardware resources
+ status_t release() const;
+
+ size_t getNumLayers() const;
+ hwc_layer_t* getLayers() const;
+
+ // for debugging
+ void dump(String8& out, char* scratch, size_t SIZE) const;
+
+private:
+ hw_module_t const* mModule;
+ hwc_composer_device_t* mHwc;
+ hwc_layer_list_t* mList;
+ size_t mCapacity;
+ hwc_display_t mDpy;
+ hwc_surface_t mSur;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3a8690e..5a0f115 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -35,6 +35,7 @@
#include "Layer.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
#define DEBUG_RESIZE 0
@@ -57,8 +58,7 @@
mSecure(false),
mTextureManager(),
mBufferManager(mTextureManager),
- mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false),
- mBypassState(false)
+ mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
{
}
@@ -83,8 +83,28 @@
sharedClient, token, mBufferManager.getDefaultBufferCount(),
getIdentity());
- status_t err = mUserClientRef.setToken(userClient, lcblk, token);
+ sp<UserClient> ourClient(mUserClientRef.getClient());
+
+ /*
+ * Here it is guaranteed that userClient != ourClient
+ * (see UserClient::getTokenForSurface()).
+ *
+ * We release the token used by this surface in ourClient below.
+ * This should be safe to do so now, since this layer won't be attached
+ * to this client, it should be okay to reuse that id.
+ *
+ * If this causes problems, an other solution would be to keep a list
+ * of all the {UserClient, token} ever used and release them when the
+ * Layer is destroyed.
+ *
+ */
+
+ if (ourClient != 0) {
+ ourClient->detachLayer(this);
+ }
+
+ status_t err = mUserClientRef.setToken(userClient, lcblk, token);
LOGE_IF(err != NO_ERROR,
"ClientRef::setToken(%p, %p, %u) failed",
userClient.get(), lcblk.get(), token);
@@ -171,7 +191,8 @@
mReqHeight = h;
mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
- mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+ mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
+ (flags & ISurfaceComposer::eOpaque) == 0;
// we use the red index
int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
@@ -182,6 +203,71 @@
return NO_ERROR;
}
+void Layer::setGeometry(hwc_layer_t* hwcl)
+{
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->hints = 0;
+ hwcl->flags = 0;
+ hwcl->transform = 0;
+ hwcl->blending = HWC_BLENDING_NONE;
+
+ // we can't do alpha-fade with the hwc HAL
+ const State& s(drawingState());
+ if (s.alpha < 0xFF) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ // we can only handle simple transformation
+ if (mOrientation & Transform::ROT_INVALID) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ Transform tr(Transform(mOrientation) * Transform(mBufferTransform));
+ hwcl->transform = tr.getOrientation();
+
+ if (needsBlending()) {
+ hwcl->blending = mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+ }
+
+ hwcl->displayFrame.left = mTransformedBounds.left;
+ hwcl->displayFrame.top = mTransformedBounds.top;
+ hwcl->displayFrame.right = mTransformedBounds.right;
+ hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+
+ hwcl->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ visibleRegionScreen.getArray(
+ &hwcl->visibleRegionScreen.numRects));
+}
+
+void Layer::setPerFrameData(hwc_layer_t* hwcl) {
+ sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+ if (buffer == NULL) {
+ // this can happen if the client never drew into this layer yet,
+ // or if we ran out of memory. In that case, don't let
+ // HWC handle it.
+ hwcl->flags |= HWC_SKIP_LAYER;
+ hwcl->handle = NULL;
+ return;
+ }
+ hwcl->handle = buffer->handle;
+
+ if (!mBufferCrop.isEmpty()) {
+ hwcl->sourceCrop.left = mBufferCrop.left;
+ hwcl->sourceCrop.top = mBufferCrop.top;
+ hwcl->sourceCrop.right = mBufferCrop.right;
+ hwcl->sourceCrop.bottom = mBufferCrop.bottom;
+ } else {
+ hwcl->sourceCrop.left = 0;
+ hwcl->sourceCrop.top = 0;
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+ }
+}
+
void Layer::reloadTexture(const Region& dirty)
{
sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
@@ -252,29 +338,6 @@
}
return;
}
-
-#ifdef USE_COMPOSITION_BYPASS
- sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
- if ((buffer != NULL) && (buffer->transform)) {
- // Here we have a "bypass" buffer, but we need to composite it
- // most likely because it's not fullscreen anymore.
- // Since the buffer may have a transformation applied by the client
- // we need to inverse this transformation here.
-
- // calculate the inverse of the buffer transform
- const uint32_t mask = HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
- const uint32_t bufferTransformInverse = buffer->transform ^ mask;
-
- // To accomplish the inverse transform, we use "mBufferTransform"
- // which is not used by Layer.cpp
- const_cast<Layer*>(this)->mBufferTransform = bufferTransformInverse;
- drawWithOpenGL(clip, tex);
- // reset to "no transfrom"
- const_cast<Layer*>(this)->mBufferTransform = 0;
- return;
- }
-#endif
-
drawWithOpenGL(clip, tex);
}
@@ -302,8 +365,10 @@
// NOTE: lcblk->resize() is protected by an internal lock
status_t err = lcblk->resize(bufferCount);
- if (err == NO_ERROR)
- mBufferManager.resize(bufferCount);
+ if (err == NO_ERROR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ mBufferManager.resize(bufferCount, mFlinger, dpy);
+ }
return err;
}
@@ -335,14 +400,13 @@
* buffer 'index' as our front buffer.
*/
- uint32_t w, h, f, bypass;
+ status_t err = NO_ERROR;
+ uint32_t w, h, f;
{ // scope for the lock
Mutex::Autolock _l(mLock);
- bypass = mBypassState;
-
// zero means default
- mFixedSize = reqWidth && reqHeight;
+ const bool fixedSize = reqWidth && reqHeight;
if (!reqFormat) reqFormat = mFormat;
if (!reqWidth) reqWidth = mWidth;
if (!reqHeight) reqHeight = mHeight;
@@ -356,6 +420,7 @@
mReqWidth = reqWidth;
mReqHeight = reqHeight;
mReqFormat = reqFormat;
+ mFixedSize = fixedSize;
mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
lcblk->reallocateAllExcept(index);
@@ -365,40 +430,9 @@
// here we have to reallocate a new buffer because the buffer could be
// used as the front buffer, or by a client in our process
// (eg: status bar), and we can't release the handle under its feet.
- uint32_t effectiveUsage = getEffectiveUsage(usage);
-
- status_t err = NO_MEMORY;
-
-#ifdef USE_COMPOSITION_BYPASS
- if (!mSecure && bypass && (effectiveUsage & GRALLOC_USAGE_HW_RENDER)) {
- // always allocate a buffer matching the screen size. the size
- // may be different from (w,h) if the buffer is rotated.
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- int32_t w = hw.getWidth();
- int32_t h = hw.getHeight();
- int32_t f = hw.getFormat();
-
- buffer = new GraphicBuffer(w, h, f, effectiveUsage | GRALLOC_USAGE_HW_FB);
- err = buffer->initCheck();
- buffer->transform = uint8_t(getOrientation());
-
- if (err != NO_ERROR) {
- // allocation didn't succeed, probably because an older bypass
- // window hasn't released all its resources yet.
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (lcblk) {
- // all buffers need reallocation
- lcblk->reallocateAll();
- }
- }
- }
-#endif
-
- if (err != NO_ERROR) {
- buffer = new GraphicBuffer(w, h, f, effectiveUsage);
- err = buffer->initCheck();
- }
+ const uint32_t effectiveUsage = getEffectiveUsage(usage);
+ buffer = new GraphicBuffer(w, h, f, effectiveUsage);
+ err = buffer->initCheck();
if (err || buffer->handle == 0) {
GraphicBuffer::dumpAllocationsToSystemLog();
@@ -445,39 +479,6 @@
return usage;
}
-bool Layer::setBypass(bool enable)
-{
- Mutex::Autolock _l(mLock);
-
- if (mNeedsScaling || mNeedsFiltering) {
- return false;
- }
-
- if (mBypassState != enable) {
- mBypassState = enable;
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (lcblk) {
- // all buffers need reallocation
- lcblk->reallocateAll();
- }
- }
-
- return true;
-}
-
-void Layer::updateBuffersOrientation()
-{
- sp<GraphicBuffer> buffer(getBypassBuffer());
- if (buffer != NULL && mOrientation != buffer->transform) {
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (lcblk) { // all buffers need reallocation
- lcblk->reallocateAll();
- }
- }
-}
-
uint32_t Layer::doTransaction(uint32_t flags)
{
const Layer::State& front(drawingState());
@@ -581,12 +582,20 @@
}
// we retired a buffer, which becomes the new front buffer
+
+ const bool noActiveBuffer = !mBufferManager.hasActiveBuffer();
if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
mPostedDirtyRegion.clear();
return;
}
+ if (noActiveBuffer) {
+ // we didn't have an active buffer, we need to recompute
+ // our visible region
+ recomputeVisibleRegions = true;
+ }
+
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
if (newFrontBuffer != NULL) {
// get the dirty region
@@ -728,9 +737,9 @@
snprintf(buffer, SIZE,
" "
"format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
- " freezeLock=%p, bypass=%d, dq-q-time=%u us\n",
+ " freezeLock=%p, dq-q-time=%u us\n",
mFormat, w0, h0, s0, w1, h1, s1,
- getFreezeLock().get(), mBypassState, totalTime);
+ getFreezeLock().get(), totalTime);
result.append(buffer);
}
@@ -803,9 +812,52 @@
{
}
-status_t Layer::BufferManager::resize(size_t size)
+status_t Layer::BufferManager::resize(size_t size,
+ const sp<SurfaceFlinger>& flinger, EGLDisplay dpy)
{
Mutex::Autolock _l(mLock);
+
+ if (size < mNumBuffers) {
+ // Move the active texture into slot 0
+ BufferData activeBufferData = mBufferData[mActiveBuffer];
+ mBufferData[mActiveBuffer] = mBufferData[0];
+ mBufferData[0] = activeBufferData;
+ mActiveBuffer = 0;
+
+ // Free the buffers that are no longer needed.
+ for (size_t i = size; i < mNumBuffers; i++) {
+ mBufferData[i].buffer = 0;
+
+ // Create a message to destroy the textures on SurfaceFlinger's GL
+ // thread.
+ class MessageDestroyTexture : public MessageBase {
+ Image mTexture;
+ EGLDisplay mDpy;
+ public:
+ MessageDestroyTexture(const Image& texture, EGLDisplay dpy)
+ : mTexture(texture), mDpy(dpy) { }
+ virtual bool handler() {
+ status_t err = Layer::BufferManager::destroyTexture(
+ &mTexture, mDpy);
+ LOGE_IF(err<0, "error destroying texture: %d (%s)",
+ mTexture.name, strerror(-err));
+ return true; // XXX: err == 0; ????
+ }
+ };
+
+ MessageDestroyTexture *msg = new MessageDestroyTexture(
+ mBufferData[i].texture, dpy);
+
+ // Don't allow this texture to be cleaned up by
+ // BufferManager::destroy.
+ mBufferData[i].texture.name = -1U;
+ mBufferData[i].texture.image = EGL_NO_IMAGE_KHR;
+
+ // Post the message to the SurfaceFlinger object.
+ flinger->postMessageAsync(msg);
+ }
+ }
+
mNumBuffers = size;
return NO_ERROR;
}
@@ -845,6 +897,10 @@
return result;
}
+bool Layer::BufferManager::hasActiveBuffer() const {
+ return mActiveBuffer >= 0;
+}
+
sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
{
BufferData* const buffers = mBufferData;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index cb62558..c367a8d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -68,6 +68,8 @@
bool isFixedSize() const;
// LayerBase interface
+ virtual void setGeometry(hwc_layer_t* hwcl);
+ virtual void setPerFrameData(hwc_layer_t* hwcl);
virtual void drawForSreenShot() const;
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
@@ -81,12 +83,6 @@
virtual sp<Surface> createSurface() const;
virtual status_t ditch();
virtual void onRemoved();
- virtual bool setBypass(bool enable);
-
- void updateBuffersOrientation();
-
- inline sp<GraphicBuffer> getBypassBuffer() const {
- return mBufferManager.getActiveBuffer(); }
// only for debugging
inline sp<GraphicBuffer> getBuffer(int i) const {
@@ -181,7 +177,8 @@
sp<GraphicBuffer> detachBuffer(size_t index);
status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
// resize the number of active buffers
- status_t resize(size_t size);
+ status_t resize(size_t size, const sp<SurfaceFlinger>& flinger,
+ EGLDisplay dpy);
// ----------------------------------------------
// must be called from GL thread
@@ -191,6 +188,8 @@
size_t getActiveBufferIndex() const;
// return the active buffer
sp<GraphicBuffer> getActiveBuffer() const;
+ // return wether we have an active buffer
+ bool hasActiveBuffer() const;
// return the active texture (or fail-over)
Texture getActiveTexture() const;
// frees resources associated with all buffers
@@ -238,7 +237,6 @@
uint32_t mReqFormat;
bool mNeedsScaling;
bool mFixedSize;
- bool mBypassState;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 79c6d0d..8a021cb 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -305,6 +305,15 @@
}
}
+void LayerBase::setGeometry(hwc_layer_t* hwcl) {
+ hwcl->flags |= HWC_SKIP_LAYER;
+}
+
+void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->handle = NULL;
+}
+
void LayerBase::draw(const Region& clip) const
{
// reset GL state
@@ -601,21 +610,6 @@
status_t LayerBaseClient::Surface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- switch (code) {
- case REGISTER_BUFFERS:
- case UNREGISTER_BUFFERS:
- case CREATE_OVERLAY:
- {
- if (!mFlinger->mAccessSurfaceFlinger.checkCalling()) {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- LOGE("Permission Denial: "
- "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
- }
return BnSurface::onTransact(code, data, reply, flags);
}
@@ -630,26 +624,6 @@
return INVALID_OPERATION;
}
-status_t LayerBaseClient::Surface::registerBuffers(
- const ISurface::BufferHeap& buffers)
-{
- return INVALID_OPERATION;
-}
-
-void LayerBaseClient::Surface::postBuffer(ssize_t offset)
-{
-}
-
-void LayerBaseClient::Surface::unregisterBuffers()
-{
-}
-
-sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
- uint32_t w, uint32_t h, int32_t format, int32_t orientation)
-{
- return NULL;
-};
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 3ec8ac3..f6c49fc 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -27,7 +27,6 @@
#include <utils/RefBase.h>
#include <ui/Region.h>
-#include <ui/Overlay.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
#include <private/surfaceflinger/SharedBufferStack.h>
@@ -35,6 +34,8 @@
#include <pixelflinger/pixelflinger.h>
+#include <hardware/hwcomposer.h>
+
#include "DisplayHardware/DisplayHardware.h"
#include "Transform.h"
@@ -109,6 +110,10 @@
virtual const char* getTypeId() const { return "LayerBase"; }
+ virtual void setGeometry(hwc_layer_t* hwcl);
+
+ virtual void setPerFrameData(hwc_layer_t* hwcl);
+
/**
* draw - performs some global clipping optimizations
* and calls onDraw().
@@ -119,11 +124,6 @@
virtual void drawForSreenShot() const;
/**
- * bypass mode
- */
- virtual bool setBypass(bool enable) { return false; }
-
- /**
* onDraw - draws the surface.
*/
virtual void onDraw(const Region& clip) const = 0;
@@ -313,12 +313,6 @@
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t setBufferCount(int bufferCount);
- virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
- virtual void postBuffer(ssize_t offset);
- virtual void unregisterBuffers();
- virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h,
- int32_t format, int32_t orientation);
-
protected:
friend class LayerBaseClient;
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp
deleted file mode 100644
index 4cfcfe3..0000000
--- a/services/surfaceflinger/LayerBlur.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2007 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 <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include "clz.h"
-#include "BlurFilter.h"
-#include "LayerBlur.h"
-#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- const sp<Client>& client)
- : LayerBaseClient(flinger, display, client), mCacheDirty(true),
- mRefreshCache(true), mCacheAge(0), mTextureName(-1U),
- mWidthScale(1.0f), mHeightScale(1.0f),
- mBlurFormat(GGL_PIXEL_FORMAT_RGB_565)
-{
-}
-
-LayerBlur::~LayerBlur()
-{
- if (mTextureName != -1U) {
- glDeleteTextures(1, &mTextureName);
- }
-}
-
-void LayerBlur::setVisibleRegion(const Region& visibleRegion)
-{
- LayerBaseClient::setVisibleRegion(visibleRegion);
- if (visibleRegionScreen.isEmpty()) {
- if (mTextureName != -1U) {
- // We're not visible, free the texture up.
- glBindTexture(GL_TEXTURE_2D, 0);
- glDeleteTextures(1, &mTextureName);
- mTextureName = -1U;
- }
- }
-}
-
-uint32_t LayerBlur::doTransaction(uint32_t flags)
-{
- // we're doing a transaction, refresh the cache!
- if (!mFlinger->isFrozen()) {
- mRefreshCache = true;
- mCacheDirty = true;
- flags |= eVisibleRegion;
- this->contentDirty = true;
- }
- return LayerBase::doTransaction(flags);
-}
-
-void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion)
-{
- // this code-path must be as tight as possible, it's called each time
- // the screen is composited.
- if (UNLIKELY(!visibleRegionScreen.isEmpty())) {
- // if anything visible below us is invalidated, the cache becomes dirty
- if (!mCacheDirty &&
- !visibleRegionScreen.intersect(outDirtyRegion).isEmpty()) {
- mCacheDirty = true;
- }
- if (mCacheDirty) {
- if (!mFlinger->isFrozen()) {
- // update everything below us that is visible
- outDirtyRegion.orSelf(visibleRegionScreen);
- nsecs_t now = systemTime();
- if ((now - mCacheAge) >= ms2ns(500)) {
- mCacheAge = now;
- mRefreshCache = true;
- mCacheDirty = false;
- } else {
- if (!mAutoRefreshPending) {
- mFlinger->postMessageAsync(
- new MessageBase(MessageQueue::INVALIDATE),
- ms2ns(500));
- mAutoRefreshPending = true;
- }
- }
- }
- }
- }
- LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
-}
-
-void LayerBlur::onDraw(const Region& clip) const
-{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- const uint32_t fbHeight = hw.getHeight();
- int x = mTransformedBounds.left;
- int y = mTransformedBounds.top;
- int w = mTransformedBounds.width();
- int h = mTransformedBounds.height();
- GLint X = x;
- GLint Y = fbHeight - (y + h);
- if (X < 0) {
- w += X;
- X = 0;
- }
- if (Y < 0) {
- h += Y;
- Y = 0;
- }
- if (w<0 || h<0) {
- // we're outside of the framebuffer
- return;
- }
-
- if (mTextureName == -1U) {
- // create the texture name the first time
- // can't do that in the ctor, because it runs in another thread.
- glGenTextures(1, &mTextureName);
- glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat);
- glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType);
- if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) {
- mReadFormat = GL_RGBA;
- mReadType = GL_UNSIGNED_BYTE;
- mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888;
- }
- }
-
- Region::const_iterator it = clip.begin();
- Region::const_iterator const end = clip.end();
- if (it != end) {
-#if defined(GL_OES_EGL_image_external)
- if (GLExtensions::getInstance().haveTextureExternal()) {
- glDisable(GL_TEXTURE_EXTERNAL_OES);
- }
-#endif
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, mTextureName);
-
- if (mRefreshCache) {
- mRefreshCache = false;
- mAutoRefreshPending = false;
-
- int32_t pixelSize = 4;
- int32_t s = w;
- if (mReadType == GL_UNSIGNED_SHORT_5_6_5) {
- // allocate enough memory for 4-bytes (2 pixels) aligned data
- s = (w + 1) & ~1;
- pixelSize = 2;
- }
-
- uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize);
-
- // This reads the frame-buffer, so a h/w GL would have to
- // finish() its rendering first. we don't want to do that
- // too often. Read data is 4-bytes aligned.
- glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels);
-
- // blur that texture.
- GGLSurface bl;
- bl.version = sizeof(GGLSurface);
- bl.width = w;
- bl.height = h;
- bl.stride = s;
- bl.format = mBlurFormat;
- bl.data = (GGLubyte*)pixels;
- blurFilter(&bl, 8, 2);
-
- if (GLExtensions::getInstance().haveNpot()) {
- glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
- mReadFormat, mReadType, pixels);
- mWidthScale = 1.0f / w;
- mHeightScale =-1.0f / h;
- mYOffset = 0;
- } else {
- GLuint tw = 1 << (31 - clz(w));
- GLuint th = 1 << (31 - clz(h));
- if (tw < GLuint(w)) tw <<= 1;
- if (th < GLuint(h)) th <<= 1;
- glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0,
- mReadFormat, mReadType, NULL);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
- mReadFormat, mReadType, pixels);
- mWidthScale = 1.0f / tw;
- mHeightScale =-1.0f / th;
- mYOffset = th-h;
- }
-
- free((void*)pixels);
- }
-
- const State& s = drawingState();
- if (UNLIKELY(s.alpha < 0xFF)) {
- const GLfloat alpha = s.alpha * (1.0f/255.0f);
- glColor4f(0, 0, 0, alpha);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- } else {
- glDisable(GL_BLEND);
- }
-
- if (mFlags & DisplayHardware::SLOW_CONFIG) {
- glDisable(GL_DITHER);
- } else {
- glEnable(GL_DITHER);
- }
-
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glScalef(mWidthScale, mHeightScale, 1);
- glTranslatef(-x, mYOffset - y, 0);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, mVertices);
- glTexCoordPointer(2, GL_FLOAT, 0, mVertices);
- while (it != end) {
- const Rect& r = *it++;
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- }
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerBlur.h b/services/surfaceflinger/LayerBlur.h
deleted file mode 100644
index 4c9ec64..0000000
--- a/services/surfaceflinger/LayerBlur.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2007 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_LAYER_BLUR_H
-#define ANDROID_LAYER_BLUR_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/Region.h>
-
-#include "LayerBase.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class LayerBlur : public LayerBaseClient
-{
-public:
- LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- const sp<Client>& client);
- virtual ~LayerBlur();
-
- virtual void onDraw(const Region& clip) const;
- virtual bool needsBlending() const { return true; }
- virtual bool isSecure() const { return false; }
- virtual const char* getTypeId() const { return "LayerBlur"; }
-
- virtual uint32_t doTransaction(uint32_t flags);
- virtual void setVisibleRegion(const Region& visibleRegion);
- virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
-
-private:
- bool mCacheDirty;
- mutable bool mRefreshCache;
- mutable bool mAutoRefreshPending;
- nsecs_t mCacheAge;
- mutable GLuint mTextureName;
- mutable GLfloat mWidthScale;
- mutable GLfloat mHeightScale;
- mutable GLfloat mYOffset;
- mutable GLint mReadFormat;
- mutable GLint mReadType;
- mutable uint32_t mBlurFormat;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_BLUR_H
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
deleted file mode 100644
index 23506cf..0000000
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
- * Copyright (C) 2007 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 <stdlib.h>
-#include <stdint.h>
-#include <math.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/StopWatch.h>
-
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <ui/FramebufferNativeWindow.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
-#include <hardware/copybit.h>
-
-#include "LayerBuffer.h"
-#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-gralloc_module_t const* LayerBuffer::sGrallocModule = 0;
-
-// ---------------------------------------------------------------------------
-
-LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- const sp<Client>& client)
- : LayerBaseClient(flinger, display, client),
- mNeedsBlending(false), mBlitEngine(0)
-{
-}
-
-LayerBuffer::~LayerBuffer()
-{
- if (mBlitEngine) {
- copybit_close(mBlitEngine);
- }
-}
-
-void LayerBuffer::onFirstRef()
-{
- LayerBaseClient::onFirstRef();
- mSurface = new SurfaceLayerBuffer(mFlinger, this);
-
- hw_module_t const* module = (hw_module_t const*)sGrallocModule;
- if (!module) {
- // NOTE: technically there is a race here, but it shouldn't
- // cause any problem since hw_get_module() always returns
- // the same value.
- if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
- sGrallocModule = (gralloc_module_t const *)module;
- }
- }
-
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-}
-
-sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
-{
- return mSurface;
-}
-
-status_t LayerBuffer::ditch()
-{
- mSurface.clear();
- return NO_ERROR;
-}
-
-bool LayerBuffer::needsBlending() const {
- return mNeedsBlending;
-}
-
-void LayerBuffer::setNeedsBlending(bool blending) {
- mNeedsBlending = blending;
-}
-
-void LayerBuffer::postBuffer(ssize_t offset)
-{
- sp<Source> source(getSource());
- if (source != 0)
- source->postBuffer(offset);
-}
-
-void LayerBuffer::unregisterBuffers()
-{
- sp<Source> source(clearSource());
- if (source != 0)
- source->unregisterBuffers();
-}
-
-uint32_t LayerBuffer::doTransaction(uint32_t flags)
-{
- sp<Source> source(getSource());
- if (source != 0)
- source->onTransaction(flags);
- uint32_t res = LayerBase::doTransaction(flags);
- // we always want filtering for these surfaces
- mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG);
- return res;
-}
-
-void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
- Region& outDirtyRegion)
-{
- // this code-path must be as tight as possible, it's called each time
- // the screen is composited.
- sp<Source> source(getSource());
- if (source != 0)
- source->onVisibilityResolved(planeTransform);
- LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
-}
-
-void LayerBuffer::validateVisibility(const Transform& globalTransform)
-{
- sp<Source> source(getSource());
- if (source != 0)
- source->onvalidateVisibility(globalTransform);
- LayerBase::validateVisibility(globalTransform);
-}
-
-void LayerBuffer::drawForSreenShot() const
-{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- clearWithOpenGL( Region(hw.bounds()) );
-}
-
-void LayerBuffer::onDraw(const Region& clip) const
-{
- sp<Source> source(getSource());
- if (LIKELY(source != 0)) {
- source->onDraw(clip);
- } else {
- clearWithOpenGL(clip);
- }
-}
-
-void LayerBuffer::serverDestroy()
-{
- sp<Source> source(clearSource());
- if (source != 0) {
- source->destroy();
- }
-}
-
-/**
- * This creates a "buffer" source for this surface
- */
-status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
-{
- Mutex::Autolock _l(mLock);
- if (mSource != 0)
- return INVALID_OPERATION;
-
- sp<BufferSource> source = new BufferSource(*this, buffers);
-
- status_t result = source->getStatus();
- if (result == NO_ERROR) {
- mSource = source;
- }
- return result;
-}
-
-/**
- * This creates an "overlay" source for this surface
- */
-sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f,
- int32_t orientation)
-{
- sp<OverlayRef> result;
- Mutex::Autolock _l(mLock);
- if (mSource != 0)
- return result;
-
- sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f, orientation);
- if (result != 0) {
- mSource = source;
- }
- return result;
-}
-
-sp<LayerBuffer::Source> LayerBuffer::getSource() const {
- Mutex::Autolock _l(mLock);
- return mSource;
-}
-
-sp<LayerBuffer::Source> LayerBuffer::clearSource() {
- sp<Source> source;
- Mutex::Autolock _l(mLock);
- source = mSource;
- mSource.clear();
- return source;
-}
-
-// ============================================================================
-// LayerBuffer::SurfaceLayerBuffer
-// ============================================================================
-
-LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(
- const sp<SurfaceFlinger>& flinger, const sp<LayerBuffer>& owner)
- : LayerBaseClient::Surface(flinger, owner->getIdentity(), owner)
-{
-}
-
-LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer()
-{
- unregisterBuffers();
-}
-
-status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
- const ISurface::BufferHeap& buffers)
-{
- sp<LayerBuffer> owner(getOwner());
- if (owner != 0)
- return owner->registerBuffers(buffers);
- return NO_INIT;
-}
-
-void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset)
-{
- sp<LayerBuffer> owner(getOwner());
- if (owner != 0)
- owner->postBuffer(offset);
-}
-
-void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers()
-{
- sp<LayerBuffer> owner(getOwner());
- if (owner != 0)
- owner->unregisterBuffers();
-}
-
-sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(
- uint32_t w, uint32_t h, int32_t format, int32_t orientation) {
- sp<OverlayRef> result;
- sp<LayerBuffer> owner(getOwner());
- if (owner != 0)
- result = owner->createOverlay(w, h, format, orientation);
- return result;
-}
-
-// ============================================================================
-// LayerBuffer::Buffer
-// ============================================================================
-
-LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers,
- ssize_t offset, size_t bufferSize)
- : mBufferHeap(buffers), mSupportsCopybit(false)
-{
- NativeBuffer& src(mNativeBuffer);
- src.crop.l = 0;
- src.crop.t = 0;
- src.crop.r = buffers.w;
- src.crop.b = buffers.h;
-
- src.img.w = buffers.hor_stride ?: buffers.w;
- src.img.h = buffers.ver_stride ?: buffers.h;
- src.img.format = buffers.format;
- src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset);
- src.img.handle = 0;
-
- gralloc_module_t const * module = LayerBuffer::getGrallocModule();
- if (module && module->perform) {
- int err = module->perform(module,
- GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
- buffers.heap->heapID(), bufferSize,
- offset, buffers.heap->base(),
- &src.img.handle);
-
- // we can fail here is the passed buffer is purely software
- mSupportsCopybit = (err == NO_ERROR);
- }
- }
-
-LayerBuffer::Buffer::~Buffer()
-{
- NativeBuffer& src(mNativeBuffer);
- if (src.img.handle) {
- native_handle_delete(src.img.handle);
- }
-}
-
-// ============================================================================
-// LayerBuffer::Source
-// LayerBuffer::BufferSource
-// LayerBuffer::OverlaySource
-// ============================================================================
-
-LayerBuffer::Source::Source(LayerBuffer& layer)
- : mLayer(layer)
-{
-}
-LayerBuffer::Source::~Source() {
-}
-void LayerBuffer::Source::onDraw(const Region& clip) const {
-}
-void LayerBuffer::Source::onTransaction(uint32_t flags) {
-}
-void LayerBuffer::Source::onVisibilityResolved(
- const Transform& planeTransform) {
-}
-void LayerBuffer::Source::postBuffer(ssize_t offset) {
-}
-void LayerBuffer::Source::unregisterBuffers() {
-}
-
-// ---------------------------------------------------------------------------
-
-LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
- const ISurface::BufferHeap& buffers)
- : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
-{
- if (buffers.heap == NULL) {
- // this is allowed, but in this case, it is illegal to receive
- // postBuffer(). The surface just erases the framebuffer with
- // fully transparent pixels.
- mBufferHeap = buffers;
- mLayer.setNeedsBlending(false);
- return;
- }
-
- status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
- if (err != NO_ERROR) {
- LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
- mStatus = err;
- return;
- }
-
- PixelFormatInfo info;
- err = getPixelFormatInfo(buffers.format, &info);
- if (err != NO_ERROR) {
- LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
- buffers.format, strerror(err));
- mStatus = err;
- return;
- }
-
- if (buffers.hor_stride<0 || buffers.ver_stride<0) {
- LOGE("LayerBuffer::BufferSource: invalid parameters "
- "(w=%d, h=%d, xs=%d, ys=%d)",
- buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
- mStatus = BAD_VALUE;
- return;
- }
-
- mBufferHeap = buffers;
- mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
- mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
- mLayer.forceVisibilityTransaction();
-}
-
-LayerBuffer::BufferSource::~BufferSource()
-{
- class MessageDestroyTexture : public MessageBase {
- SurfaceFlinger* flinger;
- GLuint name;
- public:
- MessageDestroyTexture(
- SurfaceFlinger* flinger, GLuint name)
- : flinger(flinger), name(name) { }
- virtual bool handler() {
- glDeleteTextures(1, &name);
- return true;
- }
- };
-
- if (mTexture.name != -1U) {
- // GL textures can only be destroyed from the GL thread
- getFlinger()->mEventQueue.postMessage(
- new MessageDestroyTexture(getFlinger(), mTexture.name) );
- }
- if (mTexture.image != EGL_NO_IMAGE_KHR) {
- EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
- eglDestroyImageKHR(dpy, mTexture.image);
- }
-}
-
-void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
-{
- ISurface::BufferHeap buffers;
- { // scope for the lock
- Mutex::Autolock _l(mBufferSourceLock);
- buffers = mBufferHeap;
- if (buffers.heap != 0) {
- const size_t memorySize = buffers.heap->getSize();
- if ((size_t(offset) + mBufferSize) > memorySize) {
- LOGE("LayerBuffer::BufferSource::postBuffer() "
- "invalid buffer (offset=%d, size=%d, heap-size=%d",
- int(offset), int(mBufferSize), int(memorySize));
- return;
- }
- }
- }
-
- sp<Buffer> buffer;
- if (buffers.heap != 0) {
- buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize);
- if (buffer->getStatus() != NO_ERROR)
- buffer.clear();
- setBuffer(buffer);
- mLayer.invalidate();
- }
-}
-
-void LayerBuffer::BufferSource::unregisterBuffers()
-{
- Mutex::Autolock _l(mBufferSourceLock);
- mBufferHeap.heap.clear();
- mBuffer.clear();
- mLayer.invalidate();
-}
-
-sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
-{
- Mutex::Autolock _l(mBufferSourceLock);
- return mBuffer;
-}
-
-void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
-{
- Mutex::Autolock _l(mBufferSourceLock);
- mBuffer = buffer;
-}
-
-void LayerBuffer::BufferSource::onDraw(const Region& clip) const
-{
- sp<Buffer> ourBuffer(getBuffer());
- if (UNLIKELY(ourBuffer == 0)) {
- // nothing to do, we don't have a buffer
- mLayer.clearWithOpenGL(clip);
- return;
- }
-
- status_t err = NO_ERROR;
- NativeBuffer src(ourBuffer->getBuffer());
- const Rect transformedBounds(mLayer.getTransformedBounds());
-
-#if defined(EGL_ANDROID_image_native_buffer)
- if (GLExtensions::getInstance().haveDirectTexture()) {
- err = INVALID_OPERATION;
- if (ourBuffer->supportsCopybit()) {
- copybit_device_t* copybit = mLayer.mBlitEngine;
- if (copybit && err != NO_ERROR) {
- // create our EGLImageKHR the first time
- err = initTempBuffer();
- if (err == NO_ERROR) {
- // NOTE: Assume the buffer is allocated with the proper USAGE flags
- const NativeBuffer& dst(mTempBuffer);
- region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
- err = copybit->stretch(copybit, &dst.img, &src.img,
- &dst.crop, &src.crop, &clip);
- if (err != NO_ERROR) {
- clearTempBufferImage();
- }
- }
- }
- }
- }
-#endif
- else {
- err = INVALID_OPERATION;
- }
-
- if (err != NO_ERROR) {
- // slower fallback
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = src.crop.r;
- t.height = src.crop.b;
- t.stride = src.img.w;
- t.vstride= src.img.h;
- t.format = src.img.format;
- t.data = (GGLubyte*)src.img.base;
- const Region dirty(Rect(t.width, t.height));
- mTextureManager.loadTexture(&mTexture, dirty, t);
- }
-
- mLayer.setBufferTransform(mBufferHeap.transform);
- mLayer.drawWithOpenGL(clip, mTexture);
-}
-
-status_t LayerBuffer::BufferSource::initTempBuffer() const
-{
- // figure out the size we need now
- const ISurface::BufferHeap& buffers(mBufferHeap);
- uint32_t w = mLayer.mTransformedBounds.width();
- uint32_t h = mLayer.mTransformedBounds.height();
- if (mLayer.getOrientation() & (Transform::ROT_90 | Transform::ROT_270)) {
- int t = w; w = h; h = t;
- }
-
- // we're in the copybit case, so make sure we can handle this blit
- // we don't have to keep the aspect ratio here
- copybit_device_t* copybit = mLayer.mBlitEngine;
- const int down = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
- const int up = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
- if (buffers.w > w*down) w = buffers.w / down;
- else if (w > buffers.w*up) w = buffers.w*up;
- if (buffers.h > h*down) h = buffers.h / down;
- else if (h > buffers.h*up) h = buffers.h*up;
-
- if (mTexture.image != EGL_NO_IMAGE_KHR) {
- // we have an EGLImage, make sure the needed size didn't change
- if (w!=mTexture.width || h!= mTexture.height) {
- // delete the EGLImage and texture
- clearTempBufferImage();
- } else {
- // we're good, we have an EGLImageKHR and it's (still) the
- // right size
- return NO_ERROR;
- }
- }
-
- // figure out if we need linear filtering
- if (buffers.w * h == buffers.h * w) {
- // same pixel area, don't use filtering
- mLayer.mNeedsFiltering = false;
- }
-
- // Allocate a temporary buffer and create the corresponding EGLImageKHR
- // once the EGLImage has been created we don't need the
- // graphic buffer reference anymore.
- sp<GraphicBuffer> buffer = new GraphicBuffer(
- w, h, HAL_PIXEL_FORMAT_RGB_565,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_HW_2D);
-
- status_t err = buffer->initCheck();
- if (err == NO_ERROR) {
- NativeBuffer& dst(mTempBuffer);
- dst.img.w = buffer->getStride();
- dst.img.h = h;
- dst.img.format = buffer->getPixelFormat();
- dst.img.handle = (native_handle_t *)buffer->handle;
- dst.img.base = 0;
- dst.crop.l = 0;
- dst.crop.t = 0;
- dst.crop.r = w;
- dst.crop.b = h;
-
- EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
- err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
- }
-
- return err;
-}
-
-void LayerBuffer::BufferSource::clearTempBufferImage() const
-{
- // delete the image
- EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
- eglDestroyImageKHR(dpy, mTexture.image);
-
- // and the associated texture (recreate a name)
- glDeleteTextures(1, &mTexture.name);
- Texture defaultTexture;
- mTexture = defaultTexture;
-}
-
-// ---------------------------------------------------------------------------
-
-LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
- sp<OverlayRef>* overlayRef,
- uint32_t w, uint32_t h, int32_t format, int32_t orientation)
- : Source(layer), mVisibilityChanged(false),
- mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation)
-{
- overlay_control_device_t* overlay_dev = getFlinger()->getOverlayEngine();
- if (overlay_dev == NULL) {
- // overlays not supported
- return;
- }
-
- mOverlayDevice = overlay_dev;
- overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
- if (overlay == NULL) {
- // couldn't create the overlay (no memory? no more overlays?)
- return;
- }
-
- // enable dithering...
- overlay_dev->setParameter(overlay_dev, overlay,
- OVERLAY_DITHER, OVERLAY_ENABLE);
-
- mOverlay = overlay;
- mWidth = overlay->w;
- mHeight = overlay->h;
- mFormat = overlay->format;
- mWidthStride = overlay->w_stride;
- mHeightStride = overlay->h_stride;
- mInitialized = false;
-
- mOverlayHandle = overlay->getHandleRef(overlay);
-
- sp<OverlayChannel> channel = new OverlayChannel( &layer );
-
- *overlayRef = new OverlayRef(mOverlayHandle, channel,
- mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
- getFlinger()->signalEvent();
-}
-
-LayerBuffer::OverlaySource::~OverlaySource()
-{
- if (mOverlay && mOverlayDevice) {
- overlay_control_device_t* overlay_dev = mOverlayDevice;
- overlay_dev->destroyOverlay(overlay_dev, mOverlay);
- }
-}
-
-void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
-{
- // this would be where the color-key would be set, should we need it.
- GLclampf red = 0;
- GLclampf green = 0;
- GLclampf blue = 0;
- mLayer.clearWithOpenGL(clip, red, green, blue, 0);
-}
-
-void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
-{
- const Layer::State& front(mLayer.drawingState());
- const Layer::State& temp(mLayer.currentState());
- if (temp.sequence != front.sequence) {
- mVisibilityChanged = true;
- }
-}
-
-void LayerBuffer::OverlaySource::onvalidateVisibility(const Transform&)
-{
- mVisibilityChanged = true;
-}
-
-void LayerBuffer::OverlaySource::onVisibilityResolved(
- const Transform& planeTransform)
-{
- // this code-path must be as tight as possible, it's called each time
- // the screen is composited.
- if (UNLIKELY(mOverlay != 0)) {
- if (mVisibilityChanged || !mInitialized) {
- mVisibilityChanged = false;
- mInitialized = true;
- const Rect bounds(mLayer.getTransformedBounds());
- int x = bounds.left;
- int y = bounds.top;
- int w = bounds.width();
- int h = bounds.height();
-
- // we need a lock here to protect "destroy"
- Mutex::Autolock _l(mOverlaySourceLock);
- if (mOverlay) {
- overlay_control_device_t* overlay_dev = mOverlayDevice;
- overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
- // we need to combine the layer orientation and the
- // user-requested orientation.
- Transform finalTransform(Transform(mLayer.getOrientation()) *
- Transform(mOrientation));
- overlay_dev->setParameter(overlay_dev, mOverlay,
- OVERLAY_TRANSFORM, finalTransform.getOrientation());
- overlay_dev->commit(overlay_dev, mOverlay);
- }
- }
- }
-}
-
-void LayerBuffer::OverlaySource::destroy()
-{
- // we need a lock here to protect "onVisibilityResolved"
- Mutex::Autolock _l(mOverlaySourceLock);
- if (mOverlay && mOverlayDevice) {
- overlay_control_device_t* overlay_dev = mOverlayDevice;
- overlay_dev->destroyOverlay(overlay_dev, mOverlay);
- mOverlay = 0;
- }
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/services/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h
deleted file mode 100644
index a89d8fe..0000000
--- a/services/surfaceflinger/LayerBuffer.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2007 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_LAYER_BUFFER_H
-#define ANDROID_LAYER_BUFFER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "LayerBase.h"
-#include "TextureManager.h"
-
-struct copybit_device_t;
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class Buffer;
-class Region;
-class OverlayRef;
-
-// ---------------------------------------------------------------------------
-
-class LayerBuffer : public LayerBaseClient
-{
- class Source : public LightRefBase<Source> {
- public:
- Source(LayerBuffer& layer);
- virtual ~Source();
- virtual void onDraw(const Region& clip) const;
- virtual void onTransaction(uint32_t flags);
- virtual void onVisibilityResolved(const Transform& planeTransform);
- virtual void onvalidateVisibility(const Transform& globalTransform) { }
- virtual void postBuffer(ssize_t offset);
- virtual void unregisterBuffers();
- virtual void destroy() { }
- SurfaceFlinger* getFlinger() const { return mLayer.mFlinger.get(); }
- protected:
- LayerBuffer& mLayer;
- };
-
-public:
- LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- const sp<Client>& client);
- virtual ~LayerBuffer();
-
- virtual void onFirstRef();
- virtual bool needsBlending() const;
- virtual const char* getTypeId() const { return "LayerBuffer"; }
-
- virtual sp<LayerBaseClient::Surface> createSurface() const;
- virtual status_t ditch();
- virtual void onDraw(const Region& clip) const;
- virtual void drawForSreenShot() const;
- virtual uint32_t doTransaction(uint32_t flags);
- virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
- virtual void validateVisibility(const Transform& globalTransform);
-
- status_t registerBuffers(const ISurface::BufferHeap& buffers);
- void postBuffer(ssize_t offset);
- void unregisterBuffers();
- sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format,
- int32_t orientation);
-
- sp<Source> getSource() const;
- sp<Source> clearSource();
- void setNeedsBlending(bool blending);
- Rect getTransformedBounds() const {
- return mTransformedBounds;
- }
-
- void serverDestroy();
-
-private:
- struct NativeBuffer {
- copybit_image_t img;
- copybit_rect_t crop;
- };
-
- static gralloc_module_t const* sGrallocModule;
- static gralloc_module_t const* getGrallocModule() {
- return sGrallocModule;
- }
-
- class Buffer : public LightRefBase<Buffer> {
- public:
- Buffer(const ISurface::BufferHeap& buffers,
- ssize_t offset, size_t bufferSize);
- inline bool supportsCopybit() const {
- return mSupportsCopybit;
- }
- inline status_t getStatus() const {
- return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT;
- }
- inline const NativeBuffer& getBuffer() const {
- return mNativeBuffer;
- }
- protected:
- friend class LightRefBase<Buffer>;
- Buffer& operator = (const Buffer& rhs);
- Buffer(const Buffer& rhs);
- ~Buffer();
- private:
- ISurface::BufferHeap mBufferHeap;
- NativeBuffer mNativeBuffer;
- bool mSupportsCopybit;
- };
-
- class BufferSource : public Source {
- public:
- BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers);
- virtual ~BufferSource();
-
- status_t getStatus() const { return mStatus; }
- sp<Buffer> getBuffer() const;
- void setBuffer(const sp<Buffer>& buffer);
-
- virtual void onDraw(const Region& clip) const;
- virtual void postBuffer(ssize_t offset);
- virtual void unregisterBuffers();
- virtual void destroy() { }
- private:
- status_t initTempBuffer() const;
- void clearTempBufferImage() const;
- mutable Mutex mBufferSourceLock;
- sp<Buffer> mBuffer;
- status_t mStatus;
- ISurface::BufferHeap mBufferHeap;
- size_t mBufferSize;
- mutable Texture mTexture;
- mutable NativeBuffer mTempBuffer;
- mutable TextureManager mTextureManager;
- };
-
- class OverlaySource : public Source {
- public:
- OverlaySource(LayerBuffer& layer,
- sp<OverlayRef>* overlayRef,
- uint32_t w, uint32_t h, int32_t format, int32_t orientation);
- virtual ~OverlaySource();
- virtual void onDraw(const Region& clip) const;
- virtual void onTransaction(uint32_t flags);
- virtual void onVisibilityResolved(const Transform& planeTransform);
- virtual void onvalidateVisibility(const Transform& globalTransform);
- virtual void destroy();
- private:
-
- class OverlayChannel : public BnOverlay {
- wp<LayerBuffer> mLayer;
- virtual void destroy() {
- sp<LayerBuffer> layer(mLayer.promote());
- if (layer != 0) {
- layer->serverDestroy();
- }
- }
- public:
- OverlayChannel(const sp<LayerBuffer>& layer)
- : mLayer(layer) {
- }
- };
-
- friend class OverlayChannel;
- bool mVisibilityChanged;
-
- overlay_t* mOverlay;
- overlay_handle_t mOverlayHandle;
- overlay_control_device_t* mOverlayDevice;
- uint32_t mWidth;
- uint32_t mHeight;
- int32_t mFormat;
- int32_t mWidthStride;
- int32_t mHeightStride;
- int32_t mOrientation;
- mutable Mutex mOverlaySourceLock;
- bool mInitialized;
- };
-
-
- class SurfaceLayerBuffer : public LayerBaseClient::Surface
- {
- public:
- SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
- const sp<LayerBuffer>& owner);
- virtual ~SurfaceLayerBuffer();
-
- virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
- virtual void postBuffer(ssize_t offset);
- virtual void unregisterBuffers();
-
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format, int32_t orientation);
- private:
- sp<LayerBuffer> getOwner() const {
- return static_cast<LayerBuffer*>(Surface::getOwner().get());
- }
- };
-
- mutable Mutex mLock;
- sp<Source> mSource;
- sp<Surface> mSurface;
- bool mInvalidate;
- bool mNeedsBlending;
- copybit_device_t* mBlitEngine;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_BUFFER_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index af0f95a..61d08aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -47,12 +47,11 @@
#include "clz.h"
#include "GLExtensions.h"
#include "Layer.h"
-#include "LayerBlur.h"
-#include "LayerBuffer.h"
#include "LayerDim.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
@@ -61,10 +60,6 @@
#define AID_GRAPHICS 1003
#endif
-#ifdef USE_COMPOSITION_BYPASS
-#warning "using COMPOSITION_BYPASS"
-#endif
-
#define DISPLAY_COUNT 1
namespace android {
@@ -82,6 +77,7 @@
mReadFramebuffer("android.permission.READ_FRAME_BUFFER"),
mDump("android.permission.DUMP"),
mVisibleRegionsDirty(false),
+ mHwWorkListDirty(false),
mDeferReleaseConsole(false),
mFreezeDisplay(false),
mElectronBeamAnimationMode(0),
@@ -89,6 +85,7 @@
mFreezeDisplayTime(0),
mDebugRegion(0),
mDebugBackground(0),
+ mDebugDisableHWC(0),
mDebugInSwapBuffers(0),
mLastSwapBufferTime(0),
mDebugInTransaction(0),
@@ -120,11 +117,6 @@
glDeleteTextures(1, &mWormholeTexName);
}
-overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
-{
- return graphicPlane(0).displayHardware().getOverlayEngine();
-}
-
sp<IMemoryHeap> SurfaceFlinger::getCblk() const
{
return mServerHeap;
@@ -170,7 +162,7 @@
{
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
- LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mBootFinished = true;
property_set("ctl.stop", "bootanim");
}
@@ -206,10 +198,10 @@
mServerHeap = new MemoryHeapBase(4096,
MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
-
+
mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
-
+
new(mServerCblk) surface_flinger_cblk_t;
// initialize primary screen
@@ -238,7 +230,7 @@
// Initialize OpenGL|ES
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_SCISSOR_TEST);
glShadeModel(GL_FLAT);
@@ -272,7 +264,7 @@
// start boot animation
property_set("ctl.start", "bootanim");
-
+
return NO_ERROR;
}
@@ -375,17 +367,15 @@
// post surfaces (if needed)
handlePageFlip();
+ if (UNLIKELY(mHwWorkListDirty)) {
+ // build the h/w work list
+ handleWorkList();
+ }
+
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw() && !isFrozen())) {
-
-#ifdef USE_COMPOSITION_BYPASS
- if (handleBypassLayer()) {
- unlockClients();
- return true;
- }
-#endif
-
// repaint the framebuffer (if needed)
+
const int index = hw.getCurrentBufferIndex();
GraphicLog& logger(GraphicLog::getInstance());
@@ -396,13 +386,12 @@
logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
hw.compositionComplete();
- // release the clients before we flip ('cause flip might block)
- logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index);
- unlockClients();
-
logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
postFramebuffer();
+ logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index);
+ unlockClients();
+
logger.log(GraphicLog::SF_REPAINT_DONE, index);
} else {
// pretend we did the post
@@ -412,20 +401,6 @@
return true;
}
-bool SurfaceFlinger::handleBypassLayer()
-{
- sp<Layer> bypassLayer(mBypassLayer.promote());
- if (bypassLayer != 0) {
- sp<GraphicBuffer> buffer(bypassLayer->getBypassBuffer());
- if (buffer!=0 && (buffer->usage & GRALLOC_USAGE_HW_FB)) {
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- hw.postBypassBuffer(buffer->handle);
- return true;
- }
- }
- return false;
-}
-
void SurfaceFlinger::postFramebuffer()
{
if (!mInvalidRegion.isEmpty()) {
@@ -484,6 +459,7 @@
handleTransactionLocked(transactionFlags, ditchedLayers);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
+ mHwWorkListDirty = true;
// here the transaction has been committed
}
@@ -491,6 +467,7 @@
* Clean-up all layers that went away
* (do this without the lock held)
*/
+
const size_t count = ditchedLayers.size();
for (size_t i=0 ; i<count ; i++) {
if (ditchedLayers[i] != 0) {
@@ -694,7 +671,7 @@
// Update aboveOpaqueLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
-
+
// Store the visible region is screen space
layer->setVisibleRegion(visibleRegion);
layer->setCoveredRegion(coveredRegion);
@@ -721,37 +698,11 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::setBypassLayer(const sp<LayerBase>& layer)
-{
- // if this layer is already the bypass layer, do nothing
- sp<Layer> cur(mBypassLayer.promote());
- if (mBypassLayer == layer) {
- if (cur != NULL) {
- cur->updateBuffersOrientation();
- }
- return;
- }
-
- // clear the current bypass layer
- mBypassLayer.clear();
- if (cur != 0) {
- cur->setBypass(false);
- cur.clear();
- }
-
- // set new bypass layer
- if (layer != 0) {
- if (layer->setBypass(true)) {
- mBypassLayer = static_cast<Layer*>(layer.get());
- }
- }
-}
-
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
- LayerVector& currentLayers = const_cast<LayerVector&>(
- mDrawingState.layersSortedByZ);
+ LayerVector& currentLayers(
+ const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -772,23 +723,9 @@
mVisibleLayersSortedByZ.add(currentLayers[i]);
}
-#ifdef USE_COMPOSITION_BYPASS
- sp<LayerBase> bypassLayer;
- const size_t numVisibleLayers = mVisibleLayersSortedByZ.size();
- if (numVisibleLayers == 1) {
- const sp<LayerBase>& candidate(mVisibleLayersSortedByZ[0]);
- const Region& visibleRegion(candidate->visibleRegionScreen);
- const Region reminder(screenRegion.subtract(visibleRegion));
- if (reminder.isEmpty()) {
- // fullscreen candidate!
- bypassLayer = candidate;
- }
- }
- setBypassLayer(bypassLayer);
-#endif
-
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
+ mHwWorkListDirty = true;
}
unlockPageFlip(currentLayers);
@@ -819,15 +756,29 @@
}
}
+void SurfaceFlinger::handleWorkList()
+{
+ mHwWorkListDirty = false;
+ HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
+ if (hwc.initCheck() == NO_ERROR) {
+ const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
+ const size_t count = currentLayers.size();
+ hwc.createWorkList(count);
+ hwc_layer_t* const cur(hwc.getLayers());
+ for (size_t i=0 ; cur && i<count ; i++) {
+ currentLayers[i]->setGeometry(&cur[i]);
+ if (mDebugDisableHWC) {
+ cur[i].compositionType = HWC_FRAMEBUFFER;
+ cur[i].flags |= HWC_SKIP_LAYER;
+ }
+ }
+ }
+}
void SurfaceFlinger::handleRepaint()
{
// compute the invalid region
mInvalidRegion.orSelf(mDirtyRegion);
- if (mInvalidRegion.isEmpty()) {
- // nothing to do
- return;
- }
if (UNLIKELY(mDebugRegion)) {
debugFlashRegions();
@@ -839,8 +790,8 @@
glLoadIdentity();
uint32_t flags = hw.getFlags();
- if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
- (flags & DisplayHardware::BUFFER_PRESERVED))
+ if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))
{
// we can redraw only what's dirty, but since SWAP_RECTANGLE only
// takes a rectangle, we must make sure to update that whole
@@ -883,9 +834,73 @@
// draw something...
drawWormhole();
}
+
+ status_t err = NO_ERROR;
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
+ size_t count = layers.size();
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ HWComposer& hwc(hw.getHwComposer());
+ hwc_layer_t* const cur(hwc.getLayers());
+
+ LOGE_IF(cur && hwc.getNumLayers() != count,
+ "HAL number of layers (%d) doesn't match surfaceflinger (%d)",
+ hwc.getNumLayers(), count);
+
+ // just to be extra-safe, use the smallest count
+ if (hwc.initCheck() == NO_ERROR) {
+ count = count < hwc.getNumLayers() ? count : hwc.getNumLayers();
+ }
+
+ /*
+ * update the per-frame h/w composer data for each layer
+ * and build the transparent region of the FB
+ */
+ Region transparent;
+ if (cur) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->setPerFrameData(&cur[i]);
+ if (cur[i].hints & HWC_HINT_CLEAR_FB) {
+ if (!(layer->needsBlending())) {
+ transparent.orSelf(layer->visibleRegionScreen);
+ }
+ }
+ }
+ err = hwc.prepare();
+ LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+ }
+
+ /*
+ * clear the area of the FB that need to be transparent
+ */
+ transparent.andSelf(dirty);
+ if (!transparent.isEmpty()) {
+ glClearColor(0,0,0,0);
+ Region::const_iterator it = transparent.begin();
+ Region::const_iterator const end = transparent.end();
+ const int32_t height = hw.getHeight();
+ while (it != end) {
+ const Rect& r(*it++);
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ }
+
+
+ /*
+ * and then, render the layers targeted at the framebuffer
+ */
+ for (size_t i=0 ; i<count ; i++) {
+ if (cur) {
+ if ((cur[i].compositionType != HWC_FRAMEBUFFER) &&
+ !(cur[i].flags & HWC_SKIP_LAYER)) {
+ // skip layers handled by the HAL
+ continue;
+ }
+ }
+
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));
if (!clip.isEmpty()) {
@@ -1124,7 +1139,7 @@
if (android_atomic_dec(&mTransactionCount) == 1) {
signalEvent();
- // if there is a transaction with a resize, wait for it to
+ // if there is a transaction with a resize, wait for it to
// take effect before returning.
Mutex::Autolock _l(mStateLock);
while (mResizeTransationPending) {
@@ -1168,7 +1183,7 @@
return NO_ERROR;
}
-int SurfaceFlinger::setOrientation(DisplayID dpy,
+int SurfaceFlinger::setOrientation(DisplayID dpy,
int orientation, uint32_t flags)
{
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
@@ -1201,21 +1216,17 @@
int(w), int(h));
return surfaceHandle;
}
-
+
//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
sp<Layer> normalLayer;
switch (flags & eFXSurfaceMask) {
case eFXSurfaceNormal:
- if (UNLIKELY(flags & ePushBuffers)) {
- layer = createPushBuffersSurface(client, d, w, h, flags);
- } else {
- normalLayer = createNormalSurface(client, d, w, h, flags, format);
- layer = normalLayer;
- }
+ normalLayer = createNormalSurface(client, d, w, h, flags, format);
+ layer = normalLayer;
break;
case eFXSurfaceBlur:
- layer = createBlurSurface(client, d, w, h, flags);
- break;
+ // for now we treat Blur as Dim, until we can implement it
+ // efficiently.
case eFXSurfaceDim:
layer = createDimSurface(client, d, w, h, flags);
break;
@@ -1227,7 +1238,7 @@
ssize_t token = addClientLayer(client, layer);
surfaceHandle = layer->getSurface();
- if (surfaceHandle != 0) {
+ if (surfaceHandle != 0) {
params->token = token;
params->identity = surfaceHandle->getIdentity();
params->width = w;
@@ -1279,15 +1290,6 @@
return layer;
}
-sp<LayerBlur> SurfaceFlinger::createBlurSurface(
- const sp<Client>& client, DisplayID display,
- uint32_t w, uint32_t h, uint32_t flags)
-{
- sp<LayerBlur> layer = new LayerBlur(this, display, client);
- layer->initStates(w, h, flags);
- return layer;
-}
-
sp<LayerDim> SurfaceFlinger::createDimSurface(
const sp<Client>& client, DisplayID display,
uint32_t w, uint32_t h, uint32_t flags)
@@ -1297,21 +1299,12 @@
return layer;
}
-sp<LayerBuffer> SurfaceFlinger::createPushBuffersSurface(
- const sp<Client>& client, DisplayID display,
- uint32_t w, uint32_t h, uint32_t flags)
-{
- sp<LayerBuffer> layer = new LayerBuffer(this, display, client);
- layer->initStates(w, h, flags);
- return layer;
-}
-
status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)
{
/*
* called by the window manager, when a surface should be marked for
* destruction.
- *
+ *
* The surface is removed from the current and drawing lists, but placed
* in the purgatory queue, so it's not destroyed right-away (we need
* to wait for all client's references to go away first).
@@ -1332,7 +1325,7 @@
status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
{
// called by ~ISurface() when all references are gone
-
+
class MessageDestroySurface : public MessageBase {
SurfaceFlinger* flinger;
sp<LayerBaseClient> layer;
@@ -1345,9 +1338,9 @@
layer.clear(); // clear it outside of the lock;
Mutex::Autolock _l(flinger->mStateLock);
/*
- * remove the layer from the current list -- chances are that it's
- * not in the list anyway, because it should have been removed
- * already upon request of the client (eg: window manager).
+ * remove the layer from the current list -- chances are that it's
+ * not in the list anyway, because it should have been removed
+ * already upon request of the client (eg: window manager).
* However, a buggy client could have not done that.
* Since we know we don't have any more clients, we don't need
* to use the purgatory.
@@ -1435,7 +1428,7 @@
status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
{
- const size_t SIZE = 1024;
+ const size_t SIZE = 4096;
char buffer[SIZE];
String8 result;
if (!mDump.checkCalling()) {
@@ -1462,7 +1455,7 @@
}
const bool locked(retry >= 0);
if (!locked) {
- snprintf(buffer, SIZE,
+ snprintf(buffer, SIZE,
"SurfaceFlinger appears to be unresponsive, "
"dumping anyways (no locks held)\n");
result.append(buffer);
@@ -1482,9 +1475,9 @@
mWormholeRegion.dump(result, "WormholeRegion");
const DisplayHardware& hw(graphicPlane(0).displayHardware());
snprintf(buffer, SIZE,
- " display frozen: %s, freezeCount=%d, orientation=%d, bypass=%p, canDraw=%d\n",
+ " display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
mFreezeDisplay?"yes":"no", mFreezeCount,
- mCurrentState.orientation, mBypassLayer.unsafe_get(), hw.canDraw());
+ mCurrentState.orientation, hw.canDraw());
result.append(buffer);
snprintf(buffer, SIZE,
" last eglSwapBuffers() time: %f us\n"
@@ -1504,8 +1497,16 @@
result.append(buffer);
}
+ HWComposer& hwc(hw.getHwComposer());
+ snprintf(buffer, SIZE, " h/w composer %s and %s\n",
+ hwc.initCheck()==NO_ERROR ? "present" : "not present",
+ mDebugDisableHWC ? "disabled" : "enabled");
+ result.append(buffer);
+ hwc.dump(result, buffer, SIZE);
+
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
+ hw.dump(result);
if (locked) {
mStateLock.unlock();
@@ -1579,6 +1580,11 @@
n = data.readInt32();
mDebugBackground = n ? 1 : 0;
return NO_ERROR;
+ case 1008: // toggle use of hw composer
+ n = data.readInt32();
+ mDebugDisableHWC = n ? 1 : 0;
+ mHwWorkListDirty = true;
+ // fall-through...
case 1004:{ // repaint everything
Mutex::Autolock _l(mStateLock);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
@@ -2072,7 +2078,8 @@
status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
sp<IMemoryHeap>* heap,
uint32_t* w, uint32_t* h, PixelFormat* f,
- uint32_t sw, uint32_t sh)
+ uint32_t sw, uint32_t sh,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
{
status_t result = PERMISSION_DENIED;
@@ -2126,7 +2133,10 @@
const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
- layer->drawForSreenShot();
+ const uint32_t z = layer->drawingState().z;
+ if (z >= minLayerZ && z <= maxLayerZ) {
+ layer->drawForSreenShot();
+ }
}
// XXX: this is needed on tegra
@@ -2179,7 +2189,8 @@
status_t SurfaceFlinger::captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t sw, uint32_t sh)
+ uint32_t sw, uint32_t sh,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
{
// only one display supported for now
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
@@ -2197,13 +2208,18 @@
PixelFormat* f;
uint32_t sw;
uint32_t sh;
+ uint32_t minLayerZ;
+ uint32_t maxLayerZ;
status_t result;
public:
MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
- uint32_t sw, uint32_t sh)
+ uint32_t sw, uint32_t sh,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
: flinger(flinger), dpy(dpy),
- heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), result(PERMISSION_DENIED)
+ heap(heap), w(w), h(h), f(f), sw(sw), sh(sh),
+ minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
+ result(PERMISSION_DENIED)
{
}
status_t getResult() const {
@@ -2217,14 +2233,14 @@
return true;
result = flinger->captureScreenImplLocked(dpy,
- heap, w, h, f, sw, sh);
+ heap, w, h, f, sw, sh, minLayerZ, maxLayerZ);
return true;
}
};
sp<MessageBase> msg = new MessageCaptureScreen(this,
- dpy, heap, width, height, format, sw, sh);
+ dpy, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ);
status_t res = postMessageSync(msg);
if (res == NO_ERROR) {
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
@@ -2374,12 +2390,15 @@
{
int32_t name = NAME_NOT_FOUND;
sp<Layer> layer(mFlinger->getLayer(sur));
- if (layer == 0) return name;
+ if (layer == 0) {
+ return name;
+ }
// if this layer already has a token, just return it
name = layer->getToken();
- if ((name >= 0) && (layer->getClient() == this))
+ if ((name >= 0) && (layer->getClient() == this)) {
return name;
+ }
name = 0;
do {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ca57292..ca7d27d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -48,9 +48,7 @@
class DisplayHardware;
class FreezeLock;
class Layer;
-class LayerBlur;
class LayerDim;
-class LayerBuffer;
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
@@ -194,21 +192,19 @@
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual void signal() const;
- virtual status_t captureScreen(DisplayID dpy,
- sp<IMemoryHeap>* heap,
- uint32_t* width,
- uint32_t* height,
- PixelFormat* format,
- uint32_t reqWidth,
- uint32_t reqHeight);
+
+ virtual status_t captureScreen(DisplayID dpy,
+ sp<IMemoryHeap>* heap,
+ uint32_t* width, uint32_t* height,
+ PixelFormat* format, uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
+
virtual status_t turnElectronBeamOff(int32_t mode);
virtual status_t turnElectronBeamOn(int32_t mode);
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
- overlay_control_device_t* getOverlayEngine() const;
-
status_t removeLayer(const sp<LayerBase>& layer);
status_t addLayer(const sp<LayerBase>& layer);
status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
@@ -218,11 +214,9 @@
private:
friend class Client;
friend class LayerBase;
- friend class LayerBuffer;
friend class LayerBaseClient;
friend class LayerBaseClient::Surface;
friend class Layer;
- friend class LayerBlur;
friend class LayerDim;
sp<ISurface> createSurface(const sp<Client>& client,
@@ -236,18 +230,10 @@
uint32_t w, uint32_t h, uint32_t flags,
PixelFormat& format);
- sp<LayerBlur> createBlurSurface(
- const sp<Client>& client, DisplayID display,
- uint32_t w, uint32_t h, uint32_t flags);
-
sp<LayerDim> createDimSurface(
const sp<Client>& client, DisplayID display,
uint32_t w, uint32_t h, uint32_t flags);
- sp<LayerBuffer> createPushBuffersSurface(
- const sp<Client>& client, DisplayID display,
- uint32_t w, uint32_t h, uint32_t flags);
-
status_t removeSurface(const sp<Client>& client, SurfaceID sid);
status_t destroySurface(const sp<LayerBaseClient>& layer);
status_t setClientState(const sp<Client>& client,
@@ -306,8 +292,8 @@
void handlePageFlip();
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
+ void handleWorkList();
void handleRepaint();
- bool handleBypassLayer();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
void unlockClients();
@@ -323,12 +309,12 @@
uint32_t setTransactionFlags(uint32_t flags);
void commitTransaction();
- void setBypassLayer(const sp<LayerBase>& layer);
status_t captureScreenImplLocked(DisplayID dpy,
sp<IMemoryHeap>* heap,
uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth = 0, uint32_t reqHeight = 0);
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
status_t turnElectronBeamOffImplLocked(int32_t mode);
status_t turnElectronBeamOnImplLocked(int32_t mode);
@@ -395,18 +381,19 @@
Region mInvalidRegion;
Region mWormholeRegion;
bool mVisibleRegionsDirty;
+ bool mHwWorkListDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
int32_t mElectronBeamAnimationMode;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
Vector< sp<LayerBase> > mVisibleLayersSortedByZ;
- wp<Layer> mBypassLayer;
// don't use a lock for these, we don't care
int mDebugRegion;
int mDebugBackground;
+ int mDebugDisableHWC;
volatile nsecs_t mDebugInSwapBuffers;
nsecs_t mLastSwapBufferTime;
volatile nsecs_t mDebugInTransaction;
diff --git a/services/surfaceflinger/tests/overlays/Android.mk b/services/surfaceflinger/tests/overlays/Android.mk
deleted file mode 100644
index 592b601..0000000
--- a/services/surfaceflinger/tests/overlays/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- overlays.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libui \
- libsurfaceflinger_client
-
-LOCAL_MODULE:= test-overlays
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/overlays/overlays.cpp b/services/surfaceflinger/tests/overlays/overlays.cpp
deleted file mode 100644
index c248a615..0000000
--- a/services/surfaceflinger/tests/overlays/overlays.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-
-#include <ui/Overlay.h>
-
-#include <surfaceflinger/Surface.h>
-#include <surfaceflinger/ISurface.h>
-#include <surfaceflinger/SurfaceComposerClient.h>
-
-using namespace android;
-
-namespace android {
-class Test {
-public:
- static const sp<ISurface>& getISurface(const sp<Surface>& s) {
- return s->getISurface();
- }
-};
-};
-
-int main(int argc, char** argv)
-{
- // set up the thread-pool
- sp<ProcessState> proc(ProcessState::self());
- ProcessState::self()->startThreadPool();
-
- // create a client to surfaceflinger
- sp<SurfaceComposerClient> client = new SurfaceComposerClient();
-
- // create pushbuffer surface
- sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240,
- PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);
-
- // get to the isurface
- sp<ISurface> isurface = Test::getISurface(surface);
- printf("isurface = %p\n", isurface.get());
-
- // now request an overlay
- sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);
- sp<Overlay> overlay = new Overlay(ref);
-
-
- /*
- * here we can use the overlay API
- */
-
- overlay_buffer_t buffer;
- overlay->dequeueBuffer(&buffer);
- printf("buffer = %p\n", buffer);
-
- void* address = overlay->getBufferAddress(buffer);
- printf("address = %p\n", address);
-
- overlay->queueBuffer(buffer);
-
- return 0;
-}
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
index 127cca3..99f4b4f 100644
--- a/services/surfaceflinger/tests/resize/resize.cpp
+++ b/services/surfaceflinger/tests/resize/resize.cpp
@@ -10,8 +10,6 @@
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
-#include <ui/Overlay.h>
-
using namespace android;
namespace android {
@@ -32,7 +30,6 @@
// create a client to surfaceflinger
sp<SurfaceComposerClient> client = new SurfaceComposerClient();
- // create pushbuffer surface
sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240,
PIXEL_FORMAT_RGB_565);
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index b4de4b4..194fbb6 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -10,8 +10,6 @@
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
-#include <ui/Overlay.h>
-
using namespace android;
int main(int argc, char** argv)
@@ -23,7 +21,6 @@
// create a client to surfaceflinger
sp<SurfaceComposerClient> client = new SurfaceComposerClient();
- // create pushbuffer surface
sp<SurfaceControl> surfaceControl = client->createSurface(
getpid(), 0, 160, 240, PIXEL_FORMAT_RGB_565);
client->openTransaction();