make multi-display more real

- displays are represented by a binder on the client side
- c++ clients can now create and modify displays

Change-Id: I203ea5b4beae0819d742ec5171c27568f4e8354b
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index b2f8889..9ab35b1 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -48,6 +48,11 @@
         eSynchronous = 0x01,
     };
 
+    enum {
+        eDisplayIdMain = 0,
+        eDisplayIdHdmi = 1
+    };
+
     /* create connection with surface flinger, requires
      * ACCESS_SURFACE_FLINGER permission
      */
@@ -57,6 +62,19 @@
      */
     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
 
+    /* return an IDisplayEventConnection */
+    virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
+
+    /* create a display with given id.
+     * requires ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual sp<IBinder> createDisplay() = 0;
+
+    /* get the token for the existing default displays. possible values
+     * for id are eDisplayIdMain and eDisplayIdHdmi.
+     */
+    virtual sp<IBinder> getBuiltInDisplay(int32_t id) = 0;
+
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual void setTransactionState(const Vector<ComposerState>& state,
             const Vector<DisplayState>& displays, uint32_t flags) = 0;
@@ -66,6 +84,11 @@
      */
     virtual void bootFinished() = 0;
 
+    /* verify that an ISurfaceTexture was created by SurfaceFlinger.
+     */
+    virtual bool authenticateSurfaceTexture(
+            const sp<ISurfaceTexture>& surface) const = 0;
+
     /* Capture the specified screen. requires READ_FRAME_BUFFER permission
      * This function will fail if there is a secure window on screen.
      */
@@ -74,13 +97,6 @@
             uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
             uint32_t maxLayerZ) = 0;
 
-    /* verify that an ISurfaceTexture was created by SurfaceFlinger.
-     */
-    virtual bool authenticateSurfaceTexture(
-            const sp<ISurfaceTexture>& surface) const = 0;
-
-    /* return an IDisplayEventConnection */
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
 
     /* triggers screen off and waits for it to complete */
     virtual void blank() = 0;
@@ -106,13 +122,15 @@
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
         CREATE_GRAPHIC_BUFFER_ALLOC,
-        GET_DISPLAY_INFO,
-        SET_TRANSACTION_STATE,
-        CAPTURE_SCREEN,
-        AUTHENTICATE_SURFACE,
         CREATE_DISPLAY_EVENT_CONNECTION,
+        CREATE_DISPLAY,
+        GET_BUILT_IN_DISPLAY,
+        SET_TRANSACTION_STATE,
+        AUTHENTICATE_SURFACE,
+        CAPTURE_SCREEN,
         BLANK,
         UNBLANK,
+        GET_DISPLAY_INFO,
         CONNECT_DISPLAY,
     };
 
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index b058b8d..5776038 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -59,6 +59,13 @@
     // Forcibly remove connection before all references have gone away.
     void        dispose();
 
+    // callback when the composer is dies
+    status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
+            void* cookie = NULL, uint32_t flags = 0);
+
+    // Get information about a display
+    static status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info);
+
     // ------------------------------------------------------------------------
     // surface creation / destruction
 
@@ -80,13 +87,14 @@
             uint32_t flags = 0  // usage flags
     );
 
+    static sp<IBinder> createDisplay();
 
     // ------------------------------------------------------------------------
     // Composer parameters
     // All composer parameters must be changed within a transaction
     // several surfaces can be updated in one transaction, all changes are
     // committed at once when the transaction is closed.
-    // closeGlobalTransaction() usually requires an IPC with the server.
+    // closeGlobalTransaction() requires an IPC with the server.
 
     //! Open a composer transaction on all active SurfaceComposerClients.
     static void openGlobalTransaction();
@@ -97,12 +105,6 @@
     //! Set the orientation of the given display
     static int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
 
-    // Get information about a display
-    static status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info);
-
-    status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
-            void* cookie = NULL, uint32_t flags = 0);
-
     status_t    hide(SurfaceID id);
     status_t    show(SurfaceID id, int32_t layer = -1);
     status_t    setFlags(SurfaceID id, uint32_t flags, uint32_t mask);
@@ -116,6 +118,16 @@
     status_t    setLayerStack(SurfaceID id, uint32_t layerStack);
     status_t    destroySurface(SurfaceID sid);
 
