Merge "BufferQueue: Allow detaching/reattaching buffers"
diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk
deleted file mode 100644
index 1ee7807..0000000
--- a/cmds/screenshot/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := screenshot.c
-
-LOCAL_MODULE := screenshot
-
-LOCAL_SHARED_LIBRARIES := libcutils libz liblog
-LOCAL_STATIC_LIBRARIES := libpng
-LOCAL_C_INCLUDES += external/zlib external/libpng
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/screenshot/screenshot.c b/cmds/screenshot/screenshot.c
deleted file mode 100644
index be1ecd4..0000000
--- a/cmds/screenshot/screenshot.c
+++ /dev/null
@@ -1,171 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <linux/fb.h>
-
-#include <zlib.h>
-#include <png.h>
-
-#include "private/android_filesystem_config.h"
-
-#define LOG_TAG "screenshot"
-#include <utils/Log.h>
-
-void take_screenshot(FILE *fb_in, FILE *fb_out) {
-    int fb;
-    char imgbuf[0x10000];
-    struct fb_var_screeninfo vinfo;
-    png_structp png;
-    png_infop info;
-    unsigned int r,c,rowlen;
-    unsigned int bytespp,offset;
-
-    fb = fileno(fb_in);
-    if(fb < 0) {
-        ALOGE("failed to open framebuffer\n");
-        return;
-    }
-    fb_in = fdopen(fb, "r");
-
-    if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) {
-        ALOGE("failed to get framebuffer info\n");
-        return;
-    }
-    fcntl(fb, F_SETFD, FD_CLOEXEC);
-
-    png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (png == NULL) {
-        ALOGE("failed png_create_write_struct\n");
-        fclose(fb_in);
-        return;
-    }
-
-    png_init_io(png, fb_out);
-    info = png_create_info_struct(png);
-    if (info == NULL) {
-        ALOGE("failed png_create_info_struct\n");
-        png_destroy_write_struct(&png, NULL);
-        fclose(fb_in);
-        return;
-    }
-    if (setjmp(png_jmpbuf(png))) {
-        ALOGE("failed png setjmp\n");
-        png_destroy_write_struct(&png, NULL);
-        fclose(fb_in);
-        return;
-    }
-
-    bytespp = vinfo.bits_per_pixel / 8;
-    png_set_IHDR(png, info,
-        vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, 
-        PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
-        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-    png_write_info(png, info);
-
-    rowlen=vinfo.xres * bytespp;
-    if (rowlen > sizeof(imgbuf)) {
-        ALOGE("crazy rowlen: %d\n", rowlen);
-        png_destroy_write_struct(&png, NULL);
-        fclose(fb_in);
-        return;
-    }
-
-    offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp;
-    fseek(fb_in, offset, SEEK_SET);
-
-    for(r=0; r<vinfo.yres; r++) {
-        int len = fread(imgbuf, 1, rowlen, fb_in);
-        if (len <= 0) break;
-        png_write_row(png, (png_bytep)imgbuf);
-    }
-
-    png_write_end(png, info);
-    fclose(fb_in);
-    png_destroy_write_struct(&png, NULL);
-}
-
-void fork_sound(const char* path) {
-    pid_t pid = fork();
-    if (pid == 0) {
-        execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL);
-    }
-}
-
-void usage() {
-    fprintf(stderr,
-            "usage: screenshot [-s soundfile] filename.png\n"
-            "   -s: play a sound effect to signal success\n"
-            "   -i: autoincrement to avoid overwriting filename.png\n"
-    );
-}
-
-int main(int argc, char**argv) {
-    FILE *png = NULL;
-    FILE *fb_in = NULL;
-    char outfile[PATH_MAX] = "";
-
-    char * soundfile = NULL;
-    int do_increment = 0;
-
-    int c;
-    while ((c = getopt(argc, argv, "s:i")) != -1) {
-        switch (c) {
-            case 's': soundfile = optarg; break;
-            case 'i': do_increment = 1; break;
-            case '?':
-            case 'h':
-                usage(); exit(1);
-        }
-    }
-    argc -= optind;
-    argv += optind;
-
-    if (argc < 1) {
-        usage(); exit(1);
-    }
-
-    strlcpy(outfile, argv[0], PATH_MAX);
-    if (do_increment) {
-        struct stat st;
-        char base[PATH_MAX] = "";
-        int i = 0;
-        while (stat(outfile, &st) == 0) {
-            if (!base[0]) {
-                char *p = strrchr(outfile, '.');
-                if (p) *p = '\0';
-                strcpy(base, outfile);
-            }
-            snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i);
-        }
-    }
-
-    fb_in = fopen("/dev/graphics/fb0", "r");
-    if (!fb_in) {
-        fprintf(stderr, "error: could not read framebuffer\n");
-        exit(1);
-    }
-
-    /* switch to non-root user and group */
-    gid_t groups[] = { AID_LOG, AID_SDCARD_RW };
-    setgroups(sizeof(groups)/sizeof(groups[0]), groups);
-    setuid(AID_SHELL);
-
-    png = fopen(outfile, "w");
-    if (!png) {
-        fprintf(stderr, "error: writing file %s: %s\n",
-                outfile, strerror(errno));
-        exit(1);
-    }
-
-    take_screenshot(fb_in, png);
-
-    if (soundfile) {
-        fork_sound(soundfile);
-    }
-
-    exit(0);
-}
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 5eaf00b..05b1a9c 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -218,6 +218,17 @@
 }
 
 
