Last active
February 20, 2021 11:37
-
-
Save uazo/00ebe2196e2587a5b16fd4584226939f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java | |
index 7772b54b5e..52f506bc02 100644 | |
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java | |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java | |
@@ -4,10 +4,13 @@ | |
package org.chromium.chrome.browser.bookmarks; | |
+import org.chromium.base.Log; | |
+ | |
import android.content.Intent; | |
import android.content.Context; | |
import android.content.pm.PackageManager; | |
import android.net.Uri; | |
+import android.os.Build; | |
import android.os.SystemClock; | |
import android.provider.Browser; | |
import android.Manifest.permission; | |
@@ -32,6 +35,8 @@ import org.chromium.components.url_formatter.SchemeDisplay; | |
import org.chromium.components.url_formatter.UrlFormatter; | |
import org.chromium.content_public.browser.WebContents; | |
+import org.chromium.base.ContentUriUtils; | |
+import org.chromium.chrome.R; | |
import org.chromium.chrome.browser.document.ChromeLauncherActivity; | |
import org.chromium.chrome.browser.IntentHandler; | |
import org.chromium.ui.base.PageTransition; | |
@@ -611,20 +616,44 @@ public class BookmarkBridge { | |
public void exportBookmarks(WindowAndroid window) { | |
assert mIsNativeBookmarkModelLoaded; | |
// check if we have the correct write permission | |
- if (window.hasPermission(permission.WRITE_EXTERNAL_STORAGE)) { | |
- exportBookmarksImpl(); | |
+ if (window.hasPermission(permission.WRITE_EXTERNAL_STORAGE) || | |
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { | |
+ exportBookmarksImpl(window); | |
} else { | |
String[] requestPermissions = new String[] {permission.WRITE_EXTERNAL_STORAGE}; | |
window.requestPermissions(requestPermissions, (permissions, grantResults) -> { | |
if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | |
- exportBookmarksImpl(); | |
+ exportBookmarksImpl(window); | |
} | |
}); | |
}; | |
} | |
- private void exportBookmarksImpl() { | |
- BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, BookmarkBridge.this); | |
+ private void exportBookmarksImpl(WindowAndroid window) { | |
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { | |
+ Intent fileSelector = new Intent(Intent.ACTION_CREATE_DOCUMENT); | |
+ fileSelector.addCategory(Intent.CATEGORY_OPENABLE); | |
+ fileSelector.setType("*/*"); | |
+ fileSelector.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | | |
+ Intent.FLAG_GRANT_READ_URI_PERMISSION); | |
+ // see https://issuetracker.google.com/issues/37136466 | |
+ // intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, "content://com.android.externalstorage.documents/document/primary:.myfolder"); | |
+ fileSelector.putExtra(Intent.EXTRA_TITLE, "bookmarks.html"); | |
+ window.showIntent(fileSelector, | |
+ new WindowAndroid.IntentCallback() { | |
+ @Override | |
+ public void onIntentCompleted(WindowAndroid window, int resultCode, Intent data) { | |
+ if (data == null) return; | |
+ Uri filePath = data.getData(); | |
+ BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, BookmarkBridge.this, | |
+ window, filePath.toString()); | |
+ } | |
+ }, | |
+ null); | |
+ } else { | |
+ BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, | |
+ BookmarkBridge.this, window, ""); | |
+ } | |
} | |
/** | |
@@ -1049,21 +1078,31 @@ public class BookmarkBridge { | |
} | |
@CalledByNative | |
- public void bookmarksExported(String bookmarksPath) { | |
- Context context = ContextUtils.getApplicationContext(); | |
- | |
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("file://" + bookmarksPath)); | |
- intent.putExtra(Browser.EXTRA_APPLICATION_ID, | |
- context.getPackageName()); | |
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |
- intent.putExtra(IntentHandler.EXTRA_PAGE_TRANSITION_TYPE, PageTransition.AUTO_BOOKMARK); | |
+ public void bookmarksExported(WindowAndroid window, String bookmarksPath, boolean success) { | |
+ Uri uri = Uri.parse(bookmarksPath); | |
+ Log.i("bookmarksExported", "uri=" + uri.toString() + " " + | |
+ "path=" + uri.getPath()); | |
- // If the bookmark manager is shown in a tab on a phone (rather than in a separate | |
- // activity) the component name may be null. Send the intent through | |
- // ChromeLauncherActivity instead to avoid crashing. See crbug.com/615012. | |
- intent.setClass(context, ChromeLauncherActivity.class); | |
- | |
- IntentHandler.startActivityForTrustedIntent(intent); | |
+ if (success == false) { | |
+ window.showError(R.string.saving_file_error); | |
+ } else { | |
+ Context context = ContextUtils.getApplicationContext(); | |
+ | |
+ Intent intent = new Intent(Intent.ACTION_VIEW, | |
+ ContentUriUtils.isContentUri(bookmarksPath) ? | |
+ Uri.parse(bookmarksPath) : Uri.parse("file://" + bookmarksPath)); | |
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, | |
+ context.getPackageName()); | |
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |
+ intent.putExtra(IntentHandler.EXTRA_PAGE_TRANSITION_TYPE, PageTransition.AUTO_BOOKMARK); | |
+ | |
+ // If the bookmark manager is shown in a tab on a phone (rather than in a separate | |
+ // activity) the component name may be null. Send the intent through | |
+ // ChromeLauncherActivity instead to avoid crashing. See crbug.com/615012. | |
+ intent.setClass(context, ChromeLauncherActivity.class); | |
+ | |
+ IntentHandler.startActivityForTrustedIntent(intent); | |
+ } | |
} | |
private static List<Pair<Integer, Integer>> createPairsList(int[] left, int[] right) { | |
@@ -1134,7 +1173,8 @@ public class BookmarkBridge { | |
void getChildIDs(long nativeBookmarkBridge, BookmarkBridge caller, long id, int type, | |
List<BookmarkId> bookmarksList); | |
void importBookmarks(long nativeBookmarkBridge, BookmarkBridge caller, WindowAndroid window); | |
- void exportBookmarks(long nativeBookmarkBridge, BookmarkBridge caller); | |
+ void exportBookmarks(long nativeBookmarkBridge, BookmarkBridge caller, WindowAndroid window, | |
+ String export_path); | |
BookmarkId getChildAt( | |
long nativeBookmarkBridge, BookmarkBridge caller, long id, int type, int index); | |
int getTotalBookmarkCount( | |
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc | |
index 6c90e7784c..151f77f28a 100644 | |
--- a/chrome/browser/android/bookmarks/bookmark_bridge.cc | |
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc | |
@@ -135,6 +135,40 @@ bool CanImportURL(const GURL& url) { | |
namespace { | |
+class FileBookmarksExportObserver: public BookmarksExportObserver { | |
+ public: | |
+ FileBookmarksExportObserver( | |
+ const JavaParamRef<jobject>& obj, | |
+ ui::WindowAndroid* window, | |
+ const std::string& export_path) : | |
+ obj_(ScopedJavaGlobalRef<jobject>(obj)), | |
+ window_(window), | |
+ export_path_(export_path) {} | |
+ | |
+ void OnExportFinished(Result result) override { | |
+ if (result == Result::kSuccess) { | |
+ LOG(INFO) << "Bookmarks exported successfully to " << export_path_; | |
+ } else if (result == Result::kCouldNotCreateFile) { | |
+ LOG(ERROR) << "Bookmarks export: could not create file " << export_path_; | |
+ } else if (result == Result::kCouldNotWriteHeader) { | |
+ LOG(ERROR) << "Bookmarks export: could not write header"; | |
+ } else if (result == Result::kCouldNotWriteNodes) { | |
+ LOG(ERROR) << "Bookmarks export: could not write nodes"; | |
+ } | |
+ | |
+ JNIEnv* env = AttachCurrentThread(); | |
+ Java_BookmarkBridge_bookmarksExported(env, obj_, window_->GetJavaObject(), | |
+ ConvertUTF8ToJavaString(env, export_path_), | |
+ result == Result::kSuccess); | |
+ delete this; | |
+ } | |
+ | |
+ private: | |
+ const ScopedJavaGlobalRef<jobject> obj_; | |
+ ui::WindowAndroid* window_; | |
+ const std::string export_path_; | |
+}; | |
+ | |
const int kInvalidId = -1; | |
class BookmarkTitleComparer { | |
@@ -649,10 +683,20 @@ void BookmarkBridge::ImportBookmarks(JNIEnv* env, | |
} | |
void BookmarkBridge::ExportBookmarks(JNIEnv* env, | |
- const JavaParamRef<jobject>& obj) { | |
+ const JavaParamRef<jobject>& obj, | |
+ const JavaParamRef<jobject>& java_window, | |
+ const JavaParamRef<jstring>& j_export_path) { | |
DCHECK(IsLoaded()); | |
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
+ ui::WindowAndroid* window = | |
+ ui::WindowAndroid::FromJavaWindowAndroid(java_window); | |
+ CHECK(window); | |
+ | |
+ base::string16 export_path = | |
+ base::android::ConvertJavaStringToUTF16(env, j_export_path); | |
+ | |
+ export_path_ = base::FilePath::FromUTF16Unsafe(export_path); | |
if (export_path_.empty()) { | |
if (!base::android::GetDownloadsDirectory(&export_path_)) { | |
LOG(ERROR) << "Could not retrieve downloads directory for bookmarks export"; | |
@@ -661,12 +705,8 @@ void BookmarkBridge::ExportBookmarks(JNIEnv* env, | |
export_path_ = export_path_.Append(FILE_PATH_LITERAL("bookmarks.html")); | |
} | |
- bookmark_html_writer::WriteBookmarks(profile_, export_path_, NULL); | |
- | |
- Java_BookmarkBridge_bookmarksExported(env, obj, ConvertUTF8ToJavaString(env, export_path_.MaybeAsASCII())); | |
- | |
- //NOTE: nothing will be written if write permission has not been granted before | |
- LOG(INFO) << "Bookmarks exported successfully to " << export_path_; | |
+ observer_ = new FileBookmarksExportObserver(obj, window, export_path_.MaybeAsASCII()); | |
+ bookmark_html_writer::WriteBookmarks(profile_, export_path_, observer_); | |
} | |
// Attempts to create a TemplateURL from the provided data. |title| is optional. | |
@@ -689,10 +729,10 @@ void BookmarkBridge::FileSelected(const base::FilePath& path, int index, | |
void* params) { | |
base::ThreadPool::PostTaskAndReplyWithResult( | |
FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()}, | |
- base::BindOnce(&BookmarkBridge::FileSelectedImpl, | |
+ base::BindOnce(&BookmarkBridge::FileSelectedImpl, | |
base::Unretained(this), | |
path), | |
- base::BindOnce(&BookmarkBridge::FileSelectedImplOnUIThread, | |
+ base::BindOnce(&BookmarkBridge::FileSelectedImplOnUIThread, | |
base::Unretained(this), | |
path)); | |
} | |
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser/android/bookmarks/bookmark_bridge.h | |
index b87fd636e4..706783671c 100644 | |
--- a/chrome/browser/android/bookmarks/bookmark_bridge.h | |
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.h | |
@@ -25,6 +25,7 @@ | |
#include "components/prefs/pref_change_registrar.h" | |
#include "components/search_engines/template_url.h" | |
#include "ui/shell_dialogs/select_file_dialog.h" | |
+#include "chrome/browser/bookmarks/bookmark_html_writer.h" | |
namespace bookmarks { | |
class BookmarkModel; | |
@@ -155,7 +156,9 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, | |
const base::android::JavaParamRef<jobject>& java_window); | |
void ExportBookmarks(JNIEnv* env, | |
- const base::android::JavaParamRef<jobject>& obj); | |
+ const base::android::JavaParamRef<jobject>& obj, | |
+ const base::android::JavaParamRef<jobject>& java_window, | |
+ const base::android::JavaParamRef<jstring>& j_export_path); | |
void SetBookmarkTitle(JNIEnv* env, | |
const base::android::JavaParamRef<jobject>& obj, | |
@@ -328,6 +331,7 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, | |
Profile* profile_; | |
base::FilePath export_path_; | |
+ BookmarksExportObserver* observer_; // weak | |
JavaObjectWeakGlobalRef weak_java_ref_; | |
bookmarks::BookmarkModel* bookmark_model_; // weak | |
bookmarks::ManagedBookmarkService* managed_bookmark_service_; // weak | |
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.cc b/chrome/browser/bookmarks/bookmark_html_writer.cc | |
index df6456e7dc..8d9e89016d 100644 | |
--- a/chrome/browser/bookmarks/bookmark_html_writer.cc | |
+++ b/chrome/browser/bookmarks/bookmark_html_writer.cc | |
@@ -40,6 +40,8 @@ | |
#include "ui/base/l10n/l10n_util.h" | |
#include "ui/gfx/favicon_size.h" | |
+#include "components/download/internal/common/android/download_collection_bridge.h" | |
+ | |
using bookmarks::BookmarkCodec; | |
using bookmarks::BookmarkNode; | |
using content::BrowserThread; | |
@@ -239,8 +241,14 @@ class Writer : public base::RefCountedThreadSafe<Writer> { | |
// Opens the file, returning true on success. | |
bool OpenFile() { | |
- int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE; | |
- file_.reset(new base::File(path_, flags)); | |
+ int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | | |
+ base::File::FLAG_OPEN_TRUNCATED; | |
+ if (path_.IsContentUri()) { | |
+ file_ = std::make_unique<base::File>( | |
+ download::DownloadCollectionBridge::OpenIntermediateUri(path_)); | |
+ } else { | |
+ file_.reset(new base::File(path_, flags)); | |
+ } | |
if (!file_->IsValid()) { | |
PLOG(ERROR) << "Could not create " << path_; | |
return false; | |
diff --git a/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java b/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java | |
index 680a72377e..3fa1a137a5 100644 | |
--- a/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java | |
+++ b/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java | |
@@ -225,10 +225,12 @@ public class DownloadCollectionBridge { | |
ContentResolver resolver = ContextUtils.getApplicationContext().getContentResolver(); | |
ParcelFileDescriptor pfd = | |
resolver.openFileDescriptor(Uri.parse(intermediateUri), "rw"); | |
+ try { | |
ContentValues updateValues = new ContentValues(); | |
updateValues.put("date_expires", getNewExpirationTime()); | |
ContextUtils.getApplicationContext().getContentResolver().update( | |
Uri.parse(intermediateUri), updateValues, null, null); | |
+ } catch(Exception dontcare) {} // don't care | |
return pfd.detachFd(); | |
} catch (Exception e) { | |
Log.e(TAG, "Cannot open intermediate Uri.", e); | |
diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc | |
index 72fb8f15ce..4975cc0ece 100755 | |
--- a/components/user_scripts/browser/user_script_loader.cc | |
+++ b/components/user_scripts/browser/user_script_loader.cc | |
@@ -67,7 +67,7 @@ using blink::mojom::NativeFileSystemStatus; | |
namespace { | |
-bool invalidChar(char c) | |
+bool invalidChar(unsigned char c) | |
{ | |
return !(c>=0 && c <128); | |
} | |
diff --git a/ui/android/java/strings/android_ui_strings.grd b/ui/android/java/strings/android_ui_strings.grd | |
index 9122b7a029..2211ffcbb6 100644 | |
--- a/ui/android/java/strings/android_ui_strings.grd | |
+++ b/ui/android/java/strings/android_ui_strings.grd | |
@@ -174,6 +174,9 @@ | |
<message name="IDS_OPENING_FILE_ERROR" desc="Toast when the browser is unable to open a file for upload. [CHAR-LIMIT=32]"> | |
Failed to open selected file | |
</message> | |
+ <message name="IDS_SAVING_FILE_ERROR" desc="Toast when the browser is unable to save a file. [CHAR-LIMIT=32]"> | |
+ Failed to save selected file | |
+ </message> | |
<!-- Clipboard --> | |
<message name="IDS_COPY_TO_CLIPBOARD_FAILURE_MESSAGE" desc="Notification for when copying to the clipboard fails. [CHAR-LIMIT=64]"> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment