19395f90b26e072b2748db315aaffef27c257a82dMaurice Lam/*
29395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * Copyright (C) 2017 The Android Open Source Project
39395f90b26e072b2748db315aaffef27c257a82dMaurice Lam *
49395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * Licensed under the Apache License, Version 2.0 (the "License");
59395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * you may not use this file except in compliance with the License.
69395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * You may obtain a copy of the License at
79395f90b26e072b2748db315aaffef27c257a82dMaurice Lam *
89395f90b26e072b2748db315aaffef27c257a82dMaurice Lam *      http://www.apache.org/licenses/LICENSE-2.0
99395f90b26e072b2748db315aaffef27c257a82dMaurice Lam *
109395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * Unless required by applicable law or agreed to in writing, software
119395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * distributed under the License is distributed on an "AS IS" BASIS,
129395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * See the License for the specific language governing permissions and
149395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * limitations under the License.
159395f90b26e072b2748db315aaffef27c257a82dMaurice Lam */
169395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
179395f90b26e072b2748db315aaffef27c257a82dMaurice Lampackage com.android.setupwizardlib.view;
189395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
199395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.annotation.TargetApi;
209395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.content.Context;
219395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.content.res.TypedArray;
229395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.graphics.SurfaceTexture;
239395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.graphics.drawable.Animatable;
249395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.media.MediaPlayer;
259395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.os.Build.VERSION_CODES;
269395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.support.annotation.RawRes;
279395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.support.annotation.VisibleForTesting;
289395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.util.AttributeSet;
299395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.view.Surface;
309395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.view.TextureView;
319395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport android.view.View;
329395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
339395f90b26e072b2748db315aaffef27c257a82dMaurice Lamimport com.android.setupwizardlib.R;
349395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
359395f90b26e072b2748db315aaffef27c257a82dMaurice Lam/**
369395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * A view for displaying videos in a continuous loop (without audio). This is typically used for
379395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * animated illustrations.
389395f90b26e072b2748db315aaffef27c257a82dMaurice Lam *
399395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * <p>The video can be specified using {@code app:suwVideo}, specifying the raw resource to the mp4
409395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * video. Optionally, {@code app:suwLoopStartMs} can be used to specify which part of the video it
419395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * should loop back to
429395f90b26e072b2748db315aaffef27c257a82dMaurice Lam *
439395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * <p>For optimal file size, use avconv or other video compression tool to remove the unused audio
449395f90b26e072b2748db315aaffef27c257a82dMaurice Lam * track and reduce the size of your video asset:
459395f90b26e072b2748db315aaffef27c257a82dMaurice Lam *     avconv -i [input file] -vcodec h264 -crf 20 -an [output_file]
469395f90b26e072b2748db315aaffef27c257a82dMaurice Lam */
479395f90b26e072b2748db315aaffef27c257a82dMaurice Lam@TargetApi(VERSION_CODES.ICE_CREAM_SANDWICH)
489395f90b26e072b2748db315aaffef27c257a82dMaurice Lampublic class IllustrationVideoView extends TextureView implements Animatable,
499395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        TextureView.SurfaceTextureListener,
509395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        MediaPlayer.OnPreparedListener,
519395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        MediaPlayer.OnSeekCompleteListener,
529395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        MediaPlayer.OnInfoListener {
539395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
549395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    protected float mAspectRatio = 1.0f; // initial guess until we know
559395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
56ffb2d8f2de805c6e717053caef48db1839e00d64Maurice Lam    protected MediaPlayer mMediaPlayer;
579395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
589395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    private @RawRes int mVideoResId = 0;
599395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
609395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @VisibleForTesting Surface mSurface;
619395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
629395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public IllustrationVideoView(Context context, AttributeSet attrs) {
639395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        super(context, attrs);
649395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        final TypedArray a = context.obtainStyledAttributes(attrs,
659395f90b26e072b2748db315aaffef27c257a82dMaurice Lam                R.styleable.SuwIllustrationVideoView);
669395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mVideoResId = a.getResourceId(R.styleable.SuwIllustrationVideoView_suwVideo, 0);
679395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        a.recycle();
689395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
69198bd0ddb15ad479e0d0d7214645a3c067f271a1Maurice Lam        // By default the video scales without interpolation, resulting in jagged edges in the
70198bd0ddb15ad479e0d0d7214645a3c067f271a1Maurice Lam        // video. This works around it by making the view go through scaling, which will apply
71198bd0ddb15ad479e0d0d7214645a3c067f271a1Maurice Lam        // anti-aliasing effects.
72198bd0ddb15ad479e0d0d7214645a3c067f271a1Maurice Lam        setScaleX(0.9999999f);
73198bd0ddb15ad479e0d0d7214645a3c067f271a1Maurice Lam        setScaleX(0.9999999f);
74198bd0ddb15ad479e0d0d7214645a3c067f271a1Maurice Lam
759395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        setSurfaceTextureListener(this);
769395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
779395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
789395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
799395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
809395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        int width = MeasureSpec.getSize(widthMeasureSpec);
819395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        int height = MeasureSpec.getSize(heightMeasureSpec);
829395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
839395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (height < width * mAspectRatio) {
849395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            // Height constraint is tighter. Need to scale down the width to fit aspect ratio.
859395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            width = (int) (height / mAspectRatio);
869395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        } else {
879395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            // Width constraint is tighter. Need to scale down the height to fit aspect ratio.
889395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            height = (int) (width * mAspectRatio);
899395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
909395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
919395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        super.onMeasure(
929395f90b26e072b2748db315aaffef27c257a82dMaurice Lam                MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
939395f90b26e072b2748db315aaffef27c257a82dMaurice Lam                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
949395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
959395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
969395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    /**
979395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * Set the video to be played by this view.
989395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     *
999395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * @param resId Resource ID of the video, typically an MP4 under res/raw.
1009395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     */
1019395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void setVideoResource(@RawRes int resId) {
1029395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (resId != mVideoResId) {
1039395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mVideoResId = resId;
1049395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            createMediaPlayer();
1059395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1069395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1079395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1089395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
1099395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void onWindowFocusChanged(boolean hasWindowFocus) {
1109395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        super.onWindowFocusChanged(hasWindowFocus);
1119395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (hasWindowFocus) {
1129395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            start();
1139395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        } else {
1149395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            stop();
1159395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1169395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1179395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1189395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    /**
1199395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * Creates a media player for the current URI. The media player will be started immediately if
1209395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * the view's window is visible. If there is an existing media player, it will be released.
1219395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     */
1229395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    private void createMediaPlayer() {
1239395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (mMediaPlayer != null) {
1249395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mMediaPlayer.release();
1259395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1269395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (mSurface == null || mVideoResId == 0) {
1279395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            return;
1289395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1299395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1309395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mMediaPlayer = MediaPlayer.create(getContext(), mVideoResId);
1319395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1329395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mMediaPlayer.setSurface(mSurface);
1339395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mMediaPlayer.setOnPreparedListener(this);
1349395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mMediaPlayer.setOnSeekCompleteListener(this);
1359395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mMediaPlayer.setOnInfoListener(this);
1369395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1379395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        float aspectRatio = (float) mMediaPlayer.getVideoHeight() / mMediaPlayer.getVideoWidth();
1389395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (mAspectRatio != aspectRatio) {
1399395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mAspectRatio = aspectRatio;
1409395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            requestLayout();
1419395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1429395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (getWindowVisibility() == View.VISIBLE) {
1439395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            start();
1449395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1459395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1469395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1479395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    /**
1489395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * Whether the media player should play the video in a continuous loop. The default value is
1499395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * true.
1509395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     */
1519395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    protected boolean shouldLoop() {
1529395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        return true;
1539395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1549395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1559395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    /**
1569395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * Release any resources used by this view. This is automatically called in
1579395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     * onSurfaceTextureDestroyed so in most cases you don't have to call this.
1589395f90b26e072b2748db315aaffef27c257a82dMaurice Lam     */
1599395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void release() {
1609395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (mMediaPlayer != null) {
1619395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mMediaPlayer.stop();
1629395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mMediaPlayer.release();
1639395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mMediaPlayer = null;
1649395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1659395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (mSurface != null) {
1669395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mSurface.release();
1679395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mSurface = null;
1689395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
1699395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1709395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1719395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    /* SurfaceTextureListener methods */
1729395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1739395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
1749395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
1759395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        // Keep the view hidden until video starts
1769395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        setVisibility(View.INVISIBLE);
1779395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mSurface = new Surface(surfaceTexture);
1789395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        createMediaPlayer();
1799395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1809395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1819395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
1829395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
1839395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1849395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1859395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
1869395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
1879395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        release();
1889395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        return true;
1899395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1909395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1919395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
1929395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
1939395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
1949395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1959395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    /* Animatable methods */
1969395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
1979395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
1989395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void start() {
1999395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
2009395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mMediaPlayer.start();
2019395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
2029395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
2039395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
2049395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
2059395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void stop() {
2069395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (mMediaPlayer != null) {
2079395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            mMediaPlayer.pause();
2089395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
2099395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
2109395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
2119395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
2129395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public boolean isRunning() {
2139395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        return mMediaPlayer != null && mMediaPlayer.isPlaying();
2149395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
2159395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
2169395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    /* MediaPlayer callbacks */
2179395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
2189395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
2199395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public boolean onInfo(MediaPlayer mp, int what, int extra) {
2209395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
2219395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            // Video available, show view now
2229395f90b26e072b2748db315aaffef27c257a82dMaurice Lam            setVisibility(View.VISIBLE);
2239395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        }
2249395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        return false;
2259395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
2269395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
2279395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
2289395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void onPrepared(MediaPlayer mp) {
2299395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mp.setLooping(shouldLoop());
2309395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
2319395f90b26e072b2748db315aaffef27c257a82dMaurice Lam
2329395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    @Override
2339395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    public void onSeekComplete(MediaPlayer mp) {
2349395f90b26e072b2748db315aaffef27c257a82dMaurice Lam        mp.start();
2359395f90b26e072b2748db315aaffef27c257a82dMaurice Lam    }
236616fd7a886200e2366cfc0dca4b9050bf61a6f30Ajay Nadathur
237616fd7a886200e2366cfc0dca4b9050bf61a6f30Ajay Nadathur    public int getCurrentPosition() {
238616fd7a886200e2366cfc0dca4b9050bf61a6f30Ajay Nadathur        return mMediaPlayer == null ? 0 : mMediaPlayer.getCurrentPosition();
239616fd7a886200e2366cfc0dca4b9050bf61a6f30Ajay Nadathur    }
2409395f90b26e072b2748db315aaffef27c257a82dMaurice Lam}
241