mirror of https://github.com/axmolengine/axmol.git
issue #4867:Use system widget to play video on Android
This commit is contained in:
parent
5291bbc377
commit
bda8a73ae5
|
@ -43,7 +43,7 @@ public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelpe
|
|||
// Constants
|
||||
// ===========================================================
|
||||
|
||||
private static final String TAG = Cocos2dxActivity.class.getSimpleName();
|
||||
private final static String TAG = Cocos2dxActivity.class.getSimpleName();
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
|
@ -51,7 +51,8 @@ public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelpe
|
|||
|
||||
private Cocos2dxGLSurfaceView mGLSurfaceView;
|
||||
private Cocos2dxHandler mHandler;
|
||||
private static Context sContext = null;
|
||||
private static Cocos2dxActivity sContext = null;
|
||||
private Cocos2dxVideoHelper mVideoHelper = null;
|
||||
|
||||
public static Context getContext() {
|
||||
return sContext;
|
||||
|
@ -80,12 +81,15 @@ public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelpe
|
|||
|
||||
sContext = this;
|
||||
this.mHandler = new Cocos2dxHandler(this);
|
||||
|
||||
|
||||
Cocos2dxHelper.init(this);
|
||||
|
||||
this.init();
|
||||
|
||||
Cocos2dxHelper.init(this);
|
||||
if (mVideoHelper == null) {
|
||||
mVideoHelper = new Cocos2dxVideoHelper(this, mFrameLayout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
@ -142,6 +146,7 @@ public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelpe
|
|||
}
|
||||
|
||||
|
||||
protected FrameLayout mFrameLayout = null;
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
|
@ -151,8 +156,8 @@ public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelpe
|
|||
ViewGroup.LayoutParams framelayout_params =
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
FrameLayout framelayout = new FrameLayout(this);
|
||||
framelayout.setLayoutParams(framelayout_params);
|
||||
mFrameLayout = new FrameLayout(this);
|
||||
mFrameLayout.setLayoutParams(framelayout_params);
|
||||
|
||||
// Cocos2dxEditText layout
|
||||
ViewGroup.LayoutParams edittext_layout_params =
|
||||
|
@ -162,13 +167,13 @@ public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelpe
|
|||
edittext.setLayoutParams(edittext_layout_params);
|
||||
|
||||
// ...add to FrameLayout
|
||||
framelayout.addView(edittext);
|
||||
mFrameLayout.addView(edittext);
|
||||
|
||||
// Cocos2dxGLSurfaceView
|
||||
this.mGLSurfaceView = this.onCreateView();
|
||||
|
||||
// ...add to FrameLayout
|
||||
framelayout.addView(this.mGLSurfaceView);
|
||||
mFrameLayout.addView(this.mGLSurfaceView);
|
||||
|
||||
// Switch to supported OpenGL (ARGB888) mode on emulator
|
||||
if (isAndroidEmulator())
|
||||
|
@ -178,7 +183,7 @@ public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelpe
|
|||
this.mGLSurfaceView.setCocos2dxEditText(edittext);
|
||||
|
||||
// Set framelayout as the content view
|
||||
setContentView(framelayout);
|
||||
setContentView(mFrameLayout);
|
||||
}
|
||||
|
||||
public Cocos2dxGLSurfaceView onCreateView() {
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2014 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.cocos2dx.lib.Cocos2dxVideoView.OnVideoEventListener;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
public class Cocos2dxVideoHelper {
|
||||
|
||||
private FrameLayout mLayout = null;
|
||||
private Cocos2dxActivity mActivity = null;
|
||||
private SparseArray<Cocos2dxVideoView> sVideoViews = null;
|
||||
private static VideoHandler mVideoHandler = null;
|
||||
|
||||
Cocos2dxVideoHelper(Cocos2dxActivity activity,FrameLayout layout)
|
||||
{
|
||||
mActivity = activity;
|
||||
mLayout = layout;
|
||||
|
||||
mVideoHandler = new VideoHandler(this);
|
||||
sVideoViews = new SparseArray<Cocos2dxVideoView>();
|
||||
}
|
||||
|
||||
private static int videoTag = 0;
|
||||
private final static int VideoTaskCreate = 0;
|
||||
private final static int VideoTaskRemove = 1;
|
||||
private final static int VideoTaskSetSource = 2;
|
||||
private final static int VideoTaskSetRect = 3;
|
||||
private final static int VideoTaskStart = 4;
|
||||
private final static int VideoTaskPause = 5;
|
||||
private final static int VideoTaskResume = 6;
|
||||
private final static int VideoTaskStop = 7;
|
||||
private final static int VideoTaskSeek = 8;
|
||||
private final static int VideoTaskSetVisible = 9;
|
||||
private final static int VideoTaskRestart = 10;
|
||||
private final static int VideoTaskKeepRatio = 11;
|
||||
|
||||
static class VideoHandler extends Handler{
|
||||
WeakReference<Cocos2dxVideoHelper> mReference;
|
||||
|
||||
VideoHandler(Cocos2dxVideoHelper helper){
|
||||
mReference = new WeakReference<Cocos2dxVideoHelper>(helper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case VideoTaskCreate: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._createVideoView(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskRemove: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._removeVideoView(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSetSource: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._setVideoURL(msg.arg1, msg.arg2, (String)msg.obj);
|
||||
break;
|
||||
}
|
||||
case VideoTaskStart: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._startVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSetRect: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
Rect rect = (Rect)msg.obj;
|
||||
helper._setVideoRect(msg.arg1, rect.left, rect.top, rect.right, rect.bottom);
|
||||
break;
|
||||
}
|
||||
case VideoTaskPause: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._pauseVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskResume: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._resumeVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskStop: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._stopVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSeek: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._seekVideoTo(msg.arg1, msg.arg2);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSetVisible: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
if (msg.arg2 == 1) {
|
||||
helper._setVideoVisible(msg.arg1, true);
|
||||
} else {
|
||||
helper._setVideoVisible(msg.arg1, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VideoTaskRestart: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
helper._restartVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskKeepRatio: {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
if (msg.arg2 == 1) {
|
||||
helper._setVideoKeepRatio(msg.arg1, true);
|
||||
} else {
|
||||
helper._setVideoKeepRatio(msg.arg1, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private class VideoEventRunnable implements Runnable
|
||||
{
|
||||
private int mVideoTag;
|
||||
private int mVideoEvent;
|
||||
|
||||
public VideoEventRunnable(int tag,int event) {
|
||||
mVideoTag = tag;
|
||||
mVideoEvent = event;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
nativeExecuteVideoCallback(mVideoTag, mVideoEvent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static native void nativeExecuteVideoCallback(int index,int event);
|
||||
|
||||
OnVideoEventListener videoEventListener = new OnVideoEventListener() {
|
||||
|
||||
@Override
|
||||
public void onVideoEvent(int tag,int event) {
|
||||
mActivity.runOnGLThread(new VideoEventRunnable(tag, event));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static int createVideoWidget() {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskCreate;
|
||||
msg.arg1 = videoTag;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
|
||||
return videoTag++;
|
||||
}
|
||||
|
||||
private void _createVideoView(int index) {
|
||||
Cocos2dxVideoView videoView = new Cocos2dxVideoView(mActivity,index);
|
||||
sVideoViews.put(index, videoView);
|
||||
FrameLayout.LayoutParams lParams = new FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||
mLayout.addView(videoView, lParams);
|
||||
videoView.setZOrderOnTop(true);
|
||||
videoView.setOnCompletionListener(videoEventListener);
|
||||
}
|
||||
|
||||
public static void removeVideoWidget(int index){
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskRemove;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _removeVideoView(int index) {
|
||||
Cocos2dxVideoView view = sVideoViews.get(index);
|
||||
if (view != null) {
|
||||
view.stopPlayback();
|
||||
sVideoViews.remove(index);
|
||||
mLayout.removeView(view);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoUrl(int index,int videoSource,String videoUrl) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSetSource;
|
||||
msg.arg1 = index;
|
||||
msg.arg2 = videoSource;
|
||||
msg.obj = videoUrl;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoURL(int index,int videoSource,String videoUrl) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
switch (videoSource) {
|
||||
case 0:
|
||||
videoView.setVideoFileName(videoUrl);
|
||||
break;
|
||||
case 1:
|
||||
videoView.setVideoURL(videoUrl);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoRect(int index,int left,int top,int maxWidth,int maxHeight) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSetRect;
|
||||
msg.arg1 = index;
|
||||
msg.obj = new Rect(left, top, maxWidth, maxHeight);
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoRect(int index,int left,int top,int maxWidth,int maxHeight) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.setVideoRect(left,top,maxWidth,maxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskStart;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _startVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void pauseVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskPause;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _pauseVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.pause();
|
||||
}
|
||||
}
|
||||
|
||||
public static void resumeVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskResume;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _resumeVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.resume();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskStop;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _stopVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public static void restartVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskRestart;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _restartVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.restart();
|
||||
}
|
||||
}
|
||||
|
||||
public static void seekVideoTo(int index,int msec) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSeek;
|
||||
msg.arg1 = index;
|
||||
msg.arg2 = msec;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _seekVideoTo(int index,int msec) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.seekTo(msec);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoVisible(int index, boolean visible) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSetVisible;
|
||||
msg.arg1 = index;
|
||||
if (visible) {
|
||||
msg.arg2 = 1;
|
||||
} else {
|
||||
msg.arg2 = 0;
|
||||
}
|
||||
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoVisible(int index, boolean visible) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
if (visible) {
|
||||
videoView.fixSize();
|
||||
videoView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
videoView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoKeepRatioEnabled(int index, boolean enable) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskKeepRatio;
|
||||
msg.arg1 = index;
|
||||
if (enable) {
|
||||
msg.arg2 = 1;
|
||||
} else {
|
||||
msg.arg2 = 0;
|
||||
}
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoKeepRatio(int index, boolean enable) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.setKeepRatio(enable);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,686 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
* Copyright (c) 2014 Chukong Technologies Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.content.res.Resources;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.MediaController.MediaPlayerControl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class Cocos2dxVideoView extends SurfaceView implements MediaPlayerControl {
|
||||
private String TAG = "VideoView";
|
||||
|
||||
private Uri mUri;
|
||||
private int mDuration;
|
||||
|
||||
// all possible internal states
|
||||
private static final int STATE_ERROR = -1;
|
||||
private static final int STATE_IDLE = 0;
|
||||
private static final int STATE_PREPARING = 1;
|
||||
private static final int STATE_PREPARED = 2;
|
||||
private static final int STATE_PLAYING = 3;
|
||||
private static final int STATE_PAUSED = 4;
|
||||
private static final int STATE_PLAYBACK_COMPLETED = 5;
|
||||
|
||||
// mCurrentState is a VideoView object's current state.
|
||||
// mTargetState is the state that a method caller intends to reach.
|
||||
// For instance, regardless the VideoView object's current state,
|
||||
// calling pause() intends to bring the object to a target state
|
||||
// of STATE_PAUSED.
|
||||
private int mCurrentState = STATE_IDLE;
|
||||
private int mTargetState = STATE_IDLE;
|
||||
|
||||
// All the stuff we need for playing and showing a video
|
||||
private SurfaceHolder mSurfaceHolder = null;
|
||||
private MediaPlayer mMediaPlayer = null;
|
||||
private int mVideoWidth = 0;
|
||||
private int mVideoHeight = 0;
|
||||
|
||||
private OnVideoEventListener mOnVideoEventListener;
|
||||
private MediaPlayer.OnPreparedListener mOnPreparedListener;
|
||||
private int mCurrentBufferPercentage;
|
||||
private OnErrorListener mOnErrorListener;
|
||||
|
||||
// recording the seek position while preparing
|
||||
private int mSeekWhenPrepared;
|
||||
|
||||
protected Context mContext = null;
|
||||
|
||||
protected int mViewLeft = 0;
|
||||
protected int mViewTop = 0;
|
||||
protected int mViewWidth = 0;
|
||||
protected int mViewHeight = 0;
|
||||
|
||||
protected int mVisibleLeft = 0;
|
||||
protected int mVisibleTop = 0;
|
||||
protected int mVisibleWidth = 0;
|
||||
protected int mVisibleHeight = 0;
|
||||
|
||||
private int mViewTag = 0;
|
||||
|
||||
public Cocos2dxVideoView(Context context,int tag) {
|
||||
super(context);
|
||||
|
||||
mViewTag = tag;
|
||||
mContext = context;
|
||||
initVideoView();
|
||||
}
|
||||
|
||||
public Cocos2dxVideoView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
|
||||
mContext = context;
|
||||
initVideoView();
|
||||
}
|
||||
|
||||
public Cocos2dxVideoView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
mContext = context;
|
||||
initVideoView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (mVideoWidth == 0 || mVideoHeight == 0) {
|
||||
setMeasuredDimension(mViewWidth, mViewHeight);
|
||||
Log.e(TAG, ""+mViewWidth+ ":" +mViewHeight);
|
||||
}
|
||||
else {
|
||||
setMeasuredDimension(mVisibleWidth, mVisibleHeight);
|
||||
Log.e(TAG, ""+mVisibleWidth+ ":" +mVisibleHeight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setVideoRect(int left,int top,int maxWidth,int maxHeight) {
|
||||
mViewLeft = left;
|
||||
mViewTop = top;
|
||||
mViewWidth = maxWidth;
|
||||
mViewHeight = maxHeight;
|
||||
|
||||
if (mVideoWidth != 0 && mVideoHeight != 0) {
|
||||
fixSize();
|
||||
}
|
||||
}
|
||||
|
||||
public int resolveAdjustedSize(int desiredSize, int measureSpec) {
|
||||
int result = desiredSize;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
|
||||
switch (specMode) {
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
/* Parent says we can be as big as we want. Just don't be larger
|
||||
* than max size imposed on ourselves.
|
||||
*/
|
||||
result = desiredSize;
|
||||
break;
|
||||
|
||||
case MeasureSpec.AT_MOST:
|
||||
/* Parent says we can be as big as we want, up to specSize.
|
||||
* Don't be larger than specSize, and don't be larger than
|
||||
* the max size imposed on ourselves.
|
||||
*/
|
||||
result = Math.min(desiredSize, specSize);
|
||||
break;
|
||||
|
||||
case MeasureSpec.EXACTLY:
|
||||
// No choice. Do what we are told.
|
||||
result = specSize;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean mNeedResume = false;
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (visibility == INVISIBLE) {
|
||||
mNeedResume = isPlaying();
|
||||
if (mNeedResume) {
|
||||
mSeekWhenPrepared = getCurrentPosition();
|
||||
}
|
||||
}
|
||||
else if (mNeedResume){
|
||||
start();
|
||||
mNeedResume = false;
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
private void initVideoView() {
|
||||
mVideoWidth = 0;
|
||||
mVideoHeight = 0;
|
||||
getHolder().addCallback(mSHCallback);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
mCurrentState = STATE_IDLE;
|
||||
mTargetState = STATE_IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP)
|
||||
{
|
||||
if (isPlaying()) {
|
||||
pause();
|
||||
} else if(mCurrentState == STATE_PAUSED){
|
||||
resume();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isAssetRouse = false;
|
||||
private String fileName = null;
|
||||
|
||||
public void setVideoFileName(String path) {
|
||||
if (path.startsWith("/")) {
|
||||
isAssetRouse = false;
|
||||
setVideoURI(Uri.parse(path),null);
|
||||
}
|
||||
else {
|
||||
fileName = path;
|
||||
isAssetRouse = true;
|
||||
setVideoURI(Uri.parse(path),null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVideoURL(String url) {
|
||||
isAssetRouse = false;
|
||||
setVideoURI(Uri.parse(url), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private void setVideoURI(Uri uri, Map<String, String> headers) {
|
||||
mUri = uri;
|
||||
mSeekWhenPrepared = 0;
|
||||
mVideoWidth = 0;
|
||||
mVideoHeight = 0;
|
||||
openVideo();
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void stopPlayback() {
|
||||
if (mMediaPlayer != null) {
|
||||
mMediaPlayer.stop();
|
||||
mMediaPlayer.release();
|
||||
mMediaPlayer = null;
|
||||
mCurrentState = STATE_IDLE;
|
||||
mTargetState = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
private void openVideo() {
|
||||
if (mSurfaceHolder == null) {
|
||||
// not ready for playback just yet, will try again later
|
||||
return;
|
||||
}
|
||||
if (isAssetRouse) {
|
||||
if(fileName == null)
|
||||
return;
|
||||
} else {
|
||||
if(mUri == null)
|
||||
return;
|
||||
}
|
||||
|
||||
// Tell the music playback service to pause
|
||||
// TODO: these constants need to be published somewhere in the framework.
|
||||
Intent i = new Intent("com.android.music.musicservicecommand");
|
||||
i.putExtra("command", "pause");
|
||||
mContext.sendBroadcast(i);
|
||||
|
||||
// we shouldn't clear the target state, because somebody might have
|
||||
// called start() previously
|
||||
release(false);
|
||||
|
||||
try {
|
||||
//if (mMediaPlayer == null) {
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
mMediaPlayer.setOnPreparedListener(mPreparedListener);
|
||||
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
|
||||
mMediaPlayer.setOnCompletionListener(mCompletionListener);
|
||||
mMediaPlayer.setOnErrorListener(mErrorListener);
|
||||
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
|
||||
|
||||
mMediaPlayer.setDisplay(mSurfaceHolder);
|
||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
mMediaPlayer.setScreenOnWhilePlaying(true);
|
||||
//}
|
||||
|
||||
mDuration = -1;
|
||||
mCurrentBufferPercentage = 0;
|
||||
if (isAssetRouse) {
|
||||
AssetFileDescriptor afd = mContext.getAssets().openFd(fileName);
|
||||
mMediaPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
|
||||
} else {
|
||||
mMediaPlayer.setDataSource(mContext, mUri);
|
||||
}
|
||||
|
||||
mMediaPlayer.prepareAsync();
|
||||
// we don't set the target state here either, but preserve the
|
||||
// target state that was there before.
|
||||
mCurrentState = STATE_PREPARING;
|
||||
} catch (IOException ex) {
|
||||
Log.w(TAG, "Unable to open content: " + mUri, ex);
|
||||
mCurrentState = STATE_ERROR;
|
||||
mTargetState = STATE_ERROR;
|
||||
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||||
return;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Log.w(TAG, "Unable to open content: " + mUri, ex);
|
||||
mCurrentState = STATE_ERROR;
|
||||
mTargetState = STATE_ERROR;
|
||||
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mKeepRatio = false;
|
||||
|
||||
public void setKeepRatio(boolean enabled) {
|
||||
mKeepRatio = enabled;
|
||||
fixSize();
|
||||
}
|
||||
|
||||
public void fixSize() {
|
||||
if (mViewWidth != 0 && mViewHeight != 0) {
|
||||
if (mKeepRatio) {
|
||||
if ( mVideoWidth * mViewHeight > mViewWidth * mVideoHeight ) {
|
||||
mVisibleWidth = mViewWidth;
|
||||
mVisibleHeight = mViewWidth * mVideoHeight / mVideoWidth;
|
||||
} else if ( mVideoWidth * mViewHeight < mViewWidth * mVideoHeight ) {
|
||||
mVisibleWidth = mViewHeight * mVideoWidth / mVideoHeight;
|
||||
mVisibleHeight = mViewHeight;
|
||||
}
|
||||
mVisibleLeft = mViewLeft + (mViewWidth - mVisibleWidth) / 2;
|
||||
mVisibleTop = mViewTop + (mViewHeight - mVisibleHeight) / 2;
|
||||
} else {
|
||||
mVisibleLeft = mViewLeft;
|
||||
mVisibleTop = mViewTop;
|
||||
mVisibleWidth = mViewWidth;
|
||||
mVisibleHeight = mViewHeight;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mVisibleLeft = mViewLeft;
|
||||
mVisibleTop = mViewTop;
|
||||
mVisibleWidth = mVideoWidth;
|
||||
mVisibleHeight = mVideoHeight;
|
||||
}
|
||||
|
||||
getHolder().setFixedSize(mVisibleWidth, mVisibleHeight);
|
||||
|
||||
FrameLayout.LayoutParams lParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||
lParams.leftMargin = mVisibleLeft;
|
||||
lParams.topMargin = mVisibleTop;
|
||||
setLayoutParams(lParams);
|
||||
}
|
||||
|
||||
protected
|
||||
MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
|
||||
new MediaPlayer.OnVideoSizeChangedListener() {
|
||||
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
|
||||
mVideoWidth = mp.getVideoWidth();
|
||||
mVideoHeight = mp.getVideoHeight();
|
||||
if (mVideoWidth != 0 && mVideoHeight != 0) {
|
||||
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
mCurrentState = STATE_PREPARED;
|
||||
|
||||
if (mOnPreparedListener != null) {
|
||||
mOnPreparedListener.onPrepared(mMediaPlayer);
|
||||
}
|
||||
|
||||
mVideoWidth = mp.getVideoWidth();
|
||||
mVideoHeight = mp.getVideoHeight();
|
||||
|
||||
int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
|
||||
if (seekToPosition != 0) {
|
||||
seekTo(seekToPosition);
|
||||
}
|
||||
if (mVideoWidth != 0 && mVideoHeight != 0) {
|
||||
fixSize();
|
||||
}
|
||||
|
||||
if (mTargetState == STATE_PLAYING) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private MediaPlayer.OnCompletionListener mCompletionListener =
|
||||
new MediaPlayer.OnCompletionListener() {
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
mCurrentState = STATE_PLAYBACK_COMPLETED;
|
||||
mTargetState = STATE_PLAYBACK_COMPLETED;
|
||||
|
||||
mp.release();
|
||||
if (mOnVideoEventListener != null) {
|
||||
mOnVideoEventListener.onVideoEvent(mViewTag,EVENT_COMPLETED);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private static final int EVENT_PLAYING = 0;
|
||||
private static final int EVENT_PAUSED = 1;
|
||||
private static final int EVENT_STOPPED = 2;
|
||||
private static final int EVENT_COMPLETED = 3;
|
||||
|
||||
public interface OnVideoEventListener
|
||||
{
|
||||
void onVideoEvent(int tag,int event);
|
||||
}
|
||||
|
||||
private MediaPlayer.OnErrorListener mErrorListener =
|
||||
new MediaPlayer.OnErrorListener() {
|
||||
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
|
||||
Log.d(TAG, "Error: " + framework_err + "," + impl_err);
|
||||
mCurrentState = STATE_ERROR;
|
||||
mTargetState = STATE_ERROR;
|
||||
|
||||
/* If an error handler has been supplied, use it and finish. */
|
||||
if (mOnErrorListener != null) {
|
||||
if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, pop up an error dialog so the user knows that
|
||||
* something bad has happened. Only try and pop up the dialog
|
||||
* if we're attached to a window. When we're going away and no
|
||||
* longer have a window, don't bother showing the user an error.
|
||||
*/
|
||||
if (getWindowToken() != null) {
|
||||
Resources r = mContext.getResources();
|
||||
int messageId;
|
||||
|
||||
if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
|
||||
//messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback;
|
||||
messageId = r.getIdentifier("VideoView_error_text_invalid_progressive_playback", "string", "android");
|
||||
} else {
|
||||
//messageId = com.android.internal.R.string.VideoView_error_text_unknown;
|
||||
messageId = r.getIdentifier("VideoView_error_text_unknown", "string", "android");
|
||||
}
|
||||
|
||||
int titleId = r.getIdentifier("VideoView_error_title", "string", "android");
|
||||
int buttonStringId = r.getIdentifier("VideoView_error_button", "string", "android");
|
||||
|
||||
new AlertDialog.Builder(mContext)
|
||||
.setTitle(r.getString(titleId))
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(r.getString(buttonStringId),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
/* If we get here, there is no onError listener, so
|
||||
* at least inform them that the video is over.
|
||||
*/
|
||||
if (mOnVideoEventListener != null) {
|
||||
mOnVideoEventListener.onVideoEvent(mViewTag,EVENT_COMPLETED);
|
||||
}
|
||||
}
|
||||
})
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
|
||||
new MediaPlayer.OnBufferingUpdateListener() {
|
||||
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||
mCurrentBufferPercentage = percent;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when the media file
|
||||
* is loaded and ready to go.
|
||||
*
|
||||
* @param l The callback that will be run
|
||||
*/
|
||||
public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
|
||||
{
|
||||
mOnPreparedListener = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when the end of a media file
|
||||
* has been reached during playback.
|
||||
*
|
||||
* @param l The callback that will be run
|
||||
*/
|
||||
public void setOnCompletionListener(OnVideoEventListener l)
|
||||
{
|
||||
mOnVideoEventListener = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when an error occurs
|
||||
* during playback or setup. If no listener is specified,
|
||||
* or if the listener returned false, VideoView will inform
|
||||
* the user of any errors.
|
||||
*
|
||||
* @param l The callback that will be run
|
||||
*/
|
||||
public void setOnErrorListener(OnErrorListener l)
|
||||
{
|
||||
mOnErrorListener = l;
|
||||
}
|
||||
|
||||
SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
|
||||
{
|
||||
public void surfaceChanged(SurfaceHolder holder, int format,
|
||||
int w, int h)
|
||||
{
|
||||
boolean isValidState = (mTargetState == STATE_PLAYING);
|
||||
boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
|
||||
if (mMediaPlayer != null && isValidState && hasValidSize) {
|
||||
if (mSeekWhenPrepared != 0) {
|
||||
seekTo(mSeekWhenPrepared);
|
||||
}
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder)
|
||||
{
|
||||
mSurfaceHolder = holder;
|
||||
openVideo();
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
// after we return from this we can't use the surface any more
|
||||
mSurfaceHolder = null;
|
||||
|
||||
release(true);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* release the media player in any state
|
||||
*/
|
||||
private void release(boolean cleartargetstate) {
|
||||
if (mMediaPlayer != null) {
|
||||
mMediaPlayer.reset();
|
||||
mMediaPlayer.release();
|
||||
mMediaPlayer = null;
|
||||
mCurrentState = STATE_IDLE;
|
||||
if (cleartargetstate) {
|
||||
mTargetState = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (isInPlaybackState()) {
|
||||
mMediaPlayer.start();
|
||||
mCurrentState = STATE_PLAYING;
|
||||
if (mOnVideoEventListener != null) {
|
||||
mOnVideoEventListener.onVideoEvent(mViewTag, EVENT_PLAYING);
|
||||
}
|
||||
}
|
||||
mTargetState = STATE_PLAYING;
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if (isInPlaybackState()) {
|
||||
if (mMediaPlayer.isPlaying()) {
|
||||
mMediaPlayer.pause();
|
||||
mCurrentState = STATE_PAUSED;
|
||||
if (mOnVideoEventListener != null) {
|
||||
mOnVideoEventListener.onVideoEvent(mViewTag, EVENT_PAUSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
mTargetState = STATE_PAUSED;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (isInPlaybackState()) {
|
||||
if (mMediaPlayer.isPlaying()) {
|
||||
stopPlayback();
|
||||
if (mOnVideoEventListener != null) {
|
||||
mOnVideoEventListener.onVideoEvent(mViewTag, EVENT_STOPPED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
release(false);
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
if (isInPlaybackState()) {
|
||||
if (mCurrentState == STATE_PAUSED) {
|
||||
mMediaPlayer.start();
|
||||
mCurrentState = STATE_PLAYING;
|
||||
if (mOnVideoEventListener != null) {
|
||||
mOnVideoEventListener.onVideoEvent(mViewTag, EVENT_PLAYING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
if (isInPlaybackState()) {
|
||||
mMediaPlayer.seekTo(0);
|
||||
mMediaPlayer.start();
|
||||
mCurrentState = STATE_PLAYING;
|
||||
mTargetState = STATE_PLAYING;
|
||||
}
|
||||
}
|
||||
// cache duration as mDuration for faster access
|
||||
public int getDuration() {
|
||||
if (isInPlaybackState()) {
|
||||
if (mDuration > 0) {
|
||||
return mDuration;
|
||||
}
|
||||
mDuration = mMediaPlayer.getDuration();
|
||||
return mDuration;
|
||||
}
|
||||
mDuration = -1;
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
if (isInPlaybackState()) {
|
||||
return mMediaPlayer.getCurrentPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void seekTo(int msec) {
|
||||
if (isInPlaybackState()) {
|
||||
mMediaPlayer.seekTo(msec);
|
||||
mSeekWhenPrepared = 0;
|
||||
} else {
|
||||
mSeekWhenPrepared = msec;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPlaying() {
|
||||
return isInPlaybackState() && mMediaPlayer.isPlaying();
|
||||
}
|
||||
|
||||
public int getBufferPercentage() {
|
||||
if (mMediaPlayer != null) {
|
||||
return mCurrentBufferPercentage;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isInPlaybackState() {
|
||||
return (mMediaPlayer != null &&
|
||||
mCurrentState != STATE_ERROR &&
|
||||
mCurrentState != STATE_IDLE &&
|
||||
mCurrentState != STATE_PREPARING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPause() {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeekBackward() {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeekForward() {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue