Home | History | Annotate | Download | only in common
      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      */
     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      */
     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      */
     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      */
     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      */
    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      */
    111     public static String localeToString(Locale locale) {
    112         if (locale != null) {
    113             return locale.toLanguageTag();
    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      */
    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      */
    138     public static String byteArrayToString(byte[] bytes) {
    139         return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
    140     }
    141 
    142     public static void putIntegerIfNotNull(PersistableBundle bundle, String attrName,
    143             Integer integer) {
    144         if (integer != null) {
    145             bundle.putInt(attrName, integer);
    146         }
    147     }
    148 
    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 
    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 
    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 
    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      */
    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 
    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 
    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 {
    212         String read(File file) throws IOException;
    213     }
    214 }