Add-bookmark-import-export-actions.patch 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. From: csagan5 <32685696+csagan5@users.noreply.github.com>
  2. Date: Wed, 1 Aug 2018 09:19:40 +0200
  3. Subject: Add bookmark import/export actions
  4. Add bookmark import/export actions in bookmarks activity and page
  5. Reduce permissions needed for bookmarks import/export
  6. Completely remove contacts picker permission from the file dialog
  7. ---
  8. chrome/android/java/AndroidManifest.xml | 1 -
  9. .../res/menu/bookmark_action_bar_menu.xml | 14 ++
  10. .../browser/bookmarks/BookmarkActionBar.java | 12 +
  11. .../browser/bookmarks/BookmarkActivity.java | 15 ++
  12. .../browser/bookmarks/BookmarkBridge.java | 47 ++++
  13. .../browser/bookmarks/BookmarkDelegate.java | 10 +
  14. .../browser/bookmarks/BookmarkManager.java | 20 ++
  15. .../browser/bookmarks/BookmarkPage.java | 1 +
  16. chrome/browser/BUILD.gn | 8 +-
  17. .../android/bookmarks/bookmark_bridge.cc | 217 ++++++++++++++++++
  18. .../android/bookmarks/bookmark_bridge.h | 20 +-
  19. chrome/browser/importer/profile_writer.cc | 12 +
  20. chrome/browser/importer/profile_writer.h | 6 +
  21. .../strings/android_chrome_strings.grd | 6 +
  22. chrome/common/BUILD.gn | 3 +
  23. chrome/utility/BUILD.gn | 7 +-
  24. .../utility/importer/bookmark_html_reader.cc | 27 ++-
  25. .../utility/importer/bookmark_html_reader.h | 8 +
  26. .../chromium/ui/base/SelectFileDialog.java | 18 +-
  27. ui/shell_dialogs/select_file_dialog.h | 2 +
  28. .../select_file_dialog_android.cc | 6 +
  29. ui/shell_dialogs/select_file_dialog_android.h | 2 +
  30. 22 files changed, 448 insertions(+), 14 deletions(-)
  31. diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
  32. --- a/chrome/android/java/AndroidManifest.xml
  33. +++ b/chrome/android/java/AndroidManifest.xml
  34. @@ -34,7 +34,6 @@ by a child template that "extends" this file.
  35. {% endif %}
  36. <uses-permission-sdk-23 android:name="android.permission.BLUETOOTH"/>
  37. <uses-permission-sdk-23 android:name="android.permission.BLUETOOTH_ADMIN"/>
  38. - <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS"/>
  39. <uses-permission-sdk-23 android:name="android.permission.REORDER_TASKS"/>
  40. <uses-permission-sdk-23 android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
  41. diff --git a/chrome/android/java/res/menu/bookmark_action_bar_menu.xml b/chrome/android/java/res/menu/bookmark_action_bar_menu.xml
  42. --- a/chrome/android/java/res/menu/bookmark_action_bar_menu.xml
  43. +++ b/chrome/android/java/res/menu/bookmark_action_bar_menu.xml
  44. @@ -21,6 +21,20 @@
  45. android:visible="false"
  46. app:showAsAction="ifRoom"
  47. app:iconTint="@color/default_icon_color_tint_list" />
  48. + <item
  49. + android:id="@+id/import_menu_id"
  50. + android:icon="@drawable/ic_folder_blue_24dp"
  51. + android:title="@string/import_bookmarks"
  52. + android:visible="true"
  53. + app:showAsAction="ifRoom"
  54. + app:iconTint="@color/default_icon_color_tint_list" />
  55. + <item
  56. + android:id="@+id/export_menu_id"
  57. + android:icon="@drawable/ic_file_download_white_24dp"
  58. + android:title="@string/export_bookmarks"
  59. + android:visible="true"
  60. + app:showAsAction="ifRoom"
  61. + app:iconTint="@color/default_icon_color_tint_list" />
  62. <item
  63. android:id="@+id/close_menu_id"
  64. android:icon="@drawable/btn_close"
  65. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActionBar.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActionBar.java
  66. --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActionBar.java
  67. +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActionBar.java
  68. @@ -83,6 +83,12 @@ public class BookmarkActionBar extends SelectableListToolbar<BookmarkId>
  69. } else if (menuItem.getItemId() == R.id.search_menu_id) {
  70. mDelegate.openSearchUI();
  71. return true;
  72. + } else if (menuItem.getItemId() == R.id.import_menu_id) {
  73. + mDelegate.importBookmarks();
  74. + return true;
  75. + } else if (menuItem.getItemId() == R.id.export_menu_id) {
  76. + mDelegate.exportBookmarks();
  77. + return true;
  78. }
  79. SelectionDelegate<BookmarkId> selectionDelegate = mDelegate.getSelectionDelegate();
  80. @@ -134,6 +140,8 @@ public class BookmarkActionBar extends SelectableListToolbar<BookmarkId>
  81. void showLoadingUi() {
  82. setTitle(null);
  83. setNavigationButton(NAVIGATION_BUTTON_NONE);
  84. + getMenu().findItem(R.id.import_menu_id).setVisible(false);
  85. + getMenu().findItem(R.id.export_menu_id).setVisible(false);
  86. getMenu().findItem(R.id.search_menu_id).setVisible(false);
  87. getMenu().findItem(R.id.edit_menu_id).setVisible(false);
  88. }
  89. @@ -143,6 +151,8 @@ public class BookmarkActionBar extends SelectableListToolbar<BookmarkId>
  90. super.showNormalView();
  91. if (mDelegate == null) {
  92. + getMenu().findItem(R.id.import_menu_id).setVisible(false);
  93. + getMenu().findItem(R.id.export_menu_id).setVisible(false);
  94. getMenu().findItem(R.id.search_menu_id).setVisible(false);
  95. getMenu().findItem(R.id.edit_menu_id).setVisible(false);
  96. }
  97. @@ -173,6 +183,8 @@ public class BookmarkActionBar extends SelectableListToolbar<BookmarkId>
  98. public void onFolderStateSet(BookmarkId folder) {
  99. mCurrentFolder = mDelegate.getModel().getBookmarkById(folder);
  100. + getMenu().findItem(R.id.import_menu_id).setVisible(true);
  101. + getMenu().findItem(R.id.export_menu_id).setVisible(true);
  102. getMenu().findItem(R.id.search_menu_id).setVisible(true);
  103. getMenu().findItem(R.id.edit_menu_id).setVisible(mCurrentFolder.isEditable());
  104. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java
  105. --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java
  106. +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkActivity.java
  107. @@ -13,6 +13,7 @@ import androidx.annotation.VisibleForTesting;
  108. import org.chromium.chrome.browser.SnackbarActivity;
  109. import org.chromium.components.bookmarks.BookmarkId;
  110. import org.chromium.components.embedder_support.util.UrlConstants;
  111. +import org.chromium.ui.base.ActivityWindowAndroid;
  112. /**
  113. * The activity that displays the bookmark UI on the phone. It keeps a {@link BookmarkManager}
  114. @@ -22,6 +23,7 @@ import org.chromium.components.embedder_support.util.UrlConstants;
  115. public class BookmarkActivity extends SnackbarActivity {
  116. private BookmarkManager mBookmarkManager;
  117. + private ActivityWindowAndroid mWindowAndroid;
  118. static final int EDIT_BOOKMARK_REQUEST_CODE = 14;
  119. public static final String INTENT_VISIT_BOOKMARK_ID = "BookmarkEditActivity.VisitBookmarkId";
  120. @@ -33,6 +35,18 @@ public class BookmarkActivity extends SnackbarActivity {
  121. if (TextUtils.isEmpty(url)) url = UrlConstants.BOOKMARKS_URL;
  122. mBookmarkManager.updateForUrl(url);
  123. setContentView(mBookmarkManager.getView());
  124. +
  125. + final boolean listenToActivityState = true;
  126. + mWindowAndroid = new ActivityWindowAndroid(this, listenToActivityState);
  127. + mWindowAndroid.restoreInstanceState(savedInstanceState);
  128. + mBookmarkManager.setWindow(mWindowAndroid);
  129. + }
  130. +
  131. + @Override
  132. + protected void onSaveInstanceState(Bundle outState) {
  133. + super.onSaveInstanceState(outState);
  134. +
  135. + mWindowAndroid.saveInstanceState(outState);
  136. }
  137. @Override
  138. @@ -49,6 +63,7 @@ public class BookmarkActivity extends SnackbarActivity {
  139. @Override
  140. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  141. super.onActivityResult(requestCode, resultCode, data);
  142. + mWindowAndroid.onActivityResult(requestCode, resultCode, data);
  143. if (requestCode == EDIT_BOOKMARK_REQUEST_CODE && resultCode == RESULT_OK) {
  144. BookmarkId bookmarkId = BookmarkId.getBookmarkIdFromString(data.getStringExtra(
  145. INTENT_VISIT_BOOKMARK_ID));
  146. 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
  147. --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
  148. +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
  149. @@ -4,7 +4,11 @@
  150. package org.chromium.chrome.browser.bookmarks;
  151. +import android.content.Intent;
  152. +import android.content.Context;
  153. +import android.net.Uri;
  154. import android.os.SystemClock;
  155. +import android.provider.Browser;
  156. import android.text.TextUtils;
  157. import android.util.Pair;
  158. @@ -26,6 +30,11 @@ import org.chromium.components.url_formatter.SchemeDisplay;
  159. import org.chromium.components.url_formatter.UrlFormatter;
  160. import org.chromium.content_public.browser.WebContents;
  161. +import org.chromium.chrome.browser.document.ChromeLauncherActivity;
  162. +import org.chromium.chrome.browser.IntentHandler;
  163. +import org.chromium.ui.base.PageTransition;
  164. +import org.chromium.ui.base.WindowAndroid;
  165. +
  166. import java.util.ArrayList;
  167. import java.util.List;
  168. @@ -562,6 +571,24 @@ public class BookmarkBridge {
  169. mNativeBookmarkBridge, BookmarkBridge.this, id.getId(), id.getType());
  170. }
  171. + /**
  172. + * Import bookmarks from a selected file.
  173. + * @param window The current window of the bookmarks activity or page.
  174. + */
  175. + public void importBookmarks(WindowAndroid window) {
  176. + assert mIsNativeBookmarkModelLoaded;
  177. + BookmarkBridgeJni.get().importBookmarks(mNativeBookmarkBridge, BookmarkBridge.this, window);
  178. + }
  179. +
  180. + /**
  181. + * Export bookmarks to a path selected by the user.
  182. + * @param window The current window of the bookmarks activity or page.
  183. + */
  184. + public void exportBookmarks() {
  185. + assert mIsNativeBookmarkModelLoaded;
  186. + BookmarkBridgeJni.get().exportBookmarks(mNativeBookmarkBridge, BookmarkBridge.this);
  187. + }
  188. +
  189. /**
  190. * Synchronously gets a list of bookmarks that match the specified search query.
  191. * @param query Keyword used for searching bookmarks.
  192. @@ -942,6 +969,24 @@ public class BookmarkBridge {
  193. depthList.add(depth);
  194. }
  195. + @CalledByNative
  196. + public void bookmarksExported(String bookmarksPath) {
  197. + Context context = ContextUtils.getApplicationContext();
  198. +
  199. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("file://" + bookmarksPath));
  200. + intent.putExtra(Browser.EXTRA_APPLICATION_ID,
  201. + context.getPackageName());
  202. + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  203. + intent.putExtra(IntentHandler.EXTRA_PAGE_TRANSITION_TYPE, PageTransition.AUTO_BOOKMARK);
  204. +
  205. + // If the bookmark manager is shown in a tab on a phone (rather than in a separate
  206. + // activity) the component name may be null. Send the intent through
  207. + // ChromeLauncherActivity instead to avoid crashing. See crbug.com/615012.
  208. + intent.setClass(context, ChromeLauncherActivity.class);
  209. +
  210. + IntentHandler.startActivityForTrustedIntent(intent);
  211. + }
  212. +
  213. private static List<Pair<Integer, Integer>> createPairsList(int[] left, int[] right) {
  214. List<Pair<Integer, Integer>> pairList = new ArrayList<Pair<Integer, Integer>>();
  215. for (int i = 0; i < left.length; i++) {
  216. @@ -1008,6 +1053,8 @@ public class BookmarkBridge {
  217. int getChildCount(long nativeBookmarkBridge, BookmarkBridge caller, long id, int type);
  218. void getChildIDs(long nativeBookmarkBridge, BookmarkBridge caller, long id, int type,
  219. boolean getFolders, boolean getBookmarks, List<BookmarkId> bookmarksList);
  220. + void importBookmarks(long nativeBookmarkBridge, BookmarkBridge caller, WindowAndroid window);
  221. + void exportBookmarks(long nativeBookmarkBridge, BookmarkBridge caller);
  222. BookmarkId getChildAt(
  223. long nativeBookmarkBridge, BookmarkBridge caller, long id, int type, int index);
  224. int getTotalBookmarkCount(
  225. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java
  226. --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java
  227. +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java
  228. @@ -67,6 +67,16 @@ interface BookmarkDelegate {
  229. */
  230. void openSearchUI();
  231. + /**
  232. + * Imports bookmarks from user-selected file.
  233. + */
  234. + void importBookmarks();
  235. +
  236. + /**
  237. + * Exports bookmarks to downloads directory.
  238. + */
  239. + void exportBookmarks();
  240. +
  241. /**
  242. * Dismisses the search UI.
  243. */
  244. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
  245. --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
  246. +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
  247. @@ -35,8 +35,10 @@ import org.chromium.components.bookmarks.BookmarkId;
  248. import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  249. import org.chromium.components.browser_ui.widget.selectable_list.SelectableListLayout;
  250. import org.chromium.components.browser_ui.widget.selectable_list.SelectableListToolbar.SearchDelegate;
  251. +import org.chromium.ui.base.ActivityWindowAndroid;
  252. import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate;
  253. import org.chromium.url.GURL;
  254. +import org.chromium.chrome.browser.ChromeActivity;
  255. import java.util.Stack;
  256. @@ -55,6 +57,7 @@ public class BookmarkManager
  257. private Activity mActivity;
  258. private ViewGroup mMainView;
  259. private BookmarkModel mBookmarkModel;
  260. + private ActivityWindowAndroid mWindowAndroid;
  261. private BookmarkUndoController mUndoController;
  262. private final ObserverList<BookmarkUIObserver> mUIObservers = new ObserverList<>();
  263. private BasicNativePage mNativePage;
  264. @@ -357,6 +360,13 @@ public class BookmarkManager
  265. mNativePage = nativePage;
  266. }
  267. + /**
  268. + * Sets the Android window that is used by further intents created by the bookmark activity.
  269. + */
  270. + public void setWindow(ActivityWindowAndroid window) {
  271. + mWindowAndroid = window;
  272. + }
  273. +
  274. /**
  275. * @return Current URL representing the UI state of bookmark manager. If no state has been shown
  276. * yet in this session, on phone return last used state stored in preference; on tablet
  277. @@ -529,6 +539,16 @@ public class BookmarkManager
  278. }
  279. }
  280. + @Override
  281. + public void importBookmarks() {
  282. + mBookmarkModel.importBookmarks(mWindowAndroid);
  283. + }
  284. +
  285. + @Override
  286. + public void exportBookmarks() {
  287. + mBookmarkModel.exportBookmarks();
  288. + }
  289. +
  290. @Override
  291. public void openSearchUI() {
  292. setState(BookmarkUIState.createSearchState());
  293. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
  294. --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
  295. +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
  296. @@ -29,6 +29,7 @@ public class BookmarkPage extends BasicNativePage {
  297. mManager = new BookmarkManager(activity, false, activity.getSnackbarManager());
  298. mManager.setBasicNativePage(this);
  299. + mManager.setWindow(activity.getWindowAndroid());
  300. mTitle = host.getContext().getResources().getString(R.string.bookmarks);
  301. initWithView(mManager.getView());
  302. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  303. --- a/chrome/browser/BUILD.gn
  304. +++ b/chrome/browser/BUILD.gn
  305. @@ -171,6 +171,10 @@ jumbo_static_library("browser") {
  306. "bitmap_fetcher/bitmap_fetcher_service.h",
  307. "bitmap_fetcher/bitmap_fetcher_service_factory.cc",
  308. "bitmap_fetcher/bitmap_fetcher_service_factory.h",
  309. + "importer/profile_writer.cc",
  310. + "importer/profile_writer.h",
  311. + "bookmarks/bookmark_html_writer.cc",
  312. + "bookmarks/bookmark_html_writer.h",
  313. "bluetooth/bluetooth_chooser_context.cc",
  314. "bluetooth/bluetooth_chooser_context.h",
  315. "bluetooth/bluetooth_chooser_context_factory.cc",
  316. @@ -3139,8 +3143,6 @@ jumbo_static_library("browser") {
  317. "badging/badge_manager_factory.h",
  318. "banners/app_banner_manager_desktop.cc",
  319. "banners/app_banner_manager_desktop.h",
  320. - "bookmarks/bookmark_html_writer.cc",
  321. - "bookmarks/bookmark_html_writer.h",
  322. "certificate_viewer.h",
  323. "chrome_browser_field_trials_desktop.cc",
  324. "chrome_browser_field_trials_desktop.h",
  325. @@ -3267,8 +3269,6 @@ jumbo_static_library("browser") {
  326. "importer/importer_uma.h",
  327. "importer/in_process_importer_bridge.cc",
  328. "importer/in_process_importer_bridge.h",
  329. - "importer/profile_writer.cc",
  330. - "importer/profile_writer.h",
  331. "lifetime/browser_close_manager.cc",
  332. "lifetime/browser_close_manager.h",
  333. "lifetime/termination_notification.cc",
  334. diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc
  335. --- a/chrome/browser/android/bookmarks/bookmark_bridge.cc
  336. +++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc
  337. @@ -37,6 +37,7 @@
  338. #include "components/bookmarks/common/android/bookmark_type.h"
  339. #include "components/bookmarks/common/bookmark_pref_names.h"
  340. #include "components/bookmarks/managed/managed_bookmark_service.h"
  341. +#include "components/favicon_base/favicon_usage_data.h"
  342. #include "components/dom_distiller/core/url_utils.h"
  343. #include "components/prefs/pref_service.h"
  344. #include "components/query_parser/query_parser.h"
  345. @@ -46,6 +47,21 @@
  346. #include "content/public/browser/browser_thread.h"
  347. #include "content/public/browser/web_contents.h"
  348. +#include "base/android/content_uri_utils.h"
  349. +#include "base/android/path_utils.h"
  350. +#include "base/strings/utf_string_conversions.h"
  351. +#include "chrome/utility/importer/bookmark_html_reader.h"
  352. +#include "chrome/browser/bookmarks/bookmark_html_writer.h"
  353. +#include "chrome/browser/importer/profile_writer.h"
  354. +#include "chrome/browser/platform_util.h"
  355. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  356. +#include "chrome/common/importer/imported_bookmark_entry.h"
  357. +#include "chrome/common/importer/importer_data_types.h"
  358. +#include "chrome/common/url_constants.h"
  359. +#include "components/search_engines/template_url.h"
  360. +#include "components/url_formatter/url_fixer.h"
  361. +#include "ui/android/window_android.h"
  362. +
  363. using base::android::AttachCurrentThread;
  364. using base::android::ConvertUTF8ToJavaString;
  365. using base::android::ConvertUTF16ToJavaString;
  366. @@ -63,6 +79,56 @@ using bookmarks::BookmarkPermanentNode;
  367. using bookmarks::BookmarkType;
  368. using content::BrowserThread;
  369. +namespace internal {
  370. +
  371. +// Returns true if |url| has a valid scheme that we allow to import. We
  372. +// filter out the URL with a unsupported scheme.
  373. +bool CanImportURL(const GURL& url) {
  374. + // The URL is not valid.
  375. + if (!url.is_valid())
  376. + return false;
  377. +
  378. + // Filter out the URLs with unsupported schemes.
  379. + const char* const kInvalidSchemes[] = {"wyciwyg", "place"};
  380. + for (size_t i = 0; i < base::size(kInvalidSchemes); ++i) {
  381. + if (url.SchemeIs(kInvalidSchemes[i]))
  382. + return false;
  383. + }
  384. +
  385. + // Check if |url| is about:blank.
  386. + if (url == url::kAboutBlankURL)
  387. + return true;
  388. +
  389. + // If |url| starts with chrome:// or about:, check if it's one of the URLs
  390. + // that we support.
  391. + if (url.SchemeIs(content::kChromeUIScheme) ||
  392. + url.SchemeIs(url::kAboutScheme)) {
  393. + if (url.host_piece() == chrome::kChromeUIAboutHost)
  394. + return true;
  395. +
  396. + GURL fixed_url(url_formatter::FixupURL(url.spec(), std::string()));
  397. + for (size_t i = 0; i < chrome::kNumberOfChromeHostURLs; ++i) {
  398. + if (fixed_url.DomainIs(chrome::kChromeHostURLs[i]))
  399. + return true;
  400. + }
  401. +
  402. + for (size_t i = 0; i < chrome::kNumberOfChromeDebugURLs; ++i) {
  403. + if (fixed_url == chrome::kChromeDebugURLs[i])
  404. + return true;
  405. + }
  406. +
  407. + // If url has either chrome:// or about: schemes but wasn't found in the
  408. + // above lists, it means we don't support it, so we don't allow the user
  409. + // to import it.
  410. + return false;
  411. + }
  412. +
  413. + // Otherwise, we assume the url has a valid (importable) scheme.
  414. + return true;
  415. +}
  416. +
  417. +} // internal
  418. +
  419. namespace {
  420. const int kInvalidId = -1;
  421. @@ -141,6 +207,10 @@ BookmarkBridge::~BookmarkBridge() {
  422. bookmark_model_->RemoveObserver(this);
  423. if (partner_bookmarks_shim_)
  424. partner_bookmarks_shim_->RemoveObserver(this);
  425. + // There may be pending file dialogs, we need to tell them that we've gone
  426. + // away so they don't try and call back to us.
  427. + if (select_file_dialog_)
  428. + select_file_dialog_->ListenerDestroyed();
  429. }
  430. void BookmarkBridge::Destroy(JNIEnv*, const JavaParamRef<jobject>&) {
  431. @@ -516,6 +586,153 @@ jint BookmarkBridge::GetTotalBookmarkCount(
  432. return count;
  433. }
  434. +void BookmarkBridge::ImportBookmarks(JNIEnv* env,
  435. + const JavaParamRef<jobject>& obj,
  436. + const JavaParamRef<jobject>& java_window) {
  437. + DCHECK(IsLoaded());
  438. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  439. +
  440. + ui::WindowAndroid* window =
  441. + ui::WindowAndroid::FromJavaWindowAndroid(java_window);
  442. + CHECK(window);
  443. +
  444. + select_file_dialog_ = ui::SelectFileDialog::Create(
  445. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr));
  446. +
  447. + //NOTE: extension and description are not used on Android, thus not set
  448. + ui::SelectFileDialog::FileTypeInfo file_type_info;
  449. +
  450. + const std::vector<base::string16> v_accept_types = { base::UTF8ToUTF16("text/html") };
  451. +
  452. + // Android needs the original MIME types and an additional capture value.
  453. + std::pair<std::vector<base::string16>, bool> accept_types =
  454. + std::make_pair(v_accept_types, /* use_media_capture */ false);
  455. +
  456. + select_file_dialog_->SelectFile(
  457. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  458. + base::string16(),
  459. + export_path_,
  460. + &file_type_info,
  461. + 0,
  462. + base::FilePath::StringType(),
  463. + window,
  464. + &accept_types
  465. + );
  466. +}
  467. +
  468. +void BookmarkBridge::ExportBookmarks(JNIEnv* env,
  469. + const JavaParamRef<jobject>& obj) {
  470. + DCHECK(IsLoaded());
  471. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  472. +
  473. + if (export_path_.empty()) {
  474. + if (!base::android::GetDownloadsDirectory(&export_path_)) {
  475. + LOG(ERROR) << "Could not retrieve downloads directory for bookmarks export";
  476. + return;
  477. + }
  478. + export_path_ = export_path_.Append(FILE_PATH_LITERAL("bookmarks.html"));
  479. + }
  480. +
  481. + bookmark_html_writer::WriteBookmarks(profile_, export_path_, NULL);
  482. +
  483. + Java_BookmarkBridge_bookmarksExported(env, obj, ConvertUTF8ToJavaString(env, export_path_.MaybeAsASCII()));
  484. +
  485. + //NOTE: nothing will be written if write permission has not been granted before
  486. + LOG(INFO) << "Bookmarks exported successfully to " << export_path_;
  487. +}
  488. +
  489. +// Attempts to create a TemplateURL from the provided data. |title| is optional.
  490. +// If TemplateURL creation fails, returns null.
  491. +std::unique_ptr<TemplateURL> CreateTemplateURL(const base::string16& url,
  492. + const base::string16& keyword,
  493. + const base::string16& title) {
  494. + if (url.empty() || keyword.empty())
  495. + return nullptr;
  496. + TemplateURLData data;
  497. + data.SetKeyword(keyword);
  498. + // We set short name by using the title if it exists.
  499. + // Otherwise, we use the shortcut.
  500. + data.SetShortName(title.empty() ? keyword : title);
  501. + data.SetURL(TemplateURLRef::DisplayURLToURLRef(url));
  502. + return std::make_unique<TemplateURL>(data);
  503. +}
  504. +
  505. +void BookmarkBridge::FileSelected(const base::FilePath& path, int index,
  506. + void* params) {
  507. + base::File file;
  508. + if (path.IsContentUri()) {
  509. + file = base::OpenContentUriForRead(path);
  510. + } else {
  511. + file.Initialize(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  512. + }
  513. + if (!file.IsValid()) {
  514. + select_file_dialog_->ShowToast("Cannot open bookmarks file for import");
  515. + return;
  516. + }
  517. +
  518. + auto fileLength = file.GetLength();
  519. + if (-1 == fileLength) {
  520. + select_file_dialog_->ShowToast("Cannot read bookmarks file length");
  521. + return;
  522. + }
  523. +
  524. + if (fileLength > 10 * 1024 * 1024) {
  525. + select_file_dialog_->ShowToast("Bookmark file is bigger than 10MB");
  526. + return;
  527. + }
  528. +
  529. + std::vector<char> buffer(fileLength);
  530. + if (-1 == file.ReadAtCurrentPos(buffer.data(), fileLength)) {
  531. + select_file_dialog_->ShowToast("Could not read bookmarks file");
  532. + return;
  533. + }
  534. +
  535. + if (buffer.empty()) {
  536. + select_file_dialog_->ShowToast("Empty bookmarks file");
  537. + return;
  538. + }
  539. +
  540. + std::string contents(buffer.begin(), buffer.end());
  541. +
  542. + // the following import logic comes from BookmarksFileImporter class
  543. + std::vector<ImportedBookmarkEntry> bookmarks;
  544. + std::vector<importer::SearchEngineInfo> search_engines;
  545. + favicon_base::FaviconUsageDataList favicons;
  546. +
  547. + bookmark_html_reader::ImportBookmarksFile(
  548. + base::Callback<bool(void)>(),
  549. + base::BindRepeating(internal::CanImportURL),
  550. + contents,
  551. + &bookmarks,
  552. + &search_engines,
  553. + &favicons);
  554. +
  555. + auto *writer = new ProfileWriter(profile_);
  556. +
  557. + if (!bookmarks.empty()) {
  558. + // adding bookmarks will begin extensive changes to the model
  559. + writer->AddBookmarksWithModel(bookmark_model_, bookmarks, base::ASCIIToUTF16("Imported"));
  560. + }
  561. + if (!search_engines.empty()) {
  562. + TemplateURLService::OwnedTemplateURLVector owned_template_urls;
  563. + for (const auto& search_engine : search_engines) {
  564. + std::unique_ptr<TemplateURL> owned_template_url = CreateTemplateURL(
  565. + search_engine.url, search_engine.keyword, search_engine.display_name);
  566. + if (owned_template_url)
  567. + owned_template_urls.push_back(std::move(owned_template_url));
  568. + }
  569. + writer->AddKeywords(std::move(owned_template_urls), false);
  570. + }
  571. +
  572. + select_file_dialog_->ShowToast("Bookmarks import complete");
  573. +
  574. + LOG(INFO) << "Imported " << bookmarks.size() << " bookmarks and " <<
  575. + search_engines.size() << " search engines from " << path.MaybeAsASCII();
  576. +}
  577. +
  578. +void BookmarkBridge::FileSelectionCanceled(void* params) {
  579. +}
  580. +
  581. void BookmarkBridge::SetBookmarkTitle(JNIEnv* env,
  582. const JavaParamRef<jobject>& obj,
  583. jlong id,
  584. diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser/android/bookmarks/bookmark_bridge.h
  585. --- a/chrome/browser/android/bookmarks/bookmark_bridge.h
  586. +++ b/chrome/browser/android/bookmarks/bookmark_bridge.h
  587. @@ -19,6 +19,8 @@
  588. #include "components/bookmarks/browser/base_bookmark_model_observer.h"
  589. #include "components/bookmarks/common/android/bookmark_id.h"
  590. #include "components/prefs/pref_change_registrar.h"
  591. +#include "components/search_engines/template_url.h"
  592. +#include "ui/shell_dialogs/select_file_dialog.h"
  593. namespace bookmarks {
  594. class BookmarkModel;
  595. @@ -32,7 +34,8 @@ class Profile;
  596. // bookmark page. This fetches the bookmarks, title, urls, folder
  597. // hierarchy.
  598. class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver,
  599. - public PartnerBookmarksShim::Observer {
  600. + public PartnerBookmarksShim::Observer,
  601. + public ui::SelectFileDialog::Listener {
  602. public:
  603. BookmarkBridge(JNIEnv* env,
  604. const base::android::JavaRef<jobject>& obj,
  605. @@ -42,6 +45,12 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver,
  606. bool IsDoingExtensiveChanges(JNIEnv* env,
  607. const base::android::JavaParamRef<jobject>& obj);
  608. + // SelectFileDialog::Listener implementation.
  609. + void FileSelected(const base::FilePath& path,
  610. + int index,
  611. + void* params) override;
  612. + void FileSelectionCanceled(void* params) override;
  613. +
  614. jboolean IsEditBookmarksEnabled(JNIEnv* env);
  615. void LoadEmptyPartnerBookmarkShimForTesting(
  616. @@ -131,6 +140,13 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver,
  617. jlong id,
  618. jint type);
  619. + void ImportBookmarks(JNIEnv* env,
  620. + const base::android::JavaParamRef<jobject>& obj,
  621. + const base::android::JavaParamRef<jobject>& java_window);
  622. +
  623. + void ExportBookmarks(JNIEnv* env,
  624. + const base::android::JavaParamRef<jobject>& obj);
  625. +
  626. void SetBookmarkTitle(JNIEnv* env,
  627. const base::android::JavaParamRef<jobject>& obj,
  628. jlong id,
  629. @@ -276,12 +292,14 @@ class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver,
  630. void ShimBeingDeleted(PartnerBookmarksShim* shim) override;
  631. Profile* profile_;
  632. + base::FilePath export_path_;
  633. JavaObjectWeakGlobalRef weak_java_ref_;
  634. bookmarks::BookmarkModel* bookmark_model_; // weak
  635. bookmarks::ManagedBookmarkService* managed_bookmark_service_; // weak
  636. std::unique_ptr<bookmarks::ScopedGroupBookmarkActions>
  637. grouped_bookmark_actions_;
  638. PrefChangeRegistrar pref_change_registrar_;
  639. + scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
  640. // Information about the Partner bookmarks (must check for IsLoaded()).
  641. // This is owned by profile.
  642. diff --git a/chrome/browser/importer/profile_writer.cc b/chrome/browser/importer/profile_writer.cc
  643. --- a/chrome/browser/importer/profile_writer.cc
  644. +++ b/chrome/browser/importer/profile_writer.cc
  645. @@ -96,12 +96,14 @@ void ProfileWriter::AddHistoryPage(const history::URLRows& page,
  646. HistoryServiceFactory::GetForProfile(profile_,
  647. ServiceAccessType::EXPLICIT_ACCESS)
  648. ->AddPagesWithDetails(page, visit_source);
  649. +#if !defined(OS_ANDROID)
  650. // Measure the size of the history page after Auto Import on first run.
  651. if (first_run::IsChromeFirstRun() &&
  652. visit_source == history::SOURCE_IE_IMPORTED) {
  653. UMA_HISTOGRAM_COUNTS_1M("Import.ImportedHistorySize.AutoImportFromIE",
  654. page.size());
  655. }
  656. +#endif
  657. }
  658. void ProfileWriter::AddHomepage(const GURL& home_page) {
  659. @@ -122,6 +124,16 @@ void ProfileWriter::AddBookmarks(
  660. return;
  661. BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile_);
  662. + AddBookmarksWithModel(model, bookmarks, top_level_folder_name);
  663. +}
  664. +
  665. +void ProfileWriter::AddBookmarksWithModel(
  666. + BookmarkModel* model,
  667. + const std::vector<ImportedBookmarkEntry>& bookmarks,
  668. + const base::string16& top_level_folder_name) {
  669. + if (bookmarks.empty())
  670. + return;
  671. +
  672. DCHECK(model->loaded());
  673. // If the bookmark bar is currently empty, we should import directly to it.
  674. diff --git a/chrome/browser/importer/profile_writer.h b/chrome/browser/importer/profile_writer.h
  675. --- a/chrome/browser/importer/profile_writer.h
  676. +++ b/chrome/browser/importer/profile_writer.h
  677. @@ -12,6 +12,7 @@
  678. #include "base/strings/string16.h"
  679. #include "base/time/time.h"
  680. #include "build/build_config.h"
  681. +#include "components/bookmarks/browser/bookmark_model.h"
  682. #include "components/favicon_base/favicon_usage_data.h"
  683. #include "components/history/core/browser/history_types.h"
  684. #include "components/search_engines/template_url_service.h"
  685. @@ -67,6 +68,11 @@ class ProfileWriter : public base::RefCountedThreadSafe<ProfileWriter> {
  686. const std::vector<ImportedBookmarkEntry>& bookmarks,
  687. const base::string16& top_level_folder_name);
  688. + virtual void AddBookmarksWithModel(
  689. + bookmarks::BookmarkModel* model,
  690. + const std::vector<ImportedBookmarkEntry>& bookmarks,
  691. + const base::string16& top_level_folder_name);
  692. +
  693. virtual void AddFavicons(const favicon_base::FaviconUsageDataList& favicons);
  694. // Adds the TemplateURLs in |template_urls| to the local store.
  695. diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  696. --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
  697. +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  698. @@ -245,6 +245,12 @@ CHAR-LIMIT guidelines:
  699. <message name="IDS_NOTIFICATION_CATEGORY_SITES" desc="Label for notifications from websites, within a list of notification categories. [CHAR-LIMIT=32]">
  700. Sites
  701. </message>
  702. + <message name="IDS_IMPORT_BOOKMARKS" desc="The label for the import bookmarks button.">
  703. + Import
  704. + </message>
  705. + <message name="IDS_EXPORT_BOOKMARKS" desc="The label for an export bookmarks button.">
  706. + Export
  707. + </message>
  708. <message name="IDS_NOTIFICATION_CATEGORY_VR" desc="Label for notifications in VR, within a list of notification categories. [CHAR-LIMIT=32]">
  709. Virtual Reality
  710. </message>
  711. diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
  712. --- a/chrome/common/BUILD.gn
  713. +++ b/chrome/common/BUILD.gn
  714. @@ -423,6 +423,9 @@ static_library("common") {
  715. sources += [
  716. "media/chrome_media_drm_bridge_client.cc",
  717. "media/chrome_media_drm_bridge_client.h",
  718. + ## Bromite dependencies for bookmark import functionality
  719. + "importer/imported_bookmark_entry.cc",
  720. + "importer/imported_bookmark_entry.h",
  721. ]
  722. } else {
  723. # Non-Android.
  724. diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
  725. --- a/chrome/utility/BUILD.gn
  726. +++ b/chrome/utility/BUILD.gn
  727. @@ -70,8 +70,6 @@ static_library("utility") {
  728. if (!is_android) {
  729. sources += [
  730. - "importer/bookmark_html_reader.cc",
  731. - "importer/bookmark_html_reader.h",
  732. "importer/bookmarks_file_importer.cc",
  733. "importer/bookmarks_file_importer.h",
  734. "importer/edge_database_reader_win.cc",
  735. @@ -169,6 +167,11 @@ static_library("utility") {
  736. }
  737. }
  738. + sources += [
  739. + "importer/bookmark_html_reader.cc",
  740. + "importer/bookmark_html_reader.h",
  741. + ]
  742. +
  743. if (use_nss_certs) {
  744. sources += [
  745. "importer/nss_decryptor_system_nss.cc",
  746. diff --git a/chrome/utility/importer/bookmark_html_reader.cc b/chrome/utility/importer/bookmark_html_reader.cc
  747. --- a/chrome/utility/importer/bookmark_html_reader.cc
  748. +++ b/chrome/utility/importer/bookmark_html_reader.cc
  749. @@ -17,7 +17,9 @@
  750. #include "base/strings/utf_string_conversions.h"
  751. #include "base/time/time.h"
  752. #include "chrome/common/importer/imported_bookmark_entry.h"
  753. +#if !defined(OS_ANDROID)
  754. #include "chrome/utility/importer/favicon_reencode.h"
  755. +#endif
  756. #include "components/search_engines/search_terms_data.h"
  757. #include "components/search_engines/template_url.h"
  758. #include "net/base/data_url.h"
  759. @@ -56,6 +58,7 @@ bool GetAttribute(const std::string& attribute_list,
  760. return true;
  761. }
  762. +#if !defined(OS_ANDROID)
  763. // Given the URL of a page and a favicon data URL, adds an appropriate record
  764. // to the given favicon usage vector.
  765. void DataURLToFaviconUsage(const GURL& link_url,
  766. @@ -86,6 +89,7 @@ void DataURLToFaviconUsage(const GURL& link_url,
  767. favicons->push_back(usage);
  768. }
  769. +#endif
  770. } // namespace
  771. @@ -106,14 +110,28 @@ static std::string stripDt(const std::string& lineDt) {
  772. }
  773. void ImportBookmarksFile(
  774. - base::RepeatingCallback<bool(void)> cancellation_callback,
  775. - base::RepeatingCallback<bool(const GURL&)> valid_url_callback,
  776. + const base::RepeatingCallback<bool(void)> cancellation_callback,
  777. + const base::RepeatingCallback<bool(const GURL&)> valid_url_callback,
  778. const base::FilePath& file_path,
  779. std::vector<ImportedBookmarkEntry>* bookmarks,
  780. std::vector<importer::SearchEngineInfo>* search_engines,
  781. favicon_base::FaviconUsageDataList* favicons) {
  782. std::string content;
  783. - base::ReadFileToString(file_path, &content);
  784. + if (!base::ReadFileToString(file_path, &content)) {
  785. + LOG(ERROR) << "Could not directly read bookmarks import file";
  786. + return;
  787. + }
  788. +
  789. + ImportBookmarksFile(cancellation_callback, valid_url_callback, content, bookmarks, search_engines, favicons);
  790. +}
  791. +
  792. +void ImportBookmarksFile(
  793. + base::RepeatingCallback<bool(void)> cancellation_callback,
  794. + base::RepeatingCallback<bool(const GURL&)> valid_url_callback,
  795. + const std::string& content,
  796. + std::vector<ImportedBookmarkEntry>* bookmarks,
  797. + std::vector<importer::SearchEngineInfo>* search_engines,
  798. + favicon_base::FaviconUsageDataList* favicons) {
  799. std::vector<std::string> lines = base::SplitString(
  800. content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  801. @@ -126,6 +144,7 @@ void ImportBookmarksFile(
  802. std::vector<base::string16> path;
  803. size_t toolbar_folder_index = 0;
  804. std::string charset = "UTF-8"; // If no charset is specified, assume utf-8.
  805. +
  806. for (size_t i = 0;
  807. i < lines.size() &&
  808. (cancellation_callback.is_null() || !cancellation_callback.Run());
  809. @@ -218,10 +237,12 @@ void ImportBookmarksFile(
  810. }
  811. bookmarks->push_back(entry);
  812. +#if !defined(OS_ANDROID)
  813. // Save the favicon. DataURLToFaviconUsage will handle the case where
  814. // there is no favicon.
  815. if (favicons)
  816. DataURLToFaviconUsage(url, favicon, favicons);
  817. +#endif
  818. continue;
  819. }
  820. diff --git a/chrome/utility/importer/bookmark_html_reader.h b/chrome/utility/importer/bookmark_html_reader.h
  821. --- a/chrome/utility/importer/bookmark_html_reader.h
  822. +++ b/chrome/utility/importer/bookmark_html_reader.h
  823. @@ -51,6 +51,14 @@ void ImportBookmarksFile(
  824. std::vector<importer::SearchEngineInfo>* search_engines,
  825. favicon_base::FaviconUsageDataList* favicons);
  826. +void ImportBookmarksFile(
  827. + const base::RepeatingCallback<bool(void)> cancellation_callback,
  828. + const base::RepeatingCallback<bool(const GURL&)> valid_url_callback,
  829. + const std::string& content,
  830. + std::vector<ImportedBookmarkEntry>* bookmarks,
  831. + std::vector<importer::SearchEngineInfo>* search_engines,
  832. + favicon_base::FaviconUsageDataList* favicons);
  833. +
  834. // Returns true if |url| should be imported as a search engine, i.e. because it
  835. // has replacement terms. Chrome treats such bookmarks as search engines rather
  836. // than true bookmarks.
  837. diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
  838. --- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
  839. +++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
  840. @@ -36,6 +36,7 @@ import org.chromium.base.task.PostTask;
  841. import org.chromium.base.task.TaskTraits;
  842. import org.chromium.ui.PhotoPickerListener;
  843. import org.chromium.ui.R;
  844. +import org.chromium.ui.widget.Toast;
  845. import org.chromium.ui.UiUtils;
  846. import java.io.File;
  847. @@ -55,6 +56,7 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  848. private static final String IMAGE_TYPE = "image/";
  849. private static final String VIDEO_TYPE = "video/";
  850. private static final String AUDIO_TYPE = "audio/";
  851. + private static final String HTML_TYPE = "text/html";
  852. private static final String ALL_IMAGE_TYPES = IMAGE_TYPE + "*";
  853. private static final String ALL_VIDEO_TYPES = VIDEO_TYPE + "*";
  854. private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*";
  855. @@ -133,6 +135,11 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  856. mFileTypes = fileTypes;
  857. }
  858. + @CalledByNative
  859. + private void showToast(String message) {
  860. + Toast.makeText(ContextUtils.getApplicationContext(), message, Toast.LENGTH_LONG).show();
  861. + }
  862. +
  863. /**
  864. * Creates and starts an intent based on the passed fileTypes and capture value.
  865. * @param fileTypes MIME types requested (i.e. "image/*")
  866. @@ -160,7 +167,7 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  867. List<String> missingPermissions = new ArrayList<>();
  868. String storagePermission = Manifest.permission.READ_EXTERNAL_STORAGE;
  869. boolean shouldUsePhotoPicker = shouldUsePhotoPicker();
  870. - if (shouldUsePhotoPicker) {
  871. + if (shouldUsePhotoPicker || shouldShowHtmlTypes()) {
  872. if (!window.hasPermission(storagePermission)) missingPermissions.add(storagePermission);
  873. } else {
  874. if (((mSupportsImageCapture && shouldShowImageTypes())
  875. @@ -188,7 +195,7 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  876. }
  877. // TODO(finnur): Remove once we figure out the cause of crbug.com/950024.
  878. - if (shouldUsePhotoPicker) {
  879. + if (shouldUsePhotoPicker || shouldShowHtmlTypes()) {
  880. if (permissions.length != requestPermissions.length) {
  881. throw new RuntimeException(
  882. String.format("Permissions arrays misaligned: %d != %d",
  883. @@ -202,7 +209,7 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  884. }
  885. }
  886. - if (shouldUsePhotoPicker && permissions[i].equals(storagePermission)) {
  887. + if ((shouldUsePhotoPicker || shouldShowHtmlTypes()) && permissions[i].equals(storagePermission)) {
  888. onFileNotSelected();
  889. return;
  890. }
  891. @@ -351,6 +358,7 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  892. }
  893. if (!mimeTypes.contains(mimeType)) mimeTypes.add(mimeType);
  894. }
  895. + if (mimeTypes.size() == 0) return null;
  896. return mimeTypes;
  897. }
  898. @@ -631,6 +639,10 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  899. return countAcceptTypesFor(specificType) > 0;
  900. }
  901. + private boolean shouldShowHtmlTypes() {
  902. + return countAcceptTypesFor(HTML_TYPE) > 0;
  903. + }
  904. +
  905. private boolean shouldShowImageTypes() {
  906. return shouldShowTypes(ALL_IMAGE_TYPES, IMAGE_TYPE);
  907. }
  908. diff --git a/ui/shell_dialogs/select_file_dialog.h b/ui/shell_dialogs/select_file_dialog.h
  909. --- a/ui/shell_dialogs/select_file_dialog.h
  910. +++ b/ui/shell_dialogs/select_file_dialog.h
  911. @@ -191,6 +191,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
  912. void* params);
  913. bool HasMultipleFileTypeChoices();
  914. + virtual void ShowToast(const std::string& message) = 0;
  915. +
  916. protected:
  917. friend class base::RefCountedThreadSafe<SelectFileDialog>;
  918. diff --git a/ui/shell_dialogs/select_file_dialog_android.cc b/ui/shell_dialogs/select_file_dialog_android.cc
  919. --- a/ui/shell_dialogs/select_file_dialog_android.cc
  920. +++ b/ui/shell_dialogs/select_file_dialog_android.cc
  921. @@ -139,6 +139,12 @@ void SelectFileDialogImpl::SelectFileImpl(
  922. owning_window->GetJavaObject());
  923. }
  924. +void SelectFileDialogImpl::ShowToast(const std::string& message) {
  925. + JNIEnv* env = base::android::AttachCurrentThread();
  926. +
  927. + Java_SelectFileDialog_showToast(env, java_object_, base::android::ConvertUTF8ToJavaString(env, message));
  928. +}
  929. +
  930. SelectFileDialogImpl::~SelectFileDialogImpl() {
  931. }
  932. diff --git a/ui/shell_dialogs/select_file_dialog_android.h b/ui/shell_dialogs/select_file_dialog_android.h
  933. --- a/ui/shell_dialogs/select_file_dialog_android.h
  934. +++ b/ui/shell_dialogs/select_file_dialog_android.h
  935. @@ -55,6 +55,8 @@ class SelectFileDialogImpl : public SelectFileDialog {
  936. gfx::NativeWindow owning_window,
  937. void* params) override;
  938. + void ShowToast(const std::string& message) override;
  939. +
  940. protected:
  941. ~SelectFileDialogImpl() override;
  942. --
  943. 2.17.1