From 9299c6cdd8e5d084ef4c10e5b7f044e0ea590641 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Thu, 22 Aug 2013 18:15:04 -0700 Subject: [PATCH] Ensure sample runs on Gingerbread. (DO NOT MERGE) Unfortunately, the video does not play due to a MediaPlayer exception but at least this version does not crash. Change-Id: I0baf9239a8a12f92b4805bab226f21f46fa63693 (cherry picked from commit 854e16afda1bbacbd5eee7e434059d493879497d) --- .../supportv7/media/MediaPlayerWrapper.java | 53 +- .../supportv7/media/OverlayDisplayWindow.java | 683 ++++++++++-------- .../media/SampleMediaRouteProvider.java | 45 +- .../media/SampleMediaRouterActivity.java | 33 +- 4 files changed, 466 insertions(+), 348 deletions(-) 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 9aa78d888..658caca7d 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 @@ public class MediaPlayerWrapper implements 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 @@ public class MediaPlayerWrapper implements 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 @@ public class MediaPlayerWrapper implements } } - //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 @@ public class MediaPlayerWrapper implements 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 @@ public class MediaPlayerWrapper implements } } + 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 11a28893f..e691c14e2 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 @@ package com.example.android.supportv7.media; 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.Gravity; 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 @@ import android.widget.TextView; /** * 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 @@ public class OverlayDisplayWindow { 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 b506306e3..04416c483 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.MediaRouter.ControlRequestCallback; 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 @@ final class SampleMediaRouteProvider extends MediaRouteProvider { 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 4305cea80..4f95302d7 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; 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.Handler; @@ -58,14 +57,12 @@ import android.view.View; 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; @@ -78,8 +75,6 @@ import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; -import java.util.ArrayList; -import java.util.List; import java.io.File; /** @@ -898,7 +893,7 @@ public class SampleMediaRouterActivity extends ActionBarActivity { public void onFinish(boolean error) { MediaQueueItem item = mSessionManager.finish(error); updateUi(); - if (error) { + if (error && item != null) { showToast("Failed to play item " + item.getUri()); } } @@ -908,13 +903,13 @@ public class SampleMediaRouterActivity extends ActionBarActivity { 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); } @@ -1007,7 +1002,7 @@ public class SampleMediaRouterActivity extends ActionBarActivity { }; private final class DemoPresentation extends Presentation { - private SurfaceView mSurfaceView; + private SurfaceView mPresentationSurfaceView; public DemoPresentation(Context context, Display display) { super(context, display); @@ -1026,16 +1021,16 @@ public class SampleMediaRouterActivity extends ActionBarActivity { // 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; @@ -1043,12 +1038,8 @@ public class SampleMediaRouterActivity extends ActionBarActivity { 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); } } }