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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java

Issue 2143133002: Do screenshot capture async for share intents. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase + more comments addressed. 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.share; 5 package org.chromium.chrome.browser.share;
6 6
7 import android.annotation.TargetApi; 7 import android.annotation.TargetApi;
8 import android.app.Activity; 8 import android.app.Activity;
9 import android.app.PendingIntent; 9 import android.app.PendingIntent;
10 import android.content.BroadcastReceiver; 10 import android.content.BroadcastReceiver;
(...skipping 24 matching lines...) Expand all
35 35
36 import org.chromium.base.ApiCompatibilityUtils; 36 import org.chromium.base.ApiCompatibilityUtils;
37 import org.chromium.base.ApplicationState; 37 import org.chromium.base.ApplicationState;
38 import org.chromium.base.ApplicationStatus; 38 import org.chromium.base.ApplicationStatus;
39 import org.chromium.base.ContextUtils; 39 import org.chromium.base.ContextUtils;
40 import org.chromium.base.Log; 40 import org.chromium.base.Log;
41 import org.chromium.base.VisibleForTesting; 41 import org.chromium.base.VisibleForTesting;
42 import org.chromium.base.annotations.SuppressFBWarnings; 42 import org.chromium.base.annotations.SuppressFBWarnings;
43 import org.chromium.base.metrics.RecordHistogram; 43 import org.chromium.base.metrics.RecordHistogram;
44 import org.chromium.chrome.R; 44 import org.chromium.chrome.R;
45 import org.chromium.chrome.browser.BlockingFileProvider;
45 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; 46 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
46 import org.chromium.ui.UiUtils; 47 import org.chromium.ui.UiUtils;
47 48
48 import java.io.File; 49 import java.io.File;
49 import java.io.FileOutputStream; 50 import java.io.FileOutputStream;
50 import java.io.IOException; 51 import java.io.IOException;
51 import java.util.Collections; 52 import java.util.Collections;
52 import java.util.List; 53 import java.util.List;
53 import java.util.concurrent.ExecutionException; 54 import java.util.concurrent.ExecutionException;
54 import java.util.concurrent.TimeUnit; 55 import java.util.concurrent.TimeUnit;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 * 206 *
206 * @param shareDirectly Whether it should share directly with the activity t hat was most 207 * @param shareDirectly Whether it should share directly with the activity t hat was most
207 * recently used to share. 208 * recently used to share.
208 * @param saveLastUsed Whether to save the chosen activity for future direct sharing. 209 * @param saveLastUsed Whether to save the chosen activity for future direct sharing.
209 * @param activity Activity that is used to access package manager. 210 * @param activity Activity that is used to access package manager.
210 * @param title Title of the page to be shared. 211 * @param title Title of the page to be shared.
211 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated 212 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated
212 * with a space. 213 * with a space.
213 * @param url URL of the page to be shared. 214 * @param url URL of the page to be shared.
214 * @param offlineUri URI to the offline MHTML file to be shared. 215 * @param offlineUri URI to the offline MHTML file to be shared.
215 * @param screenshot Screenshot of the page to be shared. 216 * @param screenshotUri Uri of the screenshot of the page to be shared.
216 * @param callback Optional callback to be called when user makes a choice. Will not be called 217 * @param callback Optional callback to be called when user makes a choice. Will not be called
217 * if receiving a response when the user makes a choice is n ot supported (on 218 * if receiving a response when the user makes a choice is n ot supported (on
218 * older Android versions). 219 * older Android versions).
219 */ 220 */
220 public static void share(boolean shareDirectly, boolean saveLastUsed, Activi ty activity, 221 public static void share(boolean shareDirectly, boolean saveLastUsed, Activi ty activity,
221 String title, String text, String url, @Nullable Uri offlineUri, Bit map screenshot, 222 String title, String text, String url, @Nullable Uri offlineUri, Uri screenshotUri,
222 @Nullable TargetChosenCallback callback) { 223 @Nullable TargetChosenCallback callback) {
223 if (shareDirectly) { 224 if (shareDirectly) {
224 shareWithLastUsed(activity, title, text, url, offlineUri, screenshot ); 225 shareWithLastUsed(activity, title, text, url, offlineUri, screenshot Uri);
225 } else if (TargetChosenReceiver.isSupported()) { 226 } else if (TargetChosenReceiver.isSupported()) {
226 makeIntentAndShare(saveLastUsed, activity, title, text, url, offline Uri, screenshot, 227 makeIntentAndShare(saveLastUsed, activity, title, text, url, offline Uri, screenshotUri,
227 null, callback); 228 null, callback);
228 } else { 229 } else {
229 showShareDialog( 230 showShareDialog(
230 saveLastUsed, activity, title, text, url, offlineUri, screen shot, callback); 231 saveLastUsed, activity, title, text, url, offlineUri, screen shotUri, callback);
231 } 232 }
232 } 233 }
233 234
234 /** 235 /**
235 * Trigger the share action for the given image data. 236 * Trigger the share action for the given image data.
236 * @param activity The activity used to trigger the share action. 237 * @param activity The activity used to trigger the share action.
237 * @param jpegImageData The image data to be shared in jpeg format. 238 * @param jpegImageData The image data to be shared in jpeg format.
238 */ 239 */
239 public static void shareImage(final Activity activity, final byte[] jpegImag eData) { 240 public static void shareImage(final Activity activity, final byte[] jpegImag eData) {
240 if (jpegImageData.length == 0) { 241 if (jpegImageData.length == 0) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 285
285 Intent chooserIntent = Intent.createChooser(getShareImageInt ent(imageUri), 286 Intent chooserIntent = Intent.createChooser(getShareImageInt ent(imageUri),
286 activity.getString(R.string.share_link_chooser_title )); 287 activity.getString(R.string.share_link_chooser_title ));
287 activity.startActivity(chooserIntent); 288 activity.startActivity(chooserIntent);
288 } 289 }
289 } 290 }
290 }.execute(); 291 }.execute();
291 } 292 }
292 293
293 /** 294 /**
295 * Writes the screenshot file and notifies the file provider that the file i s ready to be
296 * accessed by the client.
297 *
298 * The bitmap is compressed to JPEG before being written to the file.
299 *
300 * @param uuidUri The unique id given by the BlockingFileProvider for the sc reenshot.
Ted C 2016/08/27 00:22:12 you can use {@link BlockingFileProvider} or if you
ssid 2016/09/06 22:25:36 Done.
301 * @param screenshot The screenshot bitmap to be written to file.
302 * @param activity Activity that is used to access package manager.
303 */
304 public static void onScreenshotReady(
305 final Uri uuidUri, final Bitmap screenshot, final Activity activity) {
306 if (screenshot == null) {
307 BlockingFileProvider.notifyFileReady(uuidUri, null);
308 return;
309 }
310
311 new AsyncTask<Void, Void, File>() {
312 @Override
313 protected File doInBackground(Void... params) {
314 FileOutputStream fOut = null;
315 try {
316 File path = new File(UiUtils.getDirectoryForImageCapture(act ivity) + "/"
317 + SHARE_IMAGES_DIRECTORY_NAME);
318 if (path.exists() || path.mkdir()) {
319 String fileName = String.valueOf(System.currentTimeMilli s());
320 File saveFile = File.createTempFile(fileName, JPEG_EXTEN SION, path);
321 fOut = new FileOutputStream(saveFile);
322 screenshot.compress(Bitmap.CompressFormat.JPEG, 85, fOut );
323 fOut.flush();
324 fOut.close();
325 return saveFile;
326 }
327 } catch (IOException ie) {
328 if (fOut != null) {
329 try {
330 fOut.close();
331 } catch (IOException e) {
332 // Ignore exception.
333 }
334 }
335 }
336
337 return null;
338 }
339
340 @Override
341 protected void onPostExecute(File saveFile) {
342 Uri fileUri = null;
343 if (ApplicationStatus.getStateForApplication()
344 != ApplicationState.HAS_DESTROYED_ACTIVITIES
Ted C 2016/08/27 00:22:12 decrease indent, should be 8 from the previous lin
ssid 2016/09/06 22:25:36 Sorry, I fixed and git cl format changed back. Sto
345 && saveFile != null) {
346 fileUri = UiUtils.getUriForImageCaptureFile(activity, saveFi le);
347 }
348 BlockingFileProvider.notifyFileReady(uuidUri, fileUri);
349 }
350 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
351 }
352
353 /**
294 * Creates and shows a share intent picker dialog. 354 * Creates and shows a share intent picker dialog.
295 * 355 *
296 * @param saveLastUsed Whether to save the chosen activity for future direct sharing. 356 * @param saveLastUsed Whether to save the chosen activity for future direct sharing.
297 * @param activity Activity that is used to access package manager. 357 * @param activity Activity that is used to access package manager.
298 * @param title Title of the page to be shared. 358 * @param title Title of the page to be shared.
299 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated 359 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated
300 * with a space. 360 * with a space.
301 * @param url URL of the page to be shared. 361 * @param url URL of the page to be shared.
302 * @oaram Uri URI of the offline page to be shared. 362 * @oaram offlineUri URI of the offline page to be shared.
303 * @param screenshot Screenshot of the page to be shared. 363 * @param screenshotUri Uri of the screenshot of the page to be shared.
304 * @param callback Optional callback to be called when user makes a choice. Will not be called 364 * @param callback Optional callback to be called when user makes a choice. Will not be called
305 * if receiving a response when the user makes a choice is n ot supported (on 365 * if receiving a response when the user makes a choice is n ot supported (on
306 * older Android versions). 366 * older Android versions).
307 */ 367 */
308 private static void showShareDialog(final boolean saveLastUsed, final Activi ty activity, 368 private static void showShareDialog(final boolean saveLastUsed, final Activi ty activity,
309 final String title, final String text, final String url, final Uri o fflineUri, 369 final String title, final String text, final String url, final Uri o fflineUri,
310 final Bitmap screenshot, @Nullable final TargetChosenCallback callba ck) { 370 final Uri screenshotUri, @Nullable final TargetChosenCallback callba ck) {
311 Intent intent = getShareIntent(activity, title, text, url, null, null); 371 Intent intent = getShareIntent(activity, title, text, url, null, null);
312 PackageManager manager = activity.getPackageManager(); 372 PackageManager manager = activity.getPackageManager();
313 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent , 0); 373 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent , 0);
314 assert resolveInfoList.size() > 0; 374 assert resolveInfoList.size() > 0;
315 if (resolveInfoList.size() == 0) return; 375 if (resolveInfoList.size() == 0) return;
316 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator( manager)); 376 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator( manager));
317 377
318 final ShareDialogAdapter adapter = 378 final ShareDialogAdapter adapter =
319 new ShareDialogAdapter(activity, manager, resolveInfoList); 379 new ShareDialogAdapter(activity, manager, resolveInfoList);
320 AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style. AlertDialogTheme); 380 AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style. AlertDialogTheme);
321 builder.setTitle(activity.getString(R.string.share_link_chooser_title)); 381 builder.setTitle(activity.getString(R.string.share_link_chooser_title));
322 builder.setAdapter(adapter, null); 382 builder.setAdapter(adapter, null);
323 383
324 final AlertDialog dialog = builder.create(); 384 final AlertDialog dialog = builder.create();
325 dialog.show(); 385 dialog.show();
326 dialog.getListView().setOnItemClickListener(new OnItemClickListener() { 386 dialog.getListView().setOnItemClickListener(new OnItemClickListener() {
327 @Override 387 @Override
328 public void onItemClick(AdapterView<?> parent, View view, int positi on, long id) { 388 public void onItemClick(AdapterView<?> parent, View view, int positi on, long id) {
329 ResolveInfo info = adapter.getItem(position); 389 ResolveInfo info = adapter.getItem(position);
330 ActivityInfo ai = info.activityInfo; 390 ActivityInfo ai = info.activityInfo;
331 ComponentName component = 391 ComponentName component =
332 new ComponentName(ai.applicationInfo.packageName, ai.nam e); 392 new ComponentName(ai.applicationInfo.packageName, ai.nam e);
333 if (callback != null) callback.onTargetChosen(component); 393 if (callback != null) callback.onTargetChosen(component);
334 if (saveLastUsed) setLastShareComponentName(component); 394 if (saveLastUsed) setLastShareComponentName(component);
335 makeIntentAndShare( 395 makeIntentAndShare(false, activity, title, text, url, offlineUri , screenshotUri,
336 false, activity, title, text, url, offlineUri, screensho t, component, null); 396 component, null);
337 dialog.dismiss(); 397 dialog.dismiss();
338 } 398 }
339 }); 399 });
340 } 400 }
341 401
342 /** 402 /**
343 * Starts a share intent with the activity that was most recently used to sh are. 403 * Starts a share intent with the activity that was most recently used to sh are.
344 * If there is no most recently used activity, it does nothing. 404 * If there is no most recently used activity, it does nothing.
345 * @param activity Activity that is used to start the share intent. 405 * @param activity Activity that is used to start the share intent.
346 * @param title Title of the page to be shared. 406 * @param title Title of the page to be shared.
347 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated 407 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated
348 * with a space. 408 * with a space.
349 * @param url URL of the page to be shared. 409 * @param url URL of the page to be shared.
350 * @oaram Uri URI of the offline page to be shared. 410 * @oaram offlineUri URI of the offline page to be shared.
351 * @param screenshot Screenshot of the page to be shared. 411 * @param screenshotUri Uri of the screenshot of the page to be shared.
352 */ 412 */
353 private static void shareWithLastUsed(Activity activity, String title, Strin g text, String url, 413 private static void shareWithLastUsed(Activity activity, String title, Strin g text, String url,
354 Uri offlineUri, Bitmap screenshot) { 414 Uri offlineUri, Uri screenshotUri) {
355 ComponentName component = getLastShareComponentName(); 415 ComponentName component = getLastShareComponentName();
356 if (component == null) return; 416 if (component == null) return;
357 makeIntentAndShare( 417 makeIntentAndShare(
358 false, activity, title, text, url, offlineUri, screenshot, compo nent, null); 418 false, activity, title, text, url, offlineUri, screenshotUri, co mponent, null);
359 } 419 }
360 420
361 private static void shareIntent(boolean saveLastUsed, Activity activity, Int ent sharingIntent, 421 private static void shareIntent(boolean saveLastUsed, Activity activity, Int ent sharingIntent,
362 @Nullable TargetChosenCallback callback) { 422 @Nullable TargetChosenCallback callback) {
363 if (sharingIntent.getComponent() != null) { 423 if (sharingIntent.getComponent() != null) {
364 // If a component was specified, there should not also be a callback . 424 // If a component was specified, there should not also be a callback .
365 assert callback == null; 425 assert callback == null;
366 activity.startActivity(sharingIntent); 426 activity.startActivity(sharingIntent);
367 } else { 427 } else {
368 assert TargetChosenReceiver.isSupported(); 428 assert TargetChosenReceiver.isSupported();
369 TargetChosenReceiver.sendChooserIntent(saveLastUsed, activity, shari ngIntent, callback); 429 TargetChosenReceiver.sendChooserIntent(saveLastUsed, activity, shari ngIntent, callback);
370 } 430 }
371 } 431 }
372 432
373 private static void makeIntentAndShare(final boolean saveLastUsed, final Act ivity activity, 433 private static void makeIntentAndShare(final boolean saveLastUsed, final Act ivity activity,
374 final String title, final String text, final String url, final Uri o fflineUri, 434 final String title, final String text, final String url, final Uri o fflineUri,
375 final Bitmap screenshot, final ComponentName component, 435 final Uri screenshotUri, final ComponentName component,
376 @Nullable final TargetChosenCallback callback) { 436 @Nullable final TargetChosenCallback callback) {
377 if (screenshot == null) { 437 Intent intent = getDirectShareIntentForComponent(
378 Intent intent = getDirectShareIntentForComponent( 438 activity, title, text, url, offlineUri, screenshotUri, component );
379 activity, title, text, url, offlineUri, null, component); 439 shareIntent(saveLastUsed, activity, intent, callback);
380 shareIntent(saveLastUsed, activity, intent, callback);
381 } else {
382 new AsyncTask<Void, Void, File>() {
383 @Override
384 protected File doInBackground(Void... params) {
385 FileOutputStream fOut = null;
386 try {
387 File path = new File(UiUtils.getDirectoryForImageCapture (activity),
388 SHARE_IMAGES_DIRECTORY_NAME);
389 if (path.exists() || path.mkdir()) {
390 File saveFile = File.createTempFile(
391 String.valueOf(System.currentTimeMillis()),
392 JPEG_EXTENSION, path);
393 fOut = new FileOutputStream(saveFile);
394 screenshot.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
395 fOut.flush();
396 fOut.close();
397
398 return saveFile;
399 }
400 } catch (IOException ie) {
401 if (fOut != null) {
402 try {
403 fOut.close();
404 } catch (IOException e) {
405 // Ignore exception.
406 }
407 }
408 }
409
410 return null;
411 }
412
413 @Override
414 protected void onPostExecute(File saveFile) {
415 if (ApplicationStatus.getStateForApplication()
416 != ApplicationState.HAS_DESTROYED_ACTIVITIES) {
417 Uri screenshotUri = saveFile == null
418 ? null : UiUtils.getUriForImageCaptureFile(activ ity, saveFile);
419 shareIntent(saveLastUsed, activity,
420 getDirectShareIntentForComponent(activity, title , text, url,
421 offlineUri, screenshotUri, component ),
422 callback);
423 }
424 }
425 }.execute();
426 }
427 } 440 }
428 441
429 /** 442 /**
430 * Set the icon and the title for the menu item used for direct share. 443 * Set the icon and the title for the menu item used for direct share.
431 * 444 *
432 * @param activity Activity that is used to access the package manager. 445 * @param activity Activity that is used to access the package manager.
433 * @param item The menu item that is used for direct share 446 * @param item The menu item that is used for direct share
434 */ 447 */
435 public static void configureDirectShareMenuItem(Activity activity, MenuItem item) { 448 public static void configureDirectShareMenuItem(Activity activity, MenuItem item) {
436 Drawable directShareIcon = null; 449 Drawable directShareIcon = null;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 "Android.IsLastSharedAppInfoRetrieved", retrieved); 503 "Android.IsLastSharedAppInfoRetrieved", retrieved);
491 } 504 }
492 505
493 item.setIcon(directShareIcon); 506 item.setIcon(directShareIcon);
494 if (directShareTitle != null) { 507 if (directShareTitle != null) {
495 item.setTitle(activity.getString(R.string.accessibility_menu_share_v ia, 508 item.setTitle(activity.getString(R.string.accessibility_menu_share_v ia,
496 directShareTitle)); 509 directShareTitle));
497 } 510 }
498 } 511 }
499 512
513 /*
514 * Stores the component selected for sharing last time share was called.
515 *
516 * This method is public since it is used in tests to avoid creating share d ialog.
517 */
518 @VisibleForTesting
519 public static void setLastShareComponentName(ComponentName component) {
520 SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
521 SharedPreferences.Editor editor = preferences.edit();
522 editor.putString(PACKAGE_NAME_KEY, component.getPackageName());
523 editor.putString(CLASS_NAME_KEY, component.getClassName());
524 editor.apply();
525 }
526
500 @VisibleForTesting 527 @VisibleForTesting
501 public static Intent getShareIntent(Activity activity, String title, String text, String url, 528 public static Intent getShareIntent(Activity activity, String title, String text, String url,
502 Uri offlineUri, Uri screenshotUri) { 529 Uri offlineUri, Uri screenshotUri) {
503 if (!TextUtils.isEmpty(url)) { 530 if (!TextUtils.isEmpty(url)) {
504 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url); 531 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url);
505 if (!TextUtils.isEmpty(text)) { 532 if (!TextUtils.isEmpty(text)) {
506 // Concatenate text and URL with a space. 533 // Concatenate text and URL with a space.
507 text = text + " " + url; 534 text = text + " " + url;
508 } else { 535 } else {
509 text = url; 536 text = url;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 return intent; 580 return intent;
554 } 581 }
555 582
556 private static ComponentName getLastShareComponentName() { 583 private static ComponentName getLastShareComponentName() {
557 SharedPreferences preferences = ContextUtils.getAppSharedPreferences(); 584 SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
558 String packageName = preferences.getString(PACKAGE_NAME_KEY, null); 585 String packageName = preferences.getString(PACKAGE_NAME_KEY, null);
559 String className = preferences.getString(CLASS_NAME_KEY, null); 586 String className = preferences.getString(CLASS_NAME_KEY, null);
560 if (packageName == null || className == null) return null; 587 if (packageName == null || className == null) return null;
561 return new ComponentName(packageName, className); 588 return new ComponentName(packageName, className);
562 } 589 }
563
564 private static void setLastShareComponentName(ComponentName component) {
565 SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
566 SharedPreferences.Editor editor = preferences.edit();
567 editor.putString(PACKAGE_NAME_KEY, component.getPackageName());
568 editor.putString(CLASS_NAME_KEY, component.getClassName());
569 editor.apply();
570 }
571 } 590 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698