+// -- TouchAffineTransformation --
+void TouchAffineTransformation::applyTo(float& x, float& y) const {
+    float newX, newY;
+    newX = x * x_scale + y * x_ymix + x_offset;
+    newY = x * y_xmix + y * y_scale + y_offset;
+
+    x = newX;
+    y = newY;
+}
+
+
 // --- InputReader ---
 
 InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -2642,6 +2653,7 @@
     dumpVirtualKeys(dump);
     dumpRawPointerAxes(dump);
     dumpCalibration(dump);
+    dumpAffineTransformation(dump);
     dumpSurface(dump);
 
     dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
@@ -2740,6 +2752,11 @@
         resolveCalibration();
     }
 
+    if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) {
+        // Update location calibration to reflect current settings
+        updateAffineTransformation();
+    }
+
     if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
         // Update pointer speed.
         mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
@@ -3265,6 +3282,9 @@
             break;
         }
 
+        // Location
+        updateAffineTransformation();
+
         if (mDeviceMode == DEVICE_MODE_POINTER) {
             // Compute pointer gesture detection parameters.
             float rawDiagonal = hypotf(rawWidth, rawHeight);
@@ -3631,6 +3651,22 @@
     }
 }
 
+void TouchInputMapper::dumpAffineTransformation(String8& dump) {
+    dump.append(INDENT3 "Affine Transformation:\n");
+
+    dump.appendFormat(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
+    dump.appendFormat(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
+    dump.appendFormat(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
+    dump.appendFormat(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
+    dump.appendFormat(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
+    dump.appendFormat(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
+}
+
+void TouchInputMapper::updateAffineTransformation() {
+    mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(),
+            mSurfaceOrientation);
+}
+
 void TouchInputMapper::reset(nsecs_t when) {
     mCursorButtonAccumulator.reset(getDevice());
     mCursorScrollAccumulator.reset(getDevice());
@@ -4246,13 +4282,19 @@
             break;
         }
 
-        // X, Y, and the bounding box for coverage information
-        // Adjust coords for surface orientation.
-        float x, y, left, top, right, bottom;
+        // Adjust X,Y coords for device calibration
+        // TODO: Adjust coverage coords?
+        float xTransformed = in.x, yTransformed = in.y;
+        mAffineTransform.applyTo(xTransformed, yTransformed);
+
+        // Adjust X, Y, and coverage coords for surface orientation.
+        float x, y;
+        float left, top, right, bottom;
+
         switch (mSurfaceOrientation) {
         case DISPLAY_ORIENTATION_90:
-            x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
+            x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+            y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
             left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
             right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
             bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
@@ -4263,8 +4305,8 @@
             }
             break;
         case DISPLAY_ORIENTATION_180:
-            x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
-            y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
+            x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
+            y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
             left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
             right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
             bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
@@ -4275,8 +4317,8 @@
             }
             break;
         case DISPLAY_ORIENTATION_270:
-            x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
-            y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+            x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
+            y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
             right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
             bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
@@ -4287,8 +4329,8 @@
             }
             break;
         default:
-            x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+            x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+            y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
             left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 36b206a..c1ce5f7 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -138,6 +138,9 @@
         // The device name alias supplied by the may have changed for some devices.
         CHANGE_DEVICE_ALIAS = 1 << 5,
 
+        // The location calibration matrix changed.
+        TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+
         // All devices must be reopened.
         CHANGE_MUST_REOPEN = 1 << 31,
     };
@@ -252,6 +255,29 @@
 };
 
 
+struct TouchAffineTransformation {
+    float x_scale;
+    float x_ymix;
+    float x_offset;
+    float y_xmix;
+    float y_scale;
+    float y_offset;
+
+    TouchAffineTransformation() :
+        x_scale(1.0f), x_ymix(0.0f), x_offset(0.0f),
+        y_xmix(0.0f), y_scale(1.0f), y_offset(0.0f) {
+    }
+
+    TouchAffineTransformation(float xscale, float xymix, float xoffset,
+            float yxmix, float yscale, float yoffset) :
+        x_scale(xscale), x_ymix(xymix), x_offset(xoffset),
+        y_xmix(yxmix), y_scale(yscale), y_offset(yoffset) {
+    }
+
+    void applyTo(float& x, float& y) const;
+};
+
+
 /*
  * Input reader policy interface.
  *
@@ -287,6 +313,10 @@
 
     /* Gets a user-supplied alias for a particular input device, or an empty string if none. */
     virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
+
+    /* Gets the affine calibration associated with the specified device. */
+    virtual TouchAffineTransformation getTouchAffineTransformation(
+            const String8& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
 };
 
 
@@ -518,6 +548,7 @@
     inline int32_t getControllerNumber() const { return mControllerNumber; }
     inline int32_t getGeneration() const { return mGeneration; }
     inline const String8& getName() const { return mIdentifier.name; }
+    inline const String8& getDescriptor() { return mIdentifier.descriptor; }
     inline uint32_t getClasses() const { return mClasses; }
     inline uint32_t getSources() const { return mSources; }
 
@@ -1295,6 +1326,9 @@
         }
     } mCalibration;
 
