Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2017 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 android.support.v4.graphics;
     18 
     19 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     20 
     21 import android.content.Context;
     22 import android.content.res.Resources;
     23 import android.os.Process;
     24 import android.support.annotation.RequiresApi;
     25 import android.support.annotation.RestrictTo;
     26 import android.util.Log;
     27 
     28 import java.io.Closeable;
     29 import java.io.File;
     30 import java.io.FileInputStream;
     31 import java.io.FileOutputStream;
     32 import java.io.IOException;
     33 import java.io.InputStream;
     34 import java.nio.ByteBuffer;
     35 import java.nio.channels.FileChannel;
     36 
     37 /**
     38  * Utility methods for TypefaceCompat.
     39  * @hide
     40  */
     41 @RestrictTo(LIBRARY_GROUP)
     42 class TypefaceCompatUtil {
     43     private static final String TAG = "TypefaceCompatUtil";
     44 
     45     private TypefaceCompatUtil() {}  // Do not instantiate.
     46 
     47     private static final String CACHE_FILE_PREFIX = ".font";
     48 
     49     /**
     50      * Creates a temp file.
     51      *
     52      * Returns null if failed to create temp file.
     53      */
     54     public static File getTempFile(Context context) {
     55         final String prefix = CACHE_FILE_PREFIX + Process.myPid() + "-" + Process.myTid() + "-";
     56         for (int i = 0; i < 100; ++i) {
     57             final File file = new File(context.getCacheDir(), prefix + i);
     58             try {
     59                 if (file.createNewFile()) {
     60                     return file;
     61                 }
     62             } catch (IOException e) {
     63                 // ignore. Try next file.
     64             }
     65         }
     66         return null;
     67     }
     68 
     69     /**
     70      * Copy the file contents to the direct byte buffer.
     71      */
     72     @RequiresApi(19)
     73     private static ByteBuffer mmap(File file) {
     74         try (FileInputStream fis = new FileInputStream(file)) {
     75             FileChannel channel = fis.getChannel();
     76             final long size = channel.size();
     77             return channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
     78         } catch (IOException e) {
     79             return null;
     80         }
     81     }
     82 
     83     /**
     84      * Copy the resource contents to the direct byte buffer.
     85      */
     86     @RequiresApi(19)
     87     public static ByteBuffer copyToDirectBuffer(Context context, Resources res, int id) {
     88         File tmpFile = getTempFile(context);
     89         if (tmpFile == null) {
     90             return null;
     91         }
     92         try {
     93             if (!copyToFile(tmpFile, res, id)) {
     94                 return null;
     95             }
     96             return mmap(tmpFile);
     97         } finally {
     98             tmpFile.delete();
     99         }
    100     }
    101 
    102     /**
    103      * Helper class for reading ByteBuffer as InputStream.
    104      */
    105     private static class ByteBufferInputStream extends InputStream {
    106         private ByteBuffer mBuf;
    107 
    108         ByteBufferInputStream(ByteBuffer buf) {
    109             mBuf = buf;
    110         }
    111 
    112         @Override
    113         public int read() {
    114             if (!mBuf.hasRemaining()) {
    115                 return -1;
    116             }
    117             return mBuf.get() & 0xFF;
    118         }
    119 
    120         @Override
    121         public int read(byte[] bytes, int off, int len) {
    122             if (!mBuf.hasRemaining()) {
    123                 return -1;
    124             }
    125             len = Math.min(len, mBuf.remaining());
    126             mBuf.get(bytes, off, len);
    127             return len;
    128         }
    129     }
    130 
    131     /**
    132      * Copy the buffer contents to file.
    133      */
    134     public static boolean copyToFile(File file, ByteBuffer buffer) {
    135         return copyToFile(file, new ByteBufferInputStream(buffer));
    136     }
    137 
    138     /**
    139      * Copy the input stream contents to file.
    140      */
    141     public static boolean copyToFile(File file, InputStream is) {
    142         FileOutputStream os = null;
    143         try {
    144             os = new FileOutputStream(file, false);
    145             byte[] buffer = new byte[1024];
    146             int readLen;
    147             while ((readLen = is.read(buffer)) != -1) {
    148                 os.write(buffer, 0, readLen);
    149             }
    150             return true;
    151         } catch (IOException e) {
    152             Log.e(TAG, "Error copying resource contents to temp file: " + e.getMessage());
    153             return false;
    154         } finally {
    155             closeQuietly(os);
    156         }
    157     }
    158 
    159     /**
    160      * Copy the resource contents to file.
    161      */
    162     public static boolean copyToFile(File file, Resources res, int id) {
    163         InputStream is = null;
    164         try {
    165             is = res.openRawResource(id);
    166             return copyToFile(file, is);
    167         } finally {
    168             closeQuietly(is);
    169         }
    170     }
    171 
    172     public static void closeQuietly(Closeable c) {
    173         if (c != null) {
    174             try {
    175                 c.close();
    176             } catch (IOException e) {
    177             }
    178         }
    179     }
    180 }
    181