MovieControllerOverlay.java revision 43650c63eb751a367ff0d75af152d0b244c0e748
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.gallery3d.app; 18 19import android.content.Context; 20import android.os.Handler; 21import android.view.Gravity; 22import android.view.KeyEvent; 23import android.view.MotionEvent; 24import android.view.View; 25import android.view.View.OnClickListener; 26import android.view.animation.Animation; 27import android.view.animation.Animation.AnimationListener; 28import android.view.animation.AnimationUtils; 29import android.widget.FrameLayout; 30import android.widget.ImageView; 31import android.widget.ImageView.ScaleType; 32import android.widget.LinearLayout; 33import android.widget.ProgressBar; 34import android.widget.RelativeLayout; 35import android.widget.TextView; 36 37import com.android.gallery3d.R; 38 39/** 40 * The playback controller for the Movie Player. 41 */ 42public class MovieControllerOverlay extends FrameLayout implements 43 ControllerOverlay, 44 OnClickListener, 45 AnimationListener, 46 TimeBar.Listener { 47 48 private enum State { 49 PLAYING, 50 PAUSED, 51 ENDED, 52 ERROR, 53 LOADING 54 } 55 56 private static final float ERROR_MESSAGE_RELATIVE_PADDING = 1.0f / 6; 57 58 private Listener listener; 59 60 private final View background; 61 private final TimeBar timeBar; 62 63 private View mainView; 64 private final LinearLayout loadingView; 65 private final TextView errorView; 66 private final ImageView playPauseReplayView; 67 68 private final Handler handler; 69 private final Runnable startHidingRunnable; 70 private final Animation hideAnimation; 71 72 private State state; 73 74 private boolean hidden; 75 76 private boolean canReplay = true; 77 78 public MovieControllerOverlay(Context context) { 79 super(context); 80 81 state = State.LOADING; 82 83 LayoutParams wrapContent = 84 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 85 LayoutParams matchParent = 86 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 87 88 background = new View(context); 89 background.setBackgroundColor(context.getResources().getColor(R.color.darker_transparent)); 90 addView(background, matchParent); 91 92 timeBar = new TimeBar(context, this); 93 addView(timeBar, wrapContent); 94 95 loadingView = new LinearLayout(context); 96 loadingView.setOrientation(LinearLayout.VERTICAL); 97 loadingView.setGravity(Gravity.CENTER_HORIZONTAL); 98 ProgressBar spinner = new ProgressBar(context); 99 spinner.setIndeterminate(true); 100 loadingView.addView(spinner, wrapContent); 101 TextView loadingText = createOverlayTextView(context); 102 loadingText.setText(R.string.loading_video); 103 loadingView.addView(loadingText, wrapContent); 104 addView(loadingView, wrapContent); 105 106 playPauseReplayView = new ImageView(context); 107 playPauseReplayView.setImageResource(R.drawable.ic_vidcontrol_play); 108 playPauseReplayView.setBackgroundResource(R.drawable.bg_vidcontrol); 109 playPauseReplayView.setScaleType(ScaleType.CENTER); 110 playPauseReplayView.setFocusable(true); 111 playPauseReplayView.setClickable(true); 112 playPauseReplayView.setOnClickListener(this); 113 addView(playPauseReplayView, wrapContent); 114 115 errorView = createOverlayTextView(context); 116 addView(errorView, matchParent); 117 118 handler = new Handler(); 119 startHidingRunnable = new Runnable() { 120 public void run() { 121 startHiding(); 122 } 123 }; 124 125 hideAnimation = AnimationUtils.loadAnimation(context, R.anim.player_out); 126 hideAnimation.setAnimationListener(this); 127 128 RelativeLayout.LayoutParams params = 129 new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 130 setLayoutParams(params); 131 hide(); 132 } 133 134 private TextView createOverlayTextView(Context context) { 135 TextView view = new TextView(context); 136 view.setGravity(Gravity.CENTER); 137 view.setTextColor(0xFFFFFFFF); 138 view.setPadding(0, 15, 0, 15); 139 return view; 140 } 141 142 public void setListener(Listener listener) { 143 this.listener = listener; 144 } 145 146 public void setCanReplay(boolean canReplay) { 147 this.canReplay = canReplay; 148 } 149 150 public View getView() { 151 return this; 152 } 153 154 public void showPlaying() { 155 state = State.PLAYING; 156 showMainView(playPauseReplayView); 157 } 158 159 public void showPaused() { 160 state = State.PAUSED; 161 showMainView(playPauseReplayView); 162 } 163 164 public void showEnded() { 165 state = State.ENDED; 166 showMainView(playPauseReplayView); 167 } 168 169 public void showLoading() { 170 state = State.LOADING; 171 showMainView(loadingView); 172 } 173 174 public void showErrorMessage(String message) { 175 state = State.ERROR; 176 int padding = (int) (getMeasuredWidth() * ERROR_MESSAGE_RELATIVE_PADDING); 177 errorView.setPadding(padding, errorView.getPaddingTop(), padding, errorView.getPaddingBottom()); 178 errorView.setText(message); 179 showMainView(errorView); 180 } 181 182 public void setTimes(int currentTime, int totalTime) { 183 timeBar.setTime(currentTime, totalTime); 184 } 185 186 public void hide() { 187 boolean wasHidden = hidden; 188 hidden = true; 189 playPauseReplayView.setVisibility(View.INVISIBLE); 190 loadingView.setVisibility(View.INVISIBLE); 191 background.setVisibility(View.INVISIBLE); 192 timeBar.setVisibility(View.INVISIBLE); 193 setVisibility(View.INVISIBLE); 194 setFocusable(true); 195 requestFocus(); 196 if (listener != null && wasHidden != hidden) { 197 listener.onHidden(); 198 } 199 } 200 201 private void showMainView(View view) { 202 mainView = view; 203 errorView.setVisibility(mainView == errorView ? View.VISIBLE : View.INVISIBLE); 204 loadingView.setVisibility(mainView == loadingView ? View.VISIBLE : View.INVISIBLE); 205 playPauseReplayView.setVisibility( 206 mainView == playPauseReplayView ? View.VISIBLE : View.INVISIBLE); 207 show(); 208 } 209 210 public void show() { 211 boolean wasHidden = hidden; 212 hidden = false; 213 updateViews(); 214 setVisibility(View.VISIBLE); 215 setFocusable(false); 216 if (listener != null && wasHidden != hidden) { 217 listener.onShown(); 218 } 219 maybeStartHiding(); 220 } 221 222 private void maybeStartHiding() { 223 cancelHiding(); 224 if (state == State.PLAYING) { 225 handler.postDelayed(startHidingRunnable, 2500); 226 } 227 } 228 229 private void startHiding() { 230 startHideAnimation(timeBar); 231 startHideAnimation(playPauseReplayView); 232 } 233 234 private void startHideAnimation(View view) { 235 if (view.getVisibility() == View.VISIBLE) { 236 view.startAnimation(hideAnimation); 237 } 238 } 239 240 private void cancelHiding() { 241 handler.removeCallbacks(startHidingRunnable); 242 background.setAnimation(null); 243 timeBar.setAnimation(null); 244 playPauseReplayView.setAnimation(null); 245 } 246 247 public void onAnimationStart(Animation animation) { 248 // Do nothing. 249 } 250 251 public void onAnimationRepeat(Animation animation) { 252 // Do nothing. 253 } 254 255 public void onAnimationEnd(Animation animation) { 256 hide(); 257 } 258 259 public void onClick(View view) { 260 if (listener != null) { 261 if (view == playPauseReplayView) { 262 if (state == State.ENDED) { 263 if (canReplay) { 264 listener.onReplay(); 265 } 266 } else if (state == State.PAUSED || state == State.PLAYING) { 267 listener.onPlayPause(); 268 } 269 } 270 } 271 } 272 273 @Override 274 public boolean onKeyDown(int keyCode, KeyEvent event) { 275 if (hidden) { 276 show(); 277 } 278 return super.onKeyDown(keyCode, event); 279 } 280 281 @Override 282 public boolean onTouchEvent(MotionEvent event) { 283 if (super.onTouchEvent(event)) { 284 return true; 285 } 286 287 if (hidden) { 288 show(); 289 return true; 290 } 291 switch (event.getAction()) { 292 case MotionEvent.ACTION_DOWN: 293 cancelHiding(); 294 if (state == State.PLAYING || state == State.PAUSED) { 295 listener.onPlayPause(); 296 } 297 break; 298 case MotionEvent.ACTION_UP: 299 maybeStartHiding(); 300 break; 301 } 302 return true; 303 } 304 305 @Override 306 protected void onLayout(boolean changed, int l, int t, int r, int b) { 307 int bw; 308 int bh; 309 int y; 310 int h = b - t; 311 int w = r - l; 312 boolean error = errorView.getVisibility() == View.VISIBLE; 313 314 bw = timeBar.getBarHeight(); 315 bh = bw; 316 y = b - bh; 317 318 background.layout(l, y, r, b); 319 320 timeBar.layout(l, b - timeBar.getPreferredHeight(), r, b); 321 // Needed, otherwise the framework will not re-layout in case only the padding is changed 322 timeBar.requestLayout(); 323 324 // play pause / next / previous buttons 325 int cx = l + w / 2; // center x 326 int playbackButtonsCenterline = t + h / 2; 327 bw = playPauseReplayView.getMeasuredWidth(); 328 bh = playPauseReplayView.getMeasuredHeight(); 329 playPauseReplayView.layout( 330 cx - bw / 2, playbackButtonsCenterline - bh / 2, cx + bw / 2, 331 playbackButtonsCenterline + bh / 2); 332 333 if (mainView != null) { 334 layoutCenteredView(mainView, l, t, r, b); 335 } 336 } 337 338 private void layoutCenteredView(View view, int l, int t, int r, int b) { 339 int cw = view.getMeasuredWidth(); 340 int ch = view.getMeasuredHeight(); 341 int cl = (r - l - cw) / 2; 342 int ct = (b - t - ch) / 2; 343 view.layout(cl, ct, cl + cw, ct + ch); 344 } 345 346 @Override 347 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 348 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 349 measureChildren(widthMeasureSpec, heightMeasureSpec); 350 } 351 352 private void updateViews() { 353 if (hidden) { 354 return; 355 } 356 background.setVisibility(View.VISIBLE); 357 timeBar.setVisibility(View.VISIBLE); 358 playPauseReplayView.setImageResource( 359 state == State.PAUSED ? R.drawable.ic_vidcontrol_play : 360 state == State.PLAYING ? R.drawable.ic_vidcontrol_pause : 361 R.drawable.ic_vidcontrol_reload); 362 playPauseReplayView.setVisibility( 363 (state != State.LOADING && state != State.ERROR && 364 !(state == State.ENDED && !canReplay)) 365 ? View.VISIBLE : View.GONE); 366 requestLayout(); 367 } 368 369 // TimeBar listener 370 371 public void onScrubbingStart() { 372 cancelHiding(); 373 listener.onSeekStart(); 374 } 375 376 public void onScrubbingMove(int time) { 377 cancelHiding(); 378 listener.onSeekMove(time); 379 } 380 381 public void onScrubbingEnd(int time) { 382 maybeStartHiding(); 383 listener.onSeekEnd(time); 384 } 385} 386