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

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: Comments and rebase. 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.ChromeFileProvider;
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 blockingUri The unique id given by the
301 * {@link ChromeFileProvider#generateUriAndBlockAccess()} for the screens hot.
Ted C 2016/09/07 00:30:08 align with "The unique" above
ssid 2016/09/07 00:51:23 Done.
302 * @param screenshot The screenshot bitmap to be written to file.
303 * @param activity Activity that is used to access package manager.
304 */
305 public static void onScreenshotReady(
306 final Uri blockingUri, final Bitmap screenshot, final Activity activ ity) {
307 if (screenshot == null) {
308 ChromeFileProvider.notifyFileReady(blockingUri, null);
309 return;
310 }
311
312 new AsyncTask<Void, Void, File>() {
313 @Override
314 protected File doInBackground(Void... params) {
315 FileOutputStream fOut = null;
316 try {
317 File path = new File(UiUtils.getDirectoryForImageCapture(act ivity) + "/"
318 + SHARE_IMAGES_DIRECTORY_NAME);
319 if (path.exists() || path.mkdir()) {
320 String fileName = String.valueOf(System.currentTimeMilli s());
321 File saveFile = File.createTempFile(fileName, JPEG_EXTEN SION, path);
322 fOut = new FileOutputStream(saveFile);
323 screenshot.compress(Bitmap.CompressFormat.JPEG, 85, fOut );
324 fOut.flush();
325 fOut.close();
326 return saveFile;
327 }
328 } catch (IOException ie) {
329 if (fOut != null) {
330 try {
331 fOut.close();
332 } catch (IOException e) {
333 // Ignore exception.
334 }
335 }
336 }
337
338 return null;
339 }
340
341 @Override
342 protected void onPostExecute(File saveFile) {
343 Uri fileUri = null;
344 if (ApplicationStatus.getStateForApplication()
345 != ApplicationState.HAS_DESTROYED_ACTIVITIES
346 && saveFile != null) {
347 fileUri = UiUtils.getUriForImageCaptureFile(activity, saveFi le);
348 }
349 ChromeFileProvider.notifyFileReady(blockingUri, fileUri);
350 }
351 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
352 }
353
354 /**
294 * Creates and shows a share intent picker dialog. 355 * Creates and shows a share intent picker dialog.
295 * 356 *
296 * @param saveLastUsed Whether to save the chosen activity for future direct sharing. 357 * @param saveLastUsed Whether to save the chosen activity for future direct sharing.
297 * @param activity Activity that is used to access package manager. 358 * @param activity Activity that is used to access package manager.
298 * @param title Title of the page to be shared. 359 * @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 360 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated
300 * with a space. 361 * with a space.
301 * @param url URL of the page to be shared. 362 * @param url URL of the page to be shared.
302 * @oaram Uri URI of the offline page to be shared. 363 * @oaram offlineUri URI of the offline page to be shared.
303 * @param screenshot Screenshot of the page to be shared. 364 * @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 365 * @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 366 * if receiving a response when the user makes a choice is n ot supported (on
306 * older Android versions). 367 * older Android versions).
307 */ 368 */
308 private static void showShareDialog(final boolean saveLastUsed, final Activi ty activity, 369 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, 370 final String title, final String text, final String url, final Uri o fflineUri,
310 final Bitmap screenshot, @Nullable final TargetChosenCallback callba ck) { 371 final Uri screenshotUri, @Nullable final TargetChosenCallback callba ck) {
311 Intent intent = getShareIntent(activity, title, text, url, null, null); 372 Intent intent = getShareIntent(activity, title, text, url, null, null);
312 PackageManager manager = activity.getPackageManager(); 373 PackageManager manager = activity.getPackageManager();
313 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent , 0); 374 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent , 0);
314 assert resolveInfoList.size() > 0; 375 assert resolveInfoList.size() > 0;
315 if (resolveInfoList.size() == 0) return; 376 if (resolveInfoList.size() == 0) return;
316 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator( manager)); 377 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator( manager));
317 378
318 final ShareDialogAdapter adapter = 379 final ShareDialogAdapter adapter =
319 new ShareDialogAdapter(activity, manager, resolveInfoList); 380 new ShareDialogAdapter(activity, manager, resolveInfoList);
320 AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style. AlertDialogTheme); 381 AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style. AlertDialogTheme);
321 builder.setTitle(activity.getString(R.string.share_link_chooser_title)); 382 builder.setTitle(activity.getString(R.string.share_link_chooser_title));
322 builder.setAdapter(adapter, null); 383 builder.setAdapter(adapter, null);
323 384
324 final AlertDialog dialog = builder.create(); 385 final AlertDialog dialog = builder.create();
325 dialog.show(); 386 dialog.show();
326 dialog.getListView().setOnItemClickListener(new OnItemClickListener() { 387 dialog.getListView().setOnItemClickListener(new OnItemClickListener() {
327 @Override 388 @Override
328 public void onItemClick(AdapterView<?> parent, View view, int positi on, long id) { 389 public void onItemClick(AdapterView<?> parent, View view, int positi on, long id) {
329 ResolveInfo info = adapter.getItem(position); 390 ResolveInfo info = adapter.getItem(position);
330 ActivityInfo ai = info.activityInfo; 391 ActivityInfo ai = info.activityInfo;
331 ComponentName component = 392 ComponentName component =
332 new ComponentName(ai.applicationInfo.packageName, ai.nam e); 393 new ComponentName(ai.applicationInfo.packageName, ai.nam e);
333 if (callback != null) callback.onTargetChosen(component); 394 if (callback != null) callback.onTargetChosen(component);
334 if (saveLastUsed) setLastShareComponentName(component); 395 if (saveLastUsed) setLastShareComponentName(component);
335 makeIntentAndShare( 396 makeIntentAndShare(false, activity, title, text, url, offlineUri , screenshotUri,
336 false, activity, title, text, url, offlineUri, screensho t, component, null); 397 component, null);
337 dialog.dismiss(); 398 dialog.dismiss();
338 } 399 }
339 }); 400 });
340 } 401 }
341 402
342 /** 403 /**
343 * Starts a share intent with the activity that was most recently used to sh are. 404 * 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. 405 * If there is no most recently used activity, it does nothing.
345 * @param activity Activity that is used to start the share intent. 406 * @param activity Activity that is used to start the share intent.
346 * @param title Title of the page to be shared. 407 * @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 408 * @param text Text to be shared. If both |text| and |url| are supplied, the y are concatenated
348 * with a space. 409 * with a space.
349 * @param url URL of the page to be shared. 410 * @param url URL of the page to be shared.
350 * @oaram Uri URI of the offline page to be shared. 411 * @oaram offlineUri URI of the offline page to be shared.
351 * @param screenshot Screenshot of the page to be shared. 412 * @param screenshotUri Uri of the screenshot of the page to be shared.
352 */ 413 */
353 private static void shareWithLastUsed(Activity activity, String title, Strin g text, String url, 414 private static void shareWithLastUsed(Activity activity, String title, Strin g text, String url,
354 Uri offlineUri, Bitmap screenshot) { 415 Uri offlineUri, Uri screenshotUri) {
355 ComponentName component = getLastShareComponentName(); 416 ComponentName component = getLastShareComponentName();
356 if (component == null) return; 417 if (component == null) return;
357 makeIntentAndShare( 418 makeIntentAndShare(
358 false, activity, title, text, url, offlineUri, screenshot, compo nent, null); 419 false, activity, title, text, url, offlineUri, screenshotUri, co mponent, null);
359 } 420 }
360 421
361 private static void shareIntent(boolean saveLastUsed, Activity activity, Int ent sharingIntent, 422 private static void shareIntent(boolean saveLastUsed, Activity activity, Int ent sharingIntent,
362 @Nullable TargetChosenCallback callback) { 423 @Nullable TargetChosenCallback callback) {
363 if (sharingIntent.getComponent() != null) { 424 if (sharingIntent.getComponent() != null) {
364 // If a component was specified, there should not also be a callback . 425 // If a component was specified, there should not also be a callback .
365 assert callback == null; 426 assert callback == null;
366 activity.startActivity(sharingIntent); 427 activity.startActivity(sharingIntent);
367 } else { 428 } else {
368 assert TargetChosenReceiver.isSupported(); 429 assert TargetChosenReceiver.isSupported();
369 TargetChosenReceiver.sendChooserIntent(saveLastUsed, activity, shari ngIntent, callback); 430 TargetChosenReceiver.sendChooserIntent(saveLastUsed, activity, shari ngIntent, callback);
370 } 431 }
371 } 432 }
372 433
373 private static void makeIntentAndShare(final boolean saveLastUsed, final Act ivity activity, 434 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, 435 final String title, final String text, final String url, final Uri o fflineUri,
375 final Bitmap screenshot, final ComponentName component, 436 final Uri screenshotUri, final ComponentName component,
376 @Nullable final TargetChosenCallback callback) { 437 @Nullable final TargetChosenCallback callback) {
377 if (screenshot == null) { 438 Intent intent = getDirectShareIntentForComponent(
378 Intent intent = getDirectShareIntentForComponent( 439 activity, title, text, url, offlineUri, screenshotUri, component );
379 activity, title, text, url, offlineUri, null, component); 440 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 } 441 }
428 442
429 /** 443 /**
430 * Set the icon and the title for the menu item used for direct share. 444 * Set the icon and the title for the menu item used for direct share.
431 * 445 *
432 * @param activity Activity that is used to access the package manager. 446 * @param activity Activity that is used to access the package manager.
433 * @param item The menu item that is used for direct share 447 * @param item The menu item that is used for direct share
434 */ 448 */
435 public static void configureDirectShareMenuItem(Activity activity, MenuItem item) { 449 public static void configureDirectShareMenuItem(Activity activity, MenuItem item) {
436 Drawable directShareIcon = null; 450 Drawable directShareIcon = null;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 "Android.IsLastSharedAppInfoRetrieved", retrieved); 504 "Android.IsLastSharedAppInfoRetrieved", retrieved);
491 } 505 }
492 506
493 item.setIcon(directShareIcon); 507 item.setIcon(directShareIcon);
494 if (directShareTitle != null) { 508 if (directShareTitle != null) {
495 item.setTitle(activity.getString(R.string.accessibility_menu_share_v ia, 509 item.setTitle(activity.getString(R.string.accessibility_menu_share_v ia,
496 directShareTitle)); 510 directShareTitle));
497 } 511 }
498 } 512 }
499 513
514 /*
515 * Stores the component selected for sharing last time share was called.
516 *
517 * This method is public since it is used in tests to avoid creating share d ialog.
518 */
519 @VisibleForTesting
520 public static void setLastShareComponentName(ComponentName component) {
521 SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
522 SharedPreferences.Editor editor = preferences.edit();
523 editor.putString(PACKAGE_NAME_KEY, component.getPackageName());
524 editor.putString(CLASS_NAME_KEY, component.getClassName());
525 editor.apply();
526 }
527
500 @VisibleForTesting 528 @VisibleForTesting
501 public static Intent getShareIntent(Activity activity, String title, String text, String url, 529 public static Intent getShareIntent(Activity activity, String title, String text, String url,
502 Uri offlineUri, Uri screenshotUri) { 530 Uri offlineUri, Uri screenshotUri) {
503 if (!TextUtils.isEmpty(url)) { 531 if (!TextUtils.isEmpty(url)) {
504 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url); 532 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url);
505 if (!TextUtils.isEmpty(text)) { 533 if (!TextUtils.isEmpty(text)) {
506 // Concatenate text and URL with a space. 534 // Concatenate text and URL with a space.
507 text = text + " " + url; 535 text = text + " " + url;
508 } else { 536 } else {
509 text = url; 537 text = url;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 return intent; 581 return intent;
554 } 582 }
555 583
556 private static ComponentName getLastShareComponentName() { 584 private static ComponentName getLastShareComponentName() {
557 SharedPreferences preferences = ContextUtils.getAppSharedPreferences(); 585 SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
558 String packageName = preferences.getString(PACKAGE_NAME_KEY, null); 586 String packageName = preferences.getString(PACKAGE_NAME_KEY, null);
559 String className = preferences.getString(CLASS_NAME_KEY, null); 587 String className = preferences.getString(CLASS_NAME_KEY, null);
560 if (packageName == null || className == null) return null; 588 if (packageName == null || className == null) return null;
561 return new ComponentName(packageName, className); 589 return new ComponentName(packageName, className);
562 } 590 }
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 } 591 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698