1 /* 2 * Copyright 2018 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 17 package androidx.media.widget; 18 19 import static androidx.media.widget.VideoView2.VIEW_TYPE_SURFACEVIEW; 20 21 import android.content.Context; 22 import android.graphics.Rect; 23 import android.media.MediaPlayer; 24 import android.util.Log; 25 import android.view.SurfaceHolder; 26 import android.view.SurfaceView; 27 import android.view.View; 28 29 import androidx.annotation.NonNull; 30 import androidx.annotation.RequiresApi; 31 32 @RequiresApi(21) 33 class VideoSurfaceViewWithMp1 extends SurfaceView 34 implements VideoViewInterfaceWithMp1, SurfaceHolder.Callback { 35 private static final String TAG = "VideoSurfaceViewWithMp1"; 36 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 37 private SurfaceHolder mSurfaceHolder = null; 38 private SurfaceListener mSurfaceListener = null; 39 private MediaPlayer mMediaPlayer; 40 // A flag to indicate taking over other view should be proceed. 41 private boolean mIsTakingOverOldView; 42 private VideoViewInterfaceWithMp1 mOldView; 43 44 VideoSurfaceViewWithMp1(Context context) { 45 super(context, null); 46 getHolder().addCallback(this); 47 } 48 49 //////////////////////////////////////////////////// 50 // implements VideoViewInterfaceWithMp1 51 //////////////////////////////////////////////////// 52 53 @Override 54 public boolean assignSurfaceToMediaPlayer(MediaPlayer mp) { 55 Log.d(TAG, "assignSurfaceToMediaPlayer(): mSurfaceHolder: " + mSurfaceHolder); 56 if (mp == null || !hasAvailableSurface()) { 57 return false; 58 } 59 mp.setDisplay(mSurfaceHolder); 60 return true; 61 } 62 63 @Override 64 public void setSurfaceListener(SurfaceListener l) { 65 mSurfaceListener = l; 66 } 67 68 @Override 69 public int getViewType() { 70 return VIEW_TYPE_SURFACEVIEW; 71 } 72 73 @Override 74 public void setMediaPlayer(MediaPlayer mp) { 75 mMediaPlayer = mp; 76 if (mIsTakingOverOldView) { 77 takeOver(mOldView); 78 } 79 } 80 81 @Override 82 public void takeOver(@NonNull VideoViewInterfaceWithMp1 oldView) { 83 if (assignSurfaceToMediaPlayer(mMediaPlayer)) { 84 ((View) oldView).setVisibility(GONE); 85 mIsTakingOverOldView = false; 86 mOldView = null; 87 if (mSurfaceListener != null) { 88 mSurfaceListener.onSurfaceTakeOverDone(this); 89 } 90 } else { 91 mIsTakingOverOldView = true; 92 mOldView = oldView; 93 } 94 } 95 96 @Override 97 public boolean hasAvailableSurface() { 98 return (mSurfaceHolder != null && mSurfaceHolder.getSurface() != null); 99 } 100 101 //////////////////////////////////////////////////// 102 // implements SurfaceHolder.Callback 103 //////////////////////////////////////////////////// 104 105 @Override 106 public void surfaceCreated(SurfaceHolder holder) { 107 Log.d(TAG, "surfaceCreated: mSurfaceHolder: " + mSurfaceHolder + ", new holder: " + holder); 108 mSurfaceHolder = holder; 109 if (mIsTakingOverOldView) { 110 takeOver(mOldView); 111 } else { 112 assignSurfaceToMediaPlayer(mMediaPlayer); 113 } 114 115 if (mSurfaceListener != null) { 116 Rect rect = mSurfaceHolder.getSurfaceFrame(); 117 mSurfaceListener.onSurfaceCreated(this, rect.width(), rect.height()); 118 } 119 } 120 121 @Override 122 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 123 if (mSurfaceListener != null) { 124 mSurfaceListener.onSurfaceChanged(this, width, height); 125 } 126 } 127 128 @Override 129 public void surfaceDestroyed(SurfaceHolder holder) { 130 // After we return from this we can't use the surface any more 131 mSurfaceHolder = null; 132 if (mSurfaceListener != null) { 133 mSurfaceListener.onSurfaceDestroyed(this); 134 } 135 } 136 137 @Override 138 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 139 int videoWidth = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoWidth(); 140 int videoHeight = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoHeight(); 141 if (DEBUG) { 142 Log.d(TAG, "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " 143 + MeasureSpec.toString(heightMeasureSpec) + ")"); 144 Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight()); 145 Log.i(TAG, " viewSize: " + getWidth() + "/" + getHeight()); 146 Log.i(TAG, " mVideoWidth/height: " + videoWidth + ", " + videoHeight); 147 } 148 149 int width = getDefaultSize(videoWidth, widthMeasureSpec); 150 int height = getDefaultSize(videoHeight, heightMeasureSpec); 151 152 if (videoWidth > 0 && videoHeight > 0) { 153 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 154 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 155 156 width = widthSpecSize; 157 height = heightSpecSize; 158 159 // for compatibility, we adjust size based on aspect ratio 160 if (videoWidth * height < width * videoHeight) { 161 width = height * videoWidth / videoHeight; 162 if (DEBUG) { 163 Log.d(TAG, "image too wide, correcting. width: " + width); 164 } 165 } else if (videoWidth * height > width * videoHeight) { 166 height = width * videoHeight / videoWidth; 167 if (DEBUG) { 168 Log.d(TAG, "image too tall, correcting. height: " + height); 169 } 170 } 171 } else { 172 // no size yet, just adopt the given spec sizes 173 } 174 setMeasuredDimension(width, height); 175 if (DEBUG) { 176 Log.i(TAG, "end of onMeasure()"); 177 Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight()); 178 } 179 } 180 } 181