1 /* 2 * Copyright (c) 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 package com.android.car.media.testmediaapp; 17 18 import android.content.ContentProvider; 19 import android.content.ContentResolver; 20 import android.content.ContentValues; 21 import android.content.res.AssetFileDescriptor; 22 import android.database.Cursor; 23 import android.net.Uri; 24 import android.os.ParcelFileDescriptor; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import com.android.car.media.testmediaapp.prefs.TmaPrefs; 29 30 import java.io.File; 31 import java.io.FileNotFoundException; 32 import java.io.FileOutputStream; 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.io.OutputStream; 36 37 public class TmaPublicProvider extends ContentProvider { 38 39 private static final String TAG = "TmaAssetProvider"; 40 41 private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; 42 43 private static final String AUTHORITY = "com.android.car.media.testmediaapp.public"; 44 45 private static final String FILES = "/files/"; 46 private static final String ASSETS = "/assets/"; 47 48 private static final String CONTENT_URI_PREFIX = 49 ContentResolver.SCHEME_CONTENT + "://" + AUTHORITY + "/"; 50 51 private static final String RESOURCE_URI_PREFIX = 52 ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + AUTHORITY + "/"; 53 54 buildUriString(String localArt)55 public static String buildUriString(String localArt) { 56 String prefix = localArt.startsWith("drawable") ? RESOURCE_URI_PREFIX : CONTENT_URI_PREFIX; 57 return prefix + localArt; 58 } 59 60 private int mAssetDelay = 0; 61 62 63 @Override openFile(Uri uri, String mode)64 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 65 String path = uri.getPath(); 66 67 if (TextUtils.isEmpty(path) || !path.startsWith(FILES)) { 68 throw new FileNotFoundException(path); 69 } 70 71 Log.i(TAG, "TmaAssetProvider#openFile uri: " + uri + " path: " + path); 72 73 File localFile = new File(getContext().getFilesDir(), path); 74 if (!localFile.exists()) { 75 downloadFile(localFile, path.substring(FILES.length())); 76 } 77 78 return ParcelFileDescriptor.open(localFile,ParcelFileDescriptor.MODE_READ_ONLY); 79 } 80 81 @Override openAssetFile(Uri uri, String mode)82 public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 83 String path = uri.getPath(); 84 if (TextUtils.isEmpty(path) || !path.startsWith(ASSETS)) { 85 // The ImageDecoder and media center code always try to open as asset first, but 86 // super delegates to openFile... 87 return super.openAssetFile(uri, mode); 88 } 89 90 Log.i(TAG, "TmaAssetProvider#openAssetFile uri: " + uri + " path: " + path); 91 92 try { 93 Thread.sleep(mAssetDelay + (int)(mAssetDelay * (Math.random()))); 94 } catch (InterruptedException ignored) { 95 } 96 97 try { 98 return getContext().getAssets().openFd(path.substring(ASSETS.length())); 99 } catch (IOException e) { 100 Log.e(TAG, "openAssetFile failed: " + e); 101 return null; 102 } 103 } 104 downloadFile(File localFile, String assetsPath)105 private void downloadFile(File localFile, String assetsPath) { 106 try { 107 localFile.getParentFile().mkdirs(); 108 109 InputStream input = getContext().getAssets().open(assetsPath); 110 OutputStream output = new FileOutputStream(localFile); 111 112 byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 113 int n; 114 while (-1 != (n = input.read(buffer))) { 115 output.write(buffer, 0, n); 116 } 117 118 } catch (IOException e) { 119 Log.e(TAG, "downloadFile failed: " + e); 120 } 121 } 122 123 @Override onCreate()124 public boolean onCreate() { 125 TmaPrefs.getInstance(getContext()).mAssetReplyDelay.registerChangeListener( 126 (oldValue, newValue) -> mAssetDelay = newValue.mReplyDelayMs); 127 return true; 128 } 129 130 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)131 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 132 String sortOrder) { 133 return null; 134 } 135 136 @Override getType(Uri uri)137 public String getType(Uri uri) { 138 return null; 139 } 140 141 @Override insert(Uri uri, ContentValues values)142 public Uri insert(Uri uri, ContentValues values) { 143 return null; 144 } 145 146 @Override delete(Uri uri, String selection, String[] selectionArgs)147 public int delete(Uri uri, String selection, String[] selectionArgs) { 148 return 0; 149 } 150 151 @Override update(Uri uri, ContentValues values, String selection, String[] selectionArgs)152 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 153 return 0; 154 } 155 } 156