Merge "Reduce the time it takes to decay the glow after a pull." into gingerbread
diff --git a/core/java/android/os/storage/OnObbStateChangeListener.java b/core/java/android/os/storage/OnObbStateChangeListener.java
index 950195b..1fb1782 100644
--- a/core/java/android/os/storage/OnObbStateChangeListener.java
+++ b/core/java/android/os/storage/OnObbStateChangeListener.java
@@ -67,9 +67,9 @@
     public static final int ERROR_ALREADY_MOUNTED = 24;
 
     /**
-     * The current application does not have permission to use this OBB because
-     * the OBB indicates it's owned by a different package or the key used to
-     * open it is incorrect. Returned in status messages from calls made via
+     * The current application does not have permission to use this OBB. This
+     * could be because the OBB indicates it's owned by a different package or
+     * some other error. Returned in status messages from calls made via
      * {@link StorageManager}
      */
     public static final int ERROR_PERMISSION_DENIED = 25;
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index d1aff2a..714b259 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -33,6 +33,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.Vibrator;
 import android.os.storage.IMountService;
 import android.os.storage.IMountShutdownObserver;
@@ -60,6 +61,9 @@
     private static boolean mReboot;
     private static String mRebootReason;
 
+    // Provides shutdown assurance in case the system_server is killed
+    public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
+
     // static instance of this thread
     private static final ShutdownThread sInstance = new ShutdownThread();
     
@@ -195,7 +199,17 @@
                 actionDone();
             }
         };
-        
+
+        /*
+         * Write a system property in case the system_server reboots before we
+         * get to the actual hardware restart. If that happens, we'll retry at
+         * the beginning of the SystemServer startup.
+         */
+        {
+            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
+            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
+        }
+
         Log.i(TAG, "Sending shutdown broadcast...");
         
         // First send the high-level shut down broadcast.
@@ -325,10 +339,21 @@
             }
         }
 