+    static void setDisplaySurface(const sp<IBinder>& token,
+            const sp<ISurfaceTexture>& surface);
+    static void setDisplayLayerStack(const sp<IBinder>& token,
+            uint32_t layerStack);
+    static void setDisplayOrientation(const sp<IBinder>& token,
+            uint32_t orientation);
+    static void setDisplayViewport(const sp<IBinder>& token,
+            const Rect& viewport);
+    static void setDisplayFrame(const sp<IBinder>& token, const Rect& frame);
+
 private:
     virtual void onFirstRef();
     Composer& getComposer();
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 90e74a9..9765e28 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -106,14 +106,21 @@
         eOrientationSwapMask    = 0x01
     };
 
-    int32_t             displayId;
+    enum {
+        eSurfaceChanged     = 0x1,
+        eLayerStackChanged  = 0x2,
+        eTransformChanged   = 0x4
+    };
+
+    uint32_t what;
+    sp<IBinder> token;
     sp<ISurfaceTexture> surface;
-    uint32_t            layerStack;
-    uint32_t            orientation;
-    Rect                viewport;
-    Rect                frame;
-    status_t    write(Parcel& output) const;
-    status_t    read(const Parcel& input);
+    uint32_t layerStack;
+    uint32_t orientation;
+    Rect viewport;
+    Rect frame;
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
 };
 
 }; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5d8f1a1..76b23f3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -179,6 +179,23 @@
         return result;
     }
 
+    virtual sp<IBinder> createDisplay()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
+        return reply.readStrongBinder();
+    }
+
+    virtual sp<IBinder> getBuiltInDisplay(int32_t id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeInt32(id);
+        remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);
+        return reply.readStrongBinder();
+    }
+
     virtual void blank()
     {
         Parcel data, reply;
@@ -286,6 +303,19 @@
             reply->writeStrongBinder(connection->asBinder());
             return NO_ERROR;
         } break;
+        case CREATE_DISPLAY: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> display(createDisplay());
+            reply->writeStrongBinder(display);
+            return NO_ERROR;
+        } break;
+        case GET_BUILT_IN_DISPLAY: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int32_t id = data.readInt32();
+            sp<IBinder> display(getBuiltInDisplay(id));
+            reply->writeStrongBinder(display);
+            return NO_ERROR;
+        } break;
         case BLANK: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             blank();
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 25c773c..07f62c4 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -72,8 +72,9 @@
 
 
 status_t DisplayState::write(Parcel& output) const {
+    output.writeStrongBinder(token);
     output.writeStrongBinder(surface->asBinder());
-    output.writeInt32(displayId);
+    output.writeInt32(what);
     output.writeInt32(layerStack);
     output.writeInt32(orientation);
     memcpy(output.writeInplace(sizeof(Rect)), &viewport, sizeof(Rect));
@@ -82,8 +83,9 @@
 }
 
 status_t DisplayState::read(const Parcel& input) {
+    token = input.readStrongBinder();
     surface = interface_cast<ISurfaceTexture>(input.readStrongBinder());
-    displayId = input.readInt32();
+    what = input.readInt32();
     layerStack = input.readInt32();
     orientation = input.readInt32();
     memcpy(&viewport, input.readInplace(sizeof(Rect)), sizeof(Rect));
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7f42a34..db86d4a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -56,16 +56,10 @@
     return ComposerService::getInstance().mComposerService;
 }
 
-static inline sp<ISurfaceComposer> getComposerService() {
-    return ComposerService::getComposerService();
-}
-
 // ---------------------------------------------------------------------------
 
-// NOTE: this is NOT a member function (it's a friend defined with its
-// declaration).
 static inline
-int compare_type( const ComposerState& lhs, const ComposerState& rhs) {
+int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
     if (lhs.client < rhs.client)  return -1;
     if (lhs.client > rhs.client)  return 1;
     if (lhs.state.surface < rhs.state.surface)  return -1;
@@ -73,17 +67,21 @@
     return 0;
 }
 
