1 /* 2 * Copyright (C) 2016 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 package android.mediastress.cts.preconditions.app; 17 18 import android.app.Instrumentation; 19 import android.media.MediaFormat; 20 import android.os.Bundle; 21 import android.util.Log; 22 23 import androidx.test.InstrumentationRegistry; 24 25 import com.android.compatibility.common.util.DynamicConfigDeviceSide; 26 import com.android.compatibility.common.util.MediaUtils; 27 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.JUnit4; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.regex.Matcher; 35 import java.util.regex.Pattern; 36 37 /** 38 * Test class that uses device-side media APIs to determine up to which resolution MediaPreparer 39 * should copy media files for CtsMediaStressTestCases. 40 */ 41 @RunWith(JUnit4.class) 42 public class MediaPreparerAppTest { 43 44 private static final String TAG = MediaPreparerAppTest.class.getSimpleName(); 45 46 /** The module name used to retrieve Dynamic Configuration data */ 47 private static final String MODULE_NAME = "CtsMediaStressTestCases"; 48 49 /** The default (minimum) resolution of media file to copy to the device */ 50 private static final int DEFAULT_MAX_WIDTH = 480; 51 private static final int DEFAULT_MAX_HEIGHT = 360; 52 53 /** Instrumentation status code used to write resolution to metrics */ 54 private static final int INST_STATUS_IN_PROGRESS = 2; 55 56 /** Helper class for generating and retrieving width-height pairs */ 57 private static final class Resolution { 58 // regex that matches a resolution string 59 private static final String PATTERN = "(\\d+)x(\\d+)"; 60 // group indices for accessing resolution witdh/height from a Matcher created from PATTERN 61 private static final int WIDTH_INDEX = 1; 62 private static final int HEIGHT_INDEX = 2; 63 64 private final int width; 65 private final int height; 66 Resolution(int width, int height)67 private Resolution(int width, int height) { 68 this.width = width; 69 this.height = height; 70 } 71 Resolution(String resolution)72 private Resolution(String resolution) { 73 Pattern pattern = Pattern.compile(PATTERN); 74 Matcher matcher = pattern.matcher(resolution); 75 matcher.find(); 76 this.width = Integer.parseInt(matcher.group(WIDTH_INDEX)); 77 this.height = Integer.parseInt(matcher.group(HEIGHT_INDEX)); 78 } 79 80 @Override toString()81 public String toString() { 82 return String.format("%dx%d", width, height); 83 } 84 } 85 86 @Test testGetResolutions()87 public void testGetResolutions() throws Exception { 88 String moduleName = InstrumentationRegistry.getArguments().getString("module-name"); 89 if (moduleName == null) { 90 moduleName = MODULE_NAME; 91 Log.i(TAG, "module-name argument is null. Using the default module name: " 92 + moduleName); 93 } else { 94 Log.i(TAG, "module-name is set from the argument: " + moduleName); 95 } 96 Resolution maxRes = new Resolution(DEFAULT_MAX_WIDTH, DEFAULT_MAX_HEIGHT); 97 DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(moduleName); 98 for (String key : config.keySet()) { 99 int width = 0; 100 int height = 0; 101 for (MediaFormat format : stringsToFormats(config.getValues(key))) { 102 try { 103 width = Math.max(width, format.getInteger(MediaFormat.KEY_WIDTH)); 104 height = Math.max(height, format.getInteger(MediaFormat.KEY_HEIGHT)); 105 } catch (NullPointerException | ClassCastException e) { 106 // audio format, or invalid format created by unrelated dynamic config entry 107 // simply continue in this case 108 } 109 } 110 Resolution fileResolution = new Resolution(width, height); 111 // if the file is of greater resolution than maxRes, check for support 112 if (fileResolution.width > maxRes.width) { 113 boolean supported = true; 114 for (MediaFormat format : stringsToFormats(config.getValues(key))) { 115 supported &= MediaUtils.checkDecoderForFormat(format); 116 } 117 if (supported) { 118 // update if all MediaFormats for file are supported by device 119 maxRes = fileResolution; 120 } 121 } 122 } 123 // write resolution string to metrics 124 Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 125 Bundle maxResBundle = new Bundle(); 126 maxResBundle.putString("resolution", maxRes.toString()); 127 inst.sendStatus(INST_STATUS_IN_PROGRESS, maxResBundle); 128 } 129 130 /** 131 * Converts string representations of MediaFormats into actual MediaFormats 132 * @param formatStrings a list of string representations of MediaFormats. Each input string 133 * may represent one or more MediaFormats 134 * @return a list of MediaFormats 135 */ stringsToFormats(List<String> formatStrings)136 private List<MediaFormat> stringsToFormats(List<String> formatStrings) { 137 List<MediaFormat> formats = new ArrayList<MediaFormat>(); 138 for (String formatString : formatStrings) { 139 for (String trackFormatString : formatString.split(";")) { 140 formats.add(parseTrackFormat(trackFormatString)); 141 } 142 } 143 return formats; 144 } 145 146 /** 147 * Converts a single media track format string into a MediaFormat object 148 * @param trackFormatString a string representation of the format of one media track 149 * @return a MediaFormat 150 */ parseTrackFormat(String trackFormatString)151 private static MediaFormat parseTrackFormat(String trackFormatString) { 152 MediaFormat format = new MediaFormat(); 153 format.setString(MediaFormat.KEY_MIME, ""); 154 for (String entry : trackFormatString.split(",")) { 155 String[] kv = entry.split("="); 156 if (kv.length < 2) { 157 continue; 158 } 159 String k = kv[0]; 160 String v = kv[1]; 161 try { 162 format.setInteger(k, Integer.parseInt(v)); 163 } catch(NumberFormatException e) { 164 format.setString(k, v); 165 } 166 } 167 return format; 168 } 169 } 170