Ensure sample runs on Gingerbread.

Unfortunately, the video does not play due to a MediaPlayer
exception but at least this version does not crash.

Change-Id: I0baf9239a8a12f92b4805bab226f21f46fa63693
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/MediaPlayerWrapper.java b/samples/Support7Demos/src/com/example/android/supportv7/media/MediaPlayerWrapper.java
index 9aa78d8..658caca 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/MediaPlayerWrapper.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/MediaPlayerWrapper.java
@@ -16,16 +16,14 @@
 
 package com.example.android.supportv7.media;
 
-import com.example.android.supportv7.R;
-
 import android.content.Context;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Handler;
 import android.util.Log;
 import android.media.MediaPlayer;
 import android.view.Surface;
-import android.view.Gravity;
-import android.graphics.SurfaceTexture;
+import android.view.SurfaceHolder;
 import java.io.IOException;
 
 /**
@@ -37,7 +35,6 @@
         MediaPlayer.OnCompletionListener,
         MediaPlayer.OnErrorListener,
         MediaPlayer.OnSeekCompleteListener,
-        OverlayDisplayWindow.OverlayWindowListener,
         MediaSessionManager.Callback {
     private static final String TAG = "MediaPlayerWrapper";
     private static final boolean DEBUG = false;
@@ -54,6 +51,7 @@
     private int mState = STATE_IDLE;
     private Callback mCallback;
     private Surface mSurface;
+    private SurfaceHolder mSurfaceHolder;
     private int mSeekToPos;
 
     public MediaPlayerWrapper(Context context) {
@@ -140,21 +138,16 @@
         }
     }
 
-    //OverlayDisplayWindow listeners
-    @Override
-    public void onWindowCreated(Surface surface) {
-        if (DEBUG) {
-            Log.d(TAG, "onWindowCreated");
-        }
+    public void setSurface(Surface surface) {
         mSurface = surface;
-        mMediaPlayer.setSurface(surface);
+        mSurfaceHolder = null;
+        updateSurface();
     }
 
-    @Override
-    public void onWindowDestroyed() {
-        if (DEBUG) {
-            Log.d(TAG, "onWindowDestroyed");
-        }
+    public void setSurface(SurfaceHolder surfaceHolder) {
+        mSurface = null;
+        mSurfaceHolder = surfaceHolder;
+        updateSurface();
     }
 
     //MediaPlayer Listeners
@@ -244,9 +237,7 @@
         mMediaPlayer.setOnCompletionListener(this);
         mMediaPlayer.setOnErrorListener(this);
         mMediaPlayer.setOnSeekCompleteListener(this);
-        if (mSurface != null) {
-            mMediaPlayer.setSurface(mSurface);
-        }
+        updateSurface();
         mState = STATE_IDLE;
         mSeekToPos = 0;
     }
@@ -265,10 +256,32 @@
         }
     }
 
+    private void updateSurface() {
+        if (mSurface != null) {
+            // The setSurface API does not exist until V14+.
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                ICSMediaPlayer.setSurface(mMediaPlayer, mSurface);
+            } else {
+                throw new UnsupportedOperationException("MediaPlayer does not support "
+                        + "setSurface() on this version of the platform.");
+            }
+        } else if (mSurfaceHolder != null) {
+            mMediaPlayer.setDisplay(mSurfaceHolder);
+        } else {
+            mMediaPlayer.setDisplay(null);
+        }
+    }
+
     public static abstract class Callback {
         public void onError() {}
         public void onCompletion() {}
         public void onStatusChanged() {}
         public void onSizeChanged(int width, int height) {}
     }
+
+    private static final class ICSMediaPlayer {
+        public static final void setSurface(MediaPlayer player, Surface surface) {
+            player.setSurface(surface);
+        }
+    }
 }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
index 11a2889..e691c14 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
@@ -18,8 +18,10 @@
 import com.example.android.supportv7.R;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManager;
+import android.os.Build;
 import android.util.Log;
 import android.view.Display;
 import android.util.DisplayMetrics;
@@ -28,6 +30,8 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
 import android.view.TextureView;
 import android.view.View;
 import android.view.Surface;
@@ -38,68 +42,38 @@
 /**
  * Manages an overlay display window, used for simulating remote playback.
  */