+static inline
+int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+    return compare_type(lhs.token, rhs.token);
+}
+
 class Composer : public Singleton<Composer>
 {
     friend class Singleton<Composer>;
 
     mutable Mutex               mLock;
-    SortedVector<ComposerState> mStates;
-    int                         mOrientation;
+    SortedVector<ComposerState> mComposerStates;
+    SortedVector<DisplayState > mDisplayStates;
     uint32_t                    mForceSynchronous;
 
     Composer() : Singleton<Composer>(),
-        mOrientation(DisplayState::eOrientationUnchanged),
         mForceSynchronous(0)
     { }
 
@@ -92,7 +90,10 @@
     layer_state_t* getLayerStateLocked(
             const sp<SurfaceComposerClient>& client, SurfaceID id);
 
+    DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
+
 public:
+    sp<IBinder> createDisplay();
 
     status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
             float x, float y);
@@ -115,6 +116,12 @@
     status_t setLayerStack(const sp<SurfaceComposerClient>& client,
             SurfaceID id, uint32_t layerStack);
 
+    void setDisplaySurface(const sp<IBinder>& token, const sp<ISurfaceTexture>& surface);
+    void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+    void setDisplayOrientation(const sp<IBinder>& token, uint32_t orientation);
+    void setDisplayViewport(const sp<IBinder>& token, const Rect& viewport);
+    void setDisplayFrame(const sp<IBinder>& token, const Rect& frame);
+
     static void closeGlobalTransaction(bool synchronous) {
         Composer::getInstance().closeGlobalTransactionImpl(synchronous);
     }
@@ -124,8 +131,12 @@
 
 // ---------------------------------------------------------------------------
 
