Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3156)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/ChromeFileProvider.java

Issue 2143133002: Do screenshot capture async for share intents. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/ChromeFileProvider.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFileProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFileProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe0e0a69643a14b8431f72b1cdf5a41dbd51c0f6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFileProvider.java
@@ -0,0 +1,177 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.provider.MediaStore;
+import android.support.v4.content.FileProvider;
+
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+
+/**
+ * A file provider class that can share a potentially non-existent file and blocks the client
+ * application from accessing the file till it is written.
+ *
+ * This class serves as the default file provider, but also lets us share blocked files.
+ * For blocked files, it generates an unique identifier for the file to be shared and the embedder
+ * must write the file and notify that the file is ready using the unique uri generated. The client
+ * application is blocked from accessing the file till the file is ready. This provider allows only
+ * one blocked file to be shared at a given time.
+ */
+public class ChromeFileProvider extends FileProvider {
+ private static final String AUTHORITY_SUFFIX = ".FileProvider";
+ private static final String BLOCKED_FILE_PREFIX = "BlockedFile_";
+
+ // All these static objects must be accesseed in a synchronized block:
+ private static Object sLock = new Object();
+ private static boolean sIsFileReady;
+ private static Uri sCurrentBlockingUri;
+ private static Uri sFileUri;
+
+ /**
+ * Returns an unique uri to identify the file to be shared and block access to it till
+ * notifyFileReady is called.
+ *
+ * This function clobbers any uri that was previously created and the client application
+ * accessing those uri will get a null file descriptor.
+ * @param context Activity context that is used to access package manager.
+ */
+ public static Uri generateUriAndBlockAccess(final Context context) {
+ String authority = context.getPackageName() + AUTHORITY_SUFFIX;
+ String fileName = BLOCKED_FILE_PREFIX + String.valueOf(System.nanoTime());
+ Uri blockingUri =
+ new Uri.Builder().scheme("content").authority(authority).path(fileName).build();
+ synchronized (sLock) {
+ sCurrentBlockingUri = blockingUri;
+ sFileUri = null;
+ sIsFileReady = false;
+ // In case the previous file never got ready.
+ sLock.notify();
+ }
+ return blockingUri;
+ }
+
+ /**
+ * Notify that the file is ready to be accessed by the client application.
+ *
+ * @param blockingUri The unique uri that was generated by generateUriAndBlockAccess.
+ * @param fileUri The Uri for actual file given by FileProvider.
+ */
+ public static void notifyFileReady(Uri blockingUri, Uri fileUri) {
+ synchronized (sLock) {
+ sFileUri = fileUri;
+ // Ready is set only if the current file is ready.
+ sIsFileReady = doesMatchCurrentBlockingUri(blockingUri);
+ sLock.notify();
+ }
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ Uri fileUri = getFileUriWhenReady(uri);
+ return fileUri != null ? super.openFile(fileUri, mode) : null;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ Uri fileUri = getFileUriWhenReady(uri);
+ if (fileUri == null) return null;
+
+ // Workaround for a bad assumption that particular MediaStore columns exist by certain third
+ // party applications.
+ // http://crbug.com/467423.
+ Cursor source = super.query(fileUri, projection, selection, selectionArgs, sortOrder);
+
+ String[] columnNames = source.getColumnNames();
+ String[] newColumnNames = columnNamesWithData(columnNames);
+ if (columnNames == newColumnNames) return source;
+
+ MatrixCursor cursor = new MatrixCursor(newColumnNames, source.getCount());
+
+ source.moveToPosition(-1);
+ while (source.moveToNext()) {
+ MatrixCursor.RowBuilder row = cursor.newRow();
+ for (int i = 0; i < columnNames.length; i++) {
+ switch (source.getType(i)) {
+ case Cursor.FIELD_TYPE_INTEGER:
+ row.add(source.getInt(i));
+ break;
+ case Cursor.FIELD_TYPE_FLOAT:
+ row.add(source.getFloat(i));
+ break;
+ case Cursor.FIELD_TYPE_STRING:
+ row.add(source.getString(i));
+ break;
+ case Cursor.FIELD_TYPE_BLOB:
+ row.add(source.getBlob(i));
+ break;
+ case Cursor.FIELD_TYPE_NULL:
+ default:
+ row.add(null);
+ break;
+ }
+ }
+ }
+
+ source.close();
+ return cursor;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ if (uri.getPath().contains(BLOCKED_FILE_PREFIX)) {
Ted C 2016/09/07 17:30:13 null check uri here to be consistent
ssid 2016/09/08 03:56:56 Done.
+ synchronized (sLock) {
+ if (!doesMatchCurrentBlockingUri(uri)) return 0;
+ sFileUri = null;
+ sIsFileReady = false;
+ sCurrentBlockingUri = null;
+ }
+ }
+ return super.delete(uri, selection, selectionArgs);
+ }
+
+ /**
+ * Waits and returns file uri iff the file is ready to be accessed, or returns null if file is
+ * replaced.
+ */
+ protected static Uri getFileUriWhenReady(Uri uri) {
+ // If the uri passed is not a blocked file, then the given uri can be directly used.
+ if (uri == null || !uri.getPath().contains(BLOCKED_FILE_PREFIX)) return uri;
+
+ synchronized (sLock) {
+ // Wait only if the file is not ready and the current file has not changed.
+ while (!sIsFileReady && doesMatchCurrentBlockingUri(uri)) {
+ try {
+ sLock.wait();
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ // If the current file has changed while waiting, return null.
+ if (doesMatchCurrentBlockingUri(uri)) return sFileUri;
+ }
+ return null;
+ }
+
+ private static boolean doesMatchCurrentBlockingUri(Uri uri) {
+ return uri != null && sCurrentBlockingUri != null && sCurrentBlockingUri.equals(uri);
+ }
+
+ private String[] columnNamesWithData(String[] columnNames) {
+ for (String columnName : columnNames) {
+ if (MediaStore.MediaColumns.DATA.equals(columnName)) return columnNames;
+ }
+
+ String[] newColumnNames = Arrays.copyOf(columnNames, columnNames.length + 1);
+ newColumnNames[columnNames.length] = MediaStore.MediaColumns.DATA;
+ return newColumnNames;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698