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