+    // Affine location transformation/calibration
+    struct TouchAffineTransformation mAffineTransform;
+
     // Raw pointer axis information from the driver.
     RawPointerAxes mRawPointerAxes;
 
@@ -1344,7 +1378,9 @@
     virtual void parseCalibration();
     virtual void resolveCalibration();
     virtual void dumpCalibration(String8& dump);
+    virtual void dumpAffineTransformation(String8& dump);
     virtual bool hasStylus() const = 0;
+    virtual void updateAffineTransformation();
 
     virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0;
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index aaa973d..c6eb1fd 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -128,6 +128,7 @@
     InputReaderConfiguration mConfig;
     KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
     Vector<InputDeviceInfo> mInputDevices;
+    TouchAffineTransformation transform;
 
 protected:
     virtual ~FakeInputReaderPolicy() { }
@@ -173,6 +174,15 @@
         return mInputDevices;
     }
 
+    TouchAffineTransformation getTouchAffineTransformation(const String8& inputDeviceDescriptor,
+            int32_t surfaceRotation) {
+        return transform;
+    }
+
+    void setTouchAffineTransformation(const TouchAffineTransformation t) {
+        transform = t;
+    }
+
 private:
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) {
         *outConfig = mConfig;
@@ -2463,6 +2473,7 @@
     static const float Y_PRECISION;
 
     static const float GEOMETRIC_SCALE;
+    static const TouchAffineTransformation AFFINE_TRANSFORM;
 
     static const VirtualKeyDefinition VIRTUAL_KEYS[2];
 
@@ -2482,8 +2493,11 @@
 
     void prepareDisplay(int32_t orientation);
     void prepareVirtualKeys();
+    void prepareLocationCalibration();
     int32_t toRawX(float displayX);
     int32_t toRawY(float displayY);
+    float toCookedX(float rawX, float rawY);
+    float toCookedY(float rawX, float rawY);
     float toDisplayX(int32_t rawX);
     float toDisplayY(int32_t rawY);
 };
