Merge "DO NOT MERGE Adjust action bar home/up sizing/padding for smaller tablets." into honeycomb-mr2
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 2aa53a9..a8e0a4d 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -24,10 +24,12 @@
 
 #include "include/ARTSPController.h"
 #include "include/AwesomePlayer.h"
+#include "include/DRMExtractor.h"
 #include "include/SoftwareRenderer.h"
 #include "include/NuCachedSource2.h"
 #include "include/ThrottledSource.h"
 #include "include/MPEG2TSExtractor.h"
+#include "include/WVMExtractor.h"
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -447,6 +449,7 @@
 
     cancelPlayerEvents();
 
+    mWVMExtractor.clear();
     mCachedSource.clear();
     mAudioTrack.clear();
     mVideoTrack.clear();
@@ -554,6 +557,11 @@
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
         *eos = (finalStatus != OK);
         return true;
+    } else if (mWVMExtractor != NULL) {
+        status_t finalStatus;
+        *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
+        *eos = (finalStatus != OK);
+        return true;
     }
 
     return false;
@@ -646,6 +654,30 @@
                 }
             }
         }
+    } else if (mWVMExtractor != NULL) {
+        status_t finalStatus;
+
+        int64_t cachedDurationUs
+            = mWVMExtractor->getCachedDurationUs(&finalStatus);
+
+        bool eos = (finalStatus != OK);
+
+        if (eos) {
+            if (finalStatus == ERROR_END_OF_STREAM) {
+                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+            }
+            if (mFlags & PREPARING) {
+                LOGV("cache has reached EOS, prepare is done.");
+                finishAsyncPrepare_l();
+            }
+        } else {
+            int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
+            if (percentage > 100) {
+                percentage = 100;
+            }
+
+            notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
+        }
     }
 
     int64_t cachedDurationUs;
@@ -1320,7 +1352,7 @@
             mVideoBuffer = NULL;
         }
 
