PlayerActivity.java (14035B)
1 package de.nordgedanken.rpicms; 2 3 import android.app.Activity; 4 import android.content.Intent; 5 import android.media.MediaPlayer; 6 import android.media.MediaPlayer.OnCompletionListener; 7 import android.media.MediaPlayer.OnErrorListener; 8 import android.media.MediaPlayer.OnPreparedListener; 9 import android.os.Bundle; 10 import android.os.Handler; 11 import android.util.DisplayMetrics; 12 import android.util.Log; 13 import android.view.KeyEvent; 14 import android.view.MenuItem; 15 import android.view.View; 16 import android.widget.ImageView; 17 import android.widget.ProgressBar; 18 import android.widget.RelativeLayout.LayoutParams; 19 import android.widget.SeekBar; 20 import android.widget.TextView; 21 import android.widget.VideoView; 22 23 import java.util.Timer; 24 import java.util.TimerTask; 25 26 public class PlayerActivity extends Activity { 27 28 private static final String TAG = "PlayerActivity"; 29 30 private static final int HIDE_CONTROLLER_TIME = 5000; 31 private static final int SEEKBAR_DELAY_TIME = 100; 32 private static final int SEEKBAR_INTERVAL_TIME = 1000; 33 private static final int MIN_SCRUB_TIME = 3000; 34 private static final int SCRUB_SEGMENT_DIVISOR = 30; 35 private static final double MEDIA_BAR_TOP_MARGIN = 0.8; 36 private static final double MEDIA_BAR_RIGHT_MARGIN = 0.2; 37 private static final double MEDIA_BAR_BOTTOM_MARGIN = 0.0; 38 private static final double MEDIA_BAR_LEFT_MARGIN = 0.2; 39 private static final double MEDIA_BAR_HEIGHT = 0.1; 40 private static final double MEDIA_BAR_WIDTH = 0.9; 41 42 private VideoView mVideoView; 43 private TextView mStartText; 44 private TextView mEndText; 45 private SeekBar mSeekbar; 46 private ImageView mPlayPause; 47 private ProgressBar mLoading; 48 private View mControllers; 49 private View mContainer; 50 private Timer mSeekbarTimer; 51 private Timer mControllersTimer; 52 private PlaybackState mPlaybackState; 53 private final Handler mHandler = new Handler(); 54 private Movie mSelectedMovie; 55 private boolean mShouldStartPlayback; 56 private boolean mControlersVisible; 57 private int mDuration; 58 private DisplayMetrics mMetrics; 59 60 /* 61 * List of various states that we can be in 62 */ 63 public static enum PlaybackState { 64 PLAYING, PAUSED, BUFFERING, IDLE; 65 } 66 67 @Override 68 public void onCreate(Bundle savedInstanceState) { 69 super.onCreate(savedInstanceState); 70 setContentView(R.layout.activity_player); 71 72 mMetrics = new DisplayMetrics(); 73 getWindowManager().getDefaultDisplay().getMetrics(mMetrics); 74 75 loadViews(); 76 setupController(); 77 setupControlsCallbacks(); 78 startVideoPlayer(); 79 updateMetadata(true); 80 } 81 82 private void startVideoPlayer() { 83 Bundle b = getIntent().getExtras(); 84 mSelectedMovie = (Movie) getIntent().getSerializableExtra(getResources().getString(R.string.movie)); 85 if (null != b) { 86 mShouldStartPlayback = b.getBoolean(getResources().getString(R.string.should_start)); 87 int startPosition = b.getInt(getResources().getString(R.string.start_position), 0); 88 mVideoView.setVideoPath(mSelectedMovie.getVideoUrl()); 89 if (mShouldStartPlayback) { 90 mPlaybackState = PlaybackState.PLAYING; 91 updatePlayButton(mPlaybackState); 92 if (startPosition > 0) { 93 mVideoView.seekTo(startPosition); 94 } 95 mVideoView.start(); 96 mPlayPause.requestFocus(); 97 startControllersTimer(); 98 } else { 99 updatePlaybackLocation(); 100 mPlaybackState = PlaybackState.PAUSED; 101 updatePlayButton(mPlaybackState); 102 } 103 } 104 } 105 106 private void updatePlaybackLocation() { 107 if (mPlaybackState == PlaybackState.PLAYING || 108 mPlaybackState == PlaybackState.BUFFERING) { 109 startControllersTimer(); 110 } else { 111 stopControllersTimer(); 112 } 113 } 114 115 private void play(int position) { 116 startControllersTimer(); 117 mVideoView.seekTo(position); 118 mVideoView.start(); 119 restartSeekBarTimer(); 120 } 121 122 private void stopSeekBarTimer() { 123 Log.d(TAG, "Stopped TrickPlay Timer"); 124 if (null != mSeekbarTimer) { 125 mSeekbarTimer.cancel(); 126 } 127 } 128 129 private void restartSeekBarTimer() { 130 stopSeekBarTimer(); 131 mSeekbarTimer = new Timer(); 132 mSeekbarTimer.scheduleAtFixedRate(new UpdateSeekbarTask(), SEEKBAR_DELAY_TIME, 133 SEEKBAR_INTERVAL_TIME); 134 } 135 136 private void stopControllersTimer() { 137 if (null != mControllersTimer) { 138 mControllersTimer.cancel(); 139 } 140 } 141 142 private void startControllersTimer() { 143 if (null != mControllersTimer) { 144 mControllersTimer.cancel(); 145 } 146 mControllersTimer = new Timer(); 147 mControllersTimer.schedule(new HideControllersTask(), HIDE_CONTROLLER_TIME); 148 } 149 150 private void updateControlersVisibility(boolean show) { 151 if (show) { 152 mControllers.setVisibility(View.VISIBLE); 153 } else { 154 mControllers.setVisibility(View.INVISIBLE); 155 } 156 } 157 158 @Override 159 protected void onPause() { 160 super.onPause(); 161 Log.d(TAG, "onPause() was called"); 162 if (null != mSeekbarTimer) { 163 mSeekbarTimer.cancel(); 164 mSeekbarTimer = null; 165 } 166 if (null != mControllersTimer) { 167 mControllersTimer.cancel(); 168 } 169 mVideoView.pause(); 170 mPlaybackState = PlaybackState.PAUSED; 171 updatePlayButton(PlaybackState.PAUSED); 172 } 173 174 @Override 175 protected void onStop() { 176 Log.d(TAG, "onStop() was called"); 177 super.onStop(); 178 } 179 180 @Override 181 protected void onDestroy() { 182 Log.d(TAG, "onDestroy() is called"); 183 stopControllersTimer(); 184 stopSeekBarTimer(); 185 super.onDestroy(); 186 } 187 188 @Override 189 protected void onStart() { 190 Log.d(TAG, "onStart was called"); 191 super.onStart(); 192 } 193 194 @Override 195 protected void onResume() { 196 Log.d(TAG, "onResume() was called"); 197 super.onResume(); 198 } 199 200 private class HideControllersTask extends TimerTask { 201 @Override 202 public void run() { 203 mHandler.post(new Runnable() { 204 @Override 205 public void run() { 206 updateControlersVisibility(false); 207 mControlersVisible = false; 208 } 209 }); 210 211 } 212 } 213 214 private class UpdateSeekbarTask extends TimerTask { 215 216 @Override 217 public void run() { 218 mHandler.post(new Runnable() { 219 220 @Override 221 public void run() { 222 int currentPos = 0; 223 currentPos = mVideoView.getCurrentPosition(); 224 updateSeekbar(currentPos, mDuration); 225 } 226 }); 227 } 228 } 229 230 private class BackToDetailTask extends TimerTask { 231 232 @Override 233 public void run() { 234 mHandler.post(new Runnable() { 235 @Override 236 public void run() { 237 Intent intent = new Intent(PlayerActivity.this, DetailsActivity.class); 238 intent.putExtra(getResources().getString(R.string.movie), mSelectedMovie); 239 startActivity(intent); 240 } 241 }); 242 243 } 244 } 245 246 private void setupController() { 247 248 int w = (int) (mMetrics.widthPixels * MEDIA_BAR_WIDTH); 249 int h = (int) (mMetrics.heightPixels * MEDIA_BAR_HEIGHT); 250 int marginLeft = (int) (mMetrics.widthPixels * MEDIA_BAR_LEFT_MARGIN); 251 int marginTop = (int) (mMetrics.heightPixels * MEDIA_BAR_TOP_MARGIN); 252 int marginRight = (int) (mMetrics.widthPixels * MEDIA_BAR_RIGHT_MARGIN); 253 int marginBottom = (int) (mMetrics.heightPixels * MEDIA_BAR_BOTTOM_MARGIN); 254 LayoutParams lp = new LayoutParams(w, h); 255 lp.setMargins(marginLeft, marginTop, marginRight, marginBottom); 256 mControllers.setLayoutParams(lp); 257 mStartText.setText(getResources().getString(R.string.init_text)); 258 mEndText.setText(getResources().getString(R.string.init_text)); 259 } 260 261 private void setupControlsCallbacks() { 262 263 mVideoView.setOnErrorListener(new OnErrorListener() { 264 265 @Override 266 public boolean onError(MediaPlayer mp, int what, int extra) { 267 String msg = ""; 268 if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) { 269 msg = getString(R.string.video_error_media_load_timeout); 270 } else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { 271 msg = getString(R.string.video_error_server_unaccessible); 272 } else { 273 msg = getString(R.string.video_error_unknown_error); 274 } 275 mVideoView.stopPlayback(); 276 mPlaybackState = PlaybackState.IDLE; 277 return false; 278 } 279 }); 280 281 mVideoView.setOnPreparedListener(new OnPreparedListener() { 282 283 @Override 284 public void onPrepared(MediaPlayer mp) { 285 Log.d(TAG, "onPrepared is reached"); 286 mDuration = mp.getDuration(); 287 mEndText.setText(Utils.formatMillis(mDuration)); 288 mSeekbar.setMax(mDuration); 289 restartSeekBarTimer(); 290 } 291 }); 292 293 mVideoView.setOnCompletionListener(new OnCompletionListener() { 294 295 @Override 296 public void onCompletion(MediaPlayer mp) { 297 stopSeekBarTimer(); 298 mPlaybackState = PlaybackState.IDLE; 299 updatePlayButton(PlaybackState.IDLE); 300 mControllersTimer = new Timer(); 301 mControllersTimer.schedule(new BackToDetailTask(), HIDE_CONTROLLER_TIME); 302 } 303 }); 304 } 305 306 /* 307 * @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return 308 * super.onKeyDown(keyCode, event); } 309 */ 310 311 @Override 312 public boolean onKeyDown(int keyCode, KeyEvent event) { 313 int currentPos = 0; 314 int delta = (int) (mDuration / SCRUB_SEGMENT_DIVISOR); 315 if (delta < MIN_SCRUB_TIME) 316 delta = MIN_SCRUB_TIME; 317 318 Log.v("keycode", "duration " + mDuration + " delta:" + delta); 319 if (!mControlersVisible) { 320 updateControlersVisibility(true); 321 } 322 switch (keyCode) { 323 case KeyEvent.KEYCODE_DPAD_CENTER: 324 return true; 325 case KeyEvent.KEYCODE_DPAD_DOWN: 326 return true; 327 case KeyEvent.KEYCODE_DPAD_LEFT: 328 currentPos = mVideoView.getCurrentPosition(); 329 currentPos -= delta; 330 if (currentPos > 0) 331 play(currentPos); 332 return true; 333 case KeyEvent.KEYCODE_DPAD_RIGHT: 334 currentPos = mVideoView.getCurrentPosition(); 335 currentPos += delta; 336 if (currentPos < mDuration) 337 play(currentPos); 338 return true; 339 case KeyEvent.KEYCODE_DPAD_UP: 340 return true; 341 } 342 343 return super.onKeyDown(keyCode, event); 344 } 345 346 private void updateSeekbar(int position, int duration) { 347 mSeekbar.setProgress(position); 348 mSeekbar.setMax(duration); 349 mStartText.setText(Utils.formatMillis(position)); 350 mEndText.setText(Utils.formatMillis(duration)); 351 } 352 353 private void updatePlayButton(PlaybackState state) { 354 switch (state) { 355 case PLAYING: 356 mLoading.setVisibility(View.INVISIBLE); 357 mPlayPause.setVisibility(View.VISIBLE); 358 mPlayPause.setImageDrawable( 359 getResources().getDrawable(R.drawable.ic_pause_playcontrol_normal)); 360 break; 361 case PAUSED: 362 case IDLE: 363 mLoading.setVisibility(View.INVISIBLE); 364 mPlayPause.setVisibility(View.VISIBLE); 365 mPlayPause.setImageDrawable( 366 getResources().getDrawable(R.drawable.ic_play_playcontrol_normal)); 367 break; 368 case BUFFERING: 369 mPlayPause.setVisibility(View.INVISIBLE); 370 mLoading.setVisibility(View.VISIBLE); 371 break; 372 default: 373 break; 374 } 375 } 376 377 private void updateMetadata(boolean visible) { 378 mVideoView.invalidate(); 379 } 380 381 @Override 382 public boolean onOptionsItemSelected(MenuItem item) { 383 return true; 384 } 385 386 private void loadViews() { 387 mVideoView = (VideoView) findViewById(R.id.videoView); 388 mStartText = (TextView) findViewById(R.id.startText); 389 mEndText = (TextView) findViewById(R.id.endText); 390 mSeekbar = (SeekBar) findViewById(R.id.seekBar); 391 mPlayPause = (ImageView) findViewById(R.id.playpause); 392 mLoading = (ProgressBar) findViewById(R.id.progressBar); 393 mControllers = findViewById(R.id.controllers); 394 mContainer = findViewById(R.id.container); 395 396 mVideoView.setOnClickListener(mPlayPauseHandler); 397 } 398 399 View.OnClickListener mPlayPauseHandler = new View.OnClickListener() { 400 public void onClick(View v) { 401 Log.d(TAG, "clicked play pause button"); 402 403 if (!mControlersVisible) { 404 updateControlersVisibility(true); 405 } 406 407 if (mPlaybackState == PlaybackState.PAUSED) { 408 mPlaybackState = PlaybackState.PLAYING; 409 updatePlayButton(mPlaybackState); 410 mVideoView.start(); 411 startControllersTimer(); 412 } else { 413 mVideoView.pause(); 414 mPlaybackState = PlaybackState.PAUSED; 415 updatePlayButton(PlaybackState.PAUSED); 416 stopControllersTimer(); 417 } 418 } 419 }; 420 }