@@ -2510,6 +2524,8 @@
 const int32_t TouchInputMapperTest::RAW_SLOT_MAX = 9;
 const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH;
 const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT;
+const TouchAffineTransformation TouchInputMapperTest::AFFINE_TRANSFORM =
+        TouchAffineTransformation(1, -2, 3, -4, 5, -6);
 
 const float TouchInputMapperTest::GEOMETRIC_SCALE =
         avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1),
@@ -2531,6 +2547,10 @@
     mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE);
 }
 
+void TouchInputMapperTest::prepareLocationCalibration() {
+    mFakePolicy->setTouchAffineTransformation(AFFINE_TRANSFORM);
+}
+
 int32_t TouchInputMapperTest::toRawX(float displayX) {
     return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN);
 }
@@ -2539,6 +2559,16 @@
     return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
 }
 
+float TouchInputMapperTest::toCookedX(float rawX, float rawY) {
+    AFFINE_TRANSFORM.applyTo(rawX, rawY);
+    return rawX;
+}
+
+float TouchInputMapperTest::toCookedY(float rawX, float rawY) {
+    AFFINE_TRANSFORM.applyTo(rawX, rawY);
+    return rawY;
+}
+
 float TouchInputMapperTest::toDisplayX(int32_t rawX) {
     return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1);
 }
@@ -3226,6 +3256,30 @@
     ASSERT_EQ(tilt, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_TILT));
 }
 
+TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) {
+    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareLocationCalibration();
+    prepareButtons();
+    prepareAxes(POSITION);
+    addMapperAndConfigure(mapper);
+
+    int32_t rawX = 100;
+    int32_t rawY = 200;
+
+    float x = toDisplayX(toCookedX(rawX, rawY));
+    float y = toDisplayY(toCookedY(rawX, rawY));
+
+    processDown(mapper, rawX, rawY);
+    processSync(mapper);
+
+    NotifyMotionArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+            x, y, 1, 0, 0, 0, 0, 0, 0, 0));
+}
+
 TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) {
     SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
     addConfigurationProperty("touch.deviceType", "touchScreen");
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp
index f384ba4..feb8936 100644
--- a/services/surfaceflinger/Effects/Daltonizer.cpp
+++ b/services/surfaceflinger/Effects/Daltonizer.cpp
@@ -148,9 +148,6 @@
     // set to identity, errp, errd, errt ([0] for simulation only)
     mat4 correction(0);
 
-    // control: simulation post-correction (used for debugging):
-    // set to identity or lms2lmsp, lms2lmsd, lms2lmst
-    mat4 control;
     switch (mType) {
         case protanopia:
         case protanomaly:
@@ -172,12 +169,8 @@
             break;
     }
 
-    if (true) {
-        control = simulation;
-    }
-
-    mColorTransform = lms2rgb * control *
-            (simulation * rgb2lms + correction * (rgb2lms - simulation * rgb2lms));
+    mColorTransform = lms2rgb *
+        (simulation * rgb2lms + correction * (rgb2lms - simulation * rgb2lms));
 }
 
 } /* namespace android */