();
+ for (String ext : MediaPlayer.SUB_TYPES) {
+ File s = new File(videoPath.substring(0, videoPath.lastIndexOf('.') > 0 ? videoPath.lastIndexOf('.') : videoPath.length()) + ext);
+ if (s.exists() && s.isFile() && s.canRead())
+ files.add(s.getAbsolutePath());
+ }
+
+ if (files.isEmpty())
+ return null;
+ else
+ return files.toArray(new String[files.size()]);
+ }
+
+}
diff --git a/src/io/vov/vitamio/activity/VideoActivity.java b/src/io/vov/vitamio/activity/VideoActivity.java
index 2dbfea4..81d7af8 100644
--- a/src/io/vov/vitamio/activity/VideoActivity.java
+++ b/src/io/vov/vitamio/activity/VideoActivity.java
@@ -1,51 +1,803 @@
package io.vov.vitamio.activity;
+import android.annotation.SuppressLint;
import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
+import android.os.BatteryManager;
import android.os.Bundle;
-
-import me.abitno.utils.IntentHelper;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.TextView;
+import android.widget.Toast;
import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.R;
import io.vov.vitamio.widget.MediaController;
import io.vov.vitamio.widget.VideoView;
+import me.abitno.utils.BitmapHelper;
+import me.abitno.utils.FileHelper;
+import me.abitno.utils.FileUtils;
+import me.abitno.utils.IntentHelper;
+import me.abitno.utils.Log;
+import me.abitno.utils.Media;
+import me.abitno.utils.ToastHelper;
+import me.abitno.utils.UIUtils;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@SuppressLint("HandlerLeak")
+public class VideoActivity extends Activity implements MediaController.MediaPlayerControl, VideoView.SurfaceCallback {
+
+ private static final int RESULT_FAILED = -7;
+ private static final int DEFAULT_BUF_SIZE = 0;
+ private static final int DEFAULT_VIDEO_QUALITY = MediaPlayer.VIDEOQUALITY_MEDIUM;
+ private static final boolean DEFAULT_DEINTERLACE = false;
+ private static final float DEFAULT_ASPECT_RATIO = 0f;
+ private static final float DEFAULT_STEREO_VOLUME = 1.0f;
+ private static final String SNAP_SHOT_PATH = "/Player";
-public class VideoActivity extends Activity {
+ private static final IntentFilter USER_PRESENT_FILTER = new IntentFilter(Intent.ACTION_USER_PRESENT);
+ private static final IntentFilter SCREEN_FILTER = new IntentFilter(Intent.ACTION_SCREEN_ON);
+ private static final IntentFilter HEADSET_FILTER = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+ private static final IntentFilter BATTERY_FILTER = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ private boolean mCreated = false;
+ private boolean mNeedLock;
+ private String mDisplayName;
+ private String mBatteryLevel;
+ private boolean mFromStart;
+ private int mLoopCount;
+ private boolean mSaveUri;
+ private int mParentId;
+ private float mStartPos;
+ private View mViewRoot;
private VideoView mVideoView;
+ private View mVideoLoadingLayout;
+ private TextView mVideoLoadingText;
private Uri mUri;
+ private ScreenReceiver mScreenReceiver;
+ private HeadsetPlugReceiver mHeadsetPlugReceiver;
+ private UserPresentReceiver mUserPresentReceiver;
+ private BatteryReceiver mBatteryReceiver;
+ private boolean mReceiverRegistered = false;
+ private boolean mHeadsetPlaying = false;
+ private boolean mCloseComplete = false;
+
+ private MediaController mMediaController;
+ private PlayerService vPlayer;
+ private ServiceConnection vPlayerServiceConnection;
+ private Animation mLoadingAnimation;
+ private View mLoadingProgressView;
+
+ static {
+ SCREEN_FILTER.addAction(Intent.ACTION_SCREEN_OFF);
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
if (!io.vov.vitamio.LibsChecker.checkVitamioLibs(this))
return;
- super.onCreate(savedInstanceState);
+
+ vPlayerServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ vPlayer = ((PlayerService.LocalBinder) service).getService();
+ mServiceConnected = true;
+ if (mSurfaceCreated)
+ vPlayerHandler.sendEmptyMessage(OPEN_FILE);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ vPlayer = null;
+ mServiceConnected = false;
+ }
+ };
+
setVolumeControlStream(AudioManager.STREAM_MUSIC);
- setContentView(R.layout.activity_video);
parseIntent(getIntent());
+ loadView(R.layout.activity_video);
+ manageReceivers();
+
+ mCreated = true;
}
- private void parseIntent(Intent intent) {
- mUri = IntentHelper.getIntentUri(intent);
- mVideoView = (VideoView) findViewById(R.id.video);
- mVideoView.setVideoURI(mUri);
- mVideoView.setVideoTitle(intent.getStringExtra("displayName"));
- mVideoView.setVideoQuality(MediaPlayer.VIDEOQUALITY_HIGH);
- mVideoView.setMediaController(new MediaController(this));
+ private void attachMediaController() {
+ if (mMediaController != null) {
+ mNeedLock = mMediaController.isLocked();
+ mMediaController.release();
+ }
+ mMediaController = new MediaController(this, mNeedLock);
+ mMediaController.setMediaPlayer(this);
+ mMediaController.setAnchorView(mVideoView.getRootView());
+ setFileName();
+ setBatteryLevel();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ if (!mCreated)
+ return;
+ bindService(new Intent(this, PlayerService.class), vPlayerServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (!mCreated)
+ return;
+
+ if (isInitialized()) {
+ KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
+ if (!keyguardManager.inKeyguardRestrictedInputMode()) {
+ startPlayer();
+ }
+ } else {
+ if (mCloseComplete) {
+ reOpen();
+ }
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (!mCreated)
+ return;
+ if (isInitialized()) {
+ if (vPlayer != null && vPlayer.isPlaying()) {
+ stopPlayer();
+ }
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (!mCreated)
+ return;
+ if (isInitialized()) {
+ vPlayer.releaseSurface();
+ }
+ if (mServiceConnected) {
+ unbindService(vPlayerServiceConnection);
+ mServiceConnected = false;
+ }
+
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (!mCreated)
+ return;
+ manageReceivers();
+ if (isInitialized() && !vPlayer.isPlaying())
+ release();
+ if (mMediaController != null)
+ mMediaController.release();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
- if (mVideoView != null)
- mVideoView.setVideoLayout(VideoView.VIDEO_LAYOUT_SCALE, 0);
+ if (isInitialized()) {
+ setVideoLayout();
+ attachMediaController();
+ }
+
super.onConfigurationChanged(newConfig);
}
- private void resultFinish() {
- this.finish();
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ // http://code.google.com/p/android/issues/detail?id=19917
+ outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
+ super.onSaveInstanceState(outState);
+ }
+
+ public void showMenu() {
+
+ }
+
+ private void loadView(int id) {
+ setContentView(id);
+ mViewRoot = findViewById(R.id.video_root);
+ mVideoView = (VideoView) findViewById(R.id.video);
+ mVideoView.initialize(this, this, false);
+ mVideoLoadingText = (TextView) findViewById(R.id.video_loading_text);
+ mVideoLoadingLayout = findViewById(R.id.video_loading);
+ mLoadingProgressView = mVideoLoadingLayout.findViewById(R.id.video_loading_progress);
+
+ mLoadingAnimation = AnimationUtils.loadAnimation(VideoActivity.this, R.anim.loading_rotate);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ private void parseIntent(Intent i) {
+
+ Uri dat = IntentHelper.getIntentUri(i);
+ if (dat == null)
+ resultFinish(RESULT_FAILED);
+
+ String datString = dat.toString();
+ if (!datString.equals(dat.toString()))
+ dat = Uri.parse(datString);
+
+ mUri = dat;
+
+ mNeedLock = i.getBooleanExtra("lockScreen", false);
+ mDisplayName = i.getStringExtra("displayName");
+ mFromStart = i.getBooleanExtra("fromStart", false);
+ mSaveUri = i.getBooleanExtra("saveUri", true);
+ mStartPos = i.getFloatExtra("startPosition", -1.0f);
+ mLoopCount = i.getIntExtra("loopCount", 1);
+ mParentId = i.getIntExtra("parentId", 0);
+ Log.i("L: %b, N: %s, S: %b, P: %f, LP: %d", mNeedLock, mDisplayName, mFromStart, mStartPos, mLoopCount);
+ }
+
+ private void manageReceivers() {
+ if (!mReceiverRegistered) {
+ mScreenReceiver = new ScreenReceiver();
+ registerReceiver(mScreenReceiver, SCREEN_FILTER);
+ mUserPresentReceiver = new UserPresentReceiver();
+ registerReceiver(mUserPresentReceiver, USER_PRESENT_FILTER);
+ mBatteryReceiver = new BatteryReceiver();
+ registerReceiver(mBatteryReceiver, BATTERY_FILTER);
+ mHeadsetPlugReceiver = new HeadsetPlugReceiver();
+ registerReceiver(mHeadsetPlugReceiver, HEADSET_FILTER);
+ mReceiverRegistered = true;
+ } else {
+ try {
+ if (mScreenReceiver != null)
+ unregisterReceiver(mScreenReceiver);
+ if (mUserPresentReceiver != null)
+ unregisterReceiver(mUserPresentReceiver);
+ if (mHeadsetPlugReceiver != null)
+ unregisterReceiver(mHeadsetPlugReceiver);
+ if (mBatteryReceiver != null)
+ unregisterReceiver(mBatteryReceiver);
+ } catch (IllegalArgumentException e) {
+ }
+ mReceiverRegistered = false;
+ }
+ }
+
+ private void setFileName() {
+ if (mUri != null) {
+ String name = null;
+ if (mUri.getScheme() == null || mUri.getScheme().equals("file"))
+ name = FileUtils.getName(mUri.toString());
+ else
+ name = mUri.getLastPathSegment();
+ if (name == null)
+ name = "null";
+ if (mDisplayName == null)
+ mDisplayName = name;
+ mMediaController.setFileName(mDisplayName);
+ }
+ }
+
+ private void applyResult(int resultCode) {
+ vPlayerHandler.removeMessages(BUFFER_PROGRESS);
+ Intent i = new Intent();
+ i.putExtra("filePath", mUri.toString());
+ if (isInitialized()) {
+ i.putExtra("position", (double) vPlayer.getCurrentPosition() / vPlayer.getDuration());
+ i.putExtra("duration", vPlayer.getDuration());
+ }
+ switch (resultCode) {
+ case RESULT_FAILED:
+ ToastHelper.showToast(this, Toast.LENGTH_LONG, R.string.video_cannot_play);
+ break;
+ case RESULT_CANCELED:
+ case RESULT_OK:
+ break;
+ }
+ setResult(resultCode, i);
+ }
+
+ private void resultFinish(int resultCode) {
+ applyResult(resultCode);
+ if (UIUtils.hasICS() && resultCode != RESULT_FAILED) {
+ android.os.Process.killProcess(android.os.Process.myPid());
+ } else {
+ finish();
+ }
+ }
+
+ private void release() {
+ if (vPlayer != null) {
+ if (UIUtils.hasICS()) {
+ android.os.Process.killProcess(android.os.Process.myPid());
+ } else {
+ vPlayer.release();
+ vPlayer.releaseContext();
+ }
+ }
+ }
+
+ private void reOpen(Uri path, String name, boolean fromStart) {
+ if (isInitialized()) {
+ vPlayer.release();
+ vPlayer.releaseContext();
+ }
+ Intent i = getIntent();
+ i.putExtra("lockScreen", mMediaController.isLocked());
+ i.putExtra("startPosition", 7.7f);
+ i.putExtra("fromStart", fromStart);
+ i.putExtra("displayName", name);
+ i.setData(path);
+ parseIntent(i);
+ mUri = path;
+ if (mViewRoot != null)
+ mViewRoot.invalidate();
+ mOpened.set(false);
+ loadView(R.layout.activity_video);
+ }
+
+ public void reOpen() {
+ reOpen(mUri, mDisplayName, false);
+ }
+
+ protected void startPlayer() {
+ if (isInitialized() && mScreenReceiver.screenOn && !vPlayer.isBuffering()) {
+ Log.i("VideoActivity#startPlayer");
+ if (!vPlayer.isPlaying()) {
+ vPlayer.start();
+ }
+ }
+ }
+
+ protected void stopPlayer() {
+ if (isInitialized()) {
+ vPlayer.stop();
+ }
+ }
+
+ private void setBatteryLevel() {
+ if (mMediaController != null)
+ mMediaController.setBatteryLevel(mBatteryLevel);
+ }
+
+ private class BatteryReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+ int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
+ int percent = scale > 0 ? level * 100 / scale : 0;
+ if (percent > 100)
+ percent = 100;
+ mBatteryLevel = String.valueOf(percent) + "%";
+ setBatteryLevel();
+ }
+ }
+
+ private class UserPresentReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (isRootActivity()) {
+ startPlayer();
+ }
+ }
+ }
+
+ private boolean isRootActivity() {
+ ActivityManager activity = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ return activity.getRunningTasks(1).get(0).topActivity.flattenToString().endsWith("me.abitno.vplayer.VideoActivity");
+ }
+
+ public class HeadsetPlugReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null && intent.hasExtra("state")) {
+ int state = intent.getIntExtra("state", -1);
+ if (state == 0) {
+ mHeadsetPlaying = isPlaying();
+ stopPlayer();
+ } else if (state == 1) {
+ if (mHeadsetPlaying)
+ startPlayer();
+ }
+ }
+ };
+ }
+
+ private class ScreenReceiver extends BroadcastReceiver {
+ private boolean screenOn = true;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+ screenOn = false;
+ stopPlayer();
+ } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
+ screenOn = true;
+ }
+ }
+ }
+
+ private void loadVPlayerPrefs() {
+ if (!isInitialized())
+ return;
+ vPlayer.setBuffer(VideoActivity.DEFAULT_BUF_SIZE);
+ vPlayer.setVideoQuality(DEFAULT_VIDEO_QUALITY);
+ vPlayer.setDeinterlace(DEFAULT_DEINTERLACE);
+ vPlayer.setVolume(DEFAULT_STEREO_VOLUME, DEFAULT_STEREO_VOLUME);
+ if (mVideoView != null && isInitialized())
+ setVideoLayout();
+ }
+
+ private boolean isInitialized() {
+ return (mCreated && vPlayer != null && vPlayer.isInitialized());
+ }
+
+ private AtomicBoolean mOpened = new AtomicBoolean(Boolean.FALSE);
+ private boolean mSurfaceCreated = false;
+ private boolean mServiceConnected = false;
+ private Object mOpenLock = new Object();
+ private static final int OPEN_FILE = 0;
+ private static final int OPEN_START = 1;
+ private static final int OPEN_SUCCESS = 2;
+ private static final int OPEN_FAILED = 3;
+ private static final int HW_FAILED = 4;
+ private static final int LOAD_PREFS = 5;
+ private static final int BUFFER_START = 11;
+ private static final int BUFFER_PROGRESS = 12;
+ private static final int BUFFER_COMPLETE = 13;
+ private static final int CLOSE_START = 21;
+ private static final int CLOSE_COMPLETE = 22;
+ private Handler vPlayerHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case OPEN_FILE:
+ synchronized (mOpenLock) {
+ if (!mOpened.get() && vPlayer != null) {
+ mOpened.set(true);
+ vPlayer.setVPlayerListener(vPlayerListener);
+ if (vPlayer.isInitialized())
+ mUri = vPlayer.getUri();
+
+ if (mVideoView != null)
+ vPlayer.setDisplay(mVideoView.getHolder());
+ if (mUri != null)
+ vPlayer.initialize(mUri, mDisplayName, mSaveUri, getStartPosition(), vPlayerListener, mParentId);
+ }
+ }
+ break;
+ case OPEN_START:
+ mVideoLoadingText.setText(R.string.video_layout_loading);
+ setVideoLoadingLayoutVisibility(View.VISIBLE);
+ break;
+ case OPEN_SUCCESS:
+ loadVPlayerPrefs();
+ setVideoLoadingLayoutVisibility(View.GONE);
+ setVideoLayout();
+ vPlayer.start();
+ attachMediaController();
+ break;
+ case OPEN_FAILED:
+ resultFinish(RESULT_FAILED);
+ break;
+ case BUFFER_START:
+ setVideoLoadingLayoutVisibility(View.VISIBLE);
+ vPlayerHandler.sendEmptyMessageDelayed(BUFFER_PROGRESS, 1000);
+ break;
+ case BUFFER_PROGRESS:
+ if (vPlayer.getBufferProgress() >= 100) {
+ setVideoLoadingLayoutVisibility(View.GONE);
+ } else {
+ mVideoLoadingText.setText(getString(R.string.video_layout_buffering_progress, vPlayer.getBufferProgress()));
+ vPlayerHandler.sendEmptyMessageDelayed(BUFFER_PROGRESS, 1000);
+ stopPlayer();
+ }
+ break;
+ case BUFFER_COMPLETE:
+ setVideoLoadingLayoutVisibility(View.GONE);
+ vPlayerHandler.removeMessages(BUFFER_PROGRESS);
+ break;
+ case CLOSE_START:
+ mVideoLoadingText.setText(R.string.closing_file);
+ setVideoLoadingLayoutVisibility(View.VISIBLE);
+ break;
+ case CLOSE_COMPLETE:
+ mCloseComplete = true;
+ break;
+ case HW_FAILED:
+ if (mVideoView != null) {
+ mVideoView.setVisibility(View.GONE);
+ mVideoView.setVisibility(View.VISIBLE);
+ mVideoView.initialize(VideoActivity.this, VideoActivity.this, false);
+ }
+ break;
+ case LOAD_PREFS:
+ loadVPlayerPrefs();
+ break;
+ }
+ }
+ };
+
+ private void setVideoLoadingLayoutVisibility(int visibility) {
+ if (mVideoLoadingLayout != null && mLoadingProgressView != null) {
+ if (visibility == View.VISIBLE)
+ mLoadingProgressView.startAnimation(mLoadingAnimation);
+ mVideoLoadingLayout.setVisibility(visibility);
+ }
+ }
+
+ private PlayerService.VPlayerListener vPlayerListener = new PlayerService.VPlayerListener() {
+ @Override
+ public void onHWRenderFailed() {
+
+ }
+
+ @Override
+ public void onOpenStart() {
+ vPlayerHandler.sendEmptyMessage(OPEN_START);
+ }
+
+ @Override
+ public void onOpenSuccess() {
+ vPlayerHandler.sendEmptyMessage(OPEN_SUCCESS);
+ }
+
+ @Override
+ public void onOpenFailed() {
+ vPlayerHandler.sendEmptyMessage(OPEN_FAILED);
+ }
+
+ @Override
+ public void onBufferStart() {
+ vPlayerHandler.sendEmptyMessage(BUFFER_START);
+ stopPlayer();
+ }
+
+ @Override
+ public void onBufferComplete() {
+ Log.i("VideoActivity#onBufferComplete " + vPlayer.needResume());
+ vPlayerHandler.sendEmptyMessage(BUFFER_COMPLETE);
+ if (vPlayer != null && !vPlayer.needResume())
+ startPlayer();
+ }
+
+ @Override
+ public void onPlaybackComplete() {
+ if (mLoopCount == 0 || mLoopCount-- > 1) {
+ vPlayer.start();
+ vPlayer.seekTo(0);
+ } else {
+ resultFinish(RESULT_OK);
+ }
+ }
+
+ @Override
+ public void onCloseStart() {
+ vPlayerHandler.sendEmptyMessage(CLOSE_START);
+ }
+
+ @Override
+ public void onCloseComplete() {
+ vPlayerHandler.sendEmptyMessage(CLOSE_COMPLETE);
+ }
+
+ @Override
+ public void onVideoSizeChanged(int width, int height) {
+ if (mVideoView != null) {
+ setVideoLayout();
+ }
+ }
+
+ @Override
+ public void onDownloadRateChanged(int kbPerSec) {
+ if (!Media.isNative(mUri.toString()) && mMediaController != null) {
+ mMediaController.setDownloadRate(String.format("%dKB/s", kbPerSec));
+ }
+ }
+ };
+
+ private int mVideoMode = VideoView.VIDEO_LAYOUT_SCALE;
+
+ public static final String SESSION_LAST_POSITION_SUFIX = ".last";
+
+ private void setVideoLayout() {
+ mVideoView.setVideoLayout(mVideoMode, DEFAULT_ASPECT_RATIO, vPlayer.getVideoWidth(), vPlayer.getVideoHeight(), vPlayer.getVideoAspectRatio());
+ }
+
+ private float getStartPosition() {
+ return mStartPos;
+ }
+
+ @Override
+ public int getBufferPercentage() {
+ if (isInitialized())
+ return (int) (vPlayer.getBufferProgress() * 100);
+ return 0;
+ }
+
+ @Override
+ public long getCurrentPosition() {
+ if (isInitialized())
+ return vPlayer.getCurrentPosition();
+ return (long) (getStartPosition() * vPlayer.getDuration());
+ }
+
+ @Override
+ public long getDuration() {
+ if (isInitialized())
+ return vPlayer.getDuration();
+ return 0;
+ }
+
+ @Override
+ public boolean isPlaying() {
+ if (isInitialized())
+ return vPlayer.isPlaying();
+ return false;
+ }
+
+ @Override
+ public void pause() {
+ if (isInitialized())
+ vPlayer.stop();
+ }
+
+ @Override
+ public void seekTo(long arg0) {
+ if (isInitialized())
+ vPlayer.seekTo((float) ((double) arg0 / vPlayer.getDuration()));
+ }
+
+ @Override
+ public void start() {
+ if (isInitialized())
+ vPlayer.start();
+ }
+
+ @Override
+ public void previous() {
+ }
+
+ @Override
+ public void next() {
+ }
+
+ private static final int VIDEO_MAXIMUM_HEIGHT = 2048;
+ private static final int VIDEO_MAXIMUM_WIDTH = 2048;
+
+ @Override
+ public float scale(float scaleFactor) {
+ float userRatio = DEFAULT_ASPECT_RATIO;
+ int videoWidth = vPlayer.getVideoWidth();
+ int videoHeight = vPlayer.getVideoHeight();
+ float videoRatio = vPlayer.getVideoAspectRatio();
+ float currentRatio = mVideoView.mVideoHeight / (float) videoHeight;
+
+ currentRatio += (scaleFactor - 1);
+ if (videoWidth * currentRatio >= VIDEO_MAXIMUM_WIDTH)
+ currentRatio = VIDEO_MAXIMUM_WIDTH / (float) videoWidth;
+
+ if (videoHeight * currentRatio >= VIDEO_MAXIMUM_HEIGHT)
+ currentRatio = VIDEO_MAXIMUM_HEIGHT / (float) videoHeight;
+
+ if (currentRatio < 0.5f)
+ currentRatio = 0.5f;
+
+ mVideoView.mVideoHeight = (int) (videoHeight * currentRatio);
+ mVideoView.setVideoLayout(mVideoMode, userRatio, videoWidth, videoHeight, videoRatio);
+ return currentRatio;
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ @Override
+ public void snapshot() {
+ if (!FileHelper.sdAvailable()) {
+ ToastHelper.showToast(this, R.string.file_explorer_sdcard_not_available);
+ } else {
+ Uri imgUri = null;
+ Bitmap bitmap = vPlayer.getCurrentFrame();
+ if (bitmap != null) {
+ File screenshotsDirectory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + SNAP_SHOT_PATH);
+ if (!screenshotsDirectory.exists()) {
+ screenshotsDirectory.mkdirs();
+ }
+
+ File savePath = new File(screenshotsDirectory.getPath() + "/" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".jpg");
+ if (BitmapHelper.saveBitmapToFile(bitmap, savePath.getPath())) {
+ imgUri = Uri.fromFile(savePath);
+ }
+ }
+ if (imgUri != null) {
+ sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, imgUri));
+ ToastHelper.showToast(this, Toast.LENGTH_LONG, getString(R.string.video_screenshot_save_in, imgUri.getPath()));
+ } else {
+ ToastHelper.showToast(this, R.string.video_screenshot_failed);
+ }
+ }
+ }
+
+ @Override
+ public void toggleVideoMode(int mode) {
+ mVideoMode = mode;
+ setVideoLayout();
+ }
+
+ @Override
+ public void stop() {
+ onBackPressed();
+ }
+
+ @Override
+ public long goForward() {
+ return 0;
+ }
+
+ @Override
+ public long goBack() {
+ return 0;
+ }
+
+ @Override
+ public void removeLoadingView() {
+ mVideoLoadingLayout.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onSurfaceCreated(SurfaceHolder holder) {
+ Log.i("onSurfaceCreated");
+ mSurfaceCreated = true;
+ if (mServiceConnected)
+ vPlayerHandler.sendEmptyMessage(OPEN_FILE);
+ if (vPlayer != null)
+ vPlayer.setDisplay(holder);
+ }
+
+ @Override
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ if (vPlayer != null) {
+ vPlayer.setDisplay(holder);
+ setVideoLayout();
+ }
+ }
+
+ @Override
+ public void onSurfaceDestroyed(SurfaceHolder holder) {
+ Log.i("onSurfaceDestroyed");
+ if (vPlayer != null && vPlayer.isInitialized()) {
+ if (vPlayer.isPlaying()) {
+ vPlayer.stop();
+ vPlayer.setState(PlayerService.STATE_NEED_RESUME);
+ }
+ vPlayer.releaseSurface();
+ if (vPlayer.needResume())
+ vPlayer.start();
+ }
}
}
diff --git a/src/io/vov/vitamio/widget/CommonGestures.java b/src/io/vov/vitamio/utils/CommonGestures.java
similarity index 96%
rename from src/io/vov/vitamio/widget/CommonGestures.java
rename to src/io/vov/vitamio/utils/CommonGestures.java
index cdaa667..a5228e9 100644
--- a/src/io/vov/vitamio/widget/CommonGestures.java
+++ b/src/io/vov/vitamio/utils/CommonGestures.java
@@ -1,4 +1,4 @@
-package io.vov.vitamio.widget;
+package io.vov.vitamio.utils;
import android.annotation.SuppressLint;
import android.app.Activity;
@@ -7,8 +7,6 @@
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
-import io.vov.vitamio.utils.DeviceUtils;
-
public class CommonGestures {
public static final int SCALE_STATE_BEGIN = 0;
public static final int SCALE_STATE_SCALEING = 1;
@@ -73,7 +71,7 @@ public void onLongPress(MotionEvent e) {
}
@SuppressLint("NewApi")
- private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener {
+ private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (mListener != null && mGestureEnabled)
diff --git a/src/io/vov/vitamio/widget/MediaController.java b/src/io/vov/vitamio/widget/MediaController.java
index cc5ee35..2697296 100644
--- a/src/io/vov/vitamio/widget/MediaController.java
+++ b/src/io/vov/vitamio/widget/MediaController.java
@@ -1,351 +1,440 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- * Copyright (C) 2012 YIXIA.COM
- *
- * 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 io.vov.vitamio.widget;
-import io.vov.utils.Log;
-import io.vov.utils.StringUtils;
-import io.vov.vitamio.R;
-import io.vov.vitamio.widget.OutlineTextView;
-
+import android.annotation.TargetApi;
+import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
-import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.PopupWindow;
-import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
-/**
- * A view containing controls for a MediaPlayer. Typically contains the buttons
- * like "Play/Pause" and a progress slider. It takes care of synchronizing the
- * controls with the state of the MediaPlayer.
- *
- * The way to use this class is to a) instantiate it programatically or b)
- * create it in your xml layout.
- *
- * a) The MediaController will create a default set of controls and put them in
- * a window floating above your application. Specifically, the controls will
- * float above the view specified with setAnchorView(). By default, the window
- * will disappear if left idle for three seconds and reappear when the user
- * touches the anchor view. To customize the MediaController's style, layout and
- * controls you should extend MediaController and override the {#link
- * {@link #makeControllerView()} method.
- *
- * b) The MediaController is a FrameLayout, you can put it in your layout xml
- * and get it through {@link #findViewById(int)}.
- *
- * NOTES: In each way, if you want customize the MediaController, the SeekBar's
- * id must be mediacontroller_progress, the Play/Pause's must be
- * mediacontroller_pause, current time's must be mediacontroller_time_current,
- * total time's must be mediacontroller_time_total, file name's must be
- * mediacontroller_file_name. And your resources must have a pause_button
- * drawable and a play_button drawable.
- *
- * Functions like show() and hide() have no effect when MediaController is
- * created in an xml layout.
- */
+import io.vov.vitamio.R;
+import io.vov.vitamio.utils.CommonGestures;
+import io.vov.vitamio.utils.CommonGestures.TouchListener;
+
+import me.abitno.utils.FractionalTouchDelegate;
+import me.abitno.utils.Log;
+import me.abitno.utils.StringHelper;
+import me.abitno.utils.StringUtils;
+import me.abitno.utils.UIUtils;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
public class MediaController extends FrameLayout {
private MediaPlayerControl mPlayer;
- private Context mContext;
+ private Activity mContext;
private PopupWindow mWindow;
- private int mAnimStyle;
private View mAnchor;
private View mRoot;
- private ProgressBar mProgress;
+ private ImageButton mLock;
+ private ImageButton mScreenToggle;
+ private ImageButton mSnapshot;
+ private SeekBar mProgress;
private TextView mEndTime, mCurrentTime;
- private TextView mFileName;
- private OutlineTextView mInfoView;
- private String mTitle;
private long mDuration;
private boolean mShowing;
+ private boolean mScreenLocked = false;
private boolean mDragging;
private boolean mInstantSeeking = true;
- private static final int sDefaultTimeout = 3000;
- private static final int FADE_OUT = 1;
- private static final int SHOW_PROGRESS = 2;
- private boolean mFromXml = false;
+ private static final int DEFAULT_TIME_OUT = 3000;
+ private static final int DEFAULT_LONG_TIME_SHOW = 120000;
+ private static final int DEFAULT_SEEKBAR_VALUE = 1000;
+ private static final int TIME_TICK_INTERVAL = 1000;
private ImageButton mPauseButton;
+ private View mMediaController;
+ private View mControlsLayout;
+ private View mSystemInfoLayout;
+ private View mControlsButtons;
+ private View mMenu;
+ private TextView mDateTime;
+ private TextView mDownloadRate;
+ private TextView mFileName;
+ private TextView mBatteryLevel;
+
+ private TextView mOperationInfo;
+ private View mOperationVolLum;
+ private ImageView mVolLumNum;
+ private ImageView mVolLumBg;
+
private AudioManager mAM;
+ private int mMaxVolume;
+ private float mBrightness = 0.01f;
+ private int mVolume = 0;
+ private Handler mHandler;
- public MediaController(Context context, AttributeSet attrs) {
- super(context, attrs);
- mRoot = this;
- mFromXml = true;
- initController(context);
- }
+ private Animation mAnimSlideInTop;
+ private Animation mAnimSlideInBottom;
+ private Animation mAnimSlideOutTop;
+ private Animation mAnimSlideOutBottom;
+
+ private CommonGestures mGestures;
+ private int mVideoMode;
public MediaController(Context context) {
super(context);
- if (!mFromXml && initController(context))
- initFloatingWindow();
+ mContext = (Activity) context;
+ initFloatingWindow();
+ initResources();
}
- private boolean initController(Context context) {
- mContext = context;
- mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- return true;
- }
-
- @Override
- public void onFinishInflate() {
- if (mRoot != null)
- initControllerView(mRoot);
+ public MediaController(Context context, boolean locked) {
+ this(context);
+ mScreenLocked = locked;
+ lock(mScreenLocked);
}
private void initFloatingWindow() {
mWindow = new PopupWindow(mContext);
- mWindow.setFocusable(false);
+ mWindow.setFocusable(true);
mWindow.setBackgroundDrawable(null);
mWindow.setOutsideTouchable(true);
- mAnimStyle = android.R.style.Animation;
}
- /**
- * Set the view that acts as the anchor for the control view. This can for
- * example be a VideoView, or your Activity's main view.
- *
- * @param view
- * The view to which to anchor the controller when it is visible.
- */
- public void setAnchorView(View view) {
- mAnchor = view;
- if (!mFromXml) {
- removeAllViews();
- mRoot = makeControllerView();
- mWindow.setContentView(mRoot);
- mWindow.setWidth(LayoutParams.MATCH_PARENT);
- mWindow.setHeight(LayoutParams.WRAP_CONTENT);
- }
- initControllerView(mRoot);
- }
-
- /**
- * Create the view that holds the widgets that control playback. Derived
- * classes can override this to create their own.
- *
- * @return The controller view.
- */
- protected View makeControllerView() {
- return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.mediacontroller, this);
+ @TargetApi(11)
+ public void setWindowLayoutType() {
+ if (UIUtils.hasICS()) {
+ try {
+ mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+ Method setWindowLayoutType = PopupWindow.class.getMethod("setWindowLayoutType", new Class[] { int.class });
+ setWindowLayoutType.invoke(mWindow, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
+ } catch (Exception e) {
+ Log.e("setWindowLayoutType", e);
+ }
+ }
}
- private void initControllerView(View v) {
- mPauseButton = (ImageButton) v.findViewById(R.id.mediacontroller_play_pause);
- if (mPauseButton != null) {
- mPauseButton.requestFocus();
- mPauseButton.setOnClickListener(mPauseListener);
- }
+ @TargetApi(11)
+ private void initResources() {
+ mHandler = new MHandler(this);
+ mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mMaxVolume = mAM.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ mGestures = new CommonGestures(mContext);
+ mGestures.setTouchListener(mTouchListener, true);
+
+ mAnimSlideOutBottom = AnimationUtils.loadAnimation(mContext, R.anim.slide_out_bottom);
+ mAnimSlideOutTop = AnimationUtils.loadAnimation(mContext, R.anim.slide_out_top);
+ mAnimSlideInBottom = AnimationUtils.loadAnimation(mContext, R.anim.slide_in_bottom);
+ mAnimSlideInTop = AnimationUtils.loadAnimation(mContext, R.anim.slide_in_top);
+ mAnimSlideOutBottom.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ mMediaController.setVisibility(View.GONE);
+ showButtons(false);
+ mHandler.removeMessages(MSG_HIDE_SYSTEM_UI);
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_SYSTEM_UI, DEFAULT_TIME_OUT);
+ }
- mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_seekbar);
- if (mProgress != null) {
- if (mProgress instanceof SeekBar) {
- SeekBar seeker = (SeekBar) mProgress;
- seeker.setOnSeekBarChangeListener(mSeekListener);
- seeker.setThumbOffset(1);
+ @Override
+ public void onAnimationRepeat(Animation animation) {
}
- mProgress.setMax(1000);
+ });
+
+ removeAllViews();
+
+ mRoot = inflateLayout();
+ mWindow.setContentView(mRoot);
+ mWindow.setWidth(android.view.ViewGroup.LayoutParams.MATCH_PARENT);
+ mWindow.setHeight(android.view.ViewGroup.LayoutParams.MATCH_PARENT);
+
+ findViewItems(mRoot);
+ showSystemUi(false);
+ if (UIUtils.hasHoneycomb()) {
+ mRoot.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
+ public void onSystemUiVisibilityChange(int visibility) {
+ if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_SYSTEM_UI, DEFAULT_TIME_OUT);
+ }
+ }
+ });
}
+ }
+
+ private View inflateLayout() {
+ return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.mediacontroller, this);
+ }
+
+ private void findViewItems(View v) {
+ mMediaController = v.findViewById(R.id.mediacontroller);
+
+ mSystemInfoLayout = v.findViewById(R.id.info_panel);
mEndTime = (TextView) v.findViewById(R.id.mediacontroller_time_total);
mCurrentTime = (TextView) v.findViewById(R.id.mediacontroller_time_current);
+
+ mMenu = v.findViewById(R.id.video_menu);
+ mMenu.setOnClickListener(mMenuListener);
+ FractionalTouchDelegate.setupDelegate(mSystemInfoLayout, mMenu, new RectF(1.0f, 1f, 1.2f, 1.2f));
+
mFileName = (TextView) v.findViewById(R.id.mediacontroller_file_name);
- if (mFileName != null)
- mFileName.setText(mTitle);
+ mDateTime = (TextView) v.findViewById(R.id.date_time);
+ mDownloadRate = (TextView) v.findViewById(R.id.download_rate);
+ mBatteryLevel = (TextView) v.findViewById(R.id.battery_level);
+
+ mControlsLayout = v.findViewById(R.id.mediacontroller_controls);
+ mControlsButtons = v.findViewById(R.id.mediacontroller_controls_buttons);
+
+ mOperationInfo = (TextView) v.findViewById(R.id.operation_info);
+ mOperationVolLum = v.findViewById(R.id.operation_volume_brightness);
+ mVolLumBg = (ImageView) v.findViewById(R.id.operation_bg);
+ mVolLumNum = (ImageView) v.findViewById(R.id.operation_percent);
+
+ mLock = (ImageButton) v.findViewById(R.id.mediacontroller_lock);
+ mLock.setOnClickListener(mLockClickListener);
+ FractionalTouchDelegate.setupDelegate(mSystemInfoLayout, mLock, new RectF(1.0f, 1f, 1.2f, 1.2f));
+
+ mScreenToggle = (ImageButton) v.findViewById(R.id.mediacontroller_screen_size);
+ mScreenToggle.setOnClickListener(mScreenToggleListener);
+
+ mSnapshot = (ImageButton) v.findViewById(R.id.mediacontroller_snapshot);
+ mSnapshot.setOnClickListener(mSnapshotListener);
+
+ mPauseButton = (ImageButton) v.findViewById(R.id.mediacontroller_play_pause);
+ mPauseButton.setOnClickListener(mPauseListener);
+
+ mProgress = (SeekBar) v.findViewById(R.id.mediacontroller_seekbar);
+ mProgress.setOnSeekBarChangeListener(mSeekListener);
+ mProgress.setMax(DEFAULT_SEEKBAR_VALUE);
}
- public void setMediaPlayer(MediaPlayerControl player) {
- mPlayer = player;
- updatePausePlay();
+ public void setAnchorView(View view) {
+ mAnchor = view;
+ int[] location = new int[2];
+ mAnchor.getLocationOnScreen(location);
+ Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
+ setWindowLayoutType();
+ mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom);
}
- /**
- * Control the action when the seekbar dragged by user
- *
- * @param seekWhenDragging
- * True the media will seek periodically
- */
- public void setInstantSeeking(boolean seekWhenDragging) {
- mInstantSeeking = seekWhenDragging;
+ public void release() {
+ if (mWindow != null) {
+ mWindow.dismiss();
+ mWindow = null;
+ }
}
- public void show() {
- show(sDefaultTimeout);
+ private View.OnClickListener mMenuListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPlayer.showMenu();
+ }
+ };
+
+ private void setOperationInfo(String info, long time) {
+ mOperationInfo.setText(info);
+ mOperationInfo.setVisibility(View.VISIBLE);
+ mHandler.removeMessages(MSG_HIDE_OPERATION_INFO);
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_OPERATION_INFO, time);
}
- /**
- * Set the content of the file_name TextView
- *
- * @param name
- */
- public void setFileName(String name) {
- mTitle = name;
- if (mFileName != null)
- mFileName.setText(mTitle);
+ private void setBrightnessScale(float scale) {
+ setGraphicOperationProgress(R.drawable.video_brightness_bg, scale);
}
- /**
- * Set the View to hold some information when interact with the
- * MediaController
- *
- * @param v
- */
- public void setInfoView(OutlineTextView v) {
- mInfoView = v;
+ private void setVolumeScale(float scale) {
+ setGraphicOperationProgress(R.drawable.video_volumn_bg, scale);
}
- private void disableUnsupportedButtons() {
- try {
- if (mPauseButton != null && !mPlayer.canPause())
- mPauseButton.setEnabled(false);
- } catch (IncompatibleClassChangeError ex) {
- }
- }
-
- /**
- *
- * Change the animation style resource for this controller.
- *
- *
- *
- * If the controller is showing, calling this method will take effect only
- * the next time the controller is shown.
- *
- *
- * @param animationStyle
- * animation style to use when the controller appears and
- * disappears. Set to -1 for the default animation, 0 for no
- * animation, or a resource identifier for an explicit animation.
- *
- */
- public void setAnimationStyle(int animationStyle) {
- mAnimStyle = animationStyle;
- }
-
- /**
- * Show the controller on screen. It will go away automatically after
- * 'timeout' milliseconds of inactivity.
- *
- * @param timeout
- * The timeout in milliseconds. Use 0 to show the controller
- * until hide() is called.
- */
- public void show(int timeout) {
- if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) {
- if (mPauseButton != null)
- mPauseButton.requestFocus();
- disableUnsupportedButtons();
+ private void setGraphicOperationProgress(int bgID, float scale) {
+ mVolLumBg.setImageResource(bgID);
+ mOperationInfo.setVisibility(View.GONE);
+ mOperationVolLum.setVisibility(View.VISIBLE);
+ ViewGroup.LayoutParams lp = mVolLumNum.getLayoutParams();
+ lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * scale);
+ mVolLumNum.setLayoutParams(lp);
+ }
+
+ public void setFileName(String name) {
+ mFileName.setText(name);
+ }
- if (mFromXml) {
- setVisibility(View.VISIBLE);
- } else {
- int[] location = new int[2];
+ public void setDownloadRate(String rate) {
+ mDownloadRate.setVisibility(View.VISIBLE);
+ mDownloadRate.setText(rate);
+ }
- mAnchor.getLocationOnScreen(location);
- Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
+ public void setBatteryLevel(String level) {
+ mBatteryLevel.setVisibility(View.VISIBLE);
+ mBatteryLevel.setText(level);
+ }
- mWindow.setAnimationStyle(mAnimStyle);
- mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom);
- }
- mShowing = true;
- if (mShownListener != null)
- mShownListener.onShown();
- }
+ public void setMediaPlayer(MediaPlayerControl player) {
+ mPlayer = player;
updatePausePlay();
- mHandler.sendEmptyMessage(SHOW_PROGRESS);
+ }
+
+ public void show() {
+ show(DEFAULT_TIME_OUT);
+ }
+ public void show(int timeout) {
if (timeout != 0) {
- mHandler.removeMessages(FADE_OUT);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout);
+ mHandler.removeMessages(MSG_FADE_OUT);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_FADE_OUT), timeout);
}
- }
+ if (!mShowing) {
+ showButtons(true);
+ mHandler.removeMessages(MSG_HIDE_SYSTEM_UI);
+ showSystemUi(true);
+
+ mPauseButton.requestFocus();
- public boolean isShowing() {
- return mShowing;
+ mControlsLayout.startAnimation(mAnimSlideInTop);
+ mSystemInfoLayout.startAnimation(mAnimSlideInBottom);
+ mMediaController.setVisibility(View.VISIBLE);
+
+ updatePausePlay();
+ mHandler.sendEmptyMessage(MSG_TIME_TICK);
+ mHandler.sendEmptyMessage(MSG_SHOW_PROGRESS);
+
+ mShowing = true;
+ }
}
public void hide() {
- if (mAnchor == null)
- return;
-
if (mShowing) {
try {
- mHandler.removeMessages(SHOW_PROGRESS);
- if (mFromXml)
- setVisibility(View.GONE);
- else
- mWindow.dismiss();
+ mHandler.removeMessages(MSG_TIME_TICK);
+ mHandler.removeMessages(MSG_SHOW_PROGRESS);
+ mControlsLayout.startAnimation(mAnimSlideOutTop);
+ mSystemInfoLayout.startAnimation(mAnimSlideOutBottom);
} catch (IllegalArgumentException ex) {
Log.d("MediaController already removed");
}
mShowing = false;
- if (mHiddenListener != null)
- mHiddenListener.onHidden();
}
}
- public interface OnShownListener {
- public void onShown();
- }
+ private void toggleVideoMode(boolean larger, boolean recycle) {
+ if (larger) {
+ if (mVideoMode < VideoView.VIDEO_LAYOUT_ZOOM)
+ mVideoMode++;
+ else if (recycle)
+ mVideoMode = VideoView.VIDEO_LAYOUT_ORIGIN;
+ } else {
+ if (mVideoMode > VideoView.VIDEO_LAYOUT_ORIGIN)
+ mVideoMode--;
+ else if (recycle)
+ mVideoMode = VideoView.VIDEO_LAYOUT_ZOOM;
+ }
- private OnShownListener mShownListener;
+ switch (mVideoMode) {
+ case VideoView.VIDEO_LAYOUT_ORIGIN:
+ setOperationInfo(mContext.getString(R.string.video_original), 500);
+ mScreenToggle.setImageResource(R.drawable.mediacontroller_sreen_size_100);
+ break;
+ case VideoView.VIDEO_LAYOUT_SCALE:
+ setOperationInfo(mContext.getString(R.string.video_fit_screen), 500);
+ mScreenToggle.setImageResource(R.drawable.mediacontroller_screen_fit);
+ break;
+ case VideoView.VIDEO_LAYOUT_STRETCH:
+ setOperationInfo(mContext.getString(R.string.video_stretch), 500);
+ mScreenToggle.setImageResource(R.drawable.mediacontroller_screen_size);
+ break;
+ case VideoView.VIDEO_LAYOUT_ZOOM:
+ setOperationInfo(mContext.getString(R.string.video_crop), 500);
+ mScreenToggle.setImageResource(R.drawable.mediacontroller_sreen_size_crop);
+ break;
+ }
- public void setOnShownListener(OnShownListener l) {
- mShownListener = l;
+ mPlayer.toggleVideoMode(mVideoMode);
}
- public interface OnHiddenListener {
- public void onHidden();
+ private void lock(boolean toLock) {
+ if (toLock) {
+ mLock.setImageResource(R.drawable.mediacontroller_lock);
+ mMenu.setVisibility(View.GONE);
+ mControlsButtons.setVisibility(View.GONE);
+ mProgress.setEnabled(false);
+ if (mScreenLocked != toLock)
+ setOperationInfo(mContext.getString(R.string.video_screen_locked), 1000);
+ } else {
+ mLock.setImageResource(R.drawable.mediacontroller_unlock);
+ mMenu.setVisibility(View.VISIBLE);
+ mControlsButtons.setVisibility(View.VISIBLE);
+ mProgress.setEnabled(true);
+ if (mScreenLocked != toLock)
+ setOperationInfo(mContext.getString(R.string.video_screen_unlocked), 1000);
+ }
+ mScreenLocked = toLock;
+ mGestures.setTouchListener(mTouchListener, !mScreenLocked);
}
- private OnHiddenListener mHiddenListener;
-
- public void setOnHiddenListener(OnHiddenListener l) {
- mHiddenListener = l;
+ public boolean isLocked() {
+ return mScreenLocked;
}
- private Handler mHandler = new Handler() {
+ private static final int MSG_FADE_OUT = 1;
+ private static final int MSG_SHOW_PROGRESS = 2;
+ private static final int MSG_HIDE_SYSTEM_UI = 3;
+ private static final int MSG_TIME_TICK = 4;
+ private static final int MSG_HIDE_OPERATION_INFO = 5;
+ private static final int MSG_HIDE_OPERATION_VOLLUM = 6;
+
+ private static class MHandler extends Handler {
+ private WeakReference mc;
+
+ public MHandler(MediaController mc) {
+ this.mc = new WeakReference(mc);
+ }
+
@Override
public void handleMessage(Message msg) {
- long pos;
+ MediaController c = mc.get();
+ if (c == null)
+ return;
+
switch (msg.what) {
- case FADE_OUT:
- hide();
+ case MSG_FADE_OUT:
+ c.hide();
break;
- case SHOW_PROGRESS:
- pos = setProgress();
- if (!mDragging && mShowing) {
- msg = obtainMessage(SHOW_PROGRESS);
+ case MSG_SHOW_PROGRESS:
+ long pos = c.setProgress();
+ if (!c.mDragging && c.mShowing) {
+ msg = obtainMessage(MSG_SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
- updatePausePlay();
+ c.updatePausePlay();
}
break;
+ case MSG_HIDE_SYSTEM_UI:
+ if (!c.mShowing)
+ c.showSystemUi(false);
+ break;
+ case MSG_TIME_TICK:
+ c.mDateTime.setText(StringHelper.currentTimeString());
+ sendEmptyMessageDelayed(MSG_TIME_TICK, TIME_TICK_INTERVAL);
+ break;
+ case MSG_HIDE_OPERATION_INFO:
+ c.mOperationInfo.setVisibility(View.GONE);
+ break;
+ case MSG_HIDE_OPERATION_VOLLUM:
+ c.mOperationVolLum.setVisibility(View.GONE);
+ break;
}
}
};
@@ -356,45 +445,146 @@ private long setProgress() {
long position = mPlayer.getCurrentPosition();
long duration = mPlayer.getDuration();
- if (mProgress != null) {
- if (duration > 0) {
- long pos = 1000L * position / duration;
- mProgress.setProgress((int) pos);
- }
- int percent = mPlayer.getBufferPercentage();
- mProgress.setSecondaryProgress(percent * 10);
+ if (duration > 0) {
+ long pos = 1000L * position / duration;
+ mProgress.setProgress((int) pos);
}
+ int percent = mPlayer.getBufferPercentage();
+ mProgress.setSecondaryProgress(percent * 10);
mDuration = duration;
- if (mEndTime != null)
- mEndTime.setText(StringUtils.generateTime(mDuration));
- if (mCurrentTime != null)
- mCurrentTime.setText(StringUtils.generateTime(position));
+ mEndTime.setText(StringUtils.generateTime(mDuration));
+ mCurrentTime.setText(StringUtils.generateTime(position));
return position;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- show(sDefaultTimeout);
- return true;
+ mHandler.removeMessages(MSG_HIDE_SYSTEM_UI);
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_SYSTEM_UI, DEFAULT_TIME_OUT);
+ return mGestures.onTouchEvent(event) || super.onTouchEvent(event);
+ }
+
+ private TouchListener mTouchListener = new TouchListener() {
+ @Override
+ public void onGestureBegin() {
+ mBrightness = mContext.getWindow().getAttributes().screenBrightness;
+ mVolume = mAM.getStreamVolume(AudioManager.STREAM_MUSIC);
+ if (mBrightness <= 0.00f)
+ mBrightness = 0.50f;
+ if (mBrightness < 0.01f)
+ mBrightness = 0.01f;
+ if (mVolume < 0)
+ mVolume = 0;
+ }
+
+ @Override
+ public void onGestureEnd() {
+ mOperationVolLum.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onLeftSlide(float percent) {
+ setBrightness(mBrightness + percent);
+ setBrightnessScale(mContext.getWindow().getAttributes().screenBrightness);
+ }
+
+ @Override
+ public void onRightSlide(float percent) {
+ int v = (int) (percent * mMaxVolume) + mVolume;
+ setVolume(v);
+ }
+
+ @Override
+ public void onSingleTap() {
+ if (mShowing)
+ hide();
+ else
+ show();
+ if (mPlayer.getBufferPercentage() >= 100)
+ mPlayer.removeLoadingView();
+ }
+
+ @Override
+ public void onDoubleTap() {
+ toggleVideoMode(true, true);
+ }
+
+ @Override
+ public void onLongPress() {
+ doPauseResume();
+ }
+
+ @Override
+ public void onScale(float scaleFactor, int state) {
+ switch (state) {
+ case CommonGestures.SCALE_STATE_BEGIN:
+ mVideoMode = VideoView.VIDEO_LAYOUT_SCALE_ZOOM;
+ mScreenToggle.setImageResource(R.drawable.mediacontroller_sreen_size_100);
+ mPlayer.toggleVideoMode(mVideoMode);
+ break;
+ case CommonGestures.SCALE_STATE_SCALEING:
+ float currentRatio = mPlayer.scale(scaleFactor);
+ setOperationInfo((int) (currentRatio * 100) + "%", 500);
+ break;
+ case CommonGestures.SCALE_STATE_END:
+ break;
+ }
+ }
+ };
+
+ private void setVolume(int v) {
+ if (v > mMaxVolume)
+ v = mMaxVolume;
+ else if (v < 0)
+ v = 0;
+ mAM.setStreamVolume(AudioManager.STREAM_MUSIC, v, 0);
+ setVolumeScale((float) v / mMaxVolume);
+ }
+
+ private void setBrightness(float f) {
+ WindowManager.LayoutParams lp = mContext.getWindow().getAttributes();
+ lp.screenBrightness = f;
+ if (lp.screenBrightness > 1.0f)
+ lp.screenBrightness = 1.0f;
+ else if (lp.screenBrightness < 0.01f)
+ lp.screenBrightness = 0.01f;
+ mContext.getWindow().setAttributes(lp);
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
- show(sDefaultTimeout);
+ show(DEFAULT_TIME_OUT);
return false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ return super.dispatchKeyEvent(event);
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ mVolume = mAM.getStreamVolume(AudioManager.STREAM_MUSIC);
+ int step = keyCode == KeyEvent.KEYCODE_VOLUME_UP ? 1 : -1;
+ setVolume(mVolume + step);
+ mHandler.removeMessages(MSG_HIDE_OPERATION_VOLLUM);
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_OPERATION_VOLLUM, 500);
+ return true;
+ }
+
+ if (isLocked()) {
+ show();
+ return true;
+ }
+
if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
- show(sDefaultTimeout);
- if (mPauseButton != null)
- mPauseButton.requestFocus();
+ show(DEFAULT_TIME_OUT);
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
@@ -402,26 +592,38 @@ public boolean dispatchKeyEvent(KeyEvent event) {
updatePausePlay();
}
return true;
- } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
- hide();
+ } else if (keyCode == KeyEvent.KEYCODE_BACK) {
+ release();
+ mPlayer.stop();
return true;
} else {
- show(sDefaultTimeout);
+ show(DEFAULT_TIME_OUT);
}
return super.dispatchKeyEvent(event);
}
- private View.OnClickListener mPauseListener = new View.OnClickListener() {
- public void onClick(View v) {
- doPauseResume();
- show(sDefaultTimeout);
+ @TargetApi(11)
+ private void showSystemUi(boolean visible) {
+ if (UIUtils.hasHoneycomb()) {
+ int flag = visible ? 0 : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LOW_PROFILE;
+ mRoot.setSystemUiVisibility(flag);
}
- };
+ }
- private void updatePausePlay() {
- if (mRoot == null || mPauseButton == null)
- return;
+ private void showButtons(boolean showButtons) {
+ Window window = mContext.getWindow();
+ WindowManager.LayoutParams layoutParams = window.getAttributes();
+ float val = showButtons ? -1 : 0;
+ try {
+ Field buttonBrightness = layoutParams.getClass().getField("buttonBrightness");
+ buttonBrightness.set(layoutParams, val);
+ } catch (Exception e) {
+ Log.e("dimButtons", e);
+ }
+ window.setAttributes(layoutParams);
+ }
+ private void updatePausePlay() {
if (mPlayer.isPlaying())
mPauseButton.setImageResource(R.drawable.mediacontroller_pause);
else
@@ -436,19 +638,62 @@ private void doPauseResume() {
updatePausePlay();
}
+ private View.OnClickListener mPauseListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mPlayer.isPlaying())
+ show(DEFAULT_LONG_TIME_SHOW);
+ else
+ show();
+ doPauseResume();
+ }
+ };
+
+ private View.OnClickListener mLockClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hide();
+ lock(!mScreenLocked);
+ show();
+ }
+ };
+
+ private View.OnClickListener mScreenToggleListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ show(DEFAULT_TIME_OUT);
+ toggleVideoMode(true, true);
+ }
+ };
+
+ private View.OnClickListener mSnapshotListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ show(DEFAULT_TIME_OUT);
+ mSnapshot.setEnabled(false);
+ mPlayer.snapshot();
+ mSnapshot.setEnabled(true);
+ }
+ };
+
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
+ private boolean wasStopped = false;
+
+ @Override
public void onStartTrackingTouch(SeekBar bar) {
mDragging = true;
show(3600000);
- mHandler.removeMessages(SHOW_PROGRESS);
- if (mInstantSeeking)
+ mHandler.removeMessages(MSG_SHOW_PROGRESS);
+ wasStopped = !mPlayer.isPlaying();
+ if (mInstantSeeking) {
mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
- if (mInfoView != null) {
- mInfoView.setText("");
- mInfoView.setVisibility(View.VISIBLE);
+ if (wasStopped) {
+ mPlayer.start();
+ }
}
}
+ @Override
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (!fromuser)
return;
@@ -457,57 +702,60 @@ public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
String time = StringUtils.generateTime(newposition);
if (mInstantSeeking)
mPlayer.seekTo(newposition);
- if (mInfoView != null)
- mInfoView.setText(time);
- if (mCurrentTime != null)
- mCurrentTime.setText(time);
+ setOperationInfo(time, 1500);
+ mCurrentTime.setText(time);
}
+ @Override
public void onStopTrackingTouch(SeekBar bar) {
- if (!mInstantSeeking)
+ if (!mInstantSeeking) {
mPlayer.seekTo((mDuration * bar.getProgress()) / 1000);
- if (mInfoView != null) {
- mInfoView.setText("");
- mInfoView.setVisibility(View.GONE);
+ } else if (wasStopped) {
+ mPlayer.pause();
}
- show(sDefaultTimeout);
- mHandler.removeMessages(SHOW_PROGRESS);
+ mOperationInfo.setVisibility(View.GONE);
+ show(DEFAULT_TIME_OUT);
+ mHandler.removeMessages(MSG_SHOW_PROGRESS);
mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
mDragging = false;
- mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
+ mHandler.sendEmptyMessageDelayed(MSG_SHOW_PROGRESS, 1000);
}
};
- @Override
- public void setEnabled(boolean enabled) {
- if (mPauseButton != null)
- mPauseButton.setEnabled(enabled);
- if (mProgress != null)
- mProgress.setEnabled(enabled);
- disableUnsupportedButtons();
- super.setEnabled(enabled);
- }
-
public interface MediaPlayerControl {
void start();
void pause();
- long getDuration();
-
- long getCurrentPosition();
+ void stop();
void seekTo(long pos);
boolean isPlaying();
+ long getDuration();
+
+ long getCurrentPosition();
+
int getBufferPercentage();
- boolean canPause();
+ void previous();
+
+ void next();
+
+ long goForward();
+
+ long goBack();
+
+ void toggleVideoMode(int mode);
+
+ void showMenu();
+
+ void removeLoadingView();
- boolean canSeekBackward();
+ float scale(float scale);
- boolean canSeekForward();
+ void snapshot();
}
}
diff --git a/src/io/vov/vitamio/widget/VideoView.java b/src/io/vov/vitamio/widget/VideoView.java
index 2016436..043efee 100644
--- a/src/io/vov/vitamio/widget/VideoView.java
+++ b/src/io/vov/vitamio/widget/VideoView.java
@@ -1,732 +1,107 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- * Copyright (C) 2012 YIXIA.COM
- *
- * 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 io.vov.vitamio.widget;
-import io.vov.utils.Log;
-import io.vov.vitamio.MediaPlayer;
-import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
-import io.vov.vitamio.MediaPlayer.OnCompletionListener;
-import io.vov.vitamio.MediaPlayer.OnErrorListener;
-import io.vov.vitamio.MediaPlayer.OnInfoListener;
-import io.vov.vitamio.MediaPlayer.OnPreparedListener;
-import io.vov.vitamio.MediaPlayer.OnSeekCompleteListener;
-import io.vov.vitamio.MediaPlayer.OnSubtitleUpdateListener;
-import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener;
-import io.vov.vitamio.R;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-
+import me.abitno.utils.DeviceUtils;
+import me.abitno.utils.Log;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import android.view.View;
import android.view.ViewGroup.LayoutParams;
-/**
- * Displays a video file. The VideoView class can load images from various
- * sources (such as resources or content providers), takes care of computing its
- * measurement from the video so that it can be used in any layout manager, and
- * provides various display options such as scaling and tinting.
- *
- * VideoView also provide many wrapper methods for
- * {@link io.vov.vitamio.MediaPlayer}, such as {@link #getVideoWidth()},
- * {@link #setSubShown(boolean)}
- */
-public class VideoView extends SurfaceView implements MediaController.MediaPlayerControl {
- private Uri mUri;
- private String mVideoTitle;
- private long mDuration;
-
- 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;
- private static final int STATE_SUSPEND = 6;
- private static final int STATE_RESUME = 7;
- private static final int STATE_SUSPEND_UNSUPPORTED = 8;
-
- private int mCurrentState = STATE_IDLE;
- private int mTargetState = STATE_IDLE;
-
- private float mAspectRatio = 0;
- private int mVideoLayout = VIDEO_LAYOUT_SCALE;
+public class VideoView extends SurfaceView {
+ private Activity mActivity;
+ private SurfaceHolder mSurfaceHolder;
+ private int mSurfaceWidth, mSurfaceHeight;
+ private int mVideoMode = VIDEO_LAYOUT_SCALE;
public static final int VIDEO_LAYOUT_ORIGIN = 0;
public static final int VIDEO_LAYOUT_SCALE = 1;
public static final int VIDEO_LAYOUT_STRETCH = 2;
public static final int VIDEO_LAYOUT_ZOOM = 3;
-
- private SurfaceHolder mSurfaceHolder = null;
- private MediaPlayer mMediaPlayer = null;
- private int mVideoWidth;
- private int mVideoHeight;
- private float mVideoAspectRatio;
- private int mSurfaceWidth;
- private int mSurfaceHeight;
- private MediaController mMediaController;
- private OnCompletionListener mOnCompletionListener;
- private OnPreparedListener mOnPreparedListener;
- private OnErrorListener mOnErrorListener;
- private OnSeekCompleteListener mOnSeekCompleteListener;
- private OnSubtitleUpdateListener mOnSubtitleUpdateListener;
- private OnInfoListener mOnInfoListener;
- private OnBufferingUpdateListener mOnBufferingUpdateListener;
- private int mCurrentBufferPercentage;
- private long mSeekWhenPrepared;
- private boolean mCanPause = true;
- private boolean mCanSeekBack = true;
- private boolean mCanSeekForward = true;
- private Context mContext;
-
- public VideoView(Context context) {
- super(context);
- initVideoView(context);
- }
+ public static final int VIDEO_LAYOUT_SCALE_ZOOM = 4;
+ public int mVideoHeight;
public VideoView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ super(context, attrs);
+ getHolder().addCallback(mCallback);
}
- public VideoView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- initVideoView(context);
- }
+ @SuppressWarnings("deprecation")
+ public void initialize(Activity activity, SurfaceCallback l, boolean push) {
+ mActivity = activity;
+ mListener = l;
+ if (mSurfaceHolder == null)
+ mSurfaceHolder = getHolder();
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
- int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
- setMeasuredDimension(width, height);
+ // These methods is set to hw decoder or sw decoder, <= 2.3
+ if (push)
+ getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+ else
+ getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
- /**
- * Set the display options
- *
- * @param layout
- *
- * - {@link #VIDEO_LAYOUT_ORIGIN}
- *
- {@link #VIDEO_LAYOUT_SCALE}
- *
- {@link #VIDEO_LAYOUT_STRETCH}
- *
- {@link #VIDEO_LAYOUT_ZOOM}
- *
- * @param aspectRatio
- * video aspect ratio, will audo detect if 0.
- */
- public void setVideoLayout(int layout, float aspectRatio) {
+ private void setSurfaceLayout(float userRatio, int videoWidth, int videoHeight, float videoAspectRatio) {
LayoutParams lp = getLayoutParams();
- DisplayMetrics disp = mContext.getResources().getDisplayMetrics();
- int windowWidth = disp.widthPixels, windowHeight = disp.heightPixels;
+ int windowWidth = DeviceUtils.getScreenWidth(mActivity);
+ int windowHeight = DeviceUtils.getScreenHeight(mActivity);
float windowRatio = windowWidth / (float) windowHeight;
- float videoRatio = aspectRatio <= 0.01f ? mVideoAspectRatio : aspectRatio;
- mSurfaceHeight = mVideoHeight;
- mSurfaceWidth = mVideoWidth;
- if (VIDEO_LAYOUT_ORIGIN == layout && mSurfaceWidth < windowWidth && mSurfaceHeight < windowHeight) {
+ float videoRatio = userRatio <= 0.01f ? videoAspectRatio : userRatio;
+ mSurfaceHeight = videoHeight;
+ mSurfaceWidth = videoWidth;
+ if (VIDEO_LAYOUT_ORIGIN == mVideoMode && mSurfaceWidth < windowWidth && mSurfaceHeight < windowHeight) {
lp.width = (int) (mSurfaceHeight * videoRatio);
lp.height = mSurfaceHeight;
- } else if (layout == VIDEO_LAYOUT_ZOOM) {
+ } else if (mVideoMode == VIDEO_LAYOUT_ZOOM) {
lp.width = windowRatio > videoRatio ? windowWidth : (int) (videoRatio * windowHeight);
lp.height = windowRatio < videoRatio ? windowHeight : (int) (windowWidth / videoRatio);
+ } else if (mVideoMode == VIDEO_LAYOUT_SCALE_ZOOM && mVideoHeight > 0) {
+ lp.width = (int) (mVideoHeight * videoRatio);
+ lp.height = mVideoHeight;
} else {
- boolean full = layout == VIDEO_LAYOUT_STRETCH;
+ boolean full = mVideoMode == VIDEO_LAYOUT_STRETCH;
lp.width = (full || windowRatio < videoRatio) ? windowWidth : (int) (videoRatio * windowHeight);
lp.height = (full || windowRatio > videoRatio) ? windowHeight : (int) (windowWidth / videoRatio);
}
+ mVideoHeight = lp.height;
setLayoutParams(lp);
getHolder().setFixedSize(mSurfaceWidth, mSurfaceHeight);
- Log.d("VIDEO: %dx%dx%f, Surface: %dx%d, LP: %dx%d, Window: %dx%dx%f", mVideoWidth, mVideoHeight, mVideoAspectRatio, mSurfaceWidth, mSurfaceHeight, lp.width, lp.height, windowWidth, windowHeight, windowRatio);
- mVideoLayout = layout;
- mAspectRatio = aspectRatio;
+ Log.d("VIDEO: %dx%dx%f, Surface: %dx%d, LP: %dx%d, Window: %dx%dx%f", videoWidth, videoHeight, videoAspectRatio, mSurfaceWidth, mSurfaceHeight, lp.width, lp.height, windowWidth, windowHeight, windowRatio);
}
- private void initVideoView(Context ctx) {
- mContext = ctx;
- mVideoWidth = 0;
- mVideoHeight = 0;
- getHolder().addCallback(mSHCallback);
- setFocusable(true);
- setFocusableInTouchMode(true);
- requestFocus();
- mCurrentState = STATE_IDLE;
- mTargetState = STATE_IDLE;
- if (ctx instanceof Activity)
- ((Activity) ctx).setVolumeControlStream(AudioManager.STREAM_MUSIC);
+ public void setVideoLayout(int layout, float userRatio, int videoWidth, int videoHeight, float videoRatio) {
+ mVideoMode = layout;
+ setSurfaceLayout(userRatio, videoWidth, videoHeight, videoRatio);
}
- public boolean isValid() {
- return (mSurfaceHolder != null && mSurfaceHolder.getSurface().isValid());
- }
-
- public void setVideoPath(String path) {
- setVideoURI(Uri.parse(path));
- }
-
- public void setVideoURI(Uri uri) {
- mUri = uri;
- mSeekWhenPrepared = 0;
- openVideo();
- requestLayout();
- invalidate();
- }
-
- public void setVideoTitle(String title) {
- mVideoTitle = title;
- }
-
- public void stopPlayback() {
- if (mMediaPlayer != null) {
- mMediaPlayer.stop();
- mMediaPlayer.release();
- mMediaPlayer = null;
- mCurrentState = STATE_IDLE;
- mTargetState = STATE_IDLE;
- }
- }
-
- private void openVideo() {
- if (mUri == null || mSurfaceHolder == null)
- return;
-
- Intent i = new Intent("com.android.music.musicservicecommand");
- i.putExtra("command", "pause");
- mContext.sendBroadcast(i);
-
- release(false);
- try {
- mDuration = -1;
- mCurrentBufferPercentage = 0;
- mMediaPlayer = new MediaPlayer(mContext);
- mMediaPlayer.setOnPreparedListener(mPreparedListener);
- mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
- mMediaPlayer.setOnCompletionListener(mCompletionListener);
- mMediaPlayer.setOnErrorListener(mErrorListener);
- mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
- mMediaPlayer.setOnInfoListener(mInfoListener);
- mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
- mMediaPlayer.setOnSubtitleUpdateListener(mSubtitleUpdateListener);
- mMediaPlayer.setDataSource(mContext, mUri);
- mMediaPlayer.setDisplay(mSurfaceHolder);
- mMediaPlayer.setScreenOnWhilePlaying(true);
- mMediaPlayer.prepareAsync();
- mCurrentState = STATE_PREPARING;
- attachMediaController();
- } catch (IOException ex) {
- Log.e("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.e("Unable to open content: " + mUri, ex);
- mCurrentState = STATE_ERROR;
- mTargetState = STATE_ERROR;
- mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
- return;
- }
- }
-
- public void setMediaController(MediaController controller) {
- if (mMediaController != null)
- mMediaController.hide();
- mMediaController = controller;
- attachMediaController();
- }
-
- private void attachMediaController() {
- if (mMediaPlayer != null && mMediaController != null) {
- mMediaController.setMediaPlayer(this);
- View anchorView = this.getParent() instanceof View ? (View) this.getParent() : this;
- mMediaController.setAnchorView(anchorView);
- mMediaController.setEnabled(isInPlaybackState());
-
- if (TextUtils.isEmpty(mVideoTitle)) {
- if (mUri != null) {
- List paths = mUri.getPathSegments();
- String name = paths == null || paths.isEmpty() ? "null" : paths.get(paths.size() - 1);
- mMediaController.setFileName(name);
- }
- } else {
- mMediaController.setFileName(mVideoTitle);
- }
-
- }
- }
-
- OnVideoSizeChangedListener mSizeChangedListener = new OnVideoSizeChangedListener() {
- public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
- Log.d("onVideoSizeChanged: (%dx%d)", width, height);
- mVideoWidth = mp.getVideoWidth();
- mVideoHeight = mp.getVideoHeight();
- mVideoAspectRatio = mp.getVideoAspectRatio();
- if (mVideoWidth != 0 && mVideoHeight != 0)
- setVideoLayout(mVideoLayout, mAspectRatio);
- }
- };
-
- OnPreparedListener mPreparedListener = new OnPreparedListener() {
- public void onPrepared(MediaPlayer mp) {
- Log.d("onPrepared");
- mCurrentState = STATE_PREPARED;
- mTargetState = STATE_PLAYING;
-
- if (mOnPreparedListener != null)
- mOnPreparedListener.onPrepared(mMediaPlayer);
- if (mMediaController != null)
- mMediaController.setEnabled(true);
- mVideoWidth = mp.getVideoWidth();
- mVideoHeight = mp.getVideoHeight();
- mVideoAspectRatio = mp.getVideoAspectRatio();
-
- long seekToPosition = mSeekWhenPrepared;
-
- if (seekToPosition != 0)
- seekTo(seekToPosition);
- if (mVideoWidth != 0 && mVideoHeight != 0) {
- setVideoLayout(mVideoLayout, mAspectRatio);
- if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
- if (mTargetState == STATE_PLAYING) {
- start();
- if (mMediaController != null)
- mMediaController.show();
- } else if (!isPlaying() && (seekToPosition != 0 || getCurrentPosition() > 0)) {
- if (mMediaController != null)
- mMediaController.show(0);
- }
- }
- } else if (mTargetState == STATE_PLAYING) {
- start();
- }
- }
- };
-
- private OnCompletionListener mCompletionListener = new OnCompletionListener() {
- public void onCompletion(MediaPlayer mp) {
- Log.d("onCompletion");
- mCurrentState = STATE_PLAYBACK_COMPLETED;
- mTargetState = STATE_PLAYBACK_COMPLETED;
- if (mMediaController != null)
- mMediaController.hide();
- if (mOnCompletionListener != null)
- mOnCompletionListener.onCompletion(mMediaPlayer);
- }
- };
-
- private OnErrorListener mErrorListener = new OnErrorListener() {
- public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
- Log.d("Error: %d, %d", framework_err, impl_err);
- mCurrentState = STATE_ERROR;
- mTargetState = STATE_ERROR;
- if (mMediaController != null)
- mMediaController.hide();
-
- if (mOnErrorListener != null) {
- if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err))
- return true;
- }
-
- if (getWindowToken() != null) {
- int message = framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK ? R.string.vitamio_videoview_error_text_invalid_progressive_playback : R.string.vitamio_videoview_error_text_unknown;
-
- new AlertDialog.Builder(mContext).setTitle(R.string.vitamio_videoview_error_title).setMessage(message).setPositiveButton(R.string.vitamio_videoview_error_button, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- if (mOnCompletionListener != null)
- mOnCompletionListener.onCompletion(mMediaPlayer);
- }
- }).setCancelable(false).show();
- }
- return true;
- }
- };
-
- private OnBufferingUpdateListener mBufferingUpdateListener = new OnBufferingUpdateListener() {
- public void onBufferingUpdate(MediaPlayer mp, int percent) {
- mCurrentBufferPercentage = percent;
- if (mOnBufferingUpdateListener != null)
- mOnBufferingUpdateListener.onBufferingUpdate(mp, percent);
- }
- };
-
- private OnInfoListener mInfoListener = new OnInfoListener() {
+ private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
@Override
- public boolean onInfo(MediaPlayer mp, int what, int extra) {
- Log.d("onInfo: (%d, %d)", what, extra);
- if (mOnInfoListener != null) {
- mOnInfoListener.onInfo(mp, what, extra);
- } else if (mMediaPlayer != null) {
- if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START)
- mMediaPlayer.pause();
- else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END)
- mMediaPlayer.start();
- }
-
- return true;
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ holder.setKeepScreenOn(true);
+ if (mListener != null)
+ mListener.onSurfaceChanged(holder, format, width, height);
}
- };
-
- private OnSeekCompleteListener mSeekCompleteListener = new OnSeekCompleteListener() {
- @Override
- public void onSeekComplete(MediaPlayer mp) {
- Log.d("onSeekComplete");
- if (mOnSeekCompleteListener != null)
- mOnSeekCompleteListener.onSeekComplete(mp);
- }
- };
- private OnSubtitleUpdateListener mSubtitleUpdateListener = new OnSubtitleUpdateListener() {
@Override
- public void onSubtitleUpdate(byte[] pixels, int width, int height) {
- Log.i("onSubtitleUpdate: bitmap subtitle, %dx%d", width, height);
- if (mOnSubtitleUpdateListener != null)
- mOnSubtitleUpdateListener.onSubtitleUpdate(pixels, width, height);
- }
-
- @Override
- public void onSubtitleUpdate(String text) {
- Log.i("onSubtitleUpdate: %s", text);
- if (mOnSubtitleUpdateListener != null)
- mOnSubtitleUpdateListener.onSubtitleUpdate(text);
- }
- };
-
- public void setOnPreparedListener(OnPreparedListener l) {
- mOnPreparedListener = l;
- }
-
- public void setOnCompletionListener(OnCompletionListener l) {
- mOnCompletionListener = l;
- }
-
- public void setOnErrorListener(OnErrorListener l) {
- mOnErrorListener = l;
- }
-
- public void setOnBufferingUpdateListener(OnBufferingUpdateListener l) {
- mOnBufferingUpdateListener = l;
- }
-
- public void setOnSeekCompleteListener(OnSeekCompleteListener l) {
- mOnSeekCompleteListener = l;
- }
-
- public void setOnSubtitleUpdateListener(OnSubtitleUpdateListener l) {
- mOnSubtitleUpdateListener = l;
- }
-
- public void setOnInfoListener(OnInfoListener l) {
- mOnInfoListener = l;
- }
-
- SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() {
- public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
- mSurfaceWidth = w;
- mSurfaceHeight = h;
- boolean isValidState = (mTargetState == STATE_PLAYING);
- boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
- if (mMediaPlayer != null && isValidState && hasValidSize) {
- if (mSeekWhenPrepared != 0)
- seekTo(mSeekWhenPrepared);
- start();
- if (mMediaController != null) {
- if (mMediaController.isShowing())
- mMediaController.hide();
- mMediaController.show();
- }
- }
- }
-
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceHolder = holder;
- if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND && mTargetState == STATE_RESUME) {
- mMediaPlayer.setDisplay(mSurfaceHolder);
- resume();
- } else {
- openVideo();
- }
+ if (mListener != null)
+ mListener.onSurfaceCreated(holder);
}
+ @Override
public void surfaceDestroyed(SurfaceHolder holder) {
- mSurfaceHolder = null;
- if (mMediaController != null)
- mMediaController.hide();
- if (mCurrentState != STATE_SUSPEND)
- release(true);
+ if (mListener != null)
+ mListener.onSurfaceDestroyed(holder);
}
};
- private void release(boolean cleartargetstate) {
- if (mMediaPlayer != null) {
- mMediaPlayer.reset();
- mMediaPlayer.release();
- mMediaPlayer = null;
- mCurrentState = STATE_IDLE;
- if (cleartargetstate)
- mTargetState = STATE_IDLE;
- }
- }
+ private SurfaceCallback mListener;
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (isInPlaybackState() && mMediaController != null)
- toggleMediaControlsVisiblity();
- return false;
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent ev) {
- if (isInPlaybackState() && mMediaController != null)
- toggleMediaControlsVisiblity();
- return false;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_MENU && keyCode != KeyEvent.KEYCODE_CALL && keyCode != KeyEvent.KEYCODE_ENDCALL;
- if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
- if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE) {
- if (mMediaPlayer.isPlaying()) {
- pause();
- mMediaController.show();
- } else {
- start();
- mMediaController.hide();
- }
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP && mMediaPlayer.isPlaying()) {
- pause();
- mMediaController.show();
- } else {
- toggleMediaControlsVisiblity();
- }
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- private void toggleMediaControlsVisiblity() {
- if (mMediaController.isShowing()) {
- mMediaController.hide();
- } else {
- mMediaController.show();
- }
- }
+ public interface SurfaceCallback {
+ public void onSurfaceCreated(SurfaceHolder holder);
- public void start() {
- if (isInPlaybackState()) {
- mMediaPlayer.start();
- mCurrentState = STATE_PLAYING;
- }
- mTargetState = STATE_PLAYING;
- }
-
- public void pause() {
- if (isInPlaybackState()) {
- if (mMediaPlayer.isPlaying()) {
- mMediaPlayer.pause();
- mCurrentState = STATE_PAUSED;
- }
- }
- mTargetState = STATE_PAUSED;
- }
-
- public void suspend() {
- if (isInPlaybackState()) {
- release(false);
- mCurrentState = STATE_SUSPEND_UNSUPPORTED;
- Log.d("Unable to suspend video. Release MediaPlayer.");
- }
- }
-
- public void resume() {
- if (mSurfaceHolder == null && mCurrentState == STATE_SUSPEND) {
- mTargetState = STATE_RESUME;
- } else if (mCurrentState == STATE_SUSPEND_UNSUPPORTED) {
- openVideo();
- }
- }
-
- public long getDuration() {
- if (isInPlaybackState()) {
- if (mDuration > 0)
- return mDuration;
- mDuration = mMediaPlayer.getDuration();
- return mDuration;
- }
- mDuration = -1;
- return mDuration;
- }
-
- public long getCurrentPosition() {
- if (isInPlaybackState())
- return mMediaPlayer.getCurrentPosition();
- return 0;
- }
-
- public void seekTo(long 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 void setVolume(float leftVolume, float rightVolume) {
- if (mMediaPlayer != null)
- mMediaPlayer.setVolume(leftVolume, rightVolume);
- }
-
- public int getVideoWidth() {
- return mVideoWidth;
- }
-
- public int getVideoHeight() {
- return mVideoHeight;
- }
-
- public float getVideoAspectRatio() {
- return mVideoAspectRatio;
- }
-
- public void setVideoQuality(int quality) {
- if (mMediaPlayer != null)
- mMediaPlayer.setVideoQuality(quality);
- }
-
- public void setBufferSize(int bufSize) {
- if (mMediaPlayer != null)
- mMediaPlayer.setBufferSize(bufSize);
- }
-
- public boolean isBuffering() {
- if (mMediaPlayer != null)
- return mMediaPlayer.isBuffering();
- return false;
- }
-
- public void setMetaEncoding(String encoding) {
- if (mMediaPlayer != null)
- mMediaPlayer.setMetaEncoding(encoding);
- }
-
- public String getMetaEncoding() {
- if (mMediaPlayer != null)
- return mMediaPlayer.getMetaEncoding();
- return null;
- }
-
- public HashMap getAudioTrackMap(String encoding) {
- if (mMediaPlayer != null)
- return mMediaPlayer.getAudioTrackMap(encoding);
- return null;
- }
-
- public int getAudioTrack() {
- if (mMediaPlayer != null)
- return mMediaPlayer.getAudioTrack();
- return -1;
- }
-
- public void setAudioTrack(int audioIndex) {
- if (mMediaPlayer != null)
- mMediaPlayer.setAudioTrack(audioIndex);
- }
-
- public void setSubShown(boolean shown) {
- if (mMediaPlayer != null)
- mMediaPlayer.setSubShown(shown);
- }
-
- public void setSubEncoding(String encoding) {
- if (mMediaPlayer != null)
- mMediaPlayer.setSubEncoding(encoding);
- }
-
- public int getSubLocation() {
- if (mMediaPlayer != null)
- return mMediaPlayer.getSubLocation();
- return -1;
- }
-
- public void setSubPath(String subPath) {
- if (mMediaPlayer != null)
- mMediaPlayer.setSubPath(subPath);
- }
-
- public String getSubPath() {
- if (mMediaPlayer != null)
- return mMediaPlayer.getSubPath();
- return null;
- }
-
- public void setSubTrack(int trackId) {
- if (mMediaPlayer != null)
- mMediaPlayer.setSubTrack(trackId);
- }
-
- public int getSubTrack() {
- if (mMediaPlayer != null)
- return mMediaPlayer.getSubTrack();
- return -1;
- }
-
- public HashMap getSubTrackMap(String encoding) {
- if (mMediaPlayer != null)
- return mMediaPlayer.getSubTrackMap(encoding);
- return null;
- }
-
- protected boolean isInPlaybackState() {
- return (mMediaPlayer != null && mCurrentState != STATE_ERROR && mCurrentState != STATE_IDLE && mCurrentState != STATE_PREPARING);
- }
-
- public boolean canPause() {
- return mCanPause;
- }
-
- public boolean canSeekBackward() {
- return mCanSeekBack;
- }
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height);
- public boolean canSeekForward() {
- return mCanSeekForward;
+ public void onSurfaceDestroyed(SurfaceHolder holder);
}
}