-public class OverlayDisplayWindow {
+public abstract class OverlayDisplayWindow {
     private static final String TAG = "OverlayDisplayWindow";
     private static final boolean DEBUG = false;
 
-    private final float INITIAL_SCALE = 0.5f;
-    private final float MIN_SCALE = 0.3f;
-    private final float MAX_SCALE = 1.0f;
-    private final float WINDOW_ALPHA = 0.8f;
+    private static final float WINDOW_ALPHA = 0.8f;
+    private static final float INITIAL_SCALE = 0.5f;
+    private static final float MIN_SCALE = 0.3f;
+    private static final float MAX_SCALE = 1.0f;
 
-    // When true, disables support for moving and resizing the overlay.
-    // The window is made non-touchable, which makes it possible to
-    // directly interact with the content underneath.
-    private final boolean DISABLE_MOVE_AND_RESIZE = false;
+    protected final Context mContext;
+    protected final String mName;
+    protected final int mWidth;
+    protected final int mHeight;
+    protected final int mGravity;
+    protected OverlayWindowListener mListener;
 
-    private final Context mContext;
-    private final int mWidth;
-    private final int mHeight;
-    private final int mGravity;
-    private OverlayWindowListener mListener;
-    private final String mTitle;
-
-    private final DisplayManager mDisplayManager;
-    private final WindowManager mWindowManager;
-
-
-    private final Display mDefaultDisplay;
-    private final DisplayMetrics mDefaultDisplayMetrics = new DisplayMetrics();
-
-    private View mWindowContent;
-    private WindowManager.LayoutParams mWindowParams;
-    private TextureView mTextureView;
-    private TextView mTitleTextView;
-
-    private GestureDetector mGestureDetector;
-    private ScaleGestureDetector mScaleGestureDetector;
-
-    private boolean mWindowVisible;
-    private int mWindowX;
-    private int mWindowY;
-    private float mWindowScale;
-
-    private float mLiveTranslationX;
-    private float mLiveTranslationY;
-    private float mLiveScale = 1.0f;
-
-    public OverlayDisplayWindow(Context context, String name,
+    protected OverlayDisplayWindow(Context context, String name,
             int width, int height, int gravity) {
         mContext = context;
+        mName = name;
         mWidth = width;
         mHeight = height;
         mGravity = gravity;
-        mTitle = name;
+    }
 
-        mDisplayManager = (DisplayManager)context.getSystemService(
-                Context.DISPLAY_SERVICE);
-        mWindowManager = (WindowManager)context.getSystemService(
-                Context.WINDOW_SERVICE);
-
-        mDefaultDisplay = mWindowManager.getDefaultDisplay();
-        updateDefaultDisplayInfo();
-
-        createWindow();
+    public static OverlayDisplayWindow create(Context context, String name,
+            int width, int height, int gravity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return new JellybeanMr1Impl(context, name, width, height, gravity);
+        } else {
+            return new LegacyImpl(context, name, width, height, gravity);
+        }
     }
 
     public void setOverlayWindowListener(OverlayWindowListener listener) {
@@ -110,253 +84,378 @@
         return mContext;
     }
 
-    public void show() {
-        if (!mWindowVisible) {
-            mDisplayManager.registerDisplayListener(mDisplayListener, null);
-            if (!updateDefaultDisplayInfo()) {
-                mDisplayManager.unregisterDisplayListener(mDisplayListener);
-                return;
-            }
+    public abstract void show();
 
-            clearLiveState();
-            updateWindowParams();
-            mWindowManager.addView(mWindowContent, mWindowParams);
-            mWindowVisible = true;
-        }
-    }
+    public abstract void dismiss();
 
-    public void dismiss() {
-        if (mWindowVisible) {
-            mDisplayManager.unregisterDisplayListener(mDisplayListener);
-            mWindowManager.removeView(mWindowContent);
-            mWindowVisible = false;
-        }
-    }
-
-    public void relayout() {
-        if (mWindowVisible) {
-            updateWindowParams();
-            mWindowManager.updateViewLayout(mWindowContent, mWindowParams);
-        }
-    }
-
-    public void updateAspectRatio(int width, int height) {
-        if (mWidth * height < mHeight * width) {
-            mTextureView.getLayoutParams().width = mWidth;
-            mTextureView.getLayoutParams().height = mWidth * height / width;
-        } else {
-            mTextureView.getLayoutParams().width = mHeight * width / height;
-            mTextureView.getLayoutParams().height = mHeight;
-        }
-        relayout();
-    }
-
-    private boolean updateDefaultDisplayInfo() {
-        mDefaultDisplay.getMetrics(mDefaultDisplayMetrics);
-        return true;
-    }
-
-    private void createWindow() {
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-
-        mWindowContent = inflater.inflate(
-                R.layout.overlay_display_window, null);
-        mWindowContent.setOnTouchListener(mOnTouchListener);
-
-        mTextureView = (TextureView)mWindowContent.findViewById(
-                R.id.overlay_display_window_texture);
-        mTextureView.setPivotX(0);
-        mTextureView.setPivotY(0);
-        mTextureView.getLayoutParams().width = mWidth;
-        mTextureView.getLayoutParams().height = mHeight;
-        mTextureView.setOpaque(false);
-        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
-
-        mTitleTextView = (TextView)mWindowContent.findViewById(
-                R.id.overlay_display_window_title);
-        mTitleTextView.setText(mTitle);
-
-        mWindowParams = new WindowManager.LayoutParams(
-                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-        mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        if (DISABLE_MOVE_AND_RESIZE) {
-            mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-        }
-        mWindowParams.alpha = WINDOW_ALPHA;
-        mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
-        mWindowParams.setTitle(mTitle);
-
-        mGestureDetector = new GestureDetector(mContext, mOnGestureListener);
-        mScaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);
-
-        // Set the initial position and scale.
-        // The position and scale will be clamped when the display is first shown.
-        mWindowX = (mGravity & Gravity.LEFT) == Gravity.LEFT ?
-                0 : mDefaultDisplayMetrics.widthPixels;
-        mWindowY = (mGravity & Gravity.TOP) == Gravity.TOP ?
-                0 : mDefaultDisplayMetrics.heightPixels;
-        Log.d(TAG, mDefaultDisplayMetrics.toString());
-        mWindowScale = INITIAL_SCALE;
-
-        // calculate and save initial settings
-        updateWindowParams();
-        saveWindowParams();
-    }
-
-    private void updateWindowParams() {
-        float scale = mWindowScale * mLiveScale;
-        scale = Math.min(scale, (float)mDefaultDisplayMetrics.widthPixels / mWidth);
-        scale = Math.min(scale, (float)mDefaultDisplayMetrics.heightPixels / mHeight);
-        scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale));
-
-        float offsetScale = (scale / mWindowScale - 1.0f) * 0.5f;
-        int width = (int)(mWidth * scale);
-        int height = (int)(mHeight * scale);
-        int x = (int)(mWindowX + mLiveTranslationX - width * offsetScale);
-        int y = (int)(mWindowY + mLiveTranslationY - height * offsetScale);
-        x = Math.max(0, Math.min(x, mDefaultDisplayMetrics.widthPixels - width));
-        y = Math.max(0, Math.min(y, mDefaultDisplayMetrics.heightPixels - height));
-
-        if (DEBUG) {
-            Log.d(TAG, "updateWindowParams: scale=" + scale
-                    + ", offsetScale=" + offsetScale
-                    + ", x=" + x + ", y=" + y
-                    + ", width=" + width + ", height=" + height);
-        }
-
-        mTextureView.setScaleX(scale);
-        mTextureView.setScaleY(scale);
-
-        mTextureView.setTranslationX(
-                (mWidth - mTextureView.getLayoutParams().width) * scale / 2);
-        mTextureView.setTranslationY(
-                (mHeight - mTextureView.getLayoutParams().height) * scale / 2);
-
-        mWindowParams.x = x;
-        mWindowParams.y = y;
-        mWindowParams.width = width;
-        mWindowParams.height = height;
-    }
-
-    private void saveWindowParams() {
-        mWindowX = mWindowParams.x;
-        mWindowY = mWindowParams.y;
-        mWindowScale = mTextureView.getScaleX();
-        clearLiveState();
-    }
-
-    private void clearLiveState() {
-        mLiveTranslationX = 0f;
-        mLiveTranslationY = 0f;
-        mLiveScale = 1.0f;
-    }
-
-    private final DisplayManager.DisplayListener mDisplayListener =
-            new DisplayManager.DisplayListener() {
-        @Override
-        public void onDisplayAdded(int displayId) {
-        }
-
-        @Override
-        public void onDisplayChanged(int displayId) {
-            if (displayId == mDefaultDisplay.getDisplayId()) {
-                if (updateDefaultDisplayInfo()) {
-                    relayout();
-                } else {
-                    dismiss();
-                }
-            }
-        }
-
-        @Override
-        public void onDisplayRemoved(int displayId) {
-            if (displayId == mDefaultDisplay.getDisplayId()) {
-                dismiss();
-            }
-        }
-    };
-
-    private final SurfaceTextureListener mSurfaceTextureListener =
-            new SurfaceTextureListener() {
-        @Override
-        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
-                int width, int height) {
-            if (mListener != null) {
-                mListener.onWindowCreated(new Surface(surfaceTexture));
-            }
-        }
-
-        @Override
-        public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
-            if (mListener != null) {
-                mListener.onWindowDestroyed();
-            }
-            return true;
-        }
-
-        @Override
-        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
-                int width, int height) {
-        }
-
-        @Override
-        public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
-        }
-    };
-
-    private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
-        @Override
-        public boolean onTouch(View view, MotionEvent event) {
-            // Work in screen coordinates.
-            final float oldX = event.getX();
-            final float oldY = event.getY();
-            event.setLocation(event.getRawX(), event.getRawY());
-
-            mGestureDetector.onTouchEvent(event);
-            mScaleGestureDetector.onTouchEvent(event);
-
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    saveWindowParams();
-                    break;
-            }
-
-            // Revert to window coordinates.
-            event.setLocation(oldX, oldY);
-            return true;
-        }
-    };
-
-    private final GestureDetector.OnGestureListener mOnGestureListener =
-            new GestureDetector.SimpleOnGestureListener() {
-        @Override
-        public boolean onScroll(MotionEvent e1, MotionEvent e2,
-                float distanceX, float distanceY) {
-            mLiveTranslationX -= distanceX;
-            mLiveTranslationY -= distanceY;
-            relayout();
-            return true;
-        }
-    };
-
-    private final ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener =
-            new ScaleGestureDetector.SimpleOnScaleGestureListener() {
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            mLiveScale *= detector.getScaleFactor();
-            relayout();
-            return true;
-        }
-    };
+    public abstract void updateAspectRatio(int width, int height);
 
     // Watches for significant changes in the overlay display window lifecycle.
     public interface OverlayWindowListener {
         public void onWindowCreated(Surface surface);
+        public void onWindowCreated(SurfaceHolder surfaceHolder);
         public void onWindowDestroyed();
     }
+
+    /**
+     * Implementation for older versions.
+     */
+    private static final class LegacyImpl extends OverlayDisplayWindow {
+        private final WindowManager mWindowManager;
+
+        private boolean mWindowVisible;
+        private SurfaceView mSurfaceView;
+
+        public LegacyImpl(Context context, String name,
+                int width, int height, int gravity) {
+            super(context, name, width, height, gravity);
+
+            mWindowManager = (WindowManager)context.getSystemService(
+                    Context.WINDOW_SERVICE);
+        }
+
+        @Override
+        public void show() {
+            if (!mWindowVisible) {
+                mSurfaceView = new SurfaceView(mContext);
+
+                Display display = mWindowManager.getDefaultDisplay();
+
+                WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+                params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+                params.alpha = WINDOW_ALPHA;
+                params.gravity = Gravity.LEFT | Gravity.BOTTOM;
+                params.setTitle(mName);
+
+                int width = (int)(display.getWidth() * INITIAL_SCALE);
+                int height = (int)(display.getHeight() * INITIAL_SCALE);
+                if (mWidth > mHeight) {
+                    height = mHeight * width / mWidth;
+                } else {
+                    width = mWidth * height / mHeight;
+                }
+                params.width = width;
+                params.height = height;
+
+                mWindowManager.addView(mSurfaceView, params);
+                mWindowVisible = true;
+
+                mListener.onWindowCreated(mSurfaceView.getHolder());
+            }
+        }
+
+        @Override
+        public void dismiss() {
+            if (mWindowVisible) {
+                mListener.onWindowDestroyed();
+
+                mWindowManager.removeView(mSurfaceView);
+                mWindowVisible = false;
+            }
+        }
+
+        @Override
+        public void updateAspectRatio(int width, int height) {
+        }
+    }
+
+    /**
+     * Implementation for API version 17+.
+     */
+    private static final class JellybeanMr1Impl extends OverlayDisplayWindow {
+        // When true, disables support for moving and resizing the overlay.
+        // The window is made non-touchable, which makes it possible to
+        // directly interact with the content underneath.
+        private static final boolean DISABLE_MOVE_AND_RESIZE = false;
+
+        private final DisplayManager mDisplayManager;
+        private final WindowManager mWindowManager;
+
+        private final Display mDefaultDisplay;
+        private final DisplayMetrics mDefaultDisplayMetrics = new DisplayMetrics();
+
+        private View mWindowContent;
+        private WindowManager.LayoutParams mWindowParams;
+        private TextureView mTextureView;
+        private TextView mNameTextView;
+
+        private GestureDetector mGestureDetector;
+        private ScaleGestureDetector mScaleGestureDetector;
+
+        private boolean mWindowVisible;
+        private int mWindowX;
+        private int mWindowY;
+        private float mWindowScale;
+
+        private float mLiveTranslationX;
+        private float mLiveTranslationY;
+        private float mLiveScale = 1.0f;
+
+        public JellybeanMr1Impl(Context context, String name,
+                int width, int height, int gravity) {
+            super(context, name, width, height, gravity);
+
+            mDisplayManager = (DisplayManager)context.getSystemService(
+                    Context.DISPLAY_SERVICE);
+            mWindowManager = (WindowManager)context.getSystemService(
+                    Context.WINDOW_SERVICE);
+
+            mDefaultDisplay = mWindowManager.getDefaultDisplay();
+            updateDefaultDisplayInfo();
+
+            createWindow();
+        }
+
+        @Override
+        public void show() {
+            if (!mWindowVisible) {
+                mDisplayManager.registerDisplayListener(mDisplayListener, null);
+                if (!updateDefaultDisplayInfo()) {
+                    mDisplayManager.unregisterDisplayListener(mDisplayListener);
+                    return;
+                }
+
+                clearLiveState();
+                updateWindowParams();
+                mWindowManager.addView(mWindowContent, mWindowParams);
+                mWindowVisible = true;
+            }
+        }
+
+        @Override
+        public void dismiss() {
+            if (mWindowVisible) {
+                mDisplayManager.unregisterDisplayListener(mDisplayListener);
+                mWindowManager.removeView(mWindowContent);
+                mWindowVisible = false;
+            }
+        }
+
+        @Override
+        public void updateAspectRatio(int width, int height) {
+            if (mWidth * height < mHeight * width) {
+                mTextureView.getLayoutParams().width = mWidth;
+                mTextureView.getLayoutParams().height = mWidth * height / width;
+            } else {
+                mTextureView.getLayoutParams().width = mHeight * width / height;
+                mTextureView.getLayoutParams().height = mHeight;
+            }
+            relayout();
+        }
+
+        private void relayout() {
+            if (mWindowVisible) {
+                updateWindowParams();
+                mWindowManager.updateViewLayout(mWindowContent, mWindowParams);
+            }
+        }
+
+        private boolean updateDefaultDisplayInfo() {
+            mDefaultDisplay.getMetrics(mDefaultDisplayMetrics);
+            return true;
+        }
+
+        private void createWindow() {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+
+            mWindowContent = inflater.inflate(
+                    R.layout.overlay_display_window, null);
+            mWindowContent.setOnTouchListener(mOnTouchListener);
+
+            mTextureView = (TextureView)mWindowContent.findViewById(
+                    R.id.overlay_display_window_texture);
+            mTextureView.setPivotX(0);
+            mTextureView.setPivotY(0);
+            mTextureView.getLayoutParams().width = mWidth;
+            mTextureView.getLayoutParams().height = mHeight;
+            mTextureView.setOpaque(false);
+            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+
+            mNameTextView = (TextView)mWindowContent.findViewById(
+                    R.id.overlay_display_window_title);
+            mNameTextView.setText(mName);
+
+            mWindowParams = new WindowManager.LayoutParams(
+                    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+            if (DISABLE_MOVE_AND_RESIZE) {
+                mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+            }
+            mWindowParams.alpha = WINDOW_ALPHA;
+            mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
+            mWindowParams.setTitle(mName);
+
+            mGestureDetector = new GestureDetector(mContext, mOnGestureListener);
+            mScaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);
+
+            // Set the initial position and scale.
+            // The position and scale will be clamped when the display is first shown.
+            mWindowX = (mGravity & Gravity.LEFT) == Gravity.LEFT ?
+                    0 : mDefaultDisplayMetrics.widthPixels;
+            mWindowY = (mGravity & Gravity.TOP) == Gravity.TOP ?
+                    0 : mDefaultDisplayMetrics.heightPixels;
+            Log.d(TAG, mDefaultDisplayMetrics.toString());
+            mWindowScale = INITIAL_SCALE;
+
+            // calculate and save initial settings
+            updateWindowParams();
+            saveWindowParams();
+        }
+
+        private void updateWindowParams() {
+            float scale = mWindowScale * mLiveScale;
+            scale = Math.min(scale, (float)mDefaultDisplayMetrics.widthPixels / mWidth);
+            scale = Math.min(scale, (float)mDefaultDisplayMetrics.heightPixels / mHeight);
+            scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale));
+
+            float offsetScale = (scale / mWindowScale - 1.0f) * 0.5f;
+            int width = (int)(mWidth * scale);
+            int height = (int)(mHeight * scale);
+            int x = (int)(mWindowX + mLiveTranslationX - width * offsetScale);
+            int y = (int)(mWindowY + mLiveTranslationY - height * offsetScale);
+            x = Math.max(0, Math.min(x, mDefaultDisplayMetrics.widthPixels - width));
+            y = Math.max(0, Math.min(y, mDefaultDisplayMetrics.heightPixels - height));
+
+            if (DEBUG) {
+                Log.d(TAG, "updateWindowParams: scale=" + scale
+                        + ", offsetScale=" + offsetScale
+                        + ", x=" + x + ", y=" + y
+                        + ", width=" + width + ", height=" + height);
+            }
+
+            mTextureView.setScaleX(scale);
+            mTextureView.setScaleY(scale);
+
+            mTextureView.setTranslationX(
+                    (mWidth - mTextureView.getLayoutParams().width) * scale / 2);
+            mTextureView.setTranslationY(
+                    (mHeight - mTextureView.getLayoutParams().height) * scale / 2);
+
+            mWindowParams.x = x;
+            mWindowParams.y = y;
+            mWindowParams.width = width;
+            mWindowParams.height = height;
+        }
+
+        private void saveWindowParams() {
+            mWindowX = mWindowParams.x;
+            mWindowY = mWindowParams.y;
+            mWindowScale = mTextureView.getScaleX();
+            clearLiveState();
+        }
+
+        private void clearLiveState() {
+            mLiveTranslationX = 0f;
+            mLiveTranslationY = 0f;
+            mLiveScale = 1.0f;
+        }
+
+        private final DisplayManager.DisplayListener mDisplayListener =
+                new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                if (displayId == mDefaultDisplay.getDisplayId()) {
+                    if (updateDefaultDisplayInfo()) {
+                        relayout();
+                    } else {
+                        dismiss();
+                    }
+                }
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                if (displayId == mDefaultDisplay.getDisplayId()) {
+                    dismiss();
+                }
+            }
+        };
+
+        private final SurfaceTextureListener mSurfaceTextureListener =
+                new SurfaceTextureListener() {
+            @Override
+            public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
+                    int width, int height) {
+                if (mListener != null) {
+                    mListener.onWindowCreated(new Surface(surfaceTexture));
+                }
+            }
+
+            @Override
+            public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+                if (mListener != null) {
+                    mListener.onWindowDestroyed();
+                }
+                return true;
+            }
+
+            @Override
+            public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
+                    int width, int height) {
+            }
+
+            @Override
+            public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+            }
+        };
+
+        private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View view, MotionEvent event) {
+                // Work in screen coordinates.
+                final float oldX = event.getX();
+                final float oldY = event.getY();
+                event.setLocation(event.getRawX(), event.getRawY());
+
+                mGestureDetector.onTouchEvent(event);
+                mScaleGestureDetector.onTouchEvent(event);
+
+                switch (event.getActionMasked()) {
+                    case MotionEvent.ACTION_UP:
+                    case MotionEvent.ACTION_CANCEL:
+                        saveWindowParams();
+                        break;
+                }
+
+                // Revert to window coordinates.
+                event.setLocation(oldX, oldY);
+                return true;
+            }
+        };
+
+        private final GestureDetector.OnGestureListener mOnGestureListener =
+                new GestureDetector.SimpleOnGestureListener() {
+            @Override
+            public boolean onScroll(MotionEvent e1, MotionEvent e2,
+                    float distanceX, float distanceY) {
+                mLiveTranslationX -= distanceX;
+                mLiveTranslationY -= distanceY;
+                relayout();
+                return true;
+            }
+        };
+
+        private final ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener =
+                new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+            @Override
+            public boolean onScale(ScaleGestureDetector detector) {
+                mLiveScale *= detector.getScaleFactor();
+                relayout();
+                return true;
+            }
+        };
+    }
 }
