| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * 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 com.android.gallery3d.app; |
| |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.content.res.TypedArray; |
| import android.graphics.Rect; |
| import android.graphics.drawable.Drawable; |
| import android.view.Gravity; |
| import android.view.KeyEvent; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.View.OnClickListener; |
| import android.widget.FrameLayout; |
| import android.widget.ImageView; |
| import android.widget.ImageView.ScaleType; |
| import android.widget.LinearLayout; |
| import android.widget.ProgressBar; |
| import android.widget.RelativeLayout; |
| import android.widget.TextView; |
| |
| import com.android.gallery3d.R; |
| |
| /** |
| * The common playback controller for the Movie Player or Video Trimming. |
| */ |
| public abstract class CommonControllerOverlay extends FrameLayout implements |
| ControllerOverlay, |
| OnClickListener, |
| TimeBar.Listener { |
| |
| protected enum State { |
| PLAYING, |
| PAUSED, |
| ENDED, |
| ERROR, |
| LOADING, |
| BUFFERING, |
| RETRY_CONNECTING, |
| RETRY_CONNECTING_ERROR |
| } |
| |
| protected static final float ERROR_MESSAGE_RELATIVE_PADDING = 1.0f / 6; |
| |
| protected Listener mListener; |
| |
| protected final View mBackground; |
| protected TimeBar mTimeBar; |
| |
| protected View mMainView; |
| protected final LinearLayout mLoadingView; |
| protected final TextView mErrorView; |
| protected final ImageView mPlayPauseReplayView; |
| |
| protected State mState; |
| |
| protected boolean mCanReplay = true; |
| |
| public void setSeekable(boolean canSeek) { |
| mTimeBar.setSeekable(canSeek); |
| } |
| |
| public CommonControllerOverlay(Context context) { |
| super(context); |
| |
| mState = State.LOADING; |
| // TODO: Move the following layout code into xml file. |
| LayoutParams wrapContent = |
| new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); |
| LayoutParams matchParent = |
| new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); |
| |
| mBackground = new View(context); |
| mBackground.setBackgroundColor(context.getResources().getColor(R.color.darker_transparent)); |
| addView(mBackground, matchParent); |
| |
| // Depending on the usage, the timeBar can show a single scrubber, or |
| // multiple ones for trimming. |
| createTimeBar(context); |
| addView(mTimeBar, wrapContent); |
| mTimeBar.setContentDescription( |
| context.getResources().getString(R.string.accessibility_time_bar)); |
| mLoadingView = new LinearLayout(context); |
| mLoadingView.setOrientation(LinearLayout.VERTICAL); |
| mLoadingView.setGravity(Gravity.CENTER_HORIZONTAL); |
| ProgressBar spinner = new ProgressBar(context); |
| spinner.setIndeterminate(true); |
| mLoadingView.addView(spinner, wrapContent); |
| addView(mLoadingView, wrapContent); |
| |
| mPlayPauseReplayView = new ImageView(context); |
| mPlayPauseReplayView.setContentDescription( |
| context.getResources().getString(R.string.accessibility_play_video)); |
| mPlayPauseReplayView.setScaleType(ScaleType.CENTER); |
| mPlayPauseReplayView.setFocusable(true); |
| mPlayPauseReplayView.setClickable(true); |
| mPlayPauseReplayView.setOnClickListener(this); |
| TypedArray array = context.getTheme().obtainStyledAttributes(new int[] { |
| android.R.attr.actionBarItemBackground |
| }); |
| Drawable drawable = array.getDrawable(array.getIndex(0)); |
| if (drawable != null) { |
| mPlayPauseReplayView.setBackground(drawable); |
| } |
| addView(mPlayPauseReplayView, wrapContent); |
| |
| mErrorView = createOverlayTextView(context); |
| addView(mErrorView, matchParent); |
| |
| RelativeLayout.LayoutParams params = |
| new RelativeLayout.LayoutParams( |
| LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); |
| setLayoutParams(params); |
| } |
| |
| abstract protected void createTimeBar(Context context); |
| |
| private TextView createOverlayTextView(Context context) { |
| TextView view = new TextView(context); |
| view.setGravity(Gravity.CENTER); |
| view.setTextColor(0xFFFFFFFF); |
| view.setPadding(0, 15, 0, 15); |
| return view; |
| } |
| |
| @Override |
| public void setListener(Listener listener) { |
| this.mListener = listener; |
| } |
| |
| @Override |
| public void setCanReplay(boolean canReplay) { |
| this.mCanReplay = canReplay; |
| } |
| |
| @Override |
| public View getView() { |
| return this; |
| } |
| |
| @Override |
| public void showPlaying() { |
| mState = State.PLAYING; |
| showMainView(mPlayPauseReplayView); |
| } |
| |
| @Override |
| public void showPaused() { |
| mState = State.PAUSED; |
| showMainView(mPlayPauseReplayView); |
| } |
| |
| @Override |
| public void showEnded() { |
| mState = State.ENDED; |
| if (mCanReplay) showMainView(mPlayPauseReplayView); |
| } |
| |
| @Override |
| public void showLoading() { |
| mState = State.LOADING; |
| showMainView(mLoadingView); |
| } |
| |
| @Override |
| public void showErrorMessage(String message) { |
| mState = State.ERROR; |
| int padding = (int) (getMeasuredWidth() * ERROR_MESSAGE_RELATIVE_PADDING); |
| mErrorView.setPadding( |
| padding, mErrorView.getPaddingTop(), padding, mErrorView.getPaddingBottom()); |
| mErrorView.setText(message); |
| showMainView(mErrorView); |
| } |
| |
| @Override |
| public void setTimes(int currentTime, int totalTime, |
| int trimStartTime, int trimEndTime) { |
| mTimeBar.setTime(currentTime, totalTime, trimStartTime, trimEndTime); |
| } |
| |
| public void hide() { |
| mPlayPauseReplayView.setVisibility(View.INVISIBLE); |
| mLoadingView.setVisibility(View.INVISIBLE); |
| mBackground.setVisibility(View.INVISIBLE); |
| mTimeBar.setVisibility(View.INVISIBLE); |
| setVisibility(View.INVISIBLE); |
| setFocusable(true); |
| requestFocus(); |
| } |
| |
| private void showMainView(View view) { |
| mMainView = view; |
| mErrorView.setVisibility(mMainView == mErrorView ? View.VISIBLE : View.INVISIBLE); |
| mLoadingView.setVisibility(mMainView == mLoadingView ? View.VISIBLE : View.INVISIBLE); |
| mPlayPauseReplayView.setVisibility( |
| mMainView == mPlayPauseReplayView ? View.VISIBLE : View.INVISIBLE); |
| show(); |
| } |
| |
| @Override |
| public void show() { |
| updateViews(); |
| setVisibility(View.VISIBLE); |
| setFocusable(false); |
| } |
| |
| @Override |
| public void onClick(View view) { |
| if (mListener != null) { |
| if (view == mPlayPauseReplayView) { |
| if (mState == State.ENDED) { |
| if (mCanReplay) { |
| mListener.onReplay(); |
| } |
| } else if (mState == State.PAUSED || mState == State.PLAYING) { |
| mListener.onPlayPause(); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public boolean onKeyDown(int keyCode, KeyEvent event) { |
| return super.onKeyDown(keyCode, event); |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent event) { |
| if (super.onTouchEvent(event)) { |
| return true; |
| } |
| return false; |
| } |
| |
| // The paddings of 4 sides which covered by system components. E.g. |
| // +-----------------+\ |
| // | Action Bar | insets.top |
| // +-----------------+/ |
| // | | |
| // | Content Area | insets.right = insets.left = 0 |
| // | | |
| // +-----------------+\ |
| // | Navigation Bar | insets.bottom |
| // +-----------------+/ |
| // Please see View.fitSystemWindows() for more details. |
| protected final Rect mWindowInsets = new Rect(); |
| |
| @Override |
| protected boolean fitSystemWindows(Rect insets) { |
| // We don't set the paddings of this View, otherwise, |
| // the content will get cropped outside window |
| mWindowInsets.set(insets); |
| return true; |
| } |
| |
| @Override |
| protected void onLayout(boolean changed, int left, int top, int right, int bottom) { |
| Rect insets = mWindowInsets; |
| int pl = insets.left; // the left paddings |
| int pr = insets.right; |
| int pt = insets.top; |
| int pb = insets.bottom; |
| |
| int h = bottom - top; |
| int w = right - left; |
| boolean error = mErrorView.getVisibility() == View.VISIBLE; |
| |
| int y = h - pb; |
| // Put both TimeBar and Background just above the bottom system |
| // component. |
| // But extend the background to the width of the screen, since we don't |
| // care if it will be covered by a system component and it looks better. |
| mBackground.layout(0, y - mTimeBar.getBarHeight(), w, y); |
| mTimeBar.layout(pl, y - mTimeBar.getPreferredHeight(), w - pr, y); |
| |
| // Put the play/pause/next/ previous button in the center of the screen |
| layoutCenteredView(mPlayPauseReplayView, 0, 0, w, h); |
| |
| if (mMainView != null) { |
| layoutCenteredView(mMainView, 0, 0, w, h); |
| } |
| } |
| |
| protected void layoutCenteredView(View view, int l, int t, int r, int b) { |
| int cw = view.getMeasuredWidth(); |
| int ch = view.getMeasuredHeight(); |
| int cl = (r - l - cw) / 2; |
| int ct = (b - t - ch) / 2; |
| view.layout(cl, ct, cl + cw, ct + ch); |
| } |
| |
| @Override |
| protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
| measureChildren(widthMeasureSpec, heightMeasureSpec); |
| } |
| |
| protected void updateViews() { |
| mBackground.setVisibility(View.VISIBLE); |
| mTimeBar.setVisibility(View.VISIBLE); |
| Resources resources = getContext().getResources(); |
| int imageResource = R.drawable.ic_vidcontrol_reload; |
| String contentDescription = resources.getString(R.string.accessibility_reload_video); |
| if (mState == State.PAUSED) { |
| imageResource = R.drawable.ic_vidcontrol_play; |
| contentDescription = resources.getString(R.string.accessibility_play_video); |
| } else if (mState == State.PLAYING) { |
| imageResource = R.drawable.ic_vidcontrol_pause; |
| contentDescription = resources.getString(R.string.accessibility_pause_video); |
| } |
| |
| mPlayPauseReplayView.setImageResource(imageResource); |
| mPlayPauseReplayView.setContentDescription(contentDescription); |
| mPlayPauseReplayView.setVisibility( |
| (mState != State.LOADING && mState != State.ERROR && |
| !(mState == State.ENDED && !mCanReplay)) |
| ? View.VISIBLE : View.GONE); |
| requestLayout(); |
| } |
| |
| // TimeBar listener |
| |
| @Override |
| public void onScrubbingStart() { |
| mListener.onSeekStart(); |
| } |
| |
| @Override |
| public void onScrubbingMove(int time) { |
| mListener.onSeekMove(time); |
| } |
| |
| @Override |
| public void onScrubbingEnd(int time, int trimStartTime, int trimEndTime) { |
| mListener.onSeekEnd(time, trimStartTime, trimEndTime); |
| } |
| } |