Merge "Support for 64-bit integer type."
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 971a177..afa64f8 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -143,15 +143,20 @@
send(the_socket, message, length, 0);
}
-/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to
- * compute their checksums. To make the files portable, the length is stored in
- * network order. Note that the first four bytes are reserved for future use and
- * are always set to zero in this implementation. */
+/* Here is the file format. There are two parts in blob.value, the secret and
+ * the description. The secret is stored in ciphertext, and its original size
+ * can be found in blob.length. The description is stored after the secret in
+ * plaintext, and its size is specified in blob.info. The total size of the two
+ * parts must be no more than VALUE_SIZE bytes. The first three bytes of the
+ * file are reserved for future use and are always set to zero. Fields other
+ * than blob.info, blob.length, and blob.value are modified by encrypt_blob()
+ * and decrypt_blob(). Thus they should not be accessed from outside. */
static int the_entropy = -1;
static struct __attribute__((packed)) {
- uint32_t reserved;
+ uint8_t reserved[3];
+ uint8_t info;
uint8_t vector[AES_BLOCK_SIZE];
uint8_t encrypted[0];
uint8_t digest[MD5_DIGEST_LENGTH];
@@ -170,9 +175,13 @@
return SYSTEM_ERROR;
}
- length = blob.length + blob.value - blob.encrypted;
+ length = blob.length + (blob.value - blob.encrypted);
length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
+ if (blob.info != 0) {
+ memmove(&blob.encrypted[length], &blob.value[blob.length], blob.info);
+ }
+
blob.length = htonl(blob.length);
MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest);
@@ -180,8 +189,8 @@
AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector,
AES_ENCRYPT);
- blob.reserved = 0;
- length += blob.encrypted - (uint8_t *)&blob;
+ memset(blob.reserved, 0, sizeof(blob.reserved));
+ length += (blob.encrypted - (uint8_t *)&blob) + blob.info;
fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
length -= write(fd, &blob, length);
@@ -200,7 +209,7 @@
length = read(fd, &blob, sizeof(blob));
close(fd);
- length -= blob.encrypted - (uint8_t *)&blob;
+ length -= (blob.encrypted - (uint8_t *)&blob) + blob.info;
if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) {
return VALUE_CORRUPTED;
}
@@ -215,8 +224,13 @@
length -= blob.value - blob.digested;
blob.length = ntohl(blob.length);
- return (blob.length < 0 || blob.length > length) ? VALUE_CORRUPTED :
- NO_ERROR;
+ if (blob.length < 0 || blob.length > length) {
+ return VALUE_CORRUPTED;
+ }
+ if (blob.info != 0) {
+ memmove(&blob.value[blob.length], &blob.value[length], blob.info);
+ }
+ return NO_ERROR;
}
/* Here are the actions. Each of them is a function without arguments. All
@@ -266,6 +280,7 @@
char name[NAME_MAX];
int n = sprintf(name, "%u_", uid);
encode_key(&name[n], params[0].value, params[0].length);
+ blob.info = 0;
blob.length = params[1].length;
memcpy(blob.value, params[1].value, params[1].length);
return encrypt_blob(name, &encryption_key);
@@ -336,56 +351,88 @@
#define MASTER_KEY_FILE ".masterkey"
#define MASTER_KEY_SIZE 16
+#define SALT_SIZE 16
-static void generate_key(uint8_t *key, uint8_t *password, int length)
+static void set_key(uint8_t *key, uint8_t *password, int length, uint8_t *salt)
{
- PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
- sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+ if (salt) {
+ PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, salt, SALT_SIZE,
+ 8192, MASTER_KEY_SIZE, key);
+ } else {
+ PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
+ sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+ }
}
+/* Here is the history. To improve the security, the parameters to generate the
+ * master key has been changed. To make a seamless transition, we update the
+ * file using the same password when the user unlock it for the first time. If
+ * any thing goes wrong during the transition, the new file will not overwrite
+ * the old one. This avoids permanent damages of the existing data. */
+
static int8_t password()
{
uint8_t key[MASTER_KEY_SIZE];
AES_KEY aes_key;
- int n;
+ int8_t response = SYSTEM_ERROR;
if (state == UNINITIALIZED) {
- blob.length = MASTER_KEY_SIZE;
if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) {
return SYSTEM_ERROR;
}
} else {
- generate_key(key, params[0].value, params[0].length);
+ int fd = open(MASTER_KEY_FILE, O_RDONLY);
+ uint8_t *salt = NULL;
+ if (fd != -1) {
+ int length = read(fd, &blob, sizeof(blob));
+ close(fd);
+ if (length > SALT_SIZE && blob.info == SALT_SIZE) {
+ salt = (uint8_t *)&blob + length - SALT_SIZE;
+ }
+ }
+
+ set_key(key, params[0].value, params[0].length, salt);
AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
- n = decrypt_blob(MASTER_KEY_FILE, &aes_key);
- if (n == SYSTEM_ERROR) {
+ response = decrypt_blob(MASTER_KEY_FILE, &aes_key);
+ if (response == SYSTEM_ERROR) {
return SYSTEM_ERROR;
}
- if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
+ if (response != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
if (retry <= 0) {
reset();
return UNINITIALIZED;
}
return WRONG_PASSWORD + --retry;
}
+
+ if (!salt && params[1].length == -1) {
+ params[1] = params[0];
+ }
}
if (params[1].length == -1) {
memcpy(key, blob.value, MASTER_KEY_SIZE);
} else {
- generate_key(key, params[1].value, params[1].length);
+ uint8_t *salt = &blob.value[MASTER_KEY_SIZE];
+ if (read(the_entropy, salt, SALT_SIZE) != SALT_SIZE) {
+ return SYSTEM_ERROR;
+ }
+
+ set_key(key, params[1].value, params[1].length, salt);
AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
memcpy(key, blob.value, MASTER_KEY_SIZE);
- n = encrypt_blob(MASTER_KEY_FILE, &aes_key);
+ blob.info = SALT_SIZE;
+ blob.length = MASTER_KEY_SIZE;
+ response = encrypt_blob(MASTER_KEY_FILE, &aes_key);
}
- if (n == NO_ERROR) {
+ if (response == NO_ERROR) {
AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key);
AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key);
state = NO_ERROR;
retry = MAX_RETRY;
}
- return n;
+ return response;
}
static int8_t lock()
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 76307b2..6533600 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -115,7 +115,8 @@
*/
virtual status_t captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format) = 0;
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t reqWidth, uint32_t reqHeight) = 0;
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 8773d71..a80832d 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -170,6 +170,36 @@
};
// ---------------------------------------------------------------------------
+
+class ScreenshotClient
+{
+ sp<IMemoryHeap> mHeap;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+public:
+ ScreenshotClient();
+
+ // frees the previous screenshot and capture a new one
+ status_t update();
+ status_t update(uint32_t reqWidth, uint32_t reqHeight);
+
+ // release memory occupied by the screenshot
+ void release();
+
+ // pixels are valid until this object is freed or
+ // release() or update() is called
+ void const* getPixels() const;
+
+ uint32_t getWidth() const;
+ uint32_t getHeight() const;
+ PixelFormat getFormat() const;
+ uint32_t getStride() const;
+ // size of allocated memory in bytes
+ size_t getSize() const;
+};
+
+// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 21baf32..ee40b85 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -73,7 +73,8 @@
* policy decisions such as waking from device sleep.
*/
enum {
- /* These flags originate in RawEvents and are generally set in the key map. */
+ /* These flags originate in RawEvents and are generally set in the key map.
+ * See also labels for policy flags in KeycodeLabels.h. */
POLICY_FLAG_WAKE = 0x00000001,
POLICY_FLAG_WAKE_DROPPED = 0x00000002,
@@ -83,6 +84,7 @@
POLICY_FLAG_ALT_GR = 0x00000020,
POLICY_FLAG_MENU = 0x00000040,
POLICY_FLAG_LAUNCHER = 0x00000080,
+ POLICY_FLAG_VIRTUAL = 0x00000100,
POLICY_FLAG_RAW_MASK = 0x0000ffff,
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index e85735a..2209cb8 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -103,10 +103,6 @@
virtual bool getDisplayInfo(int32_t displayId,
int32_t* width, int32_t* height, int32_t* orientation) = 0;
- /* Provides feedback for a virtual key down.
- */
- virtual void virtualKeyDownFeedback() = 0;
-
/* Intercepts a key event.
* The policy can use this method as an opportunity to perform power management functions
* and early event preprocessing such as updating policy flags.
@@ -308,9 +304,6 @@
GetStateFunc getStateFunc);
bool markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags);
-
- // dump state
- void dumpDeviceInfo(String8& dump);
};
@@ -340,6 +333,7 @@
inline bool isIgnored() { return mMappers.isEmpty(); }
+ void dump(String8& dump);
void addMapper(InputMapper* mapper);
void configure();
void reset();
@@ -393,6 +387,7 @@
virtual uint32_t getSources() = 0;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void configure();
virtual void reset();
virtual void process(const RawEvent* rawEvent) = 0;
@@ -436,6 +431,7 @@
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -484,6 +480,7 @@
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -540,6 +537,7 @@
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void configure();
virtual void reset();
@@ -761,15 +759,16 @@
} mLocked;
virtual void configureParameters();
- virtual void logParameters();
+ virtual void dumpParameters(String8& dump);
virtual void configureRawAxes();
- virtual void logRawAxes();
+ virtual void dumpRawAxes(String8& dump);
virtual bool configureSurfaceLocked();
- virtual void logMotionRangesLocked();
+ virtual void dumpSurfaceLocked(String8& dump);
virtual void configureVirtualKeysLocked();
+ virtual void dumpVirtualKeysLocked(String8& dump);
virtual void parseCalibration();
virtual void resolveCalibration();
- virtual void logCalibration();
+ virtual void dumpCalibration(String8& dump);
enum TouchResult {
// Dispatch the touch normally.
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index c8d6ffc..f71d9cd 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -142,6 +142,7 @@
{ NULL, 0 }
};
+// See also policy flags in Input.h.
static const KeycodeLabel FLAGS[] = {
{ "WAKE", 0x00000001 },
{ "WAKE_DROPPED", 0x00000002 },
@@ -151,6 +152,7 @@
{ "ALT_GR", 0x00000020 },
{ "MENU", 0x00000040 },
{ "LAUNCHER", 0x00000080 },
+ { "VIRTUAL", 0x00000100 },
{ NULL, 0 }
};
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 040060e..d676f5e 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -126,11 +126,14 @@
virtual status_t captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format)
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t reqWidth, uint32_t reqHeight)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeInt32(dpy);
+ data.writeInt32(reqWidth);
+ data.writeInt32(reqHeight);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
*width = reply.readInt32();
@@ -208,10 +211,13 @@
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
+ uint32_t reqWidth = data.readInt32();
+ uint32_t reqHeight = data.readInt32();
sp<IMemoryHeap> heap;
uint32_t w, h;
PixelFormat f;
- status_t res = captureScreen(dpy, &heap, &w, &h, &f);
+ status_t res = captureScreen(dpy, &heap, &w, &h, &f,
+ reqWidth, reqHeight);
reply->writeStrongBinder(heap->asBinder());
reply->writeInt32(w);
reply->writeInt32(h);
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 4096ac6..f270461 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -545,5 +545,55 @@
}
// ----------------------------------------------------------------------------
+
+ScreenshotClient::ScreenshotClient()
+ : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
+}
+
+status_t ScreenshotClient::update() {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, 0, 0);
+}
+
+status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, reqWidth, reqHeight);
+}
+
+void ScreenshotClient::release() {
+ mHeap = 0;
+}
+
+void const* ScreenshotClient::getPixels() const {
+ return mHeap->getBase();
+}
+
+uint32_t ScreenshotClient::getWidth() const {
+ return mWidth;
+}
+
+uint32_t ScreenshotClient::getHeight() const {
+ return mHeight;
+}
+
+PixelFormat ScreenshotClient::getFormat() const {
+ return mFormat;
+}
+
+uint32_t ScreenshotClient::getStride() const {
+ return mWidth;
+}
+
+size_t ScreenshotClient::getSize() const {
+ return mHeap->getSize();
+}
+
+// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index f2b029a..825febc 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -33,6 +33,9 @@
#include <math.h>
#define INDENT " "
+#define INDENT2 " "
+#define INDENT3 " "
+#define INDENT4 " "
namespace android {
@@ -63,6 +66,10 @@
return sqrtf(x * x + y * y);
}
+static inline const char* toString(bool value) {
+ return value ? "true" : "false";
+}
+
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
int32_t mask;
@@ -236,16 +243,14 @@
String8 name = mEventHub->getDeviceName(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- // Write a log message about the added device as a heading for subsequent log messages.
- LOGI("Device added: id=0x%x, name=%s", deviceId, name.string());
-
InputDevice* device = createDevice(deviceId, name, classes);
device->configure();
if (device->isIgnored()) {
- LOGI(INDENT "Sources: none (device is ignored)");
+ LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", deviceId, name.string());
} else {
- LOGI(INDENT "Sources: 0x%08x", device->getSources());
+ LOGI("Device added: id=0x%x, name=%s, sources=%08x", deviceId, name.string(),
+ device->getSources());
}
bool added = false;
@@ -287,7 +292,6 @@
return;
}
- // Write a log message about the removed device as a heading for subsequent log messages.
if (device->isIgnored()) {
LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)",
device->getId(), device->getName().string());
@@ -571,59 +575,15 @@
}
void InputReader::dump(String8& dump) {
- dumpDeviceInfo(dump);
-}
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
-static void dumpMotionRange(String8& dump,
- const char* name, const InputDeviceInfo::MotionRange* range) {
- if (range) {
- dump.appendFormat(" %s = { min: %0.3f, max: %0.3f, flat: %0.3f, fuzz: %0.3f }\n",
- name, range->min, range->max, range->flat, range->fuzz);
- }
-}
-
-#define DUMP_MOTION_RANGE(range) \
- dumpMotionRange(dump, #range, deviceInfo.getMotionRange(AINPUT_MOTION_RANGE_##range));
-
-void InputReader::dumpDeviceInfo(String8& dump) {
- Vector<int32_t> deviceIds;
- getInputDeviceIds(deviceIds);
-
- InputDeviceInfo deviceInfo;
- for (size_t i = 0; i < deviceIds.size(); i++) {
- int32_t deviceId = deviceIds[i];
-
- status_t result = getInputDeviceInfo(deviceId, & deviceInfo);
- if (result == NAME_NOT_FOUND) {
- continue;
- } else if (result != OK) {
- dump.appendFormat(" ** Unexpected error %d getting information about input devices.\n",
- result);
- continue;
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ mDevices.valueAt(i)->dump(dump);
}
-
- dump.appendFormat(" Device %d: '%s'\n",
- deviceInfo.getId(), deviceInfo.getName().string());
- dump.appendFormat(" sources = 0x%08x\n",
- deviceInfo.getSources());
- dump.appendFormat(" keyboardType = %d\n",
- deviceInfo.getKeyboardType());
-
- dump.append(" motion ranges:\n");
- DUMP_MOTION_RANGE(X);
- DUMP_MOTION_RANGE(Y);
- DUMP_MOTION_RANGE(PRESSURE);
- DUMP_MOTION_RANGE(SIZE);
- DUMP_MOTION_RANGE(TOUCH_MAJOR);
- DUMP_MOTION_RANGE(TOUCH_MINOR);
- DUMP_MOTION_RANGE(TOOL_MAJOR);
- DUMP_MOTION_RANGE(TOOL_MINOR);
- DUMP_MOTION_RANGE(ORIENTATION);
- }
+ } // release device registy reader lock
}
-#undef DUMP_MOTION_RANGE
-
// --- InputReaderThread ---
@@ -654,6 +614,43 @@
mMappers.clear();
}
+static void dumpMotionRange(String8& dump, const InputDeviceInfo& deviceInfo,
+ int32_t rangeType, const char* name) {
+ const InputDeviceInfo::MotionRange* range = deviceInfo.getMotionRange(rangeType);
+ if (range) {
+ dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
+ name, range->min, range->max, range->flat, range->fuzz);
+ }
+}
+
+void InputDevice::dump(String8& dump) {
+ InputDeviceInfo deviceInfo;
+ getDeviceInfo(& deviceInfo);
+
+ dump.appendFormat(INDENT "Device 0x%x: %s\n", deviceInfo.getId(),
+ deviceInfo.getName().string());
+ dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
+ dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
+ if (!deviceInfo.getMotionRanges().isEmpty()) {
+ dump.append(INDENT2 "Motion Ranges:\n");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_X, "X");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_Y, "Y");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_PRESSURE, "Pressure");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_SIZE, "Size");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MAJOR, "TouchMajor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MINOR, "TouchMinor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MAJOR, "ToolMajor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MINOR, "ToolMinor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_ORIENTATION, "Orientation");
+ }
+
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->dump(dump);
+ }
+}
+
void InputDevice::addMapper(InputMapper* mapper) {
mMappers.add(mapper);
}
@@ -763,6 +760,9 @@
info->addSource(getSources());
}
+void InputMapper::dump(String8& dump) {
+}
+
void InputMapper::configure() {
}
@@ -856,6 +856,19 @@
info->setKeyboardType(mKeyboardType);
}
+void KeyboardInputMapper::dump(String8& dump) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+ dump.append(INDENT2 "Keyboard Input Mapper:\n");
+ dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dump.appendFormat(INDENT3 "Sources: 0x%x\n", mSources);
+ 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);
+ dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
+ } // release lock
+}
+
void KeyboardInputMapper::reset() {
for (;;) {
int32_t keyCode, scanCode;
@@ -980,7 +993,10 @@
int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
+ keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
+ if (policyFlags & POLICY_FLAG_VIRTUAL) {
+ keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
}
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
@@ -1044,6 +1060,18 @@
info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale);
}
+void TrackballInputMapper::dump(String8& dump) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+ dump.append(INDENT2 "Trackball Input Mapper:\n");
+ dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ 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));
+ dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
+ } // release lock
+}
+
void TrackballInputMapper::initializeLocked() {
mAccumulator.clear();
@@ -1275,6 +1303,21 @@
} // release lock
}
+void TouchInputMapper::dump(String8& dump) {
+ { // 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 "XPrecision: %0.3f\n", mLocked.xPrecision);
+ dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mLocked.yPrecision);
+ } // release lock
+}
+
void TouchInputMapper::initializeLocked() {
mCurrentTouch.clear();
mLastTouch.clear();
@@ -1301,16 +1344,13 @@
// Configure basic parameters.
configureParameters();
- logParameters();
// Configure absolute axis information.
configureRawAxes();
- logRawAxes();
// Prepare input device calibration.
parseCalibration();
resolveCalibration();
- logCalibration();
{ // acquire lock
AutoMutex _l(mLock);
@@ -1326,16 +1366,13 @@
mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
}
-void TouchInputMapper::logParameters() {
- if (mParameters.useBadTouchFilter) {
- LOGI(INDENT "Bad touch filter enabled.");
- }
- if (mParameters.useAveragingTouchFilter) {
- LOGI(INDENT "Averaging touch filter enabled.");
- }
- if (mParameters.useJumpyTouchFilter) {
- LOGI(INDENT "Jumpy touch filter enabled.");
- }
+void TouchInputMapper::dumpParameters(String8& dump) {
+ dump.appendFormat(INDENT3 "UseBadTouchFilter: %s\n",
+ toString(mParameters.useBadTouchFilter));
+ dump.appendFormat(INDENT3 "UseAveragingTouchFilter: %s\n",
+ toString(mParameters.useAveragingTouchFilter));
+ dump.appendFormat(INDENT3 "UseJumpyTouchFilter: %s\n",
+ toString(mParameters.useJumpyTouchFilter));
}
void TouchInputMapper::configureRawAxes() {
@@ -1349,24 +1386,25 @@
mRawAxes.orientation.clear();
}
-static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) {
+static void dumpAxisInfo(String8& dump, RawAbsoluteAxisInfo axis, const char* name) {
if (axis.valid) {
- LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d",
+ dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d\n",
name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz);
} else {
- LOGI(INDENT "Raw %s axis: unknown range", name);
+ dump.appendFormat(INDENT4 "%s: unknown range\n", name);
}
}
-void TouchInputMapper::logRawAxes() {
- logAxisInfo(mRawAxes.x, "x");
- logAxisInfo(mRawAxes.y, "y");
- logAxisInfo(mRawAxes.pressure, "pressure");
- logAxisInfo(mRawAxes.touchMajor, "touchMajor");
- logAxisInfo(mRawAxes.touchMinor, "touchMinor");
- logAxisInfo(mRawAxes.toolMajor, "toolMajor");
- logAxisInfo(mRawAxes.toolMinor, "toolMinor");
- logAxisInfo(mRawAxes.orientation, "orientation");
+void TouchInputMapper::dumpRawAxes(String8& dump) {
+ dump.append(INDENT3 "Raw Axes:\n");
+ dumpAxisInfo(dump, mRawAxes.x, "X");
+ dumpAxisInfo(dump, mRawAxes.y, "Y");
+ dumpAxisInfo(dump, mRawAxes.pressure, "Pressure");
+ dumpAxisInfo(dump, mRawAxes.touchMajor, "TouchMajor");
+ dumpAxisInfo(dump, mRawAxes.touchMinor, "TouchMinor");
+ dumpAxisInfo(dump, mRawAxes.toolMajor, "ToolMajor");
+ dumpAxisInfo(dump, mRawAxes.toolMinor, "ToolMinor");
+ dumpAxisInfo(dump, mRawAxes.orientation, "Orientation");
}
bool TouchInputMapper::configureSurfaceLocked() {
@@ -1391,10 +1429,8 @@
bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
if (sizeChanged) {
- LOGI("Device reconfigured (display size changed): id=0x%x, name=%s",
- getDeviceId(), getDeviceName().string());
- LOGI(INDENT "Width: %dpx", width);
- LOGI(INDENT "Height: %dpx", height);
+ LOGI("Device reconfigured: id=0x%x, name=%s, display size is now %dx%d",
+ getDeviceId(), getDeviceName().string(), width, height);
mLocked.surfaceWidth = width;
mLocked.surfaceHeight = height;
@@ -1562,39 +1598,13 @@
mLocked.orientedRanges.y.fuzz = orientedYScale;
}
- if (sizeChanged) {
- logMotionRangesLocked();
- }
-
return true;
}
-static void logMotionRangeInfo(InputDeviceInfo::MotionRange* range, const char* name) {
- if (range) {
- LOGI(INDENT "Output %s range: min=%f, max=%f, flat=%f, fuzz=%f",
- name, range->min, range->max, range->flat, range->fuzz);
- } else {
- LOGI(INDENT "Output %s range: unsupported", name);
- }
-}
-
-void TouchInputMapper::logMotionRangesLocked() {
- logMotionRangeInfo(& mLocked.orientedRanges.x, "x");
- logMotionRangeInfo(& mLocked.orientedRanges.y, "y");
- logMotionRangeInfo(mLocked.orientedRanges.havePressure
- ? & mLocked.orientedRanges.pressure : NULL, "pressure");
- logMotionRangeInfo(mLocked.orientedRanges.haveSize
- ? & mLocked.orientedRanges.size : NULL, "size");
- logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea
- ? & mLocked.orientedRanges.touchMajor : NULL, "touchMajor");
- logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea
- ? & mLocked.orientedRanges.touchMinor : NULL, "touchMinor");
- logMotionRangeInfo(mLocked.orientedRanges.haveToolArea
- ? & mLocked.orientedRanges.toolMajor : NULL, "toolMajor");
- logMotionRangeInfo(mLocked.orientedRanges.haveToolArea
- ? & mLocked.orientedRanges.toolMinor : NULL, "toolMinor");
- logMotionRangeInfo(mLocked.orientedRanges.haveOrientation
- ? & mLocked.orientedRanges.orientation : NULL, "orientation");
+void TouchInputMapper::dumpSurfaceLocked(String8& dump) {
+ dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mLocked.surfaceWidth);
+ dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mLocked.surfaceHeight);
+ dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mLocked.surfaceOrientation);
}
void TouchInputMapper::configureVirtualKeysLocked() {
@@ -1651,9 +1661,21 @@
virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
* touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
- LOGI(INDENT "VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
- virtualKey.scanCode, virtualKey.keyCode,
- virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
+ }
+}
+
+void TouchInputMapper::dumpVirtualKeysLocked(String8& dump) {
+ if (!mLocked.virtualKeys.isEmpty()) {
+ dump.append(INDENT3 "Virtual Keys:\n");
+
+ for (size_t i = 0; i < mLocked.virtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mLocked.virtualKeys.itemAt(i);
+ dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, "
+ "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
+ i, virtualKey.scanCode, virtualKey.keyCode,
+ virtualKey.hitLeft, virtualKey.hitRight,
+ virtualKey.hitTop, virtualKey.hitBottom);
+ }
}
}
@@ -1861,19 +1883,19 @@
}
}
-void TouchInputMapper::logCalibration() {
- LOGI(INDENT "Calibration:");
+void TouchInputMapper::dumpCalibration(String8& dump) {
+ dump.append(INDENT3 "Calibration:\n");
// Touch Area
switch (mCalibration.touchAreaCalibration) {
case Calibration::TOUCH_AREA_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.touchArea.calibration: none");
+ dump.append(INDENT4 "touch.touchArea.calibration: none\n");
break;
case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC:
- LOGI(INDENT INDENT "touch.touchArea.calibration: geometric");
+ dump.append(INDENT4 "touch.touchArea.calibration: geometric\n");
break;
case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE:
- LOGI(INDENT INDENT "touch.touchArea.calibration: pressure");
+ dump.append(INDENT4 "touch.touchArea.calibration: pressure\n");
break;
default:
assert(false);
@@ -1882,40 +1904,43 @@
// Tool Area
switch (mCalibration.toolAreaCalibration) {
case Calibration::TOOL_AREA_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.toolArea.calibration: none");
+ dump.append(INDENT4 "touch.toolArea.calibration: none\n");
break;
case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC:
- LOGI(INDENT INDENT "touch.toolArea.calibration: geometric");
+ dump.append(INDENT4 "touch.toolArea.calibration: geometric\n");
break;
case Calibration::TOOL_AREA_CALIBRATION_LINEAR:
- LOGI(INDENT INDENT "touch.toolArea.calibration: linear");
+ dump.append(INDENT4 "touch.toolArea.calibration: linear\n");
break;
default:
assert(false);
}
if (mCalibration.haveToolAreaLinearScale) {
- LOGI(INDENT INDENT "touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale);
+ dump.appendFormat(INDENT4 "touch.toolArea.linearScale: %0.3f\n",
+ mCalibration.toolAreaLinearScale);
}
if (mCalibration.haveToolAreaLinearBias) {
- LOGI(INDENT INDENT "touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias);
+ dump.appendFormat(INDENT4 "touch.toolArea.linearBias: %0.3f\n",
+ mCalibration.toolAreaLinearBias);
}
if (mCalibration.haveToolAreaIsSummed) {
- LOGI(INDENT INDENT "touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed);
+ dump.appendFormat(INDENT4 "touch.toolArea.isSummed: %d\n",
+ mCalibration.toolAreaIsSummed);
}
// Pressure
switch (mCalibration.pressureCalibration) {
case Calibration::PRESSURE_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.pressure.calibration: none");
+ dump.append(INDENT4 "touch.pressure.calibration: none\n");
break;
case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
- LOGI(INDENT INDENT "touch.pressure.calibration: physical");
+ dump.append(INDENT4 "touch.pressure.calibration: physical\n");
break;
case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
- LOGI(INDENT INDENT "touch.pressure.calibration: amplitude");
+ dump.append(INDENT4 "touch.pressure.calibration: amplitude\n");
break;
default:
assert(false);
@@ -1923,10 +1948,10 @@
switch (mCalibration.pressureSource) {
case Calibration::PRESSURE_SOURCE_PRESSURE:
- LOGI(INDENT INDENT "touch.pressure.source: pressure");
+ dump.append(INDENT4 "touch.pressure.source: pressure\n");
break;
case Calibration::PRESSURE_SOURCE_TOUCH:
- LOGI(INDENT INDENT "touch.pressure.source: touch");
+ dump.append(INDENT4 "touch.pressure.source: touch\n");
break;
case Calibration::PRESSURE_SOURCE_DEFAULT:
break;
@@ -1935,16 +1960,17 @@
}
if (mCalibration.havePressureScale) {
- LOGI(INDENT INDENT "touch.pressure.scale: %f", mCalibration.pressureScale);
+ dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n",
+ mCalibration.pressureScale);
}
// Size
switch (mCalibration.sizeCalibration) {
case Calibration::SIZE_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.size.calibration: none");
+ dump.append(INDENT4 "touch.size.calibration: none\n");
break;
case Calibration::SIZE_CALIBRATION_NORMALIZED:
- LOGI(INDENT INDENT "touch.size.calibration: normalized");
+ dump.append(INDENT4 "touch.size.calibration: normalized\n");
break;
default:
assert(false);
@@ -1953,10 +1979,10 @@
// Orientation
switch (mCalibration.orientationCalibration) {
case Calibration::ORIENTATION_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.orientation.calibration: none");
+ dump.append(INDENT4 "touch.orientation.calibration: none\n");
break;
case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
- LOGI(INDENT INDENT "touch.orientation.calibration: interpolated");
+ dump.append(INDENT4 "touch.orientation.calibration: interpolated\n");
break;
default:
assert(false);
@@ -2139,10 +2165,7 @@
int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
int32_t metaState = mContext->getGlobalMetaState();
- if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
- getPolicy()->virtualKeyDownFeedback();
- }
-
+ policyFlags |= POLICY_FLAG_VIRTUAL;
int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b21a8d..fb76720 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -271,6 +271,17 @@
}
}
+void Layer::drawForSreenShot() const
+{
+ bool currentFixedSize = mFixedSize;
+ bool currentBlending = mNeedsBlending;
+ const_cast<Layer*>(this)->mFixedSize = false;
+ const_cast<Layer*>(this)->mFixedSize = true;
+ LayerBase::drawForSreenShot();
+ const_cast<Layer*>(this)->mFixedSize = currentFixedSize;
+ const_cast<Layer*>(this)->mNeedsBlending = currentBlending;
+}
+
void Layer::onDraw(const Region& clip) const
{
Texture tex(mBufferManager.getActiveTexture());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 188da6a..caa6d17 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -70,6 +70,7 @@
// 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);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 3d049a7..14191cb 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -326,6 +326,12 @@
onDraw(clip);
}
+void LayerBase::drawForSreenShot() const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ onDraw( Region(hw.bounds()) );
+}
+
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
GLclampf green, GLclampf blue,
GLclampf alpha) const
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c66dc34..bdee05b 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -121,6 +121,7 @@
* to perform the actual drawing.
*/
virtual void draw(const Region& clip) const;
+ virtual void drawForSreenShot() const;
/**
* onDraw - draws the surface.
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index fdf9abc..c060895 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -132,6 +132,12 @@
LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
}
+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());
diff --git a/services/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h
index 1c0bf83..fece858 100644
--- a/services/surfaceflinger/LayerBuffer.h
+++ b/services/surfaceflinger/LayerBuffer.h
@@ -64,6 +64,7 @@
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);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 17b98a6..e6bdfd1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1653,9 +1653,117 @@
// ---------------------------------------------------------------------------
+status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
+ sp<IMemoryHeap>* heap,
+ uint32_t* w, uint32_t* h, PixelFormat* f,
+ uint32_t sw, uint32_t sh)
+{
+ status_t result = PERMISSION_DENIED;
+
+ // only one display supported for now
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+
+ if ((sw > hw_w) || (sh > hw_h))
+ return BAD_VALUE;
+
+ sw = (!sw) ? hw_w : sw;
+ sh = (!sh) ? hw_h : sh;
+ const size_t size = sw * sh * 4;
+
+ // make sure to clear all GL error flags
+ while ( glGetError() != GL_NO_ERROR ) ;
+
+ // create a FBO
+ GLuint name, tname;
+ glGenRenderbuffersOES(1, &tname);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
+ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
+ GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
+
+ GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+ if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
+
+ // invert everything, b/c glReadPixel() below will invert the FB
+ glViewport(0, 0, sw, sh);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrthof(0, hw_w, 0, hw_h, 0, 1);
+ glMatrixMode(GL_MODELVIEW);
+
+ // redraw the screen entirely...
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->drawForSreenShot();
+ }
+
+ // XXX: this is needed on tegra
+ glScissor(0, 0, sw, sh);
+
+ // check for errors and return screen capture
+ if (glGetError() != GL_NO_ERROR) {
+ // error while rendering
+ result = INVALID_OPERATION;
+ } else {
+ // allocate shared memory large enough to hold the
+ // screen capture
+ sp<MemoryHeapBase> base(
+ new MemoryHeapBase(size, 0, "screen-capture") );
+ void* const ptr = base->getBase();
+ if (ptr) {
+ // capture the screen with glReadPixels()
+ glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
+ if (glGetError() == GL_NO_ERROR) {
+ *heap = base;
+ *w = sw;
+ *h = sh;
+ *f = PIXEL_FORMAT_RGBA_8888;
+ result = NO_ERROR;
+ }
+ } else {
+ result = NO_MEMORY;
+ }
+ }
+
+ glEnable(GL_SCISSOR_TEST);
+ glViewport(0, 0, hw_w, hw_h);
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+
+
+ } else {
+ result = BAD_VALUE;
+ }
+
+ // release FBO resources
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDeleteRenderbuffersOES(1, &tname);
+ glDeleteFramebuffersOES(1, &name);
+ return result;
+}
+
+
status_t SurfaceFlinger::captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format)
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t sw, uint32_t sh)
{
// only one display supported for now
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
@@ -1671,12 +1779,15 @@
uint32_t* w;
uint32_t* h;
PixelFormat* f;
+ uint32_t sw;
+ uint32_t sh;
status_t result;
public:
MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
- sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f)
+ sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
+ uint32_t sw, uint32_t sh)
: flinger(flinger), dpy(dpy),
- heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED)
+ heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), result(PERMISSION_DENIED)
{
}
status_t getResult() const {
@@ -1689,94 +1800,15 @@
if (flinger->mSecureFrameBuffer)
return true;
- // make sure to clear all GL error flags
- while ( glGetError() != GL_NO_ERROR ) ;
+ result = flinger->captureScreenImplLocked(dpy,
+ heap, w, h, f, sw, sh);
- // get screen geometry
- const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware());
- const uint32_t sw = hw.getWidth();
- const uint32_t sh = hw.getHeight();
- const Region screenBounds(hw.bounds());
- const size_t size = sw * sh * 4;
-
- // create a FBO
- GLuint name, tname;
- glGenRenderbuffersOES(1, &tname);
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
- glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
- GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
-
- GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
- if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
-
- // invert everything, b/c glReadPixel() below will invert the FB
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrthof(0, sw, 0, sh, 0, 1);
- glMatrixMode(GL_MODELVIEW);
-
- // redraw the screen entirely...
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
- const Vector< sp<LayerBase> >& layers(
- flinger->mVisibleLayersSortedByZ);
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(layers[i]);
- if (!strcmp(layer->getTypeId(), "LayerBuffer")) {
- // we cannot render LayerBuffer because it doens't
- // use OpenGL, and won't show-up in the FBO.
- continue;
- }
- layer->draw(screenBounds);
- }
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
-
- // check for errors and return screen capture
- if (glGetError() != GL_NO_ERROR) {
- // error while rendering
- result = INVALID_OPERATION;
- } else {
- // allocate shared memory large enough to hold the
- // screen capture
- sp<MemoryHeapBase> base(
- new MemoryHeapBase(size, 0, "screen-capture") );
- void* const ptr = base->getBase();
- if (ptr) {
- // capture the screen with glReadPixels()
- glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
- if (glGetError() == GL_NO_ERROR) {
- *heap = base;
- *w = sw;
- *h = sh;
- *f = PIXEL_FORMAT_RGBA_8888;
- result = NO_ERROR;
- }
- } else {
- result = NO_MEMORY;
- }
- }
- } else {
- result = BAD_VALUE;
- }
-
- // release FBO resources
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteRenderbuffersOES(1, &tname);
- glDeleteFramebuffersOES(1, &name);
return true;
}
};
sp<MessageBase> msg = new MessageCaptureScreen(this,
- dpy, heap, width, height, format);
+ dpy, heap, width, height, format, sw, sh);
status_t res = postMessageSync(msg);
if (res == NO_ERROR) {
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6e9ecbd..732e57e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -197,7 +197,9 @@
sp<IMemoryHeap>* heap,
uint32_t* width,
uint32_t* height,
- PixelFormat* format);
+ PixelFormat* format,
+ uint32_t reqWidth,
+ uint32_t reqHeight);
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
@@ -319,6 +321,11 @@
void commitTransaction();
+ status_t captureScreenImplLocked(DisplayID dpy,
+ sp<IMemoryHeap>* heap,
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t reqWidth = 0, uint32_t reqHeight = 0);
+
friend class FreezeLock;
sp<FreezeLock> getFreezeLock() const;
inline void incFreezeCount() {
diff --git a/services/surfaceflinger/tests/screencap/screencap.cpp b/services/surfaceflinger/tests/screencap/screencap.cpp
index 9e893f4..6cf1504 100644
--- a/services/surfaceflinger/tests/screencap/screencap.cpp
+++ b/services/surfaceflinger/tests/screencap/screencap.cpp
@@ -42,7 +42,7 @@
sp<IMemoryHeap> heap;
uint32_t w, h;
PixelFormat f;
- status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
+ status_t err = composer->captureScreen(0, &heap, &w, &h, &f, 0, 0);
if (err != NO_ERROR) {
fprintf(stderr, "screen capture failed: %s\n", strerror(-err));
exit(0);