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