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