2021-06-27 20:44:35 +00:00
|
|
|
package androidx.browser.browseractions;
|
|
|
|
|
|
|
|
import android.content.ClipData;
|
|
|
|
import android.content.ContentResolver;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.BitmapFactory;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.os.AsyncTask;
|
|
|
|
import android.os.Build;
|
|
|
|
import android.os.ParcelFileDescriptor;
|
|
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import androidx.annotation.RestrictTo;
|
|
|
|
import androidx.annotation.UiThread;
|
|
|
|
import androidx.concurrent.futures.ResolvableFuture;
|
|
|
|
import androidx.core.content.FileProvider;
|
|
|
|
import androidx.core.util.AtomicFile;
|
|
|
|
import c.d.b.a.a;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
@RestrictTo({RestrictTo.Scope.LIBRARY})
|
|
|
|
@Deprecated
|
|
|
|
public final class BrowserServiceFileProvider extends FileProvider {
|
|
|
|
private static final String AUTHORITY_SUFFIX = ".image_provider";
|
|
|
|
private static final String CLIP_DATA_LABEL = "image_provider_uris";
|
|
|
|
private static final String CONTENT_SCHEME = "content";
|
|
|
|
private static final String FILE_EXTENSION = ".png";
|
|
|
|
private static final String FILE_SUB_DIR = "image_provider";
|
|
|
|
private static final String FILE_SUB_DIR_NAME = "image_provider_images/";
|
|
|
|
private static final String LAST_CLEANUP_TIME_KEY = "last_cleanup_time";
|
|
|
|
private static final String TAG = "BrowserServiceFP";
|
|
|
|
public static Object sFileCleanupLock = new Object();
|
|
|
|
|
|
|
|
/* renamed from: androidx.browser.browseractions.BrowserServiceFileProvider$1 reason: invalid class name */
|
|
|
|
public class AnonymousClass1 implements Runnable {
|
|
|
|
public final /* synthetic */ ContentResolver val$resolver;
|
|
|
|
public final /* synthetic */ ResolvableFuture val$result;
|
|
|
|
public final /* synthetic */ Uri val$uri;
|
|
|
|
|
|
|
|
public AnonymousClass1(ContentResolver contentResolver, Uri uri, ResolvableFuture resolvableFuture) {
|
|
|
|
this.val$resolver = contentResolver;
|
|
|
|
this.val$uri = uri;
|
|
|
|
this.val$result = resolvableFuture;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // java.lang.Runnable
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
ParcelFileDescriptor openFileDescriptor = this.val$resolver.openFileDescriptor(this.val$uri, "r");
|
|
|
|
if (openFileDescriptor == null) {
|
|
|
|
this.val$result.setException(new FileNotFoundException());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Bitmap decodeFileDescriptor = BitmapFactory.decodeFileDescriptor(openFileDescriptor.getFileDescriptor());
|
|
|
|
openFileDescriptor.close();
|
|
|
|
if (decodeFileDescriptor == null) {
|
|
|
|
this.val$result.setException(new IOException("File could not be decoded."));
|
|
|
|
} else {
|
|
|
|
this.val$result.set(decodeFileDescriptor);
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
this.val$result.setException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class FileCleanupTask extends AsyncTask<Void, Void, Void> {
|
|
|
|
private static final long CLEANUP_REQUIRED_TIME_SPAN;
|
|
|
|
private static final long DELETION_FAILED_REATTEMPT_DURATION;
|
|
|
|
private static final long IMAGE_RETENTION_DURATION;
|
|
|
|
private final Context mAppContext;
|
|
|
|
|
|
|
|
static {
|
|
|
|
TimeUnit timeUnit = TimeUnit.DAYS;
|
|
|
|
IMAGE_RETENTION_DURATION = timeUnit.toMillis(7);
|
|
|
|
CLEANUP_REQUIRED_TIME_SPAN = timeUnit.toMillis(7);
|
|
|
|
DELETION_FAILED_REATTEMPT_DURATION = timeUnit.toMillis(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public FileCleanupTask(Context context) {
|
|
|
|
this.mAppContext = context.getApplicationContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean isImageFile(File file) {
|
|
|
|
return file.getName().endsWith("..png");
|
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean shouldCleanUp(SharedPreferences sharedPreferences) {
|
2021-08-09 22:51:56 +00:00
|
|
|
return System.currentTimeMillis() > sharedPreferences.getLong(BrowserServiceFileProvider.LAST_CLEANUP_TIME_KEY, System.currentTimeMillis()) + CLEANUP_REQUIRED_TIME_SPAN;
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public Void doInBackground(Void... voidArr) {
|
2021-08-09 22:51:56 +00:00
|
|
|
SharedPreferences sharedPreferences = this.mAppContext.getSharedPreferences(this.mAppContext.getPackageName() + BrowserServiceFileProvider.AUTHORITY_SUFFIX, 0);
|
2021-06-27 20:44:35 +00:00
|
|
|
if (!shouldCleanUp(sharedPreferences)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
synchronized (BrowserServiceFileProvider.sFileCleanupLock) {
|
2021-08-09 22:51:56 +00:00
|
|
|
File file = new File(this.mAppContext.getFilesDir(), BrowserServiceFileProvider.FILE_SUB_DIR);
|
2021-06-27 20:44:35 +00:00
|
|
|
if (!file.exists()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
File[] listFiles = file.listFiles();
|
|
|
|
long currentTimeMillis = System.currentTimeMillis() - IMAGE_RETENTION_DURATION;
|
|
|
|
boolean z2 = true;
|
|
|
|
for (File file2 : listFiles) {
|
|
|
|
if (isImageFile(file2)) {
|
|
|
|
if (file2.lastModified() < currentTimeMillis && !file2.delete()) {
|
2021-08-09 22:51:56 +00:00
|
|
|
Log.e(BrowserServiceFileProvider.TAG, "Fail to delete image: " + file2.getAbsoluteFile());
|
2021-06-27 20:44:35 +00:00
|
|
|
z2 = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
long currentTimeMillis2 = z2 ? System.currentTimeMillis() : (System.currentTimeMillis() - CLEANUP_REQUIRED_TIME_SPAN) + DELETION_FAILED_REATTEMPT_DURATION;
|
|
|
|
SharedPreferences.Editor edit = sharedPreferences.edit();
|
2021-08-09 22:51:56 +00:00
|
|
|
edit.putLong(BrowserServiceFileProvider.LAST_CLEANUP_TIME_KEY, currentTimeMillis2);
|
2021-06-27 20:44:35 +00:00
|
|
|
edit.apply();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class FileSaveTask extends AsyncTask<String, Void, Void> {
|
|
|
|
private final Context mAppContext;
|
|
|
|
private final Bitmap mBitmap;
|
|
|
|
private final Uri mFileUri;
|
|
|
|
private final String mFilename;
|
|
|
|
private final ResolvableFuture<Uri> mResultFuture;
|
|
|
|
|
|
|
|
public FileSaveTask(Context context, String str, Bitmap bitmap, Uri uri, ResolvableFuture<Uri> resolvableFuture) {
|
|
|
|
this.mAppContext = context.getApplicationContext();
|
|
|
|
this.mFilename = str;
|
|
|
|
this.mBitmap = bitmap;
|
|
|
|
this.mFileUri = uri;
|
|
|
|
this.mResultFuture = resolvableFuture;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void saveFileBlocking(File file) {
|
|
|
|
FileOutputStream fileOutputStream;
|
|
|
|
IOException e;
|
|
|
|
if (Build.VERSION.SDK_INT >= 22) {
|
|
|
|
AtomicFile atomicFile = new AtomicFile(file);
|
|
|
|
try {
|
|
|
|
fileOutputStream = atomicFile.startWrite();
|
|
|
|
try {
|
|
|
|
this.mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
|
|
|
|
fileOutputStream.close();
|
|
|
|
atomicFile.finishWrite(fileOutputStream);
|
|
|
|
this.mResultFuture.set(this.mFileUri);
|
|
|
|
} catch (IOException e2) {
|
|
|
|
e = e2;
|
|
|
|
}
|
|
|
|
} catch (IOException e3) {
|
|
|
|
e = e3;
|
|
|
|
fileOutputStream = null;
|
|
|
|
atomicFile.failWrite(fileOutputStream);
|
|
|
|
this.mResultFuture.setException(e);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
FileOutputStream fileOutputStream2 = new FileOutputStream(file);
|
|
|
|
this.mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream2);
|
|
|
|
fileOutputStream2.close();
|
|
|
|
this.mResultFuture.set(this.mFileUri);
|
|
|
|
} catch (IOException e4) {
|
|
|
|
this.mResultFuture.setException(e4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void saveFileIfNeededBlocking() {
|
2021-08-09 22:51:56 +00:00
|
|
|
File file = new File(this.mAppContext.getFilesDir(), BrowserServiceFileProvider.FILE_SUB_DIR);
|
2021-06-27 20:44:35 +00:00
|
|
|
synchronized (BrowserServiceFileProvider.sFileCleanupLock) {
|
|
|
|
if (file.exists() || file.mkdir()) {
|
2021-08-09 22:51:56 +00:00
|
|
|
File file2 = new File(file, this.mFilename + BrowserServiceFileProvider.FILE_EXTENSION);
|
2021-06-27 20:44:35 +00:00
|
|
|
if (file2.exists()) {
|
|
|
|
this.mResultFuture.set(this.mFileUri);
|
|
|
|
} else {
|
|
|
|
saveFileBlocking(file2);
|
|
|
|
}
|
|
|
|
file2.setLastModified(System.currentTimeMillis());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.mResultFuture.setException(new IOException("Could not create file directory."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Void doInBackground(String... strArr) {
|
|
|
|
saveFileIfNeededBlocking();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onPostExecute(Void r3) {
|
|
|
|
new FileCleanupTask(this.mAppContext).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, new Void[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Uri generateUri(Context context, String str) {
|
2021-08-28 06:29:07 +00:00
|
|
|
String v = a.v(FILE_SUB_DIR_NAME, str, FILE_EXTENSION);
|
2021-08-09 22:51:56 +00:00
|
|
|
Uri.Builder scheme = new Uri.Builder().scheme(CONTENT_SCHEME);
|
2021-08-28 06:29:07 +00:00
|
|
|
return scheme.authority(context.getPackageName() + AUTHORITY_SUFFIX).path(v).build();
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void grantReadPermission(@NonNull Intent intent, @Nullable List<Uri> list, @NonNull Context context) {
|
|
|
|
if (!(list == null || list.size() == 0)) {
|
|
|
|
ContentResolver contentResolver = context.getContentResolver();
|
|
|
|
intent.addFlags(1);
|
2021-08-09 22:51:56 +00:00
|
|
|
ClipData newUri = ClipData.newUri(contentResolver, CLIP_DATA_LABEL, list.get(0));
|
2021-06-27 20:44:35 +00:00
|
|
|
for (int i = 1; i < list.size(); i++) {
|
|
|
|
newUri.addItem(new ClipData.Item(list.get(i)));
|
|
|
|
}
|
|
|
|
intent.setClipData(newUri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
public static c.i.b.d.a.a<Bitmap> loadBitmap(@NonNull ContentResolver contentResolver, @NonNull Uri uri) {
|
|
|
|
ResolvableFuture create = ResolvableFuture.create();
|
|
|
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(new AnonymousClass1(contentResolver, uri, create));
|
|
|
|
return create;
|
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
@UiThread
|
|
|
|
public static ResolvableFuture<Uri> saveBitmap(@NonNull Context context, @NonNull Bitmap bitmap, @NonNull String str, int i) {
|
2021-10-09 06:29:02 +00:00
|
|
|
StringBuilder S = a.S(str, "_");
|
|
|
|
S.append(Integer.toString(i));
|
|
|
|
String sb = S.toString();
|
2021-06-27 20:44:35 +00:00
|
|
|
Uri generateUri = generateUri(context, sb);
|
|
|
|
ResolvableFuture<Uri> create = ResolvableFuture.create();
|
|
|
|
new FileSaveTask(context, sb, bitmap, generateUri, create).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[0]);
|
|
|
|
return create;
|
|
|
|
}
|
|
|
|
}
|