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);
}
}
}