1 /* 2 * Copyright (C) 2020 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.mediav2.common.cts; 18 19 import android.app.Activity; 20 import android.os.Bundle; 21 import android.os.SystemClock; 22 import android.util.Log; 23 import android.util.Pair; 24 import android.view.Surface; 25 import android.view.SurfaceHolder; 26 import android.view.SurfaceView; 27 import android.view.View; 28 import android.view.WindowManager; 29 import android.widget.LinearLayout; 30 31 import java.util.ArrayList; 32 import java.util.concurrent.TimeUnit; 33 import java.util.concurrent.locks.Condition; 34 import java.util.concurrent.locks.Lock; 35 import java.util.concurrent.locks.ReentrantLock; 36 37 public class CodecDynamicTestActivity extends Activity implements SurfaceHolder.Callback { 38 private static final String LOG_TAG = CodecDynamicTestActivity.class.getSimpleName(); 39 40 private final int mMaxSurfaces = 32; 41 private LinearLayout mLayOutList; 42 private final ArrayList<SurfaceView> mSurfaceViews = new ArrayList<>(); 43 private final ArrayList<SurfaceHolder> mHolders = new ArrayList<>(); 44 private final ArrayList<Surface> mSurfaces = new ArrayList<>(); 45 private final Lock[] mLocks = new Lock[mMaxSurfaces]; 46 private final Condition[] mConditions = new Condition[mMaxSurfaces]; 47 private final ReentrantLock mMutex = new ReentrantLock(); 48 private final boolean[] mIsUsable = new boolean[mMaxSurfaces]; 49 addSurfaceView()50 public int addSurfaceView() { 51 if (mMaxSurfaces == mSurfaceViews.size()) { 52 throw new RuntimeException("number of surfaceViews exceed preconfigured limit"); 53 } 54 View view = getLayoutInflater().inflate(R.layout.display_surface_layout, mLayOutList, 55 false); 56 SurfaceView surfaceView = view.findViewById(R.id.add_surface); 57 SurfaceHolder holder = surfaceView.getHolder(); 58 holder.addCallback(this); 59 int index = mSurfaceViews.size(); 60 mLocks[index].lock(); 61 mSurfaceViews.add(surfaceView); 62 mSurfaces.add(null); 63 mHolders.add(holder); 64 mLocks[index].unlock(); 65 runOnUiThread(() -> mLayOutList.addView(view)); 66 return index; 67 } 68 69 @Override onCreate(Bundle savedInstanceState)70 protected void onCreate(Bundle savedInstanceState) { 71 Log.v(LOG_TAG, "onCreate"); 72 super.onCreate(savedInstanceState); 73 74 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 75 setTurnScreenOn(true); 76 setShowWhenLocked(true); 77 78 setContentView(R.layout.main_layout); 79 mLayOutList = findViewById(R.id.layout_list); 80 for (int i = 0; i < mMaxSurfaces; i++) { 81 mIsUsable[i] = false; 82 mLocks[i] = new ReentrantLock(); 83 mConditions[i] = mLocks[i].newCondition(); 84 } 85 } 86 87 @Override surfaceCreated(SurfaceHolder holder)88 public void surfaceCreated(SurfaceHolder holder) { 89 Log.v(LOG_TAG, "surface created"); 90 int index = mHolders.indexOf(holder); 91 mLocks[index].lock(); 92 mSurfaces.set(index, mHolders.get(index).getSurface()); 93 mLocks[index].unlock(); 94 } 95 96 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)97 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 98 Log.v(LOG_TAG, "surface changed " + format + " " + width + " " + height); 99 } 100 101 @Override surfaceDestroyed(SurfaceHolder holder)102 public void surfaceDestroyed(SurfaceHolder holder) { 103 Log.v(LOG_TAG, "surface deleted"); 104 int index = mHolders.indexOf(holder); 105 markSurface(index, false); 106 mLocks[index].lock(); 107 mSurfaces.set(index, null); 108 mLocks[index].unlock(); 109 } 110 waitTillSurfaceIsCreated(int index)111 public void waitTillSurfaceIsCreated(int index) throws InterruptedException { 112 final long mWaitTimeMs = 1000; 113 final int retries = 3; 114 mLocks[index].lock(); 115 final long start = SystemClock.elapsedRealtime(); 116 while ((SystemClock.elapsedRealtime() - start) < (retries * mWaitTimeMs) 117 && mSurfaces.get(index) == null) { 118 mConditions[index].await(mWaitTimeMs, TimeUnit.MILLISECONDS); 119 } 120 mLocks[index].unlock(); 121 if (mSurfaces.get(index) == null) { 122 throw new InterruptedException("Taking too long to attach a SurfaceView to a window."); 123 } 124 markSurface(index, true); 125 } 126 getSurface()127 public Pair<Integer, Surface> getSurface() { 128 Pair<Integer, Surface> obj = null; 129 mMutex.lock(); 130 for (int index = 0; index < mSurfaces.size(); index++) { 131 if (mIsUsable[index]) { 132 mIsUsable[index] = false; 133 obj = Pair.create(index, mSurfaces.get(index)); 134 break; 135 } 136 } 137 mMutex.unlock(); 138 return obj; 139 } 140 markSurface(int index, boolean usable)141 public void markSurface(int index, boolean usable) { 142 mMutex.lock(); 143 mIsUsable[index] = usable; 144 mMutex.unlock(); 145 } 146 } 147