1 /* 2 * Copyright 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 android.media.cujcommon.cts; 18 19 import static org.junit.Assert.assertEquals; 20 21 import android.net.Uri; 22 import android.os.Bundle; 23 import android.view.SurfaceView; 24 import android.view.WindowManager; 25 import android.widget.ScrollView; 26 27 import androidx.appcompat.app.AppCompatActivity; 28 import androidx.media3.common.MediaItem; 29 import androidx.media3.common.Player; 30 import androidx.media3.exoplayer.ExoPlayer; 31 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.List; 35 36 public class ScrollTestActivity extends AppCompatActivity { 37 38 protected static final int SURFACE_HEIGHT = 600; /* Surface layout_height is 600dp*/ 39 protected SurfaceView mFirstSurfaceView; 40 protected SurfaceView mSecondSurfaceView; 41 protected ExoPlayer mFirstPlayer; 42 protected ExoPlayer mSecondPlayer; 43 protected static List<String> sVideoUrls = new ArrayList<>(); 44 protected Player.Listener mPlayerListener; 45 protected ScrollView mScrollView; 46 protected boolean mIsFirstSurfaceActive; 47 48 @Override onCreate(Bundle savedInstanceState)49 protected void onCreate(Bundle savedInstanceState) { 50 super.onCreate(savedInstanceState); 51 setContentView(R.layout.activity_main_scroll); 52 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 53 buildPlayer(); 54 } 55 56 /** 57 * Build the two players with two surface view and changes the surface and player according to 58 * the top position of the view. 59 */ buildPlayer()60 protected void buildPlayer() { 61 mScrollView = this.findViewById(R.id.scroll_view); 62 mFirstPlayer = new ExoPlayer.Builder(getApplicationContext()).build(); 63 mFirstSurfaceView = findViewById(R.id.firstSurface); 64 mFirstPlayer.setVideoSurfaceView(mFirstSurfaceView); 65 mSecondPlayer = new ExoPlayer.Builder(getApplicationContext()).build(); 66 mSecondSurfaceView = findViewById(R.id.secondSurface); 67 mSecondPlayer.setVideoSurfaceView(mSecondSurfaceView); 68 69 mScrollView.getViewTreeObserver().addOnScrollChangedListener(() -> { 70 if (mIsFirstSurfaceActive && mScrollView.getScrollY() >= SURFACE_HEIGHT) { 71 mFirstPlayer.pause(); 72 mIsFirstSurfaceActive = false; 73 mSecondPlayer.play(); 74 } else if (!mIsFirstSurfaceActive && mScrollView.getScrollY() < SURFACE_HEIGHT) { 75 mSecondPlayer.pause(); 76 mIsFirstSurfaceActive = true; 77 mFirstPlayer.play(); 78 } 79 }); 80 } 81 82 /** 83 * Prepare input list and add alternate urls to first and second player's playlist. 84 */ prepareMediaItems(List<String> urls)85 public void prepareMediaItems(List<String> urls) { 86 sVideoUrls = urls != null ? Collections.unmodifiableList(urls) : null; 87 if (sVideoUrls == null) { 88 return; 89 } 90 assertEquals(0, (sVideoUrls.size() % 2)); 91 for (int i = 0; i < sVideoUrls.size(); ) { 92 mFirstPlayer.addMediaItem(MediaItem.fromUri(Uri.parse(sVideoUrls.get(i++)))); 93 mSecondPlayer.addMediaItem(MediaItem.fromUri(Uri.parse(sVideoUrls.get(i++)))); 94 } 95 } 96 97 /** 98 * Prepare both players, and start the first player. 99 */ 100 @Override onStart()101 protected void onStart() { 102 super.onStart(); 103 mFirstPlayer.prepare(); 104 mSecondPlayer.prepare(); 105 mIsFirstSurfaceActive = true; 106 mFirstPlayer.play(); 107 } 108 109 /** 110 * Stop both players. 111 */ 112 @Override onStop()113 protected void onStop() { 114 mFirstPlayer.stop(); 115 mSecondPlayer.stop(); 116 super.onStop(); 117 } 118 119 /** 120 * Release the players and destroy the activity. 121 */ 122 @Override onDestroy()123 protected void onDestroy() { 124 super.onDestroy(); 125 mFirstPlayer.release(); 126 mSecondPlayer.release(); 127 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 128 } 129 130 /** 131 * Register listener to receive events from the player. 132 * 133 * <p>This method can be called from any thread. 134 * 135 * @param listener The listener to register. 136 */ addPlayerListener(Player.Listener listener)137 public void addPlayerListener(Player.Listener listener) { 138 mSecondPlayer.addListener(listener); 139 mFirstPlayer.addListener(listener); 140 this.mPlayerListener = listener; 141 } 142 143 /** 144 * Unregister a listener registered through addPlayerListener(Listener). The listener will no 145 * longer receive events. 146 */ removePlayerListener()147 public void removePlayerListener() { 148 mSecondPlayer.removeListener(this.mPlayerListener); 149 mFirstPlayer.removeListener(this.mPlayerListener); 150 } 151 } 152