OLD | NEW |
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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 import java.util.concurrent.TimeUnit; | 52 import java.util.concurrent.TimeUnit; |
53 import java.util.concurrent.TimeoutException; | 53 import java.util.concurrent.TimeoutException; |
54 | 54 |
55 /** | 55 /** |
56 * A helper class that helps to start an intent to share titles and URLs. | 56 * A helper class that helps to start an intent to share titles and URLs. |
57 */ | 57 */ |
58 public class ShareHelper { | 58 public class ShareHelper { |
59 | 59 |
60 private static final String TAG = "share"; | 60 private static final String TAG = "share"; |
61 | 61 |
| 62 /** The task ID of the activity that triggered the share action. */ |
| 63 public static final String EXTRA_TASK_ID = "org.chromium.chrome.extra.TASK_I
D"; |
| 64 |
62 private static final String JPEG_EXTENSION = ".jpg"; | 65 private static final String JPEG_EXTENSION = ".jpg"; |
63 private static final String PACKAGE_NAME_KEY = "last_shared_package_name"; | 66 private static final String PACKAGE_NAME_KEY = "last_shared_package_name"; |
64 private static final String CLASS_NAME_KEY = "last_shared_class_name"; | 67 private static final String CLASS_NAME_KEY = "last_shared_class_name"; |
65 private static final String EXTRA_SHARE_SCREENSHOT_AS_STREAM = "share_screen
shot_as_stream"; | 68 private static final String EXTRA_SHARE_SCREENSHOT_AS_STREAM = "share_screen
shot_as_stream"; |
66 private static final long COMPONENT_INFO_READ_TIMEOUT_IN_MS = 1000; | 69 private static final long COMPONENT_INFO_READ_TIMEOUT_IN_MS = 1000; |
67 | 70 |
68 /** | 71 /** |
69 * Directory name for shared images. | 72 * Directory name for shared images. |
70 * | 73 * |
71 * Named "screenshot" for historical reasons as we only initially shared scr
eenshot images. | 74 * Named "screenshot" for historical reasons as we only initially shared scr
eenshot images. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 context.getApplicationContext().unregisterReceiver(sLastRegister
edReceiver); | 136 context.getApplicationContext().unregisterReceiver(sLastRegister
edReceiver); |
134 sLastRegisteredReceiver = null; | 137 sLastRegisteredReceiver = null; |
135 } | 138 } |
136 if (!intent.hasExtra(EXTRA_RECEIVER_TOKEN) | 139 if (!intent.hasExtra(EXTRA_RECEIVER_TOKEN) |
137 || intent.getIntExtra(EXTRA_RECEIVER_TOKEN, 0) != this.hashC
ode()) { | 140 || intent.getIntExtra(EXTRA_RECEIVER_TOKEN, 0) != this.hashC
ode()) { |
138 return; | 141 return; |
139 } | 142 } |
140 | 143 |
141 ComponentName target = intent.getParcelableExtra(Intent.EXTRA_CHOSEN
_COMPONENT); | 144 ComponentName target = intent.getParcelableExtra(Intent.EXTRA_CHOSEN
_COMPONENT); |
142 if (target != null) { | 145 if (target != null) { |
143 setLastShareComponentName(context, target); | 146 setLastShareComponentName(target); |
144 } | 147 } |
145 } | 148 } |
146 } | 149 } |
147 | 150 |
148 /** | 151 /** |
149 * Clears all shared image files. | 152 * Clears all shared image files. |
150 */ | 153 */ |
151 public static void clearSharedImages(final Context context) { | 154 public static void clearSharedImages(final Context context) { |
152 new AsyncTask<Void, Void, Void>() { | 155 new AsyncTask<Void, Void, Void>() { |
153 @Override | 156 @Override |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 /** | 255 /** |
253 * Creates and shows a share intent picker dialog. | 256 * Creates and shows a share intent picker dialog. |
254 * | 257 * |
255 * @param activity Activity that is used to access package manager. | 258 * @param activity Activity that is used to access package manager. |
256 * @param title Title of the page to be shared. | 259 * @param title Title of the page to be shared. |
257 * @param url URL of the page to be shared. | 260 * @param url URL of the page to be shared. |
258 * @param screenshot Screenshot of the page to be shared. | 261 * @param screenshot Screenshot of the page to be shared. |
259 */ | 262 */ |
260 private static void showShareDialog(final Activity activity, final String ti
tle, | 263 private static void showShareDialog(final Activity activity, final String ti
tle, |
261 final String url, final Bitmap screenshot) { | 264 final String url, final Bitmap screenshot) { |
262 Intent intent = getShareIntent(title, url, null); | 265 Intent intent = getShareIntent(activity, title, url, null); |
263 PackageManager manager = activity.getPackageManager(); | 266 PackageManager manager = activity.getPackageManager(); |
264 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent
, 0); | 267 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent
, 0); |
265 assert resolveInfoList.size() > 0; | 268 assert resolveInfoList.size() > 0; |
266 if (resolveInfoList.size() == 0) return; | 269 if (resolveInfoList.size() == 0) return; |
267 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator(
manager)); | 270 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator(
manager)); |
268 | 271 |
269 final ShareDialogAdapter adapter = | 272 final ShareDialogAdapter adapter = |
270 new ShareDialogAdapter(activity, manager, resolveInfoList); | 273 new ShareDialogAdapter(activity, manager, resolveInfoList); |
271 AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.
AlertDialogTheme); | 274 AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.
AlertDialogTheme); |
272 builder.setTitle(activity.getString(R.string.share_link_chooser_title)); | 275 builder.setTitle(activity.getString(R.string.share_link_chooser_title)); |
273 builder.setAdapter(adapter, null); | 276 builder.setAdapter(adapter, null); |
274 | 277 |
275 final AlertDialog dialog = builder.create(); | 278 final AlertDialog dialog = builder.create(); |
276 dialog.show(); | 279 dialog.show(); |
277 dialog.getListView().setOnItemClickListener(new OnItemClickListener() { | 280 dialog.getListView().setOnItemClickListener(new OnItemClickListener() { |
278 @Override | 281 @Override |
279 public void onItemClick(AdapterView<?> parent, View view, int positi
on, long id) { | 282 public void onItemClick(AdapterView<?> parent, View view, int positi
on, long id) { |
280 ResolveInfo info = adapter.getItem(position); | 283 ResolveInfo info = adapter.getItem(position); |
281 ActivityInfo ai = info.activityInfo; | 284 ActivityInfo ai = info.activityInfo; |
282 ComponentName component = | 285 ComponentName component = |
283 new ComponentName(ai.applicationInfo.packageName, ai.nam
e); | 286 new ComponentName(ai.applicationInfo.packageName, ai.nam
e); |
284 setLastShareComponentName(activity, component); | 287 setLastShareComponentName(component); |
285 makeIntentAndShare(activity, title, url, screenshot, component); | 288 makeIntentAndShare(activity, title, url, screenshot, component); |
286 dialog.dismiss(); | 289 dialog.dismiss(); |
287 } | 290 } |
288 }); | 291 }); |
289 } | 292 } |
290 | 293 |
291 /** | 294 /** |
292 * Starts a share intent with the activity that was most recently used to sh
are. | 295 * Starts a share intent with the activity that was most recently used to sh
are. |
293 * If there is no most recently used activity, it does nothing. | 296 * If there is no most recently used activity, it does nothing. |
294 * @param activity Activity that is used to start the share intent. | 297 * @param activity Activity that is used to start the share intent. |
295 * @param title Title of the page to be shared. | 298 * @param title Title of the page to be shared. |
296 * @param url URL of the page to be shared. | 299 * @param url URL of the page to be shared. |
297 * @param screenshot Screenshot of the page to be shared. | 300 * @param screenshot Screenshot of the page to be shared. |
298 */ | 301 */ |
299 private static void shareWithLastUsed( | 302 private static void shareWithLastUsed( |
300 Activity activity, String title, String url, Bitmap screenshot) { | 303 Activity activity, String title, String url, Bitmap screenshot) { |
301 ComponentName component = getLastShareComponentName(activity); | 304 ComponentName component = getLastShareComponentName(); |
302 if (component == null) return; | 305 if (component == null) return; |
303 makeIntentAndShare(activity, title, url, screenshot, component); | 306 makeIntentAndShare(activity, title, url, screenshot, component); |
304 } | 307 } |
305 | 308 |
306 private static void shareIntent(Activity activity, Intent sharingIntent) { | 309 private static void shareIntent(Activity activity, Intent sharingIntent) { |
307 if (sharingIntent.getComponent() != null) { | 310 if (sharingIntent.getComponent() != null) { |
308 activity.startActivity(sharingIntent); | 311 activity.startActivity(sharingIntent); |
309 } else { | 312 } else { |
310 assert TargetChosenReceiver.isSupported(); | 313 assert TargetChosenReceiver.isSupported(); |
311 TargetChosenReceiver.sendChooserIntent(activity, sharingIntent); | 314 TargetChosenReceiver.sendChooserIntent(activity, sharingIntent); |
312 } | 315 } |
313 } | 316 } |
314 | 317 |
315 private static void makeIntentAndShare(final Activity activity, final String
title, | 318 private static void makeIntentAndShare(final Activity activity, final String
title, |
316 final String url, final Bitmap screenshot, final ComponentName compo
nent) { | 319 final String url, final Bitmap screenshot, final ComponentName compo
nent) { |
317 if (screenshot == null) { | 320 if (screenshot == null) { |
318 shareIntent(activity, getDirectShareIntentForComponent(title, url, n
ull, component)); | 321 shareIntent(activity, |
| 322 getDirectShareIntentForComponent(activity, title, url, null,
component)); |
319 } else { | 323 } else { |
320 new AsyncTask<Void, Void, File>() { | 324 new AsyncTask<Void, Void, File>() { |
321 @Override | 325 @Override |
322 protected File doInBackground(Void... params) { | 326 protected File doInBackground(Void... params) { |
323 FileOutputStream fOut = null; | 327 FileOutputStream fOut = null; |
324 try { | 328 try { |
325 File path = new File(UiUtils.getDirectoryForImageCapture
(activity), | 329 File path = new File(UiUtils.getDirectoryForImageCapture
(activity), |
326 SHARE_IMAGES_DIRECTORY_NAME); | 330 SHARE_IMAGES_DIRECTORY_NAME); |
327 if (path.exists() || path.mkdir()) { | 331 if (path.exists() || path.mkdir()) { |
328 File saveFile = File.createTempFile( | 332 File saveFile = File.createTempFile( |
(...skipping 19 matching lines...) Expand all Loading... |
348 return null; | 352 return null; |
349 } | 353 } |
350 | 354 |
351 @Override | 355 @Override |
352 protected void onPostExecute(File saveFile) { | 356 protected void onPostExecute(File saveFile) { |
353 if (ApplicationStatus.getStateForApplication() | 357 if (ApplicationStatus.getStateForApplication() |
354 != ApplicationState.HAS_DESTROYED_ACTIVITIES) { | 358 != ApplicationState.HAS_DESTROYED_ACTIVITIES) { |
355 Uri screenshotUri = saveFile == null | 359 Uri screenshotUri = saveFile == null |
356 ? null : UiUtils.getUriForImageCaptureFile(activ
ity, saveFile); | 360 ? null : UiUtils.getUriForImageCaptureFile(activ
ity, saveFile); |
357 shareIntent(activity, getDirectShareIntentForComponent( | 361 shareIntent(activity, getDirectShareIntentForComponent( |
358 title, url, screenshotUri, component)); | 362 activity, title, url, screenshotUri, component))
; |
359 } | 363 } |
360 } | 364 } |
361 }.execute(); | 365 }.execute(); |
362 } | 366 } |
363 } | 367 } |
364 | 368 |
365 /** | 369 /** |
366 * Set the icon and the title for the menu item used for direct share. | 370 * Set the icon and the title for the menu item used for direct share. |
367 * | 371 * |
368 * @param activity Activity that is used to access the package manager. | 372 * @param activity Activity that is used to access the package manager. |
369 * @param item The menu item that is used for direct share | 373 * @param item The menu item that is used for direct share |
370 */ | 374 */ |
371 public static void configureDirectShareMenuItem(Activity activity, MenuItem
item) { | 375 public static void configureDirectShareMenuItem(Activity activity, MenuItem
item) { |
372 Drawable directShareIcon = null; | 376 Drawable directShareIcon = null; |
373 CharSequence directShareTitle = null; | 377 CharSequence directShareTitle = null; |
374 | 378 |
375 final ComponentName component = getLastShareComponentName(activity); | 379 final ComponentName component = getLastShareComponentName(); |
376 boolean isComponentValid = false; | 380 boolean isComponentValid = false; |
377 if (component != null) { | 381 if (component != null) { |
378 Intent intent = getShareIntent("", "", null); | 382 Intent intent = getShareIntent(activity, "", "", null); |
379 intent.setPackage(component.getPackageName()); | 383 intent.setPackage(component.getPackageName()); |
380 PackageManager manager = activity.getPackageManager(); | 384 PackageManager manager = activity.getPackageManager(); |
381 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(in
tent, 0); | 385 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(in
tent, 0); |
382 for (ResolveInfo info : resolveInfoList) { | 386 for (ResolveInfo info : resolveInfoList) { |
383 ActivityInfo ai = info.activityInfo; | 387 ActivityInfo ai = info.activityInfo; |
384 if (component.equals(new ComponentName(ai.applicationInfo.packag
eName, ai.name))) { | 388 if (component.equals(new ComponentName(ai.applicationInfo.packag
eName, ai.name))) { |
385 isComponentValid = true; | 389 isComponentValid = true; |
386 break; | 390 break; |
387 } | 391 } |
388 } | 392 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 } | 431 } |
428 | 432 |
429 item.setIcon(directShareIcon); | 433 item.setIcon(directShareIcon); |
430 if (directShareTitle != null) { | 434 if (directShareTitle != null) { |
431 item.setTitle(activity.getString(R.string.accessibility_menu_share_v
ia, | 435 item.setTitle(activity.getString(R.string.accessibility_menu_share_v
ia, |
432 directShareTitle)); | 436 directShareTitle)); |
433 } | 437 } |
434 } | 438 } |
435 | 439 |
436 @VisibleForTesting | 440 @VisibleForTesting |
437 public static Intent getShareIntent(String title, String url, Uri screenshot
Uri) { | 441 protected static Intent getShareIntent( |
| 442 Activity activity, String title, String url, Uri screenshotUri) { |
438 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url); | 443 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url); |
439 Intent intent = new Intent(Intent.ACTION_SEND); | 444 Intent intent = new Intent(Intent.ACTION_SEND); |
440 intent.addFlags(ApiCompatibilityUtils.getActivityNewDocumentFlag()); | 445 intent.addFlags(ApiCompatibilityUtils.getActivityNewDocumentFlag()); |
441 intent.setType("text/plain"); | 446 intent.setType("text/plain"); |
442 intent.putExtra(Intent.EXTRA_SUBJECT, title); | 447 intent.putExtra(Intent.EXTRA_SUBJECT, title); |
443 intent.putExtra(Intent.EXTRA_TEXT, url); | 448 intent.putExtra(Intent.EXTRA_TEXT, url); |
| 449 intent.putExtra(EXTRA_TASK_ID, activity.getTaskId()); |
| 450 |
444 if (screenshotUri != null) { | 451 if (screenshotUri != null) { |
445 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); | 452 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); |
446 // To give read access to an Intent target, we need to put |screensh
otUri| in clipData | 453 // To give read access to an Intent target, we need to put |screensh
otUri| in clipData |
447 // because adding Intent.FLAG_GRANT_READ_URI_PERMISSION doesn't work
for | 454 // because adding Intent.FLAG_GRANT_READ_URI_PERMISSION doesn't work
for |
448 // EXTRA_SHARE_SCREENSHOT_AS_STREAM. | 455 // EXTRA_SHARE_SCREENSHOT_AS_STREAM. |
449 intent.setClipData(ClipData.newRawUri("", screenshotUri)); | 456 intent.setClipData(ClipData.newRawUri("", screenshotUri)); |
450 intent.putExtra(EXTRA_SHARE_SCREENSHOT_AS_STREAM, screenshotUri); | 457 intent.putExtra(EXTRA_SHARE_SCREENSHOT_AS_STREAM, screenshotUri); |
451 } | 458 } |
452 return intent; | 459 return intent; |
453 } | 460 } |
454 | 461 |
455 private static Intent getShareImageIntent(Uri imageUri) { | 462 private static Intent getShareImageIntent(Uri imageUri) { |
456 Intent intent = new Intent(Intent.ACTION_SEND); | 463 Intent intent = new Intent(Intent.ACTION_SEND); |
457 intent.addFlags(ApiCompatibilityUtils.getActivityNewDocumentFlag()); | 464 intent.addFlags(ApiCompatibilityUtils.getActivityNewDocumentFlag()); |
458 intent.setType("image/jpeg"); | 465 intent.setType("image/jpeg"); |
459 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); | 466 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); |
460 intent.putExtra(Intent.EXTRA_STREAM, imageUri); | 467 intent.putExtra(Intent.EXTRA_STREAM, imageUri); |
461 return intent; | 468 return intent; |
462 } | 469 } |
463 | 470 |
464 private static Intent getDirectShareIntentForComponent( | 471 private static Intent getDirectShareIntentForComponent( |
465 String title, String url, Uri screenshotUri, ComponentName component
) { | 472 Activity activity, String title, String url, |
466 Intent intent = getShareIntent(title, url, screenshotUri); | 473 Uri screenshotUri, ComponentName component) { |
| 474 Intent intent = getShareIntent(activity, title, url, screenshotUri); |
467 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | 475 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT |
468 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); | 476 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); |
469 intent.setComponent(component); | 477 intent.setComponent(component); |
470 return intent; | 478 return intent; |
471 } | 479 } |
472 | 480 |
473 private static ComponentName getLastShareComponentName(Context context) { | 481 private static ComponentName getLastShareComponentName() { |
474 SharedPreferences preferences = ContextUtils.getAppSharedPreferences(); | 482 SharedPreferences preferences = ContextUtils.getAppSharedPreferences(); |
475 String packageName = preferences.getString(PACKAGE_NAME_KEY, null); | 483 String packageName = preferences.getString(PACKAGE_NAME_KEY, null); |
476 String className = preferences.getString(CLASS_NAME_KEY, null); | 484 String className = preferences.getString(CLASS_NAME_KEY, null); |
477 if (packageName == null || className == null) return null; | 485 if (packageName == null || className == null) return null; |
478 return new ComponentName(packageName, className); | 486 return new ComponentName(packageName, className); |
479 } | 487 } |
480 | 488 |
481 private static void setLastShareComponentName(Context context, ComponentName
component) { | 489 private static void setLastShareComponentName(ComponentName component) { |
482 SharedPreferences preferences = ContextUtils.getAppSharedPreferences(); | 490 SharedPreferences preferences = ContextUtils.getAppSharedPreferences(); |
483 SharedPreferences.Editor editor = preferences.edit(); | 491 SharedPreferences.Editor editor = preferences.edit(); |
484 editor.putString(PACKAGE_NAME_KEY, component.getPackageName()); | 492 editor.putString(PACKAGE_NAME_KEY, component.getPackageName()); |
485 editor.putString(CLASS_NAME_KEY, component.getClassName()); | 493 editor.putString(CLASS_NAME_KEY, component.getClassName()); |
486 editor.apply(); | 494 editor.apply(); |
487 } | 495 } |
488 } | 496 } |
OLD | NEW |