11ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang/*
21ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * Copyright 2018 The Android Open Source Project
31ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang *
41ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * Licensed under the Apache License, Version 2.0 (the "License");
51ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * you may not use this file except in compliance with the License.
61ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * You may obtain a copy of the License at
71ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang *
81ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang *      http://www.apache.org/licenses/LICENSE-2.0
91ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang *
101ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * Unless required by applicable law or agreed to in writing, software
111ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * distributed under the License is distributed on an "AS IS" BASIS,
121ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * See the License for the specific language governing permissions and
141ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang * limitations under the License.
151ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang */
161ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
171ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangpackage androidx.media.widget;
181ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
191ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport static androidx.media.widget.VideoView2.VIEW_TYPE_SURFACEVIEW;
201ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
211ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport android.content.Context;
221ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport android.graphics.Rect;
231ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport android.util.Log;
241ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport android.view.Surface;
251ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport android.view.SurfaceHolder;
261ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport android.view.SurfaceView;
271ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport android.view.View;
281ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
291ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport androidx.annotation.NonNull;
301ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport androidx.annotation.RequiresApi;
311ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangimport androidx.media.MediaPlayer2;
321ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
331ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang@RequiresApi(21)
341ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kangclass VideoSurfaceView extends SurfaceView
351ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        implements VideoViewInterface, SurfaceHolder.Callback {
361ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    private static final String TAG = "VideoSurfaceView";
371ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
381ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    private Surface mSurface = null;
391ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    private SurfaceListener mSurfaceListener = null;
401ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    private MediaPlayer2 mMediaPlayer;
411ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    // A flag to indicate taking over other view should be proceed.
421ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    private boolean mIsTakingOverOldView;
431ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    private VideoViewInterface mOldView;
441ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
451ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    VideoSurfaceView(Context context) {
461ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        super(context, null);
471ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        getHolder().addCallback(this);
481ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
491ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
501ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    ////////////////////////////////////////////////////
511ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    // implements VideoViewInterfaceWithMp1
521ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    ////////////////////////////////////////////////////
531ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
541ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
551ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public boolean assignSurfaceToMediaPlayer(MediaPlayer2 mp) {
561ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        Log.d(TAG, "assignSurfaceToMediaPlayer(): mSurface: " + mSurface);
571ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (mp == null || !hasAvailableSurface()) {
581ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            return false;
591ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
601ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        mp.setSurface(mSurface);
611ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        return true;
621ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
631ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
641ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
651ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public void setSurfaceListener(SurfaceListener l) {
661ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        mSurfaceListener = l;
671ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
681ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
691ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
701ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public int getViewType() {
711ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        return VIEW_TYPE_SURFACEVIEW;
721ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
731ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
741ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
751ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public void setMediaPlayer(MediaPlayer2 mp) {
761ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        mMediaPlayer = mp;
771ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (mIsTakingOverOldView) {
781ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            takeOver(mOldView);
791ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
801ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
811ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
821ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
831ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public void takeOver(@NonNull VideoViewInterface oldView) {
841ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (assignSurfaceToMediaPlayer(mMediaPlayer)) {
851ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            ((View) oldView).setVisibility(GONE);
861ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            mIsTakingOverOldView = false;
871ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            mOldView = null;
881ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            if (mSurfaceListener != null) {
891ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                mSurfaceListener.onSurfaceTakeOverDone(this);
901ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            }
911ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        } else {
921ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            mIsTakingOverOldView = true;
931ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            mOldView = oldView;
941ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
951ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
961ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
971ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
981ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public boolean hasAvailableSurface() {
991ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        return mSurface != null && mSurface.isValid();
1001ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
1011ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1021ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    ////////////////////////////////////////////////////
1031ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    // implements SurfaceHolder.Callback
1041ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    ////////////////////////////////////////////////////
1051ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1061ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
1071ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public void surfaceCreated(SurfaceHolder holder) {
1081ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        Log.d(TAG, "surfaceCreated: mSurface: " + mSurface + ", new : " + holder.getSurface());
1091ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        mSurface = holder.getSurface();
1101ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (mIsTakingOverOldView) {
1111ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            takeOver(mOldView);
1121ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        } else {
1131ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            assignSurfaceToMediaPlayer(mMediaPlayer);
1141ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
1151ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1161ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (mSurfaceListener != null) {
1171ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            Rect rect = holder.getSurfaceFrame();
1181ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            mSurfaceListener.onSurfaceCreated(this, rect.width(), rect.height());
1191ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
1201ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
1211ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1221ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
1231ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
1241ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (mSurfaceListener != null) {
1251ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            mSurfaceListener.onSurfaceChanged(this, width, height);
1261ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
1271ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
1281ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1291ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
1301ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    public void surfaceDestroyed(SurfaceHolder holder) {
1311ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        // After we return from this we can't use the surface any more
1321ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        mSurface = null;
1331ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (mSurfaceListener != null) {
1341ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            mSurfaceListener.onSurfaceDestroyed(this);
1351ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
1361ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
1371ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1381ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    @Override
1391ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1401ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        int videoWidth = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoWidth();
1411ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        int videoHeight = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoHeight();
1421ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (DEBUG) {
1431ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            Log.d(TAG, "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
1441ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                    + MeasureSpec.toString(heightMeasureSpec) + ")");
1451ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight());
1461ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            Log.i(TAG, " viewSize: " + getWidth() + "/" + getHeight());
1471ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            Log.i(TAG, " mVideoWidth/height: " + videoWidth + ", " + videoHeight);
1481ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
1491ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1501ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        int width = getDefaultSize(videoWidth, widthMeasureSpec);
1511ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        int height = getDefaultSize(videoHeight, heightMeasureSpec);
1521ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1531ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (videoWidth > 0 && videoHeight > 0) {
1541ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
1551ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
1561ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1571ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            width = widthSpecSize;
1581ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            height = heightSpecSize;
1591ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang
1601ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            // for compatibility, we adjust size based on aspect ratio
1611ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            if (videoWidth * height < width * videoHeight) {
1621ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                width = height * videoWidth / videoHeight;
1631ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                if (DEBUG) {
1641ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                    Log.d(TAG, "image too wide, correcting. width: " + width);
1651ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                }
1661ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            } else if (videoWidth * height > width * videoHeight) {
1671ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                height = width * videoHeight / videoWidth;
1681ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                if (DEBUG) {
1691ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                    Log.d(TAG, "image too tall, correcting. height: " + height);
1701ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang                }
1711ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            }
1721ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        } else {
1731ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            // no size yet, just adopt the given spec sizes
1741ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
1751ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        setMeasuredDimension(width, height);
1761ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        if (DEBUG) {
1771ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            Log.i(TAG, "end of onMeasure()");
1781ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang            Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight());
1791ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang        }
1801ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang    }
1811ed376b73eeaea2ba6211cde50575bf9734ff705Insun Kang}
182