1 /* 2 * Copyright 2019 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.car.media.testmediaapp.loader; 18 19 import android.content.Context; 20 import android.util.Log; 21 22 import androidx.annotation.Nullable; 23 24 import org.json.JSONArray; 25 import org.json.JSONException; 26 import org.json.JSONObject; 27 28 import java.io.ByteArrayOutputStream; 29 import java.io.Closeable; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.util.ArrayList; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 38 class TmaLoaderUtils { 39 40 private static final String TAG = "TmaLoaderUtils"; 41 42 /** The default buffer size to use to read files. */ 43 private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; 44 private static final String[] NO_STRINGS = {}; 45 TmaLoaderUtils()46 private TmaLoaderUtils() { 47 } 48 49 @Nullable jsonFromAsset(Context context, String assetPathName)50 static JSONObject jsonFromAsset(Context context, String assetPathName) { 51 String jsonString = stringFromAsset(context, assetPathName); 52 try { 53 return (jsonString != null) ? new JSONObject(jsonString) : null; 54 } catch (JSONException e) { 55 Log.e(TAG, "Failed to convert to json object: " + e); 56 return null; 57 } 58 } 59 60 /** Returns a map from the enum value names to the enum values. */ enumNamesToValues(T[] values)61 static <T extends Enum> Map<String, T> enumNamesToValues(T[] values) { 62 Map<String, T> result = new HashMap<>(); 63 for (T val : values) { 64 result.put(val.name(), val); 65 } 66 return result; 67 } 68 69 /** Returns the enum value mapped to the name of the given key, or fallback if missing. */ 70 @Nullable getEnum( JSONObject json, K key, Map<String, E> enumMap, E fallback)71 static <K extends Enum, E extends Enum> E getEnum( 72 JSONObject json, K key, Map<String, E> enumMap, E fallback) { 73 E result = enumMap.get(getString(json, key)); 74 return (result != null) ? result : fallback; 75 } 76 77 /** Returns the array mapped to the name of the given key, or null if missing. */ 78 @Nullable getArray(JSONObject json, T key)79 static <T extends Enum> JSONArray getArray(JSONObject json, T key) { 80 try { 81 return json.has(key.name()) ? json.getJSONArray(key.name()) : null; 82 } catch (JSONException e) { 83 Log.e(TAG, "JSONException getting array for: " + key + " e: " + e); 84 return null; 85 } 86 } 87 88 /** Returns the array mapped to the name of the given key, or empty if missing. */ getEnumArray(JSONObject json, T key, Map<String, U> enumMap)89 static <T extends Enum, U extends Enum> List<U> getEnumArray(JSONObject json, T key, 90 Map<String, U> enumMap) { 91 try { 92 JSONArray array = json.has(key.name()) ? json.getJSONArray(key.name()) : null; 93 int count = (array != null) ? array.length() : 0; 94 List<U> result = new ArrayList<>(count); 95 for (int i = 0; i < count; i++) { 96 result.add(enumMap.get(array.getString(i))); 97 } 98 return result; 99 } catch (JSONException e) { 100 Log.e(TAG, "JSONException getting array for: " + key + " e: " + e); 101 return new ArrayList<>(); 102 } 103 } 104 105 /** Returns the string mapped to the name of the given key, or null if missing. */ 106 @Nullable getString(JSONObject json, T key)107 static <T extends Enum> String getString(JSONObject json, T key) { 108 try { 109 return json.has(key.name()) ? json.getString(key.name()) : null; 110 } catch (JSONException e) { 111 Log.e(TAG, "JSONException getting string for: " + key + " e: " + e); 112 return null; 113 } 114 } 115 116 /** Returns the integer mapped to the name of the given key, or 0 if missing. */ getInt(JSONObject json, T key)117 static <T extends Enum> int getInt(JSONObject json, T key) { 118 try { 119 return json.has(key.name()) ? json.getInt(key.name()) : 0; 120 } catch (JSONException e) { 121 Log.e(TAG, "JSONException getting int for: " + key + " e: " + e); 122 return 0; 123 } 124 } 125 126 /** Takes a | separated list of flags and turns it into a bitfield value. */ parseFlags(@ullable String jsonFlags, Map<String, Integer> flagsMap)127 static int parseFlags(@Nullable String jsonFlags, Map<String, Integer> flagsMap) { 128 int result = 0; 129 String[] flags = (jsonFlags != null) ? jsonFlags.split("\\|") : NO_STRINGS; 130 for (String flag : flags) { 131 Integer value = flagsMap.get(flag); 132 if (value != null) { 133 result |= value; 134 } else { 135 Log.e(TAG, "Unknown flag: " + flag); 136 } 137 } 138 return result; 139 } 140 copy(InputStream input, OutputStream output)141 private static void copy(InputStream input, OutputStream output) throws IOException { 142 byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 143 int n; 144 while (-1 != (n = input.read(buffer))) { 145 output.write(buffer, 0, n); 146 } 147 } 148 toByteArray(InputStream input)149 private static byte[] toByteArray(InputStream input) throws IOException { 150 ByteArrayOutputStream output = new ByteArrayOutputStream(); 151 copy(input, output); 152 return output.toByteArray(); 153 } 154 155 @Nullable stringFromAsset(Context context, String assetPathName)156 private static String stringFromAsset(Context context, String assetPathName) { 157 InputStream stream = null; 158 try { 159 stream = context.getAssets().open(assetPathName); 160 if (stream == null) { 161 return null; 162 } 163 return new String(toByteArray(stream)); 164 } catch (IOException e) { 165 Log.e(TAG, "failed to load string from asset: " + e); 166 return null; 167 } finally { 168 close(stream); 169 } 170 } 171 close(@ullable Closeable closeable)172 private static void close(@Nullable Closeable closeable) { 173 if (closeable == null) { 174 return; 175 } 176 try { 177 closeable.close(); 178 } catch (IOException e) { 179 Log.e(TAG, "Error in close(): " + e); 180 } 181 } 182 } 183