Home | History | Annotate | Download | only in media
      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 com.example.androidx.media;
     18 
     19 import android.annotation.SuppressLint;
     20 import android.app.Activity;
     21 import android.app.AlertDialog;
     22 import android.content.Context;
     23 import android.content.DialogInterface;
     24 import android.content.Intent;
     25 import android.content.res.Configuration;
     26 import android.net.Uri;
     27 import android.os.Bundle;
     28 import android.support.v4.media.session.MediaControllerCompat;
     29 import android.support.v4.media.session.PlaybackStateCompat;
     30 import android.util.AttributeSet;
     31 import android.util.Log;
     32 import android.view.KeyEvent;
     33 import android.view.MotionEvent;
     34 import android.view.View;
     35 import android.view.ViewGroup;
     36 import android.view.Window;
     37 import android.view.WindowManager;
     38 import android.widget.Toast;
     39 
     40 import androidx.fragment.app.FragmentActivity;
     41 import androidx.media.widget.MediaControlView2;
     42 import androidx.media.widget.VideoView2;
     43 
     44 /**
     45  * Test application for VideoView2/MediaControlView2
     46  */
     47 @SuppressLint("NewApi")
     48 public class VideoViewTest extends FragmentActivity {
     49     public static final String LOOPING_EXTRA_NAME =
     50             "com.example.androidx.media.VideoViewTest.IsLooping";
     51     public static final String USE_TEXTURE_VIEW_EXTRA_NAME =
     52             "com.example.androidx.media.VideoViewTest.UseTextureView";
     53     public static final String MEDIA_TYPE_ADVERTISEMENT =
     54             "com.example.androidx.media.VideoViewTest.MediaTypeAdvertisement";
     55     private static final String TAG = "VideoViewTest";
     56 
     57     private MyVideoView mVideoView = null;
     58     private float mSpeed = 1.0f;
     59 
     60     private MediaControlView2 mMediaControlView = null;
     61 
     62     private boolean mUseTextureView = false;
     63     private int mPrevWidth;
     64     private int mPrevHeight;
     65 
     66     @Override
     67     public void onCreate(Bundle savedInstanceState) {
     68         super.onCreate(savedInstanceState);
     69 
     70         //Remove title bar
     71         requestWindowFeature(Window.FEATURE_NO_TITLE);
     72 
     73         setContentView(R.layout.video_activity);
     74 
     75         mVideoView = findViewById(R.id.video_view);
     76         mVideoView.setActivity(this);
     77 
     78         String errorString = null;
     79         Intent intent = getIntent();
     80         Uri contentUri;
     81         if (intent == null || (contentUri = intent.getData()) == null || !contentUri.isAbsolute()) {
     82             errorString = "Invalid intent";
     83         } else {
     84             mUseTextureView = intent.getBooleanExtra(USE_TEXTURE_VIEW_EXTRA_NAME, false);
     85             if (mUseTextureView) {
     86                 mVideoView.setViewType(VideoView2.VIEW_TYPE_TEXTUREVIEW);
     87             }
     88             mVideoView.setVideoUri(contentUri);
     89 
     90             mMediaControlView = new MediaControlView2(this);
     91             mVideoView.setMediaControlView2(mMediaControlView, 2000);
     92             mMediaControlView.setOnFullScreenListener(new FullScreenListener());
     93         }
     94         if (errorString != null) {
     95             showErrorDialog(errorString);
     96         }
     97     }
     98 
     99     @Override
    100     protected void onResume() {
    101         super.onResume();
    102         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    103         if (mVideoView.isAttachedToWindow()) {
    104             mVideoView.getMediaController().getTransportControls().play();
    105             mVideoView.getMediaController().registerCallback(mMediaControllerCallback);
    106         } else {
    107             mVideoView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
    108                 @Override
    109                 public void onViewAttachedToWindow(View v) {
    110                     mVideoView.getMediaController().getTransportControls().play();
    111                     mVideoView.getMediaController().registerCallback(mMediaControllerCallback);
    112                 }
    113 
    114                 @Override
    115                 public void onViewDetachedFromWindow(View v) {
    116                     // No need to remove callback here since MediaSession has already been
    117                     // destroyed.
    118                 }
    119             });
    120         }
    121         setTitle(getViewTypeString(mVideoView));
    122     }
    123 
    124     @Override
    125     protected void onPause() {
    126         mVideoView.getMediaController().getTransportControls().pause();
    127         getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    128         super.onPause();
    129     }
    130 
    131     @Override
    132     protected void onDestroy() {
    133         Log.d(TAG, "onDestroy");
    134         mVideoView.getMediaController().unregisterCallback(mMediaControllerCallback);
    135         mVideoView.getMediaController().getTransportControls().stop();
    136         super.onDestroy();
    137     }
    138 
    139     @Override
    140     public boolean onTouchEvent(MotionEvent ev) {
    141         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    142             int screenWidth = getResources().getDisplayMetrics().widthPixels;
    143             if (ev.getRawX() < (screenWidth / 2.0f)) {
    144                 // TODO: getSpeed() not needed?
    145                 mSpeed -= 0.1f;
    146             } else {
    147                 mSpeed += 0.1f;
    148             }
    149             mVideoView.setSpeed(mSpeed);
    150             Toast.makeText(this, "speed rate: " + String.format("%.2f", mSpeed), Toast.LENGTH_SHORT)
    151                     .show();
    152         }
    153         return super.onTouchEvent(ev);
    154     }
    155 
    156     private void showErrorDialog(String errorMessage) {
    157         AlertDialog.Builder builder = new AlertDialog.Builder(this);
    158         builder.setTitle("Playback error")
    159                 .setMessage(errorMessage)
    160                 .setCancelable(false)
    161                 .setPositiveButton("OK",
    162                         new DialogInterface.OnClickListener() {
    163                             @Override
    164                             public void onClick(DialogInterface dialogInterface, int i) {
    165                                 finish();
    166                             }
    167                         }).show();
    168     }
    169 
    170     MediaControllerCompat.Callback mMediaControllerCallback = new MediaControllerCompat.Callback() {
    171         @Override
    172         public void onPlaybackStateChanged(PlaybackStateCompat state) {
    173             switch (state.getState()) {
    174                 case PlaybackStateCompat.STATE_STOPPED:
    175                     getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    176                     break;
    177                 case PlaybackStateCompat.STATE_ERROR:
    178                     showErrorDialog("Error: (" + state.getErrorMessage() + ")");
    179                     break;
    180             }
    181         }
    182     };
    183 
    184     private class FullScreenListener
    185             implements MediaControlView2.OnFullScreenListener {
    186         @Override
    187         public void onFullScreen(View view, boolean fullScreen) {
    188             // TODO: Remove bottom controls after adding back button functionality.
    189             if (mPrevHeight == 0 && mPrevWidth == 0) {
    190                 ViewGroup.LayoutParams params = mVideoView.getLayoutParams();
    191                 mPrevWidth = params.width;
    192                 mPrevHeight = params.height;
    193             }
    194 
    195             if (fullScreen) {
    196                 // Remove notification bar
    197                 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
    198                         WindowManager.LayoutParams.FLAG_FULLSCREEN);
    199 
    200                 ViewGroup.LayoutParams params = mVideoView.getLayoutParams();
    201                 params.width = ViewGroup.LayoutParams.MATCH_PARENT;
    202                 params.height = ViewGroup.LayoutParams.MATCH_PARENT;
    203                 mVideoView.setLayoutParams(params);
    204             } else {
    205                 // Restore notification bar
    206                 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    207 
    208                 ViewGroup.LayoutParams params = mVideoView.getLayoutParams();
    209                 params.width = mPrevWidth;
    210                 params.height = mPrevHeight;
    211                 mVideoView.setLayoutParams(params);
    212             }
    213             mVideoView.requestLayout();
    214             mVideoView.invalidate();
    215         }
    216     }
    217 
    218     /**
    219      * Extension of the stock android video view used to hook and override
    220      * keypress behavior.  Mainly used to make sure that certain keystrokes
    221      * don't automatically bring up the andriod MediaController widget (which
    222      * then steals focus)
    223      *
    224      * @author johngro (at) google.com (John Grossman)
    225      */
    226     public static class MyVideoView extends VideoView2 {
    227         private float mDX;
    228         private float mDY;
    229         private Activity mActivity;
    230 
    231         public MyVideoView(Context context) {
    232             super(context);
    233         }
    234 
    235         public MyVideoView(Context context, AttributeSet attrs) {
    236             super(context, attrs);
    237         }
    238 
    239         public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
    240             super(context, attrs, defStyle);
    241         }
    242 
    243         @Override
    244         public boolean onTouchEvent(MotionEvent ev) {
    245             switch (ev.getAction()) {
    246                 case MotionEvent.ACTION_DOWN:
    247                     mDX = ev.getRawX() - getX();
    248                     mDY = ev.getRawY() - getY();
    249                     super.onTouchEvent(ev);
    250                     return true;
    251                 case MotionEvent.ACTION_MOVE:
    252                     animate()
    253                             .x(ev.getRawX() - mDX)
    254                             .y(ev.getRawY() - mDY)
    255                             .setDuration(0)
    256                             .start();
    257                     super.onTouchEvent(ev);
    258                     return true;
    259             }
    260             return super.onTouchEvent(ev);
    261         }
    262 
    263         @Override
    264         public boolean onKeyDown(int keyCode, KeyEvent event)  {
    265             if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
    266                 mActivity.finish();
    267             }
    268             return true;
    269         }
    270 
    271         public void setActivity(Activity activity) {
    272             mActivity = activity;
    273         }
    274     }
    275 
    276     @Override
    277     public void onConfigurationChanged(Configuration newConfig) {
    278         super.onConfigurationChanged(newConfig);
    279         if (mVideoView.getViewType() == VideoView2.VIEW_TYPE_SURFACEVIEW) {
    280             mVideoView.setViewType(VideoView2.VIEW_TYPE_TEXTUREVIEW);
    281             Toast.makeText(this, "switch to TextureView", Toast.LENGTH_SHORT).show();
    282             setTitle(getViewTypeString(mVideoView));
    283         } else if (mVideoView.getViewType() == VideoView2.VIEW_TYPE_TEXTUREVIEW) {
    284             mVideoView.setViewType(VideoView2.VIEW_TYPE_SURFACEVIEW);
    285             Toast.makeText(this, "switch to SurfaceView", Toast.LENGTH_SHORT).show();
    286             setTitle(getViewTypeString(mVideoView));
    287         }
    288     }
    289 
    290     private String getViewTypeString(VideoView2 videoView) {
    291         if (videoView == null) {
    292             return "Unknown";
    293         }
    294         int type = videoView.getViewType();
    295         if (type == VideoView2.VIEW_TYPE_SURFACEVIEW) {
    296             return "SurfaceView";
    297         } else if (type == VideoView2.VIEW_TYPE_TEXTUREVIEW) {
    298             return "TextureView";
    299         }
    300         return "Unknown";
    301     }
    302 }
    303