1 /* 2 * Copyright (C) 2023 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.android.sdksandboxclient; 18 19 import android.app.Activity; 20 import android.net.Uri; 21 import android.os.Bundle; 22 import android.widget.Button; 23 import android.widget.EditText; 24 25 import androidx.annotation.NonNull; 26 import androidx.media3.common.AudioAttributes; 27 import androidx.media3.common.C; 28 import androidx.media3.common.MediaItem; 29 import androidx.media3.exoplayer.ExoPlayer; 30 import androidx.media3.ui.PlayerView; 31 32 /** 33 * Displays a video view in the app. This can be used to test the differences between a video ad 34 * from the sandbox vs. an app's VideoView. 35 * 36 * <p>Open this activity using the following command: adb shell am start -n 37 * com.android.sdksandboxclient/.AppVideoView --es "video-url" "[video url]" 38 */ 39 public class AppVideoView extends Activity { 40 static final String VIDEO_URL_KEY = "video-url"; 41 42 private static final String MEDIA_ITEM_KEY = "com.android.sdksandboxclient.MEDIA_ITEM_KEY"; 43 private static final String AUTO_PLAY_POSITION_KEY = 44 "com.android.sdksandboxclient.AUTO_PLAY_POSITION_KEY"; 45 private static final String AUTO_PLAY_ENABLED_KEY = 46 "com.android.sdksandboxclient.AUTO_PLAY_ENABLED_KEY"; 47 48 private PlayerView mPlayerView; 49 private EditText mVideoUrlEdit; 50 private Button mStartAppVideoButton; 51 52 private ExoPlayer mPlayer; 53 private MediaItem mCurrentMediaItem; 54 private boolean mAutoPlay; 55 private long mAutoPlayPosition; 56 57 @Override onCreate(Bundle icicle)58 public void onCreate(Bundle icicle) { 59 super.onCreate(icicle); 60 setContentView(R.layout.activity_app_video); 61 62 mPlayerView = findViewById(R.id.app_video); 63 mVideoUrlEdit = findViewById(R.id.app_video_url_edit); 64 mStartAppVideoButton = findViewById(R.id.start_app_video_button); 65 66 registerStartAppVideoButton(); 67 68 if (!restorePlaybackParams(icicle)) { 69 // No saved state, try start video from Intent params. 70 final Bundle extras = getIntent().getExtras(); 71 final String videoUrl = extras == null ? null : extras.getString(VIDEO_URL_KEY); 72 if (videoUrl != null) { 73 mVideoUrlEdit.setText(videoUrl); 74 startVideo(videoUrl); 75 } 76 } 77 } 78 79 @Override onSaveInstanceState(@onNull Bundle outState)80 protected void onSaveInstanceState(@NonNull Bundle outState) { 81 super.onSaveInstanceState(outState); 82 savePlaybackParams(outState); 83 } 84 85 @Override onStart()86 public void onStart() { 87 super.onStart(); 88 initializePlayer(); 89 mPlayerView.onResume(); 90 } 91 92 @Override onStop()93 public void onStop() { 94 super.onStop(); 95 mPlayerView.onPause(); 96 releasePlayer(); 97 } 98 registerStartAppVideoButton()99 private void registerStartAppVideoButton() { 100 mStartAppVideoButton.setOnClickListener( 101 v -> { 102 final String videoUrl = mVideoUrlEdit.getText().toString(); 103 startVideo(videoUrl); 104 }); 105 } 106 savePlaybackParams(@onNull Bundle outState)107 private void savePlaybackParams(@NonNull Bundle outState) { 108 if (mCurrentMediaItem == null) { 109 return; 110 } 111 112 final MediaItem.LocalConfiguration configuration = mCurrentMediaItem.localConfiguration; 113 if (configuration == null) { 114 return; 115 } 116 117 outState.putParcelable(MEDIA_ITEM_KEY, configuration.uri); 118 outState.putLong(AUTO_PLAY_POSITION_KEY, mAutoPlayPosition); 119 outState.putBoolean(AUTO_PLAY_ENABLED_KEY, mAutoPlay); 120 } 121 restorePlaybackParams(Bundle icicle)122 private boolean restorePlaybackParams(Bundle icicle) { 123 if (icicle == null) { 124 return false; 125 } 126 127 final Uri mediaItemUri = icicle.getParcelable(MEDIA_ITEM_KEY, Uri.class); 128 if (mediaItemUri == null) { 129 return false; 130 } 131 132 mCurrentMediaItem = MediaItem.fromUri(mediaItemUri); 133 mAutoPlayPosition = icicle.getLong(AUTO_PLAY_POSITION_KEY); 134 mAutoPlay = icicle.getBoolean(AUTO_PLAY_ENABLED_KEY); 135 136 return true; 137 } 138 startVideo(String videoUrl)139 private void startVideo(String videoUrl) { 140 mCurrentMediaItem = MediaItem.fromUri(Uri.parse(videoUrl)); 141 mAutoPlayPosition = C.TIME_UNSET; 142 mAutoPlay = true; 143 if (mPlayer != null) { 144 mPlayer.setMediaItem(mCurrentMediaItem); 145 mPlayer.prepare(); 146 mPlayer.play(); 147 } 148 } 149 initializePlayer()150 private void initializePlayer() { 151 if (mPlayer != null) { 152 return; 153 } 154 155 AudioAttributes audioAttributes = 156 new AudioAttributes.Builder() 157 .setUsage(C.USAGE_MEDIA) 158 .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE) 159 .build(); 160 161 mPlayer = new ExoPlayer.Builder(this).setAudioAttributes(audioAttributes, true).build(); 162 mPlayer.setPlayWhenReady(mAutoPlay); 163 164 mPlayerView.setPlayer(mPlayer); 165 166 if (mCurrentMediaItem != null) { 167 mPlayer.setMediaItem(mCurrentMediaItem); 168 boolean haveStartPosition = mAutoPlayPosition != C.TIME_UNSET; 169 if (haveStartPosition) { 170 mPlayer.seekTo(0, mAutoPlayPosition); 171 } 172 mPlayer.prepare(); 173 } 174 } 175 releasePlayer()176 private void releasePlayer() { 177 if (mPlayer == null) { 178 return; 179 } 180 181 mAutoPlay = mPlayer.getPlayWhenReady(); 182 mAutoPlayPosition = mPlayer.getContentPosition(); 183 184 mPlayer.release(); 185 mPlayer = null; 186 187 mPlayerView.setPlayer(null); 188 } 189 } 190