-        if (mSeeking == SEEK && mCachedSource != NULL && mAudioSource != NULL
+        if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
                 && !(mFlags & SEEK_PREVIEW)) {
             // We're going to seek the video source first, followed by
             // the audio source.
@@ -1654,8 +1686,19 @@
 status_t AwesomePlayer::finishSetDataSource_l() {
     sp<DataSource> dataSource;
 
+    bool isWidevineStreaming = false;
+    if (!strncasecmp("widevine://", mUri.string(), 11)) {
+        isWidevineStreaming = true;
+
+        String8 newURI = String8("http://");
+        newURI.append(mUri.string() + 11);
+
+        mUri = newURI;
+    }
+
     if (!strncasecmp("http://", mUri.string(), 7)
-            || !strncasecmp("https://", mUri.string(), 8)) {
+            || !strncasecmp("https://", mUri.string(), 8)
+            || isWidevineStreaming) {
         mConnectingDataSource = new NuHTTPDataSource(
                 (mFlags & INCOGNITO) ? NuHTTPDataSource::kFlagIncognito : 0);
 
@@ -1670,39 +1713,48 @@
             return err;
         }
 
+        if (!isWidevineStreaming) {
+            // The widevine extractor does its own caching.
+
 #if 0
-        mCachedSource = new NuCachedSource2(
-                new ThrottledSource(
-                    mConnectingDataSource, 50 * 1024 /* bytes/sec */));
+            mCachedSource = new NuCachedSource2(
+                    new ThrottledSource(
+                        mConnectingDataSource, 50 * 1024 /* bytes/sec */));
 #else
-        mCachedSource = new NuCachedSource2(mConnectingDataSource);
+            mCachedSource = new NuCachedSource2(mConnectingDataSource);
 #endif
-        mConnectingDataSource.clear();
 
-        dataSource = mCachedSource;
-
-        // We're going to prefill the cache before trying to instantiate
-        // the extractor below, as the latter is an operation that otherwise
-        // could block on the datasource for a significant amount of time.
-        // During that time we'd be unable to abort the preparation phase
-        // without this prefill.
-
-        mLock.unlock();
-
-        for (;;) {
-            status_t finalStatus;
-            size_t cachedDataRemaining =
-                mCachedSource->approxDataRemaining(&finalStatus);
-
-            if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
-                    || (mFlags & PREPARE_CANCELLED)) {
-                break;
-            }
-
-            usleep(200000);
+            dataSource = mCachedSource;
+        } else {
+            dataSource = mConnectingDataSource;
         }
 
-        mLock.lock();
+        mConnectingDataSource.clear();
+
+        if (mCachedSource != NULL) {
+            // We're going to prefill the cache before trying to instantiate
+            // the extractor below, as the latter is an operation that otherwise
+            // could block on the datasource for a significant amount of time.
+            // During that time we'd be unable to abort the preparation phase
+            // without this prefill.
+
+            mLock.unlock();
+
+            for (;;) {
+                status_t finalStatus;
+                size_t cachedDataRemaining =
+                    mCachedSource->approxDataRemaining(&finalStatus);
+
+                if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+                        || (mFlags & PREPARE_CANCELLED)) {
+                    break;
+                }
+
+                usleep(200000);
+            }
+
+            mLock.lock();
+        }
 
         if (mFlags & PREPARE_CANCELLED) {
             LOGI("Prepare cancelled while waiting for initial cache fill.");
@@ -1740,10 +1792,29 @@
         return UNKNOWN_ERROR;
     }
 
-    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+    sp<MediaExtractor> extractor;
 
-    if (extractor == NULL) {
-        return UNKNOWN_ERROR;
+    if (isWidevineStreaming) {
+        String8 mimeType;
+        float confidence;
+        sp<AMessage> dummy;
+        bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy);
+
+        if (!success
+                || strcasecmp(
+                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
+            return ERROR_UNSUPPORTED;
+        }
+
+        mWVMExtractor = new WVMExtractor(dataSource);
+        mWVMExtractor->setAdaptiveStreamingMode(true);
+        extractor = mWVMExtractor;
+    } else {
+        extractor = MediaExtractor::Create(dataSource);
+
+        if (extractor == NULL) {
+            return UNKNOWN_ERROR;
+        }
     }
 
     dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
@@ -1754,7 +1825,15 @@
         }
     }
 