\ No newline at end of file
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
index b506306..04416c4 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -35,8 +35,10 @@
 import android.support.v7.media.MediaRouteProviderDescriptor;
 import android.support.v7.media.MediaRouteDescriptor;
 import android.util.Log;
-import android.widget.Toast;
 import android.view.Gravity;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
 import java.util.ArrayList;
 
 /**
@@ -188,26 +190,39 @@
         setDescriptor(providerDescriptor);
     }
 
-    private void showToast(String msg) {
-        Toast toast = Toast.makeText(getContext(),
-                "[provider] " + msg, Toast.LENGTH_LONG);
-        toast.setGravity(Gravity.TOP, 0, 100);
-        toast.show();
-    }
-
     private final class SampleRouteController extends MediaRouteProvider.RouteController {
         private final String mRouteId;
-        // Create an overlay display window (used for simulating the remote playback only)
-        private final OverlayDisplayWindow mOverlay = new OverlayDisplayWindow(getContext(),
-                getContext().getResources().getString(R.string.sample_media_route_provider_remote),
-                1024, 768, Gravity.CENTER);
-        private final MediaPlayerWrapper mMediaPlayer = new MediaPlayerWrapper(getContext());
-        private final MediaSessionManager mSessionManager = new MediaSessionManager();
+        private final OverlayDisplayWindow mOverlay;
+        private final MediaPlayerWrapper mMediaPlayer;
+        private final MediaSessionManager mSessionManager;
 
         public SampleRouteController(String routeId) {
             mRouteId = routeId;
+            mMediaPlayer = new MediaPlayerWrapper(getContext());
+            mSessionManager = new MediaSessionManager();
             mSessionManager.setCallback(mMediaPlayer);
-            mOverlay.setOverlayWindowListener(mMediaPlayer);
+
+            // Create an overlay display window (used for simulating the remote playback only)
+            mOverlay = OverlayDisplayWindow.create(getContext(),
+                    getContext().getResources().getString(
+                            R.string.sample_media_route_provider_remote),
+                    1024, 768, Gravity.CENTER);
+            mOverlay.setOverlayWindowListener(new OverlayDisplayWindow.OverlayWindowListener() {
+                @Override
+                public void onWindowCreated(Surface surface) {
+                    mMediaPlayer.setSurface(surface);
+                }
+
+                @Override
+                public void onWindowCreated(SurfaceHolder surfaceHolder) {
+                    mMediaPlayer.setSurface(surfaceHolder);
+                }
+
+                @Override
+                public void onWindowDestroyed() {
+                }
+            });
+
             mMediaPlayer.setCallback(new MediaPlayerCallback());
             Log.d(TAG, mRouteId + ": Controller created");
         }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
index fd72543..12084b9 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -31,7 +31,6 @@
 import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.media.MediaMetadataRetriever;
 import android.media.RemoteControlClient;
-import android.media.RemoteControlClient.MetadataEditor;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Environment;
@@ -59,14 +58,12 @@
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.Display;
-import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.SurfaceHolder;
 import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ArrayAdapter;
-import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -79,8 +76,6 @@
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
 
-import java.util.ArrayList;
-import java.util.List;
 import java.io.File;
 
 /**
@@ -902,7 +897,7 @@
         public void onFinish(boolean error) {
             MediaQueueItem item = mSessionManager.finish(error);
             updateUi();
-            if (error) {
+            if (error && item != null) {
                 showToast("Failed to play item " + item.getUri());
             }
         }
@@ -912,13 +907,13 @@
         public void surfaceChanged(SurfaceHolder holder, int format,
                 int width, int height) {
             Log.d(TAG, "surfaceChanged "+width+"x"+height);
-            mMediaPlayer.onWindowCreated(holder.getSurface());
+            mMediaPlayer.setSurface(holder);
         }
 
         @Override
         public void surfaceCreated(SurfaceHolder holder) {
             Log.d(TAG, "surfaceCreated");
-            mMediaPlayer.onWindowCreated(holder.getSurface());
+            mMediaPlayer.setSurface(holder);
             mLocalPlayer.updateSize(mVideoWidth, mVideoHeight);
         }
 
@@ -1011,7 +1006,7 @@
         };
 
         private final class DemoPresentation extends Presentation {
-            private SurfaceView mSurfaceView;
+            private SurfaceView mPresentationSurfaceView;
 
             public DemoPresentation(Context context, Display display) {
                 super(context, display);
@@ -1030,16 +1025,16 @@
                 // Inflate the layout.
                 setContentView(R.layout.sample_media_router_presentation);
 
-                // Set up the surface view for visual interest.
-                mSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
-                SurfaceHolder holder = mSurfaceView.getHolder();
+                // Set up the surface view.
+                mPresentationSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
+                SurfaceHolder holder = mPresentationSurfaceView.getHolder();
                 holder.addCallback(mLocalPlayer);
             }
 
             public void updateSize(int width, int height) {
-                int surfaceHeight=getWindow().getDecorView().getHeight();
-                int surfaceWidth=getWindow().getDecorView().getWidth();
-                ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
+                int surfaceHeight = getWindow().getDecorView().getHeight();
+                int surfaceWidth = getWindow().getDecorView().getWidth();
+                ViewGroup.LayoutParams lp = mPresentationSurfaceView.getLayoutParams();
                 if (surfaceWidth * height < surfaceHeight * width) {
                     lp.width = surfaceWidth;
                     lp.height = surfaceWidth * height / width;
@@ -1047,12 +1042,8 @@
                     lp.width = surfaceHeight * width / height;
                     lp.height = surfaceHeight;
                 }
-                Log.d(TAG, "video rect is "+lp.width+"x"+lp.height);
-                mSurfaceView.setLayoutParams(lp);
-            }
-
-            public void clearContent() {
-                //TO-DO: clear surface view
+                Log.d(TAG, "video rect is " + lp.width + "x" + lp.height);
+                mPresentationSurfaceView.setLayoutParams(lp);
             }
         }
     }