-        if (mReboot) {
-            Log.i(TAG, "Rebooting, reason: " + mRebootReason);
+        rebootOrShutdown(mReboot, mRebootReason);
+    }
+
+    /**
+     * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
+     * or {@link #shutdown(Context, boolean)} instead.
+     *
+     * @param reboot true to reboot or false to shutdown
+     * @param reason reason for reboot
+     */
+    public static void rebootOrShutdown(boolean reboot, String reason) {
+        if (reboot) {
+            Log.i(TAG, "Rebooting, reason: " + reason);
             try {
-                Power.reboot(mRebootReason);
+                Power.reboot(reason);
             } catch (Exception e) {
                 Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
             }
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 1a1821c..de447be 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -119,6 +119,7 @@
             uint32_t reqWidth, uint32_t reqHeight) = 0;
 
     virtual status_t turnElectronBeamOff(int32_t mode) = 0;
+    virtual status_t turnElectronBeamOn(int32_t mode) = 0;
 
     /* Signal surfaceflinger that there might be some work to do
      * This is an ASYNCHRONOUS call.
@@ -145,7 +146,8 @@
         UNFREEZE_DISPLAY,
         SIGNAL,
         CAPTURE_SCREEN,
-        TURN_ELECTRON_BEAM_OFF
+        TURN_ELECTRON_BEAM_OFF,
+        TURN_ELECTRON_BEAM_ON
     };
 
     virtual status_t    onTransact( uint32_t code,
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index d72561f..969ee79 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -151,6 +151,15 @@
         return reply.readInt32();
     }
 
+    virtual status_t turnElectronBeamOn(int32_t mode)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_ON, data, &reply);
+        return reply.readInt32();
+    }
+
     virtual void signal() const
     {
         Parcel data, reply;
@@ -239,6 +248,12 @@
             status_t res = turnElectronBeamOff(mode);
             reply->writeInt32(res);
         }
+        case TURN_ELECTRON_BEAM_ON: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int32_t mode = data.readInt32();
+            status_t res = turnElectronBeamOn(mode);
+            reply->writeInt32(res);
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/Metadata.cpp b/media/libmedia/Metadata.cpp
index 35ec6b3..aec96f1 100644
--- a/media/libmedia/Metadata.cpp
+++ b/media/libmedia/Metadata.cpp
@@ -32,7 +32,7 @@
 // All these constants below must be kept in sync with Metadata.java.
 enum MetadataId {
     FIRST_SYSTEM_ID = 1,
-    LAST_SYSTEM_ID = 31,
+    LAST_SYSTEM_ID = 32,
     FIRST_CUSTOM_ID = 8192
 };
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 69389f5..57bea8c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -303,6 +303,28 @@
 }
 
 status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
+    // Attempt to approximate overall stream bitrate by summing all
+    // tracks' individual bitrates, if not all of them advertise bitrate,
+    // we have to fail.
+
+    int64_t totalBitRate = 0;
+
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+        int32_t bitrate;
+        if (!meta->findInt32(kKeyBitRate, &bitrate)) {
+            totalBitRate = -1;
+            break;
+        }
+
+        totalBitRate += bitrate;
+    }
+
+    mBitrate = totalBitRate;
+
+    LOGV("mBitrate = %lld bits/sec", mBitrate);
+
     bool haveAudio = false;
     bool haveVideo = false;
     for (size_t i = 0; i < extractor->countTracks(); ++i) {
@@ -441,6 +463,8 @@
 
     delete mSuspensionState;
     mSuspensionState = NULL;
+
+    mBitrate = -1;
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -453,17 +477,32 @@
     }
 }
 
+bool AwesomePlayer::getBitrate(int64_t *bitrate) {
+    off_t size;
+    if (mDurationUs >= 0 && mCachedSource != NULL
+            && mCachedSource->getSize(&size) == OK) {
+        *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
+        return true;
+    }
+
+    if (mBitrate >= 0) {
+        *bitrate = mBitrate;
+        return true;
+    }
+
+    *bitrate = 0;
+
+    return false;
+}
+
 // Returns true iff cached duration is available/applicable.
 bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
-    off_t totalSize;
+    int64_t bitrate;
 
     if (mRTSPController != NULL) {
         *durationUs = mRTSPController->getQueueDurationUs(eos);
         return true;
-    } else if (mCachedSource != NULL && mDurationUs >= 0
-            && mCachedSource->getSize(&totalSize) == OK) {
-        int64_t bitrate = totalSize * 8000000ll / mDurationUs;  // in bits/sec
-
+    } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
         size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
         return true;
@@ -490,10 +529,8 @@
                 finishAsyncPrepare_l();
             }
         } else {
-            off_t size;
-            if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
-                int64_t bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
-
+            int64_t bitrate;
+            if (getBitrate(&bitrate)) {
                 size_t cachedSize = mCachedSource->cachedSize();
                 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 079adca..46a0c65 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -152,6 +152,8 @@
     bool mSeekNotificationSent;
     int64_t mSeekTimeUs;
 
+    int64_t mBitrate;  // total bitrate of the file (in bps) or -1 if unknown.
+
     bool mWatchForAudioSeekComplete;
     bool mWatchForAudioEOS;
 
@@ -254,6 +256,8 @@
     static void OnRTSPSeekDoneWrapper(void *cookie);
     void onRTSPSeekDone();
 
+    bool getBitrate(int64_t *bitrate);
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index ded3b24..5a1ea5c 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -59,7 +59,8 @@
     sp<AMessage> mNotifyMsg;
     KeyedVector<uint32_t, sp<ARTPSource> > mSources;
 
-    int32_t mNumRTCPPacketsReceived;
+    int64_t mNumRTCPPacketsReceived;
+    int64_t mNumRTPPacketsReceived;
     struct sockaddr_in mRemoteRTCPAddr;
 
     bool mIsInjected;
@@ -168,6 +169,12 @@
             break;
         }
 
+        case kWhatFakeTimestamps:
+        {
+            onFakeTimestamps();
+            break;
+        }
+
         default:
         {
             TRESPASS();
@@ -199,6 +206,7 @@
     CHECK(msg->findMessage("notify", &info->mNotifyMsg));
 
     info->mNumRTCPPacketsReceived = 0;
+    info->mNumRTPPacketsReceived = 0;
     memset(&info->mRemoteRTCPAddr, 0, sizeof(info->mRemoteRTCPAddr));
 
     if (!injected) {
@@ -373,6 +381,12 @@
 }
 
 status_t ARTPConnection::parseRTP(StreamInfo *s, const sp<ABuffer> &buffer) {
+    if (s->mNumRTPPacketsReceived++ == 0) {
+        sp<AMessage> notify = s->mNotifyMsg->dup();
+        notify->setInt32("first-rtp", true);
+        notify->post();
+    }
+
     size_t size = buffer->size();
 
     if (size < 12) {
@@ -638,5 +652,27 @@
     }
 }
 
+void ARTPConnection::fakeTimestamps() {
+    (new AMessage(kWhatFakeTimestamps, id()))->post();
+}
+
+void ARTPConnection::onFakeTimestamps() {
+    List<StreamInfo>::iterator it = mStreams.begin();
+    while (it != mStreams.end()) {
+        StreamInfo &info = *it++;
+
+        for (size_t j = 0; j < info.mSources.size(); ++j) {
+            sp<ARTPSource> source = info.mSources.valueAt(j);
+
+            if (!source->timeEstablished()) {
+                source->timeUpdate(0, 0);
+                source->timeUpdate(0 + 90000, 0x100000000ll);
+
+                mFlags |= kFakeTimestamps;
+            }
+        }
+    }
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index 77f81fa..a17b382 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -51,6 +51,8 @@
     static void MakePortPair(
             int *rtpSocket, int *rtcpSocket, unsigned *rtpPort);
 
+    void fakeTimestamps();
+
 protected:
     virtual ~ARTPConnection();
     virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -61,6 +63,7 @@
         kWhatRemoveStream,
         kWhatPollStreams,
         kWhatInjectPacket,
+        kWhatFakeTimestamps,
     };
 
     static const int64_t kSelectTimeoutUs;
@@ -78,6 +81,7 @@
     void onPollStreams();
     void onInjectPacket(const sp<AMessage> &msg);
     void onSendReceiverReports();
+    void onFakeTimestamps();
 
     status_t receive(StreamInfo *info, bool receiveRTP);
 
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 0f4c1f3..1bc9925 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -105,7 +105,9 @@
           mCheckPending(false),
           mCheckGeneration(0),
           mTryTCPInterleaving(false),
+          mTryFakeRTCP(false),
           mReceivedFirstRTCPPacket(false),
+          mReceivedFirstRTPPacket(false),
           mSeekable(false) {
         mNetLooper->setName("rtsp net");
         mNetLooper->start(false /* runOnCallingThread */,
@@ -534,6 +536,7 @@
                 mFirstAccessUnitNTP = 0;
                 mNumAccessUnitsReceived = 0;
                 mReceivedFirstRTCPPacket = false;
+                mReceivedFirstRTPPacket = false;
                 mSeekable = false;
 
                 sp<AMessage> reply = new AMessage('tear', id());
@@ -611,12 +614,17 @@
 
             case 'accu':
             {
-                int32_t firstRTCP;
-                if (msg->findInt32("first-rtcp", &firstRTCP)) {
+                int32_t first;
+                if (msg->findInt32("first-rtcp", &first)) {
                     mReceivedFirstRTCPPacket = true;
                     break;
                 }
 
+                if (msg->findInt32("first-rtp", &first)) {
+                    mReceivedFirstRTPPacket = true;
+                    break;
+                }
+
                 ++mNumAccessUnitsReceived;
                 postAccessUnitTimeoutCheck();
 
@@ -839,9 +847,17 @@
             case 'tiou':
             {
                 if (!mReceivedFirstRTCPPacket) {
-                    if (mTryTCPInterleaving) {
+                    if (mTryFakeRTCP) {
                         LOGW("Never received any data, disconnecting.");
                         (new AMessage('abor', id()))->post();
+                    } else if (mTryTCPInterleaving && mReceivedFirstRTPPacket) {
+                        LOGW("We received RTP packets but no RTCP packets, "
+                             "using fake timestamps.");
+
+                        mTryFakeRTCP = true;
+
+                        mReceivedFirstRTCPPacket = true;
+                        mRTPConn->fakeTimestamps();
                     } else {
                         LOGW("Never received any data, switching transports.");
 
@@ -987,7 +1003,9 @@
     bool mCheckPending;
     int32_t mCheckGeneration;
     bool mTryTCPInterleaving;
+    bool mTryFakeRTCP;
     bool mReceivedFirstRTCPPacket;
+    bool mReceivedFirstRTPPacket;
     bool mSeekable;
 
     struct TrackInfo {
diff --git a/native/include/android/storage_manager.h b/native/include/android/storage_manager.h
index c202693..bad24913 100644
--- a/native/include/android/storage_manager.h
+++ b/native/include/android/storage_manager.h
@@ -74,10 +74,10 @@
     AOBB_STATE_ERROR_ALREADY_MOUNTED = 24,
 
     /*
-     * The current application does not have permission to use this OBB
-     * because the OBB indicates it's owned by a different package or the
-     * key used to open it is incorrect. Can be returned as the status for
-     * callbacks made during asynchronous OBB actions.
+     * The current application does not have permission to use this OBB.
+     * This could be because the OBB indicates it's owned by a different
+     * package. Can be returned as the status for callbacks made during
+     * asynchronous OBB actions.
      */
     AOBB_STATE_ERROR_PERMISSION_DENIED = 25,
 };
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1df583a..9d7c58e 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5156,9 +5156,6 @@
                     // we don't consider this to be a failure of the core package deletion
                 }
             }
-            if (libraryPath != null) {
-                NativeLibraryHelper.removeNativeBinariesLI(libraryPath);
-            }
         }
 
         private boolean setPermissions() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 26071ae..a2a5e67 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import com.android.server.am.ActivityManagerService;
+import com.android.internal.app.ShutdownThread;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.trustedlogic.trustednfc.android.server.NfcService;
@@ -89,6 +90,24 @@
         BinderInternal.disableBackgroundScheduling(true);
         android.os.Process.setCanSelfBackground(false);
 
+        // Check whether we failed to shut down last time we tried.
+        {
+            final String shutdownAction = SystemProperties.get(
+                    ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
+            if (shutdownAction != null && shutdownAction.length() > 0) {
+                boolean reboot = (shutdownAction.charAt(0) == '1');
+
+                final String reason;
+                if (shutdownAction.length() > 1) {
+                    reason = shutdownAction.substring(1, shutdownAction.length());
+                } else {
+                    reason = null;
+                }
+
+                ShutdownThread.rebootOrShutdown(reboot, reason);
+            }
+        }
+
         String factoryTestStr = SystemProperties.get("ro.factorytest");
         int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
                 : Integer.parseInt(factoryTestStr);
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index fe9a5ab..90865da 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -396,7 +396,6 @@
 {
     status_t err = mDisplayEventThread->acquireScreen();
     if (err >= 0) {
-        mCanDraw = true;
         mScreenAcquired = true;
     }
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a919ddf..3734969 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -80,6 +80,7 @@
         mVisibleRegionsDirty(false),
         mDeferReleaseConsole(false),
         mFreezeDisplay(false),
+        mElectronBeamAnimation(false),
         mFreezeCount(0),
         mFreezeDisplayTime(0),
         mDebugRegion(0),
@@ -421,6 +422,10 @@
     int what = android_atomic_and(0, &mConsoleSignals);
     if (what & eConsoleAcquired) {
         hw.acquireScreen();
+        // this is a temporary work-around, eventually this should be called
+        // by the power-manager
+        if (mElectronBeamAnimation)
+            SurfaceFlinger::turnElectronBeamOn(0);
     }
 
     if (mDeferReleaseConsole && hw.isScreenAcquired()) {
@@ -1457,6 +1462,7 @@
         case UNFREEZE_DISPLAY:
         case BOOT_FINISHED:
         case TURN_ELECTRON_BEAM_OFF:
+        case TURN_ELECTRON_BEAM_ON:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
@@ -1545,27 +1551,18 @@
     return err;
 }
 
-
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::turnElectronBeamOffImplLocked()
+status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
+        GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
 {
-    status_t result = PERMISSION_DENIED;
-
     if (!GLExtensions::getInstance().haveFramebufferObject())
         return INVALID_OPERATION;
 
     // get screen geometry
-    const int dpy = 0;
     const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
-    if (!hw.canDraw()) {
-        // we're already off
-        return NO_ERROR;
-    }
-
     const uint32_t hw_w = hw.getWidth();
     const uint32_t hw_h = hw.getHeight();
-    const Region screenBounds(hw.bounds());
     GLfloat u = 1;
     GLfloat v = 1;
 
@@ -1576,167 +1573,344 @@
     GLuint name, tname;
     glGenTextures(1, &tname);
     glBindTexture(GL_TEXTURE_2D, tname);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+            hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
     if (glGetError() != GL_NO_ERROR) {
         GLint tw = (2 << (31 - clz(hw_w)));
         GLint th = (2 << (31 - clz(hw_h)));
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+                tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
         u = GLfloat(hw_w) / tw;
         v = GLfloat(hw_h) / th;
     }
     glGenFramebuffersOES(1, &name);
     glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
-    glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+    glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+            GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
 
-    GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
-    if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
-        // redraw the screen entirely...
-        glClearColor(0,0,0,1);
+    // 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();
+    }
+
+    // back to main framebuffer
+    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+    glDisable(GL_SCISSOR_TEST);
+    glDeleteFramebuffersOES(1, &name);
+
+    *textureName = tname;
+    *uOut = u;
+    *vOut = v;
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
+{
+    status_t result = PERMISSION_DENIED;
+
+    if (!GLExtensions::getInstance().haveFramebufferObject())
+        return INVALID_OPERATION;
+
+    // get screen geometry
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const uint32_t hw_w = hw.getWidth();
+    const uint32_t hw_h = hw.getHeight();
+    const Region screenBounds(hw.bounds());
+
+    GLfloat u, v;
+    GLuint tname;
+    result = renderScreenToTextureLocked(0, &tname, &u, &v);
+    if (result != NO_ERROR) {
+        return result;
+    }
+
+    GLfloat vtx[8];
+    const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, tname);
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+    glVertexPointer(2, GL_FLOAT, 0, vtx);
+
+    class s_curve_interpolator {
+        const float nbFrames, s, v;
+    public:
+        s_curve_interpolator(int nbFrames, float s)
+        : nbFrames(1.0f / (nbFrames-1)), s(s),
+          v(1.0f + expf(-s + 0.5f*s)) {
+        }
+        float operator()(int f) {
+            const float x = f * nbFrames;
+            return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
+        }
+    };
+
+    class v_stretch {
+        const GLfloat hw_w, hw_h;
+    public:
+        v_stretch(uint32_t hw_w, uint32_t hw_h)
+        : hw_w(hw_w), hw_h(hw_h) {
+        }
+        void operator()(GLfloat* vtx, float v) {
+            const GLfloat w = hw_w + (hw_w * v);
+            const GLfloat h = hw_h - (hw_h * v);
+            const GLfloat x = (hw_w - w) * 0.5f;
+            const GLfloat y = (hw_h - h) * 0.5f;
+            vtx[0] = x;         vtx[1] = y;
+            vtx[2] = x;         vtx[3] = y + h;
+            vtx[4] = x + w;     vtx[5] = y + h;
+            vtx[6] = x + w;     vtx[7] = y;
+        }
+    };
+
+    class h_stretch {
+        const GLfloat hw_w, hw_h;
+    public:
+        h_stretch(uint32_t hw_w, uint32_t hw_h)
+        : hw_w(hw_w), hw_h(hw_h) {
+        }
+        void operator()(GLfloat* vtx, float v) {
+            const GLfloat w = hw_w - (hw_w * v);
+            const GLfloat h = 1.0f;
+            const GLfloat x = (hw_w - w) * 0.5f;
+            const GLfloat y = (hw_h - h) * 0.5f;
+            vtx[0] = x;         vtx[1] = y;
+            vtx[2] = x;         vtx[3] = y + h;
+            vtx[4] = x + w;     vtx[5] = y + h;
+            vtx[6] = x + w;     vtx[7] = y;
+        }
+    };
+
+    // the full animation is 24 frames
+    const int nbFrames = 12;
+    s_curve_interpolator itr(nbFrames, 7.5f);
+    s_curve_interpolator itg(nbFrames, 8.0f);
+    s_curve_interpolator itb(nbFrames, 8.5f);
+
+    v_stretch vverts(hw_w, hw_h);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_ONE, GL_ONE);
+    for (int i=0 ; i<nbFrames ; i++) {
+        float x, y, w, h;
+        const float vr = itr(i);
+        const float vg = itg(i);
+        const float vb = itb(i);
+
+        // clear screen
+        glColorMask(1,1,1,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();
-        }
-        // back to main framebuffer
-        glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
-        glDisable(GL_SCISSOR_TEST);
-
-        GLfloat vtx[8];
-        const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
         glEnable(GL_TEXTURE_2D);
-        glBindTexture(GL_TEXTURE_2D, tname);
-        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-        glVertexPointer(2, GL_FLOAT, 0, vtx);
 
-        class s_curve_interpolator {
-            const float nbFrames, s, v;
-        public:
-            s_curve_interpolator(int nbFrames, float s)
-                : nbFrames(1.0f / (nbFrames-1)), s(s),
-                  v(1.0f + expf(-s + 0.5f*s)) {
-            }
-            float operator()(int f) {
-                const float x = f * nbFrames;
-                return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
-            }
-        };
+        // draw the red plane
+        vverts(vtx, vr);
+        glColorMask(1,0,0,1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
-        class v_stretch {
-            const GLfloat hw_w, hw_h;
-        public:
-            v_stretch(uint32_t hw_w, uint32_t hw_h)
-                : hw_w(hw_w), hw_h(hw_h) {
-            }
-            void operator()(GLfloat* vtx, float v) {
-                const GLfloat w = hw_w + (hw_w * v);
-                const GLfloat h = hw_h - (hw_h * v);
-                const GLfloat x = (hw_w - w) * 0.5f;
-                const GLfloat y = (hw_h - h) * 0.5f;
-                vtx[0] = x;         vtx[1] = y;
-                vtx[2] = x;         vtx[3] = y + h;
-                vtx[4] = x + w;     vtx[5] = y + h;
-                vtx[6] = x + w;     vtx[7] = y;
-            }
-        };
+        // draw the green plane
+        vverts(vtx, vg);
+        glColorMask(0,1,0,1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
-        class h_stretch {
-            const GLfloat hw_w, hw_h;
-        public:
-            h_stretch(uint32_t hw_w, uint32_t hw_h)
-                : hw_w(hw_w), hw_h(hw_h) {
-            }
-            void operator()(GLfloat* vtx, float v) {
-                const GLfloat w = hw_w - (hw_w * v);
-                const GLfloat h = 1.0f;
-                const GLfloat x = (hw_w - w) * 0.5f;
-                const GLfloat y = (hw_h - h) * 0.5f;
-                vtx[0] = x;         vtx[1] = y;
-                vtx[2] = x;         vtx[3] = y + h;
-                vtx[4] = x + w;     vtx[5] = y + h;
-                vtx[6] = x + w;     vtx[7] = y;
-            }
-        };
+        // draw the blue plane
+        vverts(vtx, vb);
+        glColorMask(0,0,1,1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
-        // the full animation is 24 frames
-        const int nbFrames = 12;
-
-        v_stretch vverts(hw_w, hw_h);
-        s_curve_interpolator itr(nbFrames, 7.5f);
-        s_curve_interpolator itg(nbFrames, 8.0f);
-        s_curve_interpolator itb(nbFrames, 8.5f);
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_ONE, GL_ONE);
-        for (int i=0 ; i<nbFrames ; i++) {
-            float x, y, w, h;
-            const float vr = itr(i);
-            const float vg = itg(i);
-            const float vb = itb(i);
-
-            // clear screen
-            glColorMask(1,1,1,1);
-            glClear(GL_COLOR_BUFFER_BIT);
-            glEnable(GL_TEXTURE_2D);
-
-            // draw the red plane
-            vverts(vtx, vr);
-            glColorMask(1,0,0,1);
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-            // draw the green plane
-            vverts(vtx, vg);
-            glColorMask(0,1,0,1);
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-            // draw the blue plane
-            vverts(vtx, vb);
-            glColorMask(0,0,1,1);
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-            // draw the white highlight (we use the last vertices)
-            glDisable(GL_TEXTURE_2D);
-            glColorMask(1,1,1,1);
-            glColor4f(vg, vg, vg, 1);
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-            hw.flip(screenBounds);
-        }
-
-        h_stretch hverts(hw_w, hw_h);
-        glDisable(GL_BLEND);
+        // draw the white highlight (we use the last vertices)
         glDisable(GL_TEXTURE_2D);
         glColorMask(1,1,1,1);
-        for (int i=0 ; i<nbFrames ; i++) {
-            const float v = itg(i);
-            hverts(vtx, v);
-            glClear(GL_COLOR_BUFFER_BIT);
-            glColor4f(1-v, 1-v, 1-v, 1);
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-            hw.flip(screenBounds);
-        }
-
-        glColorMask(1,1,1,1);
-        glEnable(GL_SCISSOR_TEST);
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-        result = NO_ERROR;
-    } else {
-        // release FBO resources
-        glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
-        result = BAD_VALUE;
+        glColor4f(vg, vg, vg, 1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+        hw.flip(screenBounds);
     }
 
-    glDeleteFramebuffersOES(1, &name);
+    h_stretch hverts(hw_w, hw_h);
+    glDisable(GL_BLEND);
+    glDisable(GL_TEXTURE_2D);
+    glColorMask(1,1,1,1);
+    for (int i=0 ; i<nbFrames ; i++) {
+        const float v = itg(i);
+        hverts(vtx, v);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glColor4f(1-v, 1-v, 1-v, 1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+        hw.flip(screenBounds);
+    }
+
+    glColorMask(1,1,1,1);
+    glEnable(GL_SCISSOR_TEST);
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glDeleteTextures(1, &tname);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
+{
+    status_t result = PERMISSION_DENIED;
+
+    if (!GLExtensions::getInstance().haveFramebufferObject())
+        return INVALID_OPERATION;
+
+
+    // get screen geometry
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const uint32_t hw_w = hw.getWidth();
+    const uint32_t hw_h = hw.getHeight();
+    const Region screenBounds(hw.bounds());
+
+    GLfloat u, v;
+    GLuint tname;
+    result = renderScreenToTextureLocked(0, &tname, &u, &v);
+    if (result != NO_ERROR) {
+        return result;
+    }
+
+    // back to main framebuffer
+    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+    glDisable(GL_SCISSOR_TEST);
+
+    GLfloat vtx[8];
+    const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, tname);
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+    glVertexPointer(2, GL_FLOAT, 0, vtx);
+
+    class s_curve_interpolator {
+        const float nbFrames, s, v;
+    public:
+        s_curve_interpolator(int nbFrames, float s)
+        : nbFrames(1.0f / (nbFrames-1)), s(s),
+          v(1.0f + expf(-s + 0.5f*s)) {
+        }
+        float operator()(int f) {
+            const float x = f * nbFrames;
+            return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
+        }
+    };
+
+    class v_stretch {
+        const GLfloat hw_w, hw_h;
+    public:
+        v_stretch(uint32_t hw_w, uint32_t hw_h)
+        : hw_w(hw_w), hw_h(hw_h) {
+        }
+        void operator()(GLfloat* vtx, float v) {
+            const GLfloat w = hw_w + (hw_w * v);
+            const GLfloat h = hw_h - (hw_h * v);
+            const GLfloat x = (hw_w - w) * 0.5f;
+            const GLfloat y = (hw_h - h) * 0.5f;
+            vtx[0] = x;         vtx[1] = y;
+            vtx[2] = x;         vtx[3] = y + h;
+            vtx[4] = x + w;     vtx[5] = y + h;
+            vtx[6] = x + w;     vtx[7] = y;
+        }
+    };
+
+    class h_stretch {
+        const GLfloat hw_w, hw_h;
+    public:
+        h_stretch(uint32_t hw_w, uint32_t hw_h)
+        : hw_w(hw_w), hw_h(hw_h) {
+        }
+        void operator()(GLfloat* vtx, float v) {
+            const GLfloat w = hw_w - (hw_w * v);
+            const GLfloat h = 1.0f;
+            const GLfloat x = (hw_w - w) * 0.5f;
+            const GLfloat y = (hw_h - h) * 0.5f;
+            vtx[0] = x;         vtx[1] = y;
+            vtx[2] = x;         vtx[3] = y + h;
+            vtx[4] = x + w;     vtx[5] = y + h;
+            vtx[6] = x + w;     vtx[7] = y;
+        }
+    };
+
+    // the full animation is 24 frames
+    const int nbFrames = 12;
+    s_curve_interpolator itr(nbFrames, 7.5f);
+    s_curve_interpolator itg(nbFrames, 8.0f);
+    s_curve_interpolator itb(nbFrames, 8.5f);
+
+    h_stretch hverts(hw_w, hw_h);
+    glDisable(GL_BLEND);
+    glDisable(GL_TEXTURE_2D);
+    glColorMask(1,1,1,1);
+    for (int i=nbFrames-1 ; i>=0 ; i--) {
+        const float v = itg(i);
+        hverts(vtx, v);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glColor4f(1-v, 1-v, 1-v, 1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+        hw.flip(screenBounds);
+    }
+
+    v_stretch vverts(hw_w, hw_h);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_ONE, GL_ONE);
+    for (int i=nbFrames-1 ; i>=0 ; i--) {
+        float x, y, w, h;
+        const float vr = itr(i);
+        const float vg = itg(i);
+        const float vb = itb(i);
+
+        // clear screen
+        glColorMask(1,1,1,1);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glEnable(GL_TEXTURE_2D);
+
+        // draw the red plane
+        vverts(vtx, vr);
+        glColorMask(1,0,0,1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+        // draw the green plane
+        vverts(vtx, vg);
+        glColorMask(0,1,0,1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+        // draw the blue plane
+        vverts(vtx, vb);
+        glColorMask(0,0,1,1);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+        hw.flip(screenBounds);
+    }
+
+    glColorMask(1,1,1,1);
+    glEnable(GL_SCISSOR_TEST);
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDeleteTextures(1, &tname);
 
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::turnElectronBeamOffImplLocked()
+{
+    DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+    if (!hw.canDraw()) {
+        // we're already off
+        return NO_ERROR;
+    }
+    status_t result = electronBeamOffAnimationImplLocked();
     if (result == NO_ERROR) {
-        DisplayHardware& hw(graphicPlane(dpy).editDisplayHardware());
         hw.setCanDraw(false);
     }
-
     return result;
 }
 
@@ -1766,12 +1940,59 @@
     status_t res = postMessageSync(msg);
     if (res == NO_ERROR) {
         res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult();
+
+        // work-around: when the power-manager calls us we activate the
+        // animation. eventually, the "on" animation will be called
+        // by the power-manager itself
+        mElectronBeamAnimation = true;
     }
     return res;
 }
 
 // ---------------------------------------------------------------------------
 
+status_t SurfaceFlinger::turnElectronBeamOnImplLocked()
+{
+    DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+    if (hw.canDraw()) {
+        // we're already on
+        return NO_ERROR;
+    }
+    status_t result = electronBeamOnAnimationImplLocked();
+    if (result == NO_ERROR) {
+        hw.setCanDraw(true);
+    }
+    return result;
+}
+
+status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode)
+{
+    if (!GLExtensions::getInstance().haveFramebufferObject())
+        return INVALID_OPERATION;
+
+    class MessageTurnElectronBeamOn : public MessageBase {
+        SurfaceFlinger* flinger;
+        status_t result;
+    public:
+        MessageTurnElectronBeamOn(SurfaceFlinger* flinger)
+            : flinger(flinger), result(PERMISSION_DENIED) {
+        }
+        status_t getResult() const {
+            return result;
+        }
+        virtual bool handler() {
+            Mutex::Autolock _l(flinger->mStateLock);
+            result = flinger->turnElectronBeamOnImplLocked();
+            return true;
+        }
+    };
+
+    postMessageAsync( new MessageTurnElectronBeamOn(this) );
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
 status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
         sp<IMemoryHeap>* heap,
         uint32_t* w, uint32_t* h, PixelFormat* f,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f85a22b..d07a3ad 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -202,6 +202,7 @@
                                                       uint32_t reqWidth,
                                                       uint32_t reqHeight);
     virtual status_t                    turnElectronBeamOff(int32_t mode);
+    virtual status_t                    turnElectronBeamOn(int32_t mode);
 
             void                        screenReleased(DisplayID dpy);
             void                        screenAcquired(DisplayID dpy);
@@ -328,6 +329,11 @@
                     uint32_t reqWidth = 0, uint32_t reqHeight = 0);
 
             status_t turnElectronBeamOffImplLocked();
+            status_t turnElectronBeamOnImplLocked();
+            status_t electronBeamOffAnimationImplLocked();
+            status_t electronBeamOnAnimationImplLocked();
+            status_t renderScreenToTextureLocked(DisplayID dpy,
+                    GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
 
             friend class FreezeLock;
             sp<FreezeLock> getFreezeLock() const;
@@ -389,6 +395,7 @@
                 bool                        mVisibleRegionsDirty;
                 bool                        mDeferReleaseConsole;
                 bool                        mFreezeDisplay;
+                bool                        mElectronBeamAnimation;
                 int32_t                     mFreezeCount;
                 nsecs_t                     mFreezeDisplayTime;
                 Vector< sp<LayerBase> >     mVisibleLayersSortedByZ;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f71ebb9..873ebac 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -871,6 +871,15 @@
                                     error.string());
                                 goto bail;
                         }
+                    } else if (tag == "uses-gl-texture") {
+                        String8 name = getAttribute(tree, NAME_ATTR, &error);
+                        if (name != "" && error == "") {
+                            printf("uses-gl-texture:'%s'\n", name.string());
+                        } else {
+                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+                                    error.string());
+                                goto bail;
+                        }
                     }
                 } else if (depth == 3 && withinApplication) {
                     withinActivity = false;