-    return setDataSource_l(extractor);
+    status_t err = setDataSource_l(extractor);
+
+    if (err != OK) {
+        mWVMExtractor.clear();
+
+        return err;
+    }
+
+    return OK;
 }
 
 void AwesomePlayer::abortPrepare(status_t err) {
@@ -1815,7 +1894,7 @@
 
     mFlags |= PREPARING_CONNECTED;
 
-    if (mCachedSource != NULL || mRTSPController != NULL) {
+    if (isStreamingHTTP() || mRTSPController != NULL) {
         postBufferingEvent_l();
     } else {
         finishAsyncPrepare_l();
@@ -1852,4 +1931,8 @@
     postCheckAudioStatusEvent_l();
 }
 
+bool AwesomePlayer::isStreamingHTTP() const {
+    return mCachedSource != NULL || mWVMExtractor != NULL;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 7c72852..83a1eaa 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -45,7 +45,8 @@
 static Mutex gWVMutex;
 
 WVMExtractor::WVMExtractor(const sp<DataSource> &source)
-    : mDataSource(source) {
+    : mDataSource(source),
+      mUseAdaptiveStreaming(false) {
     {
         Mutex::Autolock autoLock(gWVMutex);
         if (gVendorLibHandle == NULL) {
@@ -100,5 +101,21 @@
     return mImpl->getMetaData();
 }
 
+int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) {
+    // TODO: Fill this with life.
+
+    *finalStatus = OK;
+
+    return 0;
+}
+
+void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) {
+    mUseAdaptiveStreaming = adaptive;
+}
+
+bool WVMExtractor::getAdaptiveStreamingMode() const {
+    return mUseAdaptiveStreaming;
+}
+
 } //namespace android
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 4e6f75c..3a21f25 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -44,6 +44,8 @@
 class DrmManagerClinet;
 class DecryptHandle;
 
+struct WVMExtractor;
+
 struct AwesomeRenderer : public RefBase {
     AwesomeRenderer() {}
 
@@ -219,6 +221,8 @@
     DrmManagerClient *mDrmManagerClient;
     DecryptHandle *mDecryptHandle;
 
+    sp<WVMExtractor> mWVMExtractor;
+
     status_t setDataSource_l(
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL);
@@ -268,6 +272,8 @@
 
     status_t startAudioPlayer_l();
 
+    bool isStreamingHTTP() const;
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 0da45a8..62e5aa5 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -19,6 +19,7 @@
 #define WVM_EXTRACTOR_H_
 
 #include <media/stagefright/MediaExtractor.h>
+#include <utils/Errors.h>
 
 namespace android {
 
@@ -33,12 +34,31 @@
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
     virtual sp<MetaData> getMetaData();
 
+    // Return the amount of data cached from the current
+    // playback positiion (in us).
+    // While more data is still being fetched *finalStatus == OK,
+    // Once fetching is completed (no more data available), *finalStatus != OK
+    // If fetching completed normally (i.e. reached EOS instead of IO error)
+    // *finalStatus == ERROR_END_OF_STREAM
+    int64_t getCachedDurationUs(status_t *finalStatus);
+
+    // Set to use adaptive streaming mode by the WV component.
+    // If adaptive == true, adaptive streaming mode will be used.
+    // Default mode is non-adaptive streaming mode.
+    // Should set to use adaptive streaming mode only if widevine:// protocol
+    // is used.
+    void setAdaptiveStreamingMode(bool adaptive);
+
+    // Retrieve the adaptive streaming mode used by the WV component.
+    bool getAdaptiveStreamingMode() const;
+
 protected:
     virtual ~WVMExtractor();
 
 private:
     sp<DataSource> mDataSource;
     sp<MediaExtractor> mImpl;
+    bool mUseAdaptiveStreaming;
 
     WVMExtractor(const WVMExtractor &);
     WVMExtractor &operator=(const WVMExtractor &);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 26d89cd..607c60a 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -6498,8 +6498,22 @@
             }
             if (mBaseDisplayWidth < mInitialDisplayWidth
                     || mBaseDisplayHeight < mInitialDisplayHeight) {
-                Rect outer = new Rect(0, 0, mInitialDisplayWidth, mInitialDisplayHeight);
-                Rect inner = new Rect(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+                int initW, initH, baseW, baseH;
+                final boolean rotated = (mRotation == Surface.ROTATION_90
+                        || mRotation == Surface.ROTATION_270);
+                if (rotated) {
+                    initW = mInitialDisplayHeight;
+                    initH = mInitialDisplayWidth;
+                    baseW = mBaseDisplayHeight;
+                    baseH = mBaseDisplayWidth;
+                } else {
+                    initW = mInitialDisplayWidth;
+                    initH = mInitialDisplayHeight;
+                    baseW = mBaseDisplayWidth;
+                    baseH = mBaseDisplayHeight;
+                }
+                Rect outer = new Rect(0, 0, initW, initH);
+                Rect inner = new Rect(0, 0, baseW, baseH);
                 try {
                     mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
                 } catch (Surface.OutOfResourcesException e) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 3c0c9a4..144ec42 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -201,7 +201,8 @@
                 Capability.VIEW_MANIPULATION,
                 Capability.PLAY_ANIMATION,
                 Capability.ANIMATED_VIEW_MANIPULATION,
-                Capability.ADAPTER_BINDING);
+                Capability.ADAPTER_BINDING,
+                Capability.EXTENDED_VIEWINFO);
 
 
         BridgeAssetManager.initSystem();
@@ -399,15 +400,6 @@
         throw new IllegalArgumentException("viewObject is not a View");
     }
 
-    @Override
-    public int getViewBaseline(Object viewObject) {
-        if (viewObject instanceof View) {
-            return ((View) viewObject).getBaseline();
-        }
-
-        throw new IllegalArgumentException("viewObject is not a View");
-    }
-
     /**
      * Returns the lock for the bridge
      */
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
index 1ca3182..3d50b2a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
@@ -19,21 +19,23 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.widget.TextView;
 
 /**
  * Base class for mocked views.
- * 
+ *
  * TODO: implement onDraw and draw a rectangle in a random color with the name of the class
  * (or better the id of the view).
  */
 public class MockView extends TextView {
-    
+
     public MockView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        
+
         setText(this.getClass().getSimpleName());
         setTextColor(0xFF000000);
+        setGravity(Gravity.CENTER);
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index c53cb23..b800519 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -74,6 +74,7 @@
 import android.view.View.AttachInfo;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.AbsListView;
 import android.widget.AbsSpinner;
 import android.widget.AdapterView;
@@ -513,7 +514,7 @@
                 mViewRoot.draw(mCanvas);
             }
 
-            mViewInfoList = startVisitingViews(mViewRoot, 0);
+            mViewInfoList = startVisitingViews(mViewRoot, 0, params.getExtendedViewInfoMode());
 
             // success!
             return SUCCESS.createResult();
@@ -1255,7 +1256,7 @@
         }
     }
 
-    private List<ViewInfo> startVisitingViews(View view, int offset) {
+    private List<ViewInfo> startVisitingViews(View view, int offset, boolean setExtendedInfo) {
         if (view == null) {
             return null;
         }
@@ -1264,7 +1265,7 @@
         offset += view.getTop();
 
         if (view == mContentRoot) {
-            return visitAllChildren(mContentRoot, offset);
+            return visitAllChildren(mContentRoot, offset, setExtendedInfo);
         }
 
         // otherwise, look for mContentRoot in the children
@@ -1272,7 +1273,8 @@
             ViewGroup group = ((ViewGroup) view);
 
             for (int i = 0; i < group.getChildCount(); i++) {
-                List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset);
+                List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset,
+                        setExtendedInfo);
                 if (list != null) {
                     return list;
                 }
@@ -1287,8 +1289,9 @@
      * bounds of all the views.
      * @param view the root View
      * @param offset an offset for the view bounds.
+     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
      */
-    private ViewInfo visit(View view, int offset) {
+    private ViewInfo visit(View view, int offset, boolean setExtendedInfo) {
         if (view == null) {
             return null;
         }
@@ -1298,9 +1301,22 @@
                 view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
                 view, view.getLayoutParams());
 
+        if (setExtendedInfo) {
+            MarginLayoutParams marginParams = null;
+            LayoutParams params = view.getLayoutParams();
+            if (params instanceof MarginLayoutParams) {
+                marginParams = (MarginLayoutParams) params;
+            }
+            result.setExtendedInfo(view.getBaseline(),
+                    marginParams != null ? marginParams.leftMargin : 0,
+                    marginParams != null ? marginParams.topMargin : 0,
+                    marginParams != null ? marginParams.rightMargin : 0,
+                    marginParams != null ? marginParams.bottomMargin : 0);
+        }
+
         if (view instanceof ViewGroup) {
             ViewGroup group = ((ViewGroup) view);
-            result.setChildren(visitAllChildren(group, 0 /*offset*/));
+            result.setChildren(visitAllChildren(group, 0 /*offset*/, setExtendedInfo));
         }
 
         return result;
@@ -1311,15 +1327,17 @@
      * containing the bounds of all the views.
      * @param view the root View
      * @param offset an offset for the view bounds.
+     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
      */
-    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset) {
+    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
+            boolean setExtendedInfo) {
         if (viewGroup == null) {
             return null;
         }
 
         List<ViewInfo> children = new ArrayList<ViewInfo>();
         for (int i = 0; i < viewGroup.getChildCount(); i++) {
-            children.add(visit(viewGroup.getChildAt(i), offset));
+            children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo));
         }
         return children;
     }