1 /* 2 * Copyright 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 17 package com.android.managedprovisioning.common; 18 19 import android.accounts.Account; 20 import android.content.ComponentName; 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.net.Uri; 24 import android.os.PersistableBundle; 25 import android.util.Base64; 26 import java.io.ByteArrayOutputStream; 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.io.FileOutputStream; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.util.IllformedLocaleException; 34 import java.util.Locale; 35 import java.util.function.Function; 36 37 /** 38 * Class with Utils methods to store values in xml files, and to convert various 39 * types to and from string. 40 */ 41 public class StoreUtils { 42 public static final String ATTR_VALUE = "value"; 43 44 /** 45 * Directory name under parent directory {@link Context#getFilesDir()} 46 * It's directory to cache all files / uri from external provisioning intent. 47 * Files must be prefixed by their own prefixes to avoid collisions. 48 */ 49 public static final String DIR_PROVISIONING_PARAMS_FILE_CACHE = 50 "provisioning_params_file_cache"; 51 52 private static final String ATTR_ACCOUNT_NAME = "account-name"; 53 private static final String ATTR_ACCOUNT_TYPE = "account-type"; 54 55 /** 56 * Reads an account from a {@link PersistableBundle}. 57 */ persistableBundleToAccount(PersistableBundle bundle)58 public static Account persistableBundleToAccount(PersistableBundle bundle) { 59 return new Account( 60 bundle.getString(ATTR_ACCOUNT_NAME), 61 bundle.getString(ATTR_ACCOUNT_TYPE)); 62 } 63 64 /** 65 * Writes an account to a {@link PersistableBundle}. 66 */ accountToPersistableBundle(Account account)67 public static PersistableBundle accountToPersistableBundle(Account account) { 68 final PersistableBundle bundle = new PersistableBundle(); 69 bundle.putString(ATTR_ACCOUNT_NAME, account.name); 70 bundle.putString(ATTR_ACCOUNT_TYPE, account.type); 71 return bundle; 72 } 73 74 /** 75 * Serialize ComponentName. 76 */ componentNameToString(ComponentName componentName)77 public static String componentNameToString(ComponentName componentName) { 78 return componentName == null ? null 79 : componentName.getPackageName() + "/" + componentName.getClassName(); 80 } 81 82 /** 83 * Deserialize ComponentName. 84 * Don't use {@link ComponentName#unflattenFromString(String)}, because it doesn't keep 85 * original class name 86 */ stringToComponentName(String str)87 public static ComponentName stringToComponentName(String str) { 88 int sep = str.indexOf('/'); 89 if (sep < 0 || (sep+1) >= str.length()) { 90 return null; 91 } 92 String pkg = str.substring(0, sep); 93 String cls = str.substring(sep+1); 94 return new ComponentName(pkg, cls); 95 } 96 97 /** 98 * Converts a String to a Locale. 99 */ stringToLocale(String string)100 public static Locale stringToLocale(String string) throws IllformedLocaleException { 101 if (string != null) { 102 return new Locale.Builder().setLanguageTag(string.replace("_", "-")).build(); 103 } else { 104 return null; 105 } 106 } 107 108 /** 109 * Converts a Locale to a String. 110 */ localeToString(Locale locale)111 public static String localeToString(Locale locale) { 112 if (locale != null) { 113 return locale.getLanguage() + "_" + locale.getCountry(); 114 } else { 115 return null; 116 } 117 } 118 119 /** 120 * Transforms a string into a byte array. 121 * 122 * @param s the string to be transformed 123 */ stringToByteArray(String s)124 public static byte[] stringToByteArray(String s) 125 throws NumberFormatException { 126 try { 127 return Base64.decode(s, Base64.URL_SAFE); 128 } catch (IllegalArgumentException e) { 129 throw new NumberFormatException("Incorrect format. Should be Url-safe Base64 encoded."); 130 } 131 } 132 133 /** 134 * Transforms a byte array into a string. 135 * 136 * @param bytes the byte array to be transformed 137 */ byteArrayToString(byte[] bytes)138 public static String byteArrayToString(byte[] bytes) { 139 return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP); 140 } 141 putIntegerIfNotNull(PersistableBundle bundle, String attrName, Integer integer)142 public static void putIntegerIfNotNull(PersistableBundle bundle, String attrName, 143 Integer integer) { 144 if (integer != null) { 145 bundle.putInt(attrName, integer); 146 } 147 } 148 putPersistableBundlableIfNotNull(PersistableBundle bundle, String attrName, PersistableBundlable bundlable)149 public static void putPersistableBundlableIfNotNull(PersistableBundle bundle, String attrName, 150 PersistableBundlable bundlable) { 151 if (bundlable != null) { 152 bundle.putPersistableBundle(attrName, bundlable.toPersistableBundle()); 153 } 154 } 155 getObjectAttrFromPersistableBundle(PersistableBundle bundle, String attrName, Function<PersistableBundle, E> converter)156 public static <E> E getObjectAttrFromPersistableBundle(PersistableBundle bundle, 157 String attrName, Function<PersistableBundle, E> converter) { 158 final PersistableBundle attrBundle = bundle.getPersistableBundle(attrName); 159 return attrBundle == null ? null : converter.apply(attrBundle); 160 } 161 getStringAttrFromPersistableBundle(PersistableBundle bundle, String attrName, Function<String, E> converter)162 public static <E> E getStringAttrFromPersistableBundle(PersistableBundle bundle, 163 String attrName, Function<String, E> converter) { 164 final String str = bundle.getString(attrName); 165 return str == null ? null : converter.apply(str); 166 } 167 getIntegerAttrFromPersistableBundle(PersistableBundle bundle, String attrName)168 public static Integer getIntegerAttrFromPersistableBundle(PersistableBundle bundle, 169 String attrName) { 170 return bundle.containsKey(attrName) ? bundle.getInt(attrName) : null; 171 } 172 173 /** 174 * @return true if successfully copy the uri into the file. Otherwise, the outputFile will not 175 * be created. 176 */ copyUriIntoFile(ContentResolver cr, Uri uri, File outputFile)177 public static boolean copyUriIntoFile(ContentResolver cr, Uri uri, File outputFile) { 178 try (final InputStream in = cr.openInputStream(uri)) { // Throws SecurityException 179 try (final FileOutputStream out = new FileOutputStream(outputFile)) { 180 copyStream(in, out); 181 } 182 ProvisionLogger.logi("Successfully copy from uri " + uri + " to " + outputFile); 183 return true; 184 } catch (IOException | SecurityException e) { 185 ProvisionLogger.logi("Could not write file from " + uri + " to " 186 + outputFile, e); 187 // If the file was only partly written, delete it. 188 outputFile.delete(); 189 return false; 190 } 191 } 192 readString(File file)193 public static String readString(File file) throws IOException { 194 try (final InputStream in = new FileInputStream(file)) { 195 try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) { 196 copyStream(in, out); 197 return out.toString(); 198 } 199 } 200 } 201 copyStream(final InputStream in, final OutputStream out)202 public static void copyStream(final InputStream in, 203 final OutputStream out) throws IOException { 204 final byte buffer[] = new byte[1024]; 205 int bytesReadCount; 206 while ((bytesReadCount = in.read(buffer)) != -1) { 207 out.write(buffer, 0, bytesReadCount); 208 } 209 } 210 211 public interface TextFileReader { read(File file)212 String read(File file) throws IOException; 213 } 214 }