+sp<IBinder> Composer::createDisplay() {
+    return ComposerService::getComposerService()->createDisplay();
+}
+
 void Composer::closeGlobalTransactionImpl(bool synchronous) {
-    sp<ISurfaceComposer> sm(getComposerService());
+    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
 
     Vector<ComposerState> transaction;
     Vector<DisplayState> displayTransaction;
@@ -133,15 +144,11 @@
 
     { // scope for the lock
         Mutex::Autolock _l(mLock);
-        transaction = mStates;
-        mStates.clear();
+        transaction = mComposerStates;
+        mComposerStates.clear();
 
-        // FIXME: this should be the displays transaction state here
-        DisplayState item;
-        item.orientation = mOrientation;
-        displayTransaction.add(item);
-
-        mOrientation = DisplayState::eOrientationUnchanged;
+        displayTransaction = mDisplayStates;
+        mDisplayStates.clear();
 
         if (synchronous || mForceSynchronous) {
             flags |= ISurfaceComposer::eSynchronous;
@@ -159,13 +166,13 @@
     s.client = client->mClient;
     s.state.surface = id;
 
-    ssize_t index = mStates.indexOf(s);
+    ssize_t index = mComposerStates.indexOf(s);
     if (index < 0) {
         // we don't have it, add an initialized layer_state to our list
-        index = mStates.add(s);
+        index = mComposerStates.add(s);
     }
 
-    ComposerState* const out = mStates.editArray();
+    ComposerState* const out = mComposerStates.editArray();
     return &(out[index].state);
 }
 
@@ -273,16 +280,6 @@
     return NO_ERROR;
 }
 
-status_t Composer::setOrientation(int orientation) {
-    Mutex::Autolock _l(mLock);
-    mOrientation = orientation;
-
-    // Changing the orientation makes the transaction synchronous.
-    mForceSynchronous = true;
-
-    return NO_ERROR;
-}
-
 status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
         SurfaceID id, const Rect& crop) {
     Mutex::Autolock _l(mLock);
@@ -296,13 +293,76 @@
 
 // ---------------------------------------------------------------------------
 
+DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
+    DisplayState s;
+    s.token = token;
+    ssize_t index = mDisplayStates.indexOf(s);
+    if (index < 0) {
+        // we don't have it, add an initialized layer_state to our list
+        s.what = 0;
+        index = mDisplayStates.add(s);
+    }
+    return mDisplayStates.editItemAt(index);
+}
+
+void Composer::setDisplaySurface(const sp<IBinder>& token,
+        const sp<ISurfaceTexture>& surface) {
+    Mutex::Autolock _l(mLock);
+    DisplayState& s(getDisplayStateLocked(token));
+    s.surface = surface;
+    s.what |= DisplayState::eSurfaceChanged;
+}
+
+void Composer::setDisplayLayerStack(const sp<IBinder>& token,
+        uint32_t layerStack) {
+    Mutex::Autolock _l(mLock);
+    DisplayState& s(getDisplayStateLocked(token));
+    s.layerStack = layerStack;
+    s.what |= DisplayState::eLayerStackChanged;
+}
+
+void Composer::setDisplayOrientation(const sp<IBinder>& token,
+        uint32_t orientation) {
+    Mutex::Autolock _l(mLock);
+    DisplayState& s(getDisplayStateLocked(token));
+    s.orientation = orientation;
+    s.what |= DisplayState::eTransformChanged;
+    mForceSynchronous = true; // TODO: do we actually still need this?
+}
+
+// FIXME: get rid of this eventually
+status_t Composer::setOrientation(int orientation) {
+    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
+    sp<IBinder> token(sm->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    Composer::setDisplayOrientation(token, orientation);
+    return NO_ERROR;
+}
+
+void Composer::setDisplayViewport(const sp<IBinder>& token,
+        const Rect& viewport) {
+    Mutex::Autolock _l(mLock);
+    DisplayState& s(getDisplayStateLocked(token));
+    s.viewport = viewport;
+    s.what |= DisplayState::eTransformChanged;
+}
+
+void Composer::setDisplayFrame(const sp<IBinder>& token,
+        const Rect& frame) {
+    Mutex::Autolock _l(mLock);
+    DisplayState& s(getDisplayStateLocked(token));
+    s.frame = frame;
+    s.what |= DisplayState::eTransformChanged;
+}
+
+// ---------------------------------------------------------------------------
+
 SurfaceComposerClient::SurfaceComposerClient()
     : mStatus(NO_INIT), mComposer(Composer::getInstance())
 {
 }
 
 void SurfaceComposerClient::onFirstRef() {
-    sp<ISurfaceComposer> sm(getComposerService());
+    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
     if (sm != 0) {
         sp<ISurfaceComposerClient> conn = sm->createConnection();
         if (conn != 0) {
@@ -327,7 +387,7 @@
 status_t SurfaceComposerClient::linkToComposerDeath(
         const sp<IBinder::DeathRecipient>& recipient,
         void* cookie, uint32_t flags) {
-    sp<ISurfaceComposer> sm(getComposerService());
+    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
     return sm->asBinder()->linkToDeath(recipient, cookie, flags);
 }
 
@@ -379,6 +439,10 @@
     return result;
 }
 
+sp<IBinder> SurfaceComposerClient::createDisplay() {
+    return Composer::getInstance().createDisplay();
+}
+
 status_t SurfaceComposerClient::destroySurface(SurfaceID sid) {
     if (mStatus != NO_ERROR)
         return mStatus;
@@ -461,10 +525,37 @@
 
 // ----------------------------------------------------------------------------
 
+void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
+        const sp<ISurfaceTexture>& surface) {
+    Composer::getInstance().setDisplaySurface(token, surface);
+}
+
+void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
+        uint32_t layerStack) {
+    Composer::getInstance().setDisplayLayerStack(token, layerStack);
+}
+
+void SurfaceComposerClient::setDisplayOrientation(const sp<IBinder>& token,
+        uint32_t orientation) {
+    Composer::getInstance().setDisplayOrientation(token, orientation);
+}
+
+void SurfaceComposerClient::setDisplayViewport(const sp<IBinder>& token,
+        const Rect& viewport) {
+    Composer::getInstance().setDisplayViewport(token, viewport);
+}
+
+void SurfaceComposerClient::setDisplayFrame(const sp<IBinder>& token,
+        const Rect& frame) {
+    Composer::getInstance().setDisplayFrame(token, frame);
+}
+
+// ----------------------------------------------------------------------------
+
 status_t SurfaceComposerClient::getDisplayInfo(
         DisplayID dpy, DisplayInfo* info)
 {
-    return getComposerService()->getDisplayInfo(dpy, info);
+    return ComposerService::getComposerService()->getDisplayInfo(dpy, info);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index cb8fe2f..0229dad 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -51,7 +51,8 @@
 
     enum {
         DISPLAY_ID_MAIN = 0,
-        DISPLAY_ID_HDMI = 1
+        DISPLAY_ID_HDMI = 1,
+        DISPLAY_ID_COUNT
     };
 
     enum {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ac3fb90..f2b49e8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -161,6 +161,39 @@
     return bclient;
 }
 
+sp<IBinder> SurfaceFlinger::createDisplay()
+{
+    class DisplayToken : public BBinder {
+        sp<SurfaceFlinger> flinger;
+        virtual ~DisplayToken() {
+             // no more references, this display must be terminated
+             Mutex::Autolock _l(flinger->mStateLock);
+             flinger->mCurrentState.displays.removeItem(this);
+             flinger->setTransactionFlags(eDisplayTransactionNeeded);
+         }
+     public:
+        DisplayToken(const sp<SurfaceFlinger>& flinger)
+            : flinger(flinger) {
+        }
+    };
+
+    sp<BBinder> token = new DisplayToken(this);
+
+    Mutex::Autolock _l(mStateLock);
+    DisplayDeviceState info(intptr_t(token.get())); // FIXME: we shouldn't use the address for the id
+    mCurrentState.displays.add(token, info);
+
+    return token;
+}
+
+sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
+    if (uint32_t(id) >= DisplayDevice::DISPLAY_ID_COUNT) {
+        ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
+        return NULL;
+    }
+    return mDefaultDisplays[id];
+}
+
 sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
 {
     sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
@@ -358,7 +391,8 @@
         exit(0);
     }
 
-    sp<SurfaceTextureClient> stc(new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(fbs->getBufferQueue())));
+    sp<SurfaceTextureClient> stc(new SurfaceTextureClient(
+            static_cast<sp<ISurfaceTexture> >(fbs->getBufferQueue())));
 
     // initialize the config and context
     int format;
@@ -368,9 +402,14 @@
     mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
 
     // initialize our main display hardware
-    mCurrentState.displays.add(DisplayDevice::DISPLAY_ID_MAIN, DisplayDeviceState());
-    sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig);
-    mDisplays.add(DisplayDevice::DISPLAY_ID_MAIN, hw);
+
+    for (size_t i=0 ; i<DisplayDevice::DISPLAY_ID_COUNT ; i++) {
+        mDefaultDisplays[i] = new BBinder();
+        mCurrentState.displays.add(mDefaultDisplays[i], DisplayDeviceState(i));
+    }
+    sp<DisplayDevice> hw = new DisplayDevice(this,
+            DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig);
+    mDisplays.add(hw->getDisplayId(), hw);
 
     //  initialize OpenGL ES
     EGLSurface surface = hw->getEGLSurface();
