| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.support.v4.graphics; |
| |
| import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; |
| |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.net.Uri; |
| import android.os.CancellationSignal; |
| import android.os.ParcelFileDescriptor; |
| import android.os.Process; |
| import android.support.annotation.Nullable; |
| import android.support.annotation.RequiresApi; |
| import android.support.annotation.RestrictTo; |
| import android.util.Log; |
| |
| import java.io.Closeable; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.FileChannel; |
| |
| /** |
| * Utility methods for TypefaceCompat. |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP) |
| public class TypefaceCompatUtil { |
| private static final String TAG = "TypefaceCompatUtil"; |
| |
| private TypefaceCompatUtil() {} // Do not instantiate. |
| |
| private static final String CACHE_FILE_PREFIX = ".font"; |
| |
| /** |
| * Creates a temp file. |
| * |
| * Returns null if failed to create temp file. |
| */ |
| @Nullable |
| public static File getTempFile(Context context) { |
| final String prefix = CACHE_FILE_PREFIX + Process.myPid() + "-" + Process.myTid() + "-"; |
| for (int i = 0; i < 100; ++i) { |
| final File file = new File(context.getCacheDir(), prefix + i); |
| try { |
| if (file.createNewFile()) { |
| return file; |
| } |
| } catch (IOException e) { |
| // ignore. Try next file. |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Copy the file contents to the direct byte buffer. |
| */ |
| @Nullable |
| @RequiresApi(19) |
| private static ByteBuffer mmap(File file) { |
| try (FileInputStream fis = new FileInputStream(file)) { |
| FileChannel channel = fis.getChannel(); |
| final long size = channel.size(); |
| return channel.map(FileChannel.MapMode.READ_ONLY, 0, size); |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Copy the file contents to the direct byte buffer. |
| */ |
| @Nullable |
| @RequiresApi(19) |
| public static ByteBuffer mmap(Context context, CancellationSignal cancellationSignal, Uri uri) { |
| final ContentResolver resolver = context.getContentResolver(); |
| try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r", cancellationSignal); |
| FileInputStream fis = new FileInputStream(pfd.getFileDescriptor())) { |
| FileChannel channel = fis.getChannel(); |
| final long size = channel.size(); |
| return channel.map(FileChannel.MapMode.READ_ONLY, 0, size); |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Copy the resource contents to the direct byte buffer. |
| */ |
| @Nullable |
| @RequiresApi(19) |
| public static ByteBuffer copyToDirectBuffer(Context context, Resources res, int id) { |
| File tmpFile = getTempFile(context); |
| if (tmpFile == null) { |
| return null; |
| } |
| try { |
| if (!copyToFile(tmpFile, res, id)) { |
| return null; |
| } |
| return mmap(tmpFile); |
| } finally { |
| tmpFile.delete(); |
| } |
| } |
| |
| /** |
| * Copy the input stream contents to file. |
| */ |
| public static boolean copyToFile(File file, InputStream is) { |
| FileOutputStream os = null; |
| try { |
| os = new FileOutputStream(file, false); |
| byte[] buffer = new byte[1024]; |
| int readLen; |
| while ((readLen = is.read(buffer)) != -1) { |
| os.write(buffer, 0, readLen); |
| } |
| return true; |
| } catch (IOException e) { |
| Log.e(TAG, "Error copying resource contents to temp file: " + e.getMessage()); |
| return false; |
| } finally { |
| closeQuietly(os); |
| } |
| } |
| |
| /** |
| * Copy the resource contents to file. |
| */ |
| public static boolean copyToFile(File file, Resources res, int id) { |
| InputStream is = null; |
| try { |
| is = res.openRawResource(id); |
| return copyToFile(file, is); |
| } finally { |
| closeQuietly(is); |
| } |
| } |
| |
| public static void closeQuietly(Closeable c) { |
| if (c != null) { |
| try { |
| c.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| } |