• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 com.google.android.exoplayer2.transformer;
17 
18 import static com.google.android.exoplayer2.util.Assertions.checkState;
19 
20 import android.content.Context;
21 import android.os.Build;
22 import com.google.android.exoplayer2.Format;
23 import com.google.android.exoplayer2.util.Log;
24 import com.google.android.exoplayer2.util.Util;
25 import java.io.File;
26 import java.io.FileWriter;
27 import java.io.IOException;
28 import java.util.List;
29 import org.json.JSONException;
30 import org.json.JSONObject;
31 
32 /** Utilities for instrumentation tests. */
33 public final class AndroidTestUtil {
34   public static final String MP4_ASSET_URI_STRING = "asset:///media/mp4/sample.mp4";
35   public static final String MP4_ASSET_WITH_INCREASING_TIMESTAMPS_URI_STRING =
36       "asset:///media/mp4/sample_with_increasing_timestamps.mp4";
37   public static final String MP4_ASSET_SEF_URI_STRING =
38       "asset:///media/mp4/sample_sef_slow_motion.mp4";
39   public static final String MP4_REMOTE_10_SECONDS_URI_STRING =
40       "https://storage.googleapis.com/exoplayer-test-media-1/mp4/android-screens-10s.mp4";
41   /** Test clip transcoded from {@link #MP4_REMOTE_10_SECONDS_URI_STRING} with H264 and MP3. */
42   public static final String MP4_REMOTE_H264_MP3_URI_STRING =
43       "https://storage.googleapis.com/exoplayer-test-media-1/mp4/%20android-screens-10s-h264-mp3.mp4";
44 
45   public static final String MP4_REMOTE_4K60_PORTRAIT_URI_STRING =
46       "https://storage.googleapis.com/exoplayer-test-media-1/mp4/portrait_4k60.mp4";
47 
48   /**
49    * Log in logcat and in an analysis file that this test was skipped.
50    *
51    * <p>Analysis file is a JSON summarising the test, saved to the application cache.
52    *
53    * <p>The analysis json will contain a {@code skipReason} key, with the reason for skipping the
54    * test case.
55    */
recordTestSkipped(Context context, String testId, String reason)56   public static void recordTestSkipped(Context context, String testId, String reason)
57       throws JSONException, IOException {
58     Log.i(testId, reason);
59     JSONObject testJson = new JSONObject();
60     testJson.put("skipReason", reason);
61 
62     writeTestSummaryToFile(context, testId, testJson);
63   }
64 
65   /**
66    * A {@link Codec.EncoderFactory} that forces encoding, wrapping {@link DefaultEncoderFactory}.
67    */
68   public static final Codec.EncoderFactory FORCE_ENCODE_ENCODER_FACTORY =
69       new Codec.EncoderFactory() {
70         @Override
71         public Codec createForAudioEncoding(Format format, List<String> allowedMimeTypes)
72             throws TransformationException {
73           return Codec.EncoderFactory.DEFAULT.createForAudioEncoding(format, allowedMimeTypes);
74         }
75 
76         @Override
77         public Codec createForVideoEncoding(Format format, List<String> allowedMimeTypes)
78             throws TransformationException {
79           return Codec.EncoderFactory.DEFAULT.createForVideoEncoding(format, allowedMimeTypes);
80         }
81 
82         @Override
83         public boolean audioNeedsEncoding() {
84           return true;
85         }
86 
87         @Override
88         public boolean videoNeedsEncoding() {
89           return true;
90         }
91       };
92 
93   /**
94    * Returns a {@link JSONObject} containing device specific details from {@link Build}, including
95    * manufacturer, model, SDK version and build fingerprint.
96    */
getDeviceDetailsAsJsonObject()97   public static JSONObject getDeviceDetailsAsJsonObject() throws JSONException {
98     return new JSONObject()
99         .put("manufacturer", Build.MANUFACTURER)
100         .put("model", Build.MODEL)
101         .put("sdkVersion", Build.VERSION.SDK_INT)
102         .put("fingerprint", Build.FINGERPRINT);
103   }
104 
105   /**
106    * Converts an exception to a {@link JSONObject}.
107    *
108    * <p>If the exception is a {@link TransformationException}, {@code errorCode} is included.
109    */
exceptionAsJsonObject(Exception exception)110   public static JSONObject exceptionAsJsonObject(Exception exception) throws JSONException {
111     JSONObject exceptionJson = new JSONObject();
112     exceptionJson.put("message", exception.getMessage());
113     exceptionJson.put("type", exception.getClass());
114     if (exception instanceof TransformationException) {
115       exceptionJson.put("errorCode", ((TransformationException) exception).errorCode);
116     }
117     exceptionJson.put("stackTrace", Log.getThrowableString(exception));
118     return exceptionJson;
119   }
120 
121   /**
122    * Writes the summary of a test run to the application cache file.
123    *
124    * <p>The cache filename follows the pattern {@code <testId>-result.txt}.
125    *
126    * @param context The {@link Context}.
127    * @param testId A unique identifier for the transformer test run.
128    * @param testJson A {@link JSONObject} containing a summary of the test run.
129    */
writeTestSummaryToFile(Context context, String testId, JSONObject testJson)130   public static void writeTestSummaryToFile(Context context, String testId, JSONObject testJson)
131       throws IOException, JSONException {
132     testJson.put("testId", testId).put("device", getDeviceDetailsAsJsonObject());
133 
134     String analysisContents = testJson.toString(/* indentSpaces= */ 2);
135 
136     // Log contents as well as writing to file, for easier visibility on individual device testing.
137     for (String line : Util.split(analysisContents, "\n")) {
138       Log.i(testId, line);
139     }
140 
141     File analysisFile = createExternalCacheFile(context, /* fileName= */ testId + "-result.txt");
142     try (FileWriter fileWriter = new FileWriter(analysisFile)) {
143       fileWriter.write(analysisContents);
144     }
145   }
146 
147   /**
148    * Creates a {@link File} of the {@code fileName} in the application cache directory.
149    *
150    * <p>If a file of that name already exists, it is overwritten.
151    */
createExternalCacheFile(Context context, String fileName)152   /* package */ static File createExternalCacheFile(Context context, String fileName)
153       throws IOException {
154     File file = new File(context.getExternalCacheDir(), fileName);
155     checkState(!file.exists() || file.delete(), "Could not delete file: " + file.getAbsolutePath());
156     checkState(file.createNewFile(), "Could not create file: " + file.getAbsolutePath());
157     return file;
158   }
159 
AndroidTestUtil()160   private AndroidTestUtil() {}
161 }
162