@@ -571,8 +610,7 @@
 }
 
 void SurfaceFlinger::handleMessageTransaction() {
-    const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
-    uint32_t transactionFlags = peekTransactionFlags(mask);
+    uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
     if (transactionFlags) {
         handleTransaction(transactionFlags);
     }
@@ -795,8 +833,7 @@
     // with mStateLock held to guarantee that mCurrentState won't change
     // until the transaction is committed.
 
-    const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
-    transactionFlags = getTransactionFlags(mask);
+    transactionFlags = getTransactionFlags(eTransactionMask);
     handleTransactionLocked(transactionFlags);
 
     mLastTransactionTime = systemTime() - now;
@@ -832,12 +869,12 @@
      * Perform our own transaction if needed
      */
 
-    if (transactionFlags & eTransactionNeeded) {
+    if (transactionFlags & eDisplayTransactionNeeded) {
         // here we take advantage of Vector's copy-on-write semantics to
         // improve performance by skipping the transaction entirely when
         // know that the lists are identical
-        const KeyedVector<int32_t, DisplayDeviceState>& curr(mCurrentState.displays);
-        const KeyedVector<int32_t, DisplayDeviceState>& draw(mDrawingState.displays);
+        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
+        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
         if (!curr.isIdenticalTo(draw)) {
             mVisibleRegionsDirty = true;
             const size_t cc = curr.size();
@@ -848,7 +885,8 @@
             // also handle displays that changed
             // (ie: displays that are in both lists)
             for (size_t i=0 ; i<dc ; i++) {
-                if (curr.indexOfKey(draw[i].id) < 0) {
+                const ssize_t j = curr.indexOfKey(draw.keyAt(i));
+                if (j < 0) {
                     // in drawing state but not in current state
                     if (draw[i].id != DisplayDevice::DISPLAY_ID_MAIN) {
                         mDisplays.removeItem(draw[i].id);
@@ -857,14 +895,32 @@
                     }
                 } else {
                     // this display is in both lists. see if something changed.
-                    const DisplayDeviceState& state(curr[i]);
+                    const DisplayDeviceState& state(curr[j]);
+                    if (state.surface != draw[i].surface) {
+                        // changing the surface is like destroying and
+                        // recreating the DisplayDevice
+
+                        sp<SurfaceTextureClient> stc(
+                                new SurfaceTextureClient(state.surface));
+
+                        sp<DisplayDevice> disp = new DisplayDevice(this,
+                                state.id, stc, 0, mEGLConfig);
+
+                        disp->setLayerStack(state.layerStack);
+                        disp->setOrientation(state.orientation);
+                        // TODO: take viewport and frame into account
+                        mDisplays.replaceValueFor(state.id, disp);
+                    }
                     if (state.layerStack != draw[i].layerStack) {
                         const sp<DisplayDevice>& disp(getDisplayDevice(state.id));
                         disp->setLayerStack(state.layerStack);
                     }
-                    if (curr[i].orientation != draw[i].orientation) {
+                    if (state.orientation != draw[i].orientation ||
+                        state.viewport != draw[i].viewport ||
+                        state.frame != draw[i].frame) {
                         const sp<DisplayDevice>& disp(getDisplayDevice(state.id));
                         disp->setOrientation(state.orientation);
+                        // TODO: take viewport and frame into account
                     }
                 }
             }
@@ -872,10 +928,14 @@
             // find displays that were added
             // (ie: in current state but not in drawing state)
             for (size_t i=0 ; i<cc ; i++) {
-                if (mDrawingState.displays.indexOfKey(curr[i].id) < 0) {
+                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                     // FIXME: we need to pass the surface here
-                    sp<DisplayDevice> disp = new DisplayDevice(this, curr[i].id, 0, 0, mEGLConfig);
-                    mDisplays.add(curr[i].id, disp);
+                    const DisplayDeviceState& state(curr[i]);
+                    sp<SurfaceTextureClient> stc(
+                            new SurfaceTextureClient(state.surface));
+                    sp<DisplayDevice> disp = new DisplayDevice(this, state.id,
+                            stc, 0, mEGLConfig);
+                    mDisplays.add(state.id, disp);
                 }
             }
         }
@@ -1358,33 +1418,21 @@
     return old;
 }
 
-
 void SurfaceFlinger::setTransactionState(
         const Vector<ComposerState>& state,
         const Vector<DisplayState>& displays,
         uint32_t flags)
 {
     Mutex::Autolock _l(mStateLock);
-
-    int orientation = DisplayState::eOrientationUnchanged;
-    if (displays.size()) {
-        // TODO: handle all displays
-        orientation = displays[0].orientation;
-    }
-
     uint32_t transactionFlags = 0;
-    // FIXME: don't hardcode display id here
-    if (mCurrentState.displays.valueFor(0).orientation != orientation) {
-        if (uint32_t(orientation) <= DisplayState::eOrientation270) {
-            mCurrentState.displays.editValueFor(0).orientation = orientation;
-            transactionFlags |= eTransactionNeeded;
-        } else if (orientation != DisplayState::eOrientationUnchanged) {
-            ALOGW("setTransactionState: ignoring unrecognized orientation: %d",
-                    orientation);
-        }
+
+    size_t count = displays.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const DisplayState& s(displays[i]);
+        transactionFlags |= setDisplayStateLocked(s);
     }
 
-    const size_t count = state.size();
+    count = state.size();
     for (size_t i=0 ; i<count ; i++) {
         const ComposerState& s(state[i]);
         sp<Client> client( static_cast<Client *>(s.client.get()) );
@@ -1413,6 +1461,105 @@
     }
 }
 
+uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
+{
+    uint32_t flags = 0;
+    DisplayDeviceState& disp(mCurrentState.displays.editValueFor(s.token));
+    if (disp.id >= 0) {
+        const uint32_t what = s.what;
+        if (what & DisplayState::eSurfaceChanged) {
+            if (disp.surface->asBinder() != s.surface->asBinder()) {
+                disp.surface = s.surface;
+                flags |= eDisplayTransactionNeeded;
+            }
+        }
+        if (what & DisplayState::eLayerStackChanged) {
+            if (disp.layerStack != s.layerStack) {
+                disp.layerStack = s.layerStack;
+                flags |= eDisplayTransactionNeeded;
+            }
+        }
+        if (what & DisplayState::eTransformChanged) {
+            if (disp.orientation != s.orientation) {
+                disp.orientation = s.orientation;
+                flags |= eDisplayTransactionNeeded;
+            }
+            if (disp.frame != s.frame) {
+                disp.frame = s.frame;
+                flags |= eDisplayTransactionNeeded;
+            }
+            if (disp.viewport != s.viewport) {
+                disp.viewport = s.viewport;
+                flags |= eDisplayTransactionNeeded;
+            }
+        }
+    }
+    return flags;
+}
+
+uint32_t SurfaceFlinger::setClientStateLocked(
+        const sp<Client>& client,
+        const layer_state_t& s)
+{
+    uint32_t flags = 0;
+    sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
+    if (layer != 0) {
+        const uint32_t what = s.what;
+        if (what & layer_state_t::ePositionChanged) {
+            if (layer->setPosition(s.x, s.y))
+                flags |= eTraversalNeeded;
+        }
+        if (what & layer_state_t::eLayerChanged) {
+            // NOTE: index needs to be calculated before we update the state
+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+            if (layer->setLayer(s.z)) {
+                mCurrentState.layersSortedByZ.removeAt(idx);
+                mCurrentState.layersSortedByZ.add(layer);
+                // we need traversal (state changed)
+                // AND transaction (list changed)
+                flags |= eTransactionNeeded|eTraversalNeeded;
+            }
+        }
+        if (what & layer_state_t::eSizeChanged) {
+            if (layer->setSize(s.w, s.h)) {
+                flags |= eTraversalNeeded;
+            }
+        }
+        if (what & layer_state_t::eAlphaChanged) {
+            if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+                flags |= eTraversalNeeded;
+        }
+        if (what & layer_state_t::eMatrixChanged) {
+            if (layer->setMatrix(s.matrix))
+                flags |= eTraversalNeeded;
+        }
+        if (what & layer_state_t::eTransparentRegionChanged) {
+            if (layer->setTransparentRegionHint(s.transparentRegion))
+                flags |= eTraversalNeeded;
+        }
+        if (what & layer_state_t::eVisibilityChanged) {
+            if (layer->setFlags(s.flags, s.mask))
+                flags |= eTraversalNeeded;
+        }
+        if (what & layer_state_t::eCropChanged) {
+            if (layer->setCrop(s.crop))
+                flags |= eTraversalNeeded;
+        }
+        if (what & layer_state_t::eLayerStackChanged) {
+            // NOTE: index needs to be calculated before we update the state
+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+            if (layer->setLayerStack(s.layerStack)) {
+                mCurrentState.layersSortedByZ.removeAt(idx);
+                mCurrentState.layersSortedByZ.add(layer);
+                // we need traversal (state changed)
+                // AND transaction (list changed)
+                flags |= eTransactionNeeded|eTraversalNeeded;
+            }
+        }
+    }
+    return flags;
+}
+
 sp<ISurface> SurfaceFlinger::createLayer(
         ISurfaceComposerClient::surface_data_t* params,
         const String8& name,
@@ -1554,69 +1701,6 @@
     return err;
 }
 
-uint32_t SurfaceFlinger::setClientStateLocked(
-        const sp<Client>& client,
-        const layer_state_t& s)
-{
-    uint32_t flags = 0;
-    sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
-    if (layer != 0) {
-        const uint32_t what = s.what;
-        if (what & layer_state_t::ePositionChanged) {
-            if (layer->setPosition(s.x, s.y))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eLayerChanged) {
-            // NOTE: index needs to be calculated before we update the state
-            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
-            if (layer->setLayer(s.z)) {
-                mCurrentState.layersSortedByZ.removeAt(idx);
-                mCurrentState.layersSortedByZ.add(layer);
-                // we need traversal (state changed)
-                // AND transaction (list changed)
-                flags |= eTransactionNeeded|eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eSizeChanged) {
-            if (layer->setSize(s.w, s.h)) {
-                flags |= eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eAlphaChanged) {
-            if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eMatrixChanged) {
-            if (layer->setMatrix(s.matrix))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eTransparentRegionChanged) {
-            if (layer->setTransparentRegionHint(s.transparentRegion))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eVisibilityChanged) {
-            if (layer->setFlags(s.flags, s.mask))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eCropChanged) {
-            if (layer->setCrop(s.crop))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eLayerStackChanged) {
-            // NOTE: index needs to be calculated before we update the state
-            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
-            if (layer->setLayerStack(s.layerStack)) {
-                mCurrentState.layersSortedByZ.removeAt(idx);
-                mCurrentState.layersSortedByZ.add(layer);
-                // we need traversal (state changed)
-                // AND transaction (list changed)
-                flags |= eTransactionNeeded|eTraversalNeeded;
-            }
-        }
-    }
-    return flags;
-}
-
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::onScreenAcquired() {
@@ -1964,7 +2048,10 @@
                 return NO_ERROR;
             }
             case 1005:{ // force transaction
-                setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+                setTransactionFlags(
+                        eTransactionNeeded|
+                        eDisplayTransactionNeeded|
+                        eTraversalNeeded);
                 return NO_ERROR;
             }
             case 1006:{ // send empty update
@@ -2305,8 +2392,11 @@
 
 // ---------------------------------------------------------------------------
 
-SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
-    : id(DisplayDevice::DISPLAY_ID_MAIN), layerStack(0), orientation(0) {
+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() : id(-1) {
+}
+
+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(int32_t id)
+    : id(id), layerStack(0), orientation(0) {
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index da417ff..6438bee 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -78,7 +78,10 @@
 // ---------------------------------------------------------------------------
 
 enum {
-    eTransactionNeeded = 0x01, eTraversalNeeded = 0x02
+    eTransactionNeeded        = 0x01,
+    eTraversalNeeded          = 0x02,
+    eDisplayTransactionNeeded = 0x04,
+    eTransactionMask          = 0x07
 };
 
 class SurfaceFlinger : public BinderService<SurfaceFlinger>,
@@ -158,19 +161,18 @@
 
     struct DisplayDeviceState {
         DisplayDeviceState();
+        DisplayDeviceState(int32_t id);
         int32_t id;
+        sp<ISurfaceTexture> surface;
         uint32_t layerStack;
         Rect viewport;
         Rect frame;
         uint8_t orientation;
-        inline bool operator < (const DisplayDeviceState& rhs) const {
-            return id < rhs.id;
-        }
     };
 
     struct State {
         LayerVector layersSortedByZ;
-        KeyedVector<int32_t, DisplayDeviceState> displays;
+        DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
     };
 
     /* ------------------------------------------------------------------------
@@ -185,6 +187,8 @@
      */
     virtual sp<ISurfaceComposerClient> createConnection();
     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
+    virtual sp<IBinder> createDisplay();
+    virtual sp<IBinder> getBuiltInDisplay(int32_t id);
     virtual void setTransactionState(const Vector<ComposerState>& state,
             const Vector<DisplayState>& displays, uint32_t flags);
     virtual void bootFinished();
@@ -256,6 +260,7 @@
     void commitTransaction();
     uint32_t setClientStateLocked(const sp<Client>& client,
         const layer_state_t& s);
+    uint32_t setDisplayStateLocked(const DisplayState& s);
 
     /* ------------------------------------------------------------------------
      * Layer management
@@ -391,6 +396,7 @@
     EGLContext mEGLContext;
     EGLConfig mEGLConfig;
     EGLDisplay mEGLDisplay;
+    sp<IBinder> mDefaultDisplays[DisplayDevice::DISPLAY_ID_COUNT];
 
     // Can only accessed from the main thread, these members
     // don't need synchronization