1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v4.app; 18 19import android.app.Activity; 20import android.content.ComponentName; 21import android.content.Intent; 22import android.content.pm.PackageManager; 23import android.content.pm.PackageManager.NameNotFoundException; 24import android.graphics.drawable.Drawable; 25import android.net.Uri; 26import android.os.Build; 27import android.support.v4.view.MenuItemCompat; 28import android.util.Log; 29import android.view.Menu; 30import android.view.MenuItem; 31 32import java.util.ArrayList; 33 34/** 35 * Extra helper functionality for sharing data between activities. 36 * 37 * ShareCompat provides functionality to extend the {@link Intent#ACTION_SEND}/ 38 * {@link Intent#ACTION_SEND_MULTIPLE} protocol and support retrieving more info 39 * about the activity that invoked a social sharing action. 40 * 41 * {@link IntentBuilder} provides helper functions for constructing a sharing 42 * intent that always includes data about the calling activity and app. 43 * This lets the called activity provide attribution for the app that shared 44 * content. Constructing an intent this way can be done in a method-chaining style. 45 * To obtain an IntentBuilder with info about your calling activity, use the static 46 * method {@link IntentBuilder#from(Activity)}. 47 * 48 * {@link IntentReader} provides helper functions for parsing the defined extras 49 * within an {@link Intent#ACTION_SEND} or {@link Intent#ACTION_SEND_MULTIPLE} intent 50 * used to launch an activity. You can also obtain a Drawable for the caller's 51 * application icon and the application's localized label (the app's human-readable name). 52 * Social apps that enable sharing content are encouraged to use this information 53 * to call out the app that the content was shared from. 54 */ 55public class ShareCompat { 56 /** 57 * Intent extra that stores the name of the calling package for an ACTION_SEND intent. 58 * When an activity is started using startActivityForResult this is redundant info. 59 * (It is also provided by {@link Activity#getCallingPackage()}.) 60 * 61 * Instead of using this constant directly, consider using {@link #getCallingPackage(Activity)} 62 * or {@link IntentReader#getCallingPackage()}. 63 */ 64 public static final String EXTRA_CALLING_PACKAGE = 65 "android.support.v4.app.EXTRA_CALLING_PACKAGE"; 66 67 /** 68 * Intent extra that stores the {@link ComponentName} of the calling activity for 69 * an ACTION_SEND intent. 70 */ 71 public static final String EXTRA_CALLING_ACTIVITY = 72 "android.support.v4.app.EXTRA_CALLING_ACTIVITY"; 73 74 /** 75 * Compatibility shims for sharing operations 76 */ 77 interface ShareCompatImpl { 78 void configureMenuItem(MenuItem item, IntentBuilder shareIntent); 79 } 80 81 static class ShareCompatImplBase implements ShareCompatImpl { 82 public void configureMenuItem(MenuItem item, IntentBuilder shareIntent) { 83 item.setIntent(shareIntent.createChooserIntent()); 84 } 85 } 86 87 static class ShareCompatImplICS implements ShareCompatImpl { 88 public void configureMenuItem(MenuItem item, IntentBuilder shareIntent) { 89 ShareCompatICS.configureMenuItem(item, shareIntent.getActivity(), 90 shareIntent.getIntent()); 91 } 92 } 93 94 private static ShareCompatImpl IMPL; 95 96 static { 97 if (Build.VERSION.SDK_INT >= 14) { 98 IMPL = new ShareCompatImplICS(); 99 } else { 100 IMPL = new ShareCompatImplBase(); 101 } 102 } 103 104 /** 105 * Retrieve the name of the package that launched calledActivity from a share intent. 106 * Apps that provide social sharing functionality can use this to provide attribution 107 * for the app that shared the content. 108 * 109 * <p><em>Note:</em> This data may have been provided voluntarily by the calling 110 * application. As such it should not be trusted for accuracy in the context of 111 * security or verification.</p> 112 * 113 * @param calledActivity Current activity that was launched to share content 114 * @return Name of the calling package 115 */ 116 public static String getCallingPackage(Activity calledActivity) { 117 String result = calledActivity.getCallingPackage(); 118 if (result == null) { 119 result = calledActivity.getIntent().getStringExtra(EXTRA_CALLING_PACKAGE); 120 } 121 return result; 122 } 123 124 /** 125 * Retrieve the ComponentName of the activity that launched calledActivity from a share intent. 126 * Apps that provide social sharing functionality can use this to provide attribution 127 * for the app that shared the content. 128 * 129 * <p><em>Note:</em> This data may have been provided voluntarily by the calling 130 * application. As such it should not be trusted for accuracy in the context of 131 * security or verification.</p> 132 * 133 * @param calledActivity Current activity that was launched to share content 134 * @return ComponentName of the calling activity 135 */ 136 public static ComponentName getCallingActivity(Activity calledActivity) { 137 ComponentName result = calledActivity.getCallingActivity(); 138 if (result == null) { 139 result = calledActivity.getIntent().getParcelableExtra(EXTRA_CALLING_ACTIVITY); 140 } 141 return result; 142 } 143 144 /** 145 * Configure a {@link MenuItem} to act as a sharing action. 146 * 147 * <p>If the app is running on API level 14 or higher (Android 4.0/Ice Cream Sandwich) 148 * this method will configure a ShareActionProvider to provide a more robust UI 149 * for selecting the target of the share. History will be tracked for each calling 150 * activity in a file named with the prefix ".sharecompat_" in the application's 151 * private data directory. If the application wishes to set this MenuItem to show 152 * as an action in the Action Bar it should use 153 * {@link MenuItemCompat#setShowAsAction(MenuItem, int)} to request that behavior 154 * in addition to calling this method.</p> 155 * 156 * <p>If the app is running on an older platform version this method will configure 157 * a standard activity chooser dialog for the menu item.</p> 158 * 159 * <p>During the calling activity's lifecycle, if data within the share intent must 160 * change the app should change that state in one of several ways:</p> 161 * <ul> 162 * <li>Call {@link ActivityCompat#invalidateOptionsMenu(Activity)}. If the app is running 163 * on API level 11 or above and uses the Action Bar its menu will be recreated and rebuilt. 164 * If not, the activity will receive a call to {@link Activity#onPrepareOptionsMenu(Menu)} 165 * the next time the user presses the menu key to open the options menu panel. The activity 166 * can then call configureMenuItem again with a new or altered IntentBuilder to reconfigure 167 * the share menu item.</li> 168 * <li>Keep a reference to the MenuItem object for the share item once it has been created 169 * and call configureMenuItem to update the associated sharing intent as needed.</li> 170 * </ul> 171 * 172 * @param item MenuItem to configure for sharing 173 * @param shareIntent IntentBuilder with data about the content to share 174 */ 175 public static void configureMenuItem(MenuItem item, IntentBuilder shareIntent) { 176 IMPL.configureMenuItem(item, shareIntent); 177 } 178 179 /** 180 * Configure a menu item to act as a sharing action. 181 * 182 * @param menu Menu containing the item to use for sharing 183 * @param menuItemId ID of the share item within menu 184 * @param shareIntent IntentBuilder with data about the content to share 185 * @see #configureMenuItem(MenuItem, IntentBuilder) 186 */ 187 public static void configureMenuItem(Menu menu, int menuItemId, IntentBuilder shareIntent) { 188 MenuItem item = menu.findItem(menuItemId); 189 if (item == null) { 190 throw new IllegalArgumentException("Could not find menu item with id " + menuItemId + 191 " in the supplied menu"); 192 } 193 configureMenuItem(item, shareIntent); 194 } 195 196 /** 197 * IntentBuilder is a helper for constructing {@link Intent#ACTION_SEND} and 198 * {@link Intent#ACTION_SEND_MULTIPLE} sharing intents and starting activities 199 * to share content. The ComponentName and package name of the calling activity 200 * will be included. 201 */ 202 public static class IntentBuilder { 203 private Activity mActivity; 204 private Intent mIntent; 205 private CharSequence mChooserTitle; 206 private ArrayList<String> mToAddresses; 207 private ArrayList<String> mCcAddresses; 208 private ArrayList<String> mBccAddresses; 209 210 private ArrayList<Uri> mStreams; 211 212 /** 213 * Create a new IntentBuilder for launching a sharing action from launchingActivity. 214 * 215 * @param launchingActivity Activity that the share will be launched from 216 * @return a new IntentBuilder instance 217 */ 218 public static IntentBuilder from(Activity launchingActivity) { 219 return new IntentBuilder(launchingActivity); 220 } 221 222 private IntentBuilder(Activity launchingActivity) { 223 mActivity = launchingActivity; 224 mIntent = new Intent().setAction(Intent.ACTION_SEND); 225 mIntent.putExtra(EXTRA_CALLING_PACKAGE, launchingActivity.getPackageName()); 226 mIntent.putExtra(EXTRA_CALLING_ACTIVITY, launchingActivity.getComponentName()); 227 mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 228 } 229 230 /** 231 * Retrieve the Intent as configured so far by the IntentBuilder. This Intent 232 * is suitable for use in a ShareActionProvider or chooser dialog. 233 * 234 * <p>To create an intent that will launch the activity chooser so that the user 235 * may select a target for the share, see {@link #createChooserIntent()}. 236 * 237 * @return The current Intent being configured by this builder 238 */ 239 public Intent getIntent() { 240 if (mToAddresses != null) { 241 combineArrayExtra(Intent.EXTRA_EMAIL, mToAddresses); 242 mToAddresses = null; 243 } 244 if (mCcAddresses != null) { 245 combineArrayExtra(Intent.EXTRA_CC, mCcAddresses); 246 mCcAddresses = null; 247 } 248 if (mBccAddresses != null) { 249 combineArrayExtra(Intent.EXTRA_BCC, mBccAddresses); 250 mBccAddresses = null; 251 } 252 253 // Check if we need to change the action. 254 boolean needsSendMultiple = mStreams != null && mStreams.size() > 1; 255 boolean isSendMultiple = mIntent.getAction().equals(Intent.ACTION_SEND_MULTIPLE); 256 257 if (!needsSendMultiple && isSendMultiple) { 258 // Change back to a single send action; place the first stream into the 259 // intent for single sharing. 260 mIntent.setAction(Intent.ACTION_SEND); 261 if (mStreams != null && !mStreams.isEmpty()) { 262 mIntent.putExtra(Intent.EXTRA_STREAM, mStreams.get(0)); 263 } else { 264 mIntent.removeExtra(Intent.EXTRA_STREAM); 265 } 266 mStreams = null; 267 } 268 269 if (needsSendMultiple && !isSendMultiple) { 270 // Change to a multiple send action; place the relevant ArrayList into the 271 // intent for multiple sharing. 272 mIntent.setAction(Intent.ACTION_SEND_MULTIPLE); 273 if (mStreams != null && !mStreams.isEmpty()) { 274 mIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, mStreams); 275 } else { 276 mIntent.removeExtra(Intent.EXTRA_STREAM); 277 } 278 } 279 280 return mIntent; 281 } 282 283 Activity getActivity() { 284 return mActivity; 285 } 286 287 private void combineArrayExtra(String extra, ArrayList<String> add) { 288 String[] currentAddresses = mIntent.getStringArrayExtra(extra); 289 int currentLength = currentAddresses != null ? currentAddresses.length : 0; 290 String[] finalAddresses = new String[currentLength + add.size()]; 291 add.toArray(finalAddresses); 292 if (currentAddresses != null) { 293 System.arraycopy(currentAddresses, 0, finalAddresses, add.size(), currentLength); 294 } 295 mIntent.putExtra(extra, finalAddresses); 296 } 297 298 private void combineArrayExtra(String extra, String[] add) { 299 // Add any items still pending 300 Intent intent = getIntent(); 301 String[] old = intent.getStringArrayExtra(extra); 302 int oldLength = old != null ? old.length : 0; 303 String[] result = new String[oldLength + add.length]; 304 if (old != null) System.arraycopy(old, 0, result, 0, oldLength); 305 System.arraycopy(add, 0, result, oldLength, add.length); 306 intent.putExtra(extra, result); 307 } 308 309 /** 310 * Create an Intent that will launch the standard Android activity chooser, 311 * allowing the user to pick what activity/app on the system should handle 312 * the share. 313 * 314 * @return A chooser Intent for the currently configured sharing action 315 */ 316 public Intent createChooserIntent() { 317 return Intent.createChooser(getIntent(), mChooserTitle); 318 } 319 320 /** 321 * Start a chooser activity for the current share intent. 322 * 323 * <p>Note that under most circumstances you should use 324 * {@link ShareCompat#configureMenuItem(MenuItem, IntentBuilder) 325 * ShareCompat.configureMenuItem()} to add a Share item to the menu while 326 * presenting a detail view of the content to be shared instead 327 * of invoking this directly.</p> 328 */ 329 public void startChooser() { 330 mActivity.startActivity(createChooserIntent()); 331 } 332 333 /** 334 * Set the title that will be used for the activity chooser for this share. 335 * 336 * @param title Title string 337 * @return This IntentBuilder for method chaining 338 */ 339 public IntentBuilder setChooserTitle(CharSequence title) { 340 mChooserTitle = title; 341 return this; 342 } 343 344 /** 345 * Set the title that will be used for the activity chooser for this share. 346 * 347 * @param resId Resource ID of the title string to use 348 * @return This IntentBuilder for method chaining 349 */ 350 public IntentBuilder setChooserTitle(int resId) { 351 return setChooserTitle(mActivity.getText(resId)); 352 } 353 354 /** 355 * Set the type of data being shared 356 * 357 * @param mimeType mimetype of the shared data 358 * @return This IntentBuilder for method chaining 359 * @see Intent#setType(String) 360 */ 361 public IntentBuilder setType(String mimeType) { 362 mIntent.setType(mimeType); 363 return this; 364 } 365 366 /** 367 * Set the literal text data to be sent as part of the share. 368 * 369 * @param text Text to share 370 * @return This IntentBuilder for method chaining 371 * @see Intent#EXTRA_TEXT 372 */ 373 public IntentBuilder setText(CharSequence text) { 374 mIntent.putExtra(Intent.EXTRA_TEXT, text); 375 return this; 376 } 377 378 /** 379 * Set a stream URI to the data that should be shared. 380 * 381 * <p>This replaces all currently set stream URIs and will produce a single-stream 382 * ACTION_SEND intent.</p> 383 * 384 * @param streamUri URI of the stream to share 385 * @return This IntentBuilder for method chaining 386 * @see Intent#EXTRA_STREAM 387 */ 388 public IntentBuilder setStream(Uri streamUri) { 389 if (!mIntent.getAction().equals(Intent.ACTION_SEND)) { 390 mIntent.setAction(Intent.ACTION_SEND); 391 } 392 mStreams = null; 393 mIntent.putExtra(Intent.EXTRA_STREAM, streamUri); 394 return this; 395 } 396 397 /** 398 * Add a stream URI to the data that should be shared. If this is not the first 399 * stream URI added the final intent constructed will become an ACTION_SEND_MULTIPLE 400 * intent. Not all apps will handle both ACTION_SEND and ACTION_SEND_MULTIPLE. 401 * 402 * @param streamUri URI of the stream to share 403 * @return This IntentBuilder for method chaining 404 * @see Intent#EXTRA_STREAM 405 * @see Intent#ACTION_SEND 406 * @see Intent#ACTION_SEND_MULTIPLE 407 */ 408 public IntentBuilder addStream(Uri streamUri) { 409 Uri currentStream = mIntent.getParcelableExtra(Intent.EXTRA_STREAM); 410 if (currentStream == null) { 411 return setStream(streamUri); 412 } 413 if (mStreams == null) { 414 mStreams = new ArrayList<Uri>(); 415 } 416 if (currentStream != null) { 417 mIntent.removeExtra(Intent.EXTRA_STREAM); 418 mStreams.add(currentStream); 419 } 420 mStreams.add(streamUri); 421 return this; 422 } 423 424 /** 425 * Set an array of email addresses as recipients of this share. 426 * This replaces all current "to" recipients that have been set so far. 427 * 428 * @param addresses Email addresses to send to 429 * @return This IntentBuilder for method chaining 430 * @see Intent#EXTRA_EMAIL 431 */ 432 public IntentBuilder setEmailTo(String[] addresses) { 433 if (mToAddresses != null) { 434 mToAddresses = null; 435 } 436 mIntent.putExtra(Intent.EXTRA_EMAIL, addresses); 437 return this; 438 } 439 440 /** 441 * Add an email address to be used in the "to" field of the final Intent. 442 * 443 * @param address Email address to send to 444 * @return This IntentBuilder for method chaining 445 * @see Intent#EXTRA_EMAIL 446 */ 447 public IntentBuilder addEmailTo(String address) { 448 if (mToAddresses == null) { 449 mToAddresses = new ArrayList<String>(); 450 } 451 mToAddresses.add(address); 452 return this; 453 } 454 455 /** 456 * Add an array of email addresses to be used in the "to" field of the final Intent. 457 * 458 * @param addresses Email addresses to send to 459 * @return This IntentBuilder for method chaining 460 * @see Intent#EXTRA_EMAIL 461 */ 462 public IntentBuilder addEmailTo(String[] addresses) { 463 combineArrayExtra(Intent.EXTRA_EMAIL, addresses); 464 return this; 465 } 466 467 /** 468 * Set an array of email addresses to CC on this share. 469 * This replaces all current "CC" recipients that have been set so far. 470 * 471 * @param addresses Email addresses to CC on the share 472 * @return This IntentBuilder for method chaining 473 * @see Intent#EXTRA_CC 474 */ 475 public IntentBuilder setEmailCc(String[] addresses) { 476 mIntent.putExtra(Intent.EXTRA_CC, addresses); 477 return this; 478 } 479 480 /** 481 * Add an email address to be used in the "cc" field of the final Intent. 482 * 483 * @param address Email address to CC 484 * @return This IntentBuilder for method chaining 485 * @see Intent#EXTRA_CC 486 */ 487 public IntentBuilder addEmailCc(String address) { 488 if (mCcAddresses == null) { 489 mCcAddresses = new ArrayList<String>(); 490 } 491 mCcAddresses.add(address); 492 return this; 493 } 494 495 /** 496 * Add an array of email addresses to be used in the "cc" field of the final Intent. 497 * 498 * @param addresses Email addresses to CC 499 * @return This IntentBuilder for method chaining 500 * @see Intent#EXTRA_CC 501 */ 502 public IntentBuilder addEmailCc(String[] addresses) { 503 combineArrayExtra(Intent.EXTRA_CC, addresses); 504 return this; 505 } 506 507 /** 508 * Set an array of email addresses to BCC on this share. 509 * This replaces all current "BCC" recipients that have been set so far. 510 * 511 * @param addresses Email addresses to BCC on the share 512 * @return This IntentBuilder for method chaining 513 * @see Intent#EXTRA_BCC 514 */ 515 public IntentBuilder setEmailBcc(String[] addresses) { 516 mIntent.putExtra(Intent.EXTRA_BCC, addresses); 517 return this; 518 } 519 520 /** 521 * Add an email address to be used in the "bcc" field of the final Intent. 522 * 523 * @param address Email address to BCC 524 * @return This IntentBuilder for method chaining 525 * @see Intent#EXTRA_BCC 526 */ 527 public IntentBuilder addEmailBcc(String address) { 528 if (mBccAddresses == null) { 529 mBccAddresses = new ArrayList<String>(); 530 } 531 mBccAddresses.add(address); 532 return this; 533 } 534 535 /** 536 * Add an array of email addresses to be used in the "bcc" field of the final Intent. 537 * 538 * @param addresses Email addresses to BCC 539 * @return This IntentBuilder for method chaining 540 * @see Intent#EXTRA_BCC 541 */ 542 public IntentBuilder addEmailBcc(String[] addresses) { 543 combineArrayExtra(Intent.EXTRA_BCC, addresses); 544 return this; 545 } 546 547 /** 548 * Set a subject heading for this share; useful for sharing via email. 549 * 550 * @param subject Subject heading for this share 551 * @return This IntentBuilder for method chaining 552 * @see Intent#EXTRA_SUBJECT 553 */ 554 public IntentBuilder setSubject(String subject) { 555 mIntent.putExtra(Intent.EXTRA_SUBJECT, subject); 556 return this; 557 } 558 } 559 560 /** 561 * IntentReader is a helper for reading the data contained within a sharing (ACTION_SEND) 562 * Intent. It provides methods to parse standard elements included with a share 563 * in addition to extra metadata about the app that shared the content. 564 * 565 * <p>Social sharing apps are encouraged to provide attribution for the app that shared 566 * the content. IntentReader offers access to the application label, calling activity info, 567 * and application icon of the app that shared the content. This data may have been provided 568 * voluntarily by the calling app and should always be displayed to the user before submission 569 * for manual verification. The user should be offered the option to omit this information 570 * from shared posts if desired.</p> 571 * 572 * <p>Activities that intend to receive sharing intents should configure an intent-filter 573 * to accept {@link Intent#ACTION_SEND} intents ("android.intent.action.SEND") and optionally 574 * accept {@link Intent#ACTION_SEND_MULTIPLE} ("android.intent.action.SEND_MULTIPLE") if 575 * the activity is equipped to handle multiple data streams.</p> 576 */ 577 public static class IntentReader { 578 private static final String TAG = "IntentReader"; 579 580 private Activity mActivity; 581 private Intent mIntent; 582 private String mCallingPackage; 583 private ComponentName mCallingActivity; 584 585 private ArrayList<Uri> mStreams; 586 587 /** 588 * Get an IntentReader for parsing and interpreting the sharing intent 589 * used to start the given activity. 590 * 591 * @param activity Activity that was started to share content 592 * @return IntentReader for parsing sharing data 593 */ 594 public static IntentReader from(Activity activity) { 595 return new IntentReader(activity); 596 } 597 598 private IntentReader(Activity activity) { 599 mActivity = activity; 600 mIntent = activity.getIntent(); 601 mCallingPackage = ShareCompat.getCallingPackage(activity); 602 mCallingActivity = ShareCompat.getCallingActivity(activity); 603 } 604 605 /** 606 * Returns true if the activity this reader was obtained for was 607 * started with an {@link Intent#ACTION_SEND} or {@link Intent#ACTION_SEND_MULTIPLE} 608 * sharing Intent. 609 * 610 * @return true if the activity was started with an ACTION_SEND 611 * or ACTION_SEND_MULTIPLE Intent 612 */ 613 public boolean isShareIntent() { 614 final String action = mIntent.getAction(); 615 return action.equals(Intent.ACTION_SEND) || action.equals(Intent.ACTION_SEND_MULTIPLE); 616 } 617 618 /** 619 * Returns true if the activity this reader was obtained for was started with an 620 * {@link Intent#ACTION_SEND} intent and contains a single shared item. 621 * The shared content should be obtained using either the {@link #getText()} 622 * or {@link #getStream()} methods depending on the type of content shared. 623 * 624 * @return true if the activity was started with an ACTION_SEND intent 625 */ 626 public boolean isSingleShare() { 627 return mIntent.getAction().equals(Intent.ACTION_SEND); 628 } 629 630 /** 631 * Returns true if the activity this reader was obtained for was started with an 632 * {@link Intent#ACTION_SEND_MULTIPLE} intent. The Intent may contain more than 633 * one stream item. 634 * 635 * @return true if the activity was started with an ACTION_SEND_MULTIPLE intent 636 */ 637 public boolean isMultipleShare() { 638 return mIntent.getAction().equals(Intent.ACTION_SEND_MULTIPLE); 639 } 640 641 /** 642 * Get the mimetype of the data shared to this activity. 643 * 644 * @return mimetype of the shared data 645 * @see Intent#getType() 646 */ 647 public String getType() { 648 return mIntent.getType(); 649 } 650 651 /** 652 * Get the literal text shared with the target activity. 653 * 654 * @return Literal shared text or null if none was supplied 655 * @see Intent#EXTRA_TEXT 656 */ 657 public CharSequence getText() { 658 return mIntent.getCharSequenceExtra(Intent.EXTRA_TEXT); 659 } 660 661 /** 662 * Get a URI referring to a data stream shared with the target activity. 663 * 664 * <p>This call will fail if the share intent contains multiple stream items. 665 * If {@link #isMultipleShare()} returns true the application should use 666 * {@link #getStream(int)} and {@link #getStreamCount()} to retrieve the 667 * included stream items.</p> 668 * 669 * @return A URI referring to a data stream to be shared or null if one was not supplied 670 * @see Intent#EXTRA_STREAM 671 */ 672 public Uri getStream() { 673 return mIntent.getParcelableExtra(Intent.EXTRA_STREAM); 674 } 675 676 /** 677 * Get the URI of a stream item shared with the target activity. 678 * Index should be in the range [0-getStreamCount()). 679 * 680 * @param index Index of text item to retrieve 681 * @return Requested stream item URI 682 * @see Intent#EXTRA_STREAM 683 * @see Intent#ACTION_SEND_MULTIPLE 684 */ 685 public Uri getStream(int index) { 686 if (mStreams == null && isMultipleShare()) { 687 mStreams = mIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); 688 } 689 if (mStreams != null) { 690 return mStreams.get(index); 691 } 692 if (index == 0) { 693 return mIntent.getParcelableExtra(Intent.EXTRA_STREAM); 694 } 695 throw new IndexOutOfBoundsException("Stream items available: " + getStreamCount() + 696 " index requested: " + index); 697 } 698 699 /** 700 * Return the number of stream items shared. The return value will be 0 or 1 if 701 * this was an {@link Intent#ACTION_SEND} intent, or 0 or more if it was an 702 * {@link Intent#ACTION_SEND_MULTIPLE} intent. 703 * 704 * @return Count of text items contained within the Intent 705 */ 706 public int getStreamCount() { 707 if (mStreams == null && isMultipleShare()) { 708 mStreams = mIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); 709 } 710 if (mStreams != null) { 711 return mStreams.size(); 712 } 713 return mIntent.hasExtra(Intent.EXTRA_STREAM) ? 1 : 0; 714 } 715 716 /** 717 * Get an array of Strings, each an email address to share to. 718 * 719 * @return An array of email addresses or null if none were supplied. 720 * @see Intent#EXTRA_EMAIL 721 */ 722 public String[] getEmailTo() { 723 return mIntent.getStringArrayExtra(Intent.EXTRA_EMAIL); 724 } 725 726 /** 727 * Get an array of Strings, each an email address to CC on this share. 728 * 729 * @return An array of email addresses or null if none were supplied. 730 * @see Intent#EXTRA_CC 731 */ 732 public String[] getEmailCc() { 733 return mIntent.getStringArrayExtra(Intent.EXTRA_CC); 734 } 735 736 /** 737 * Get an array of Strings, each an email address to BCC on this share. 738 * 739 * @return An array of email addresses or null if none were supplied. 740 * @see Intent#EXTRA_BCC 741 */ 742 public String[] getEmailBcc() { 743 return mIntent.getStringArrayExtra(Intent.EXTRA_BCC); 744 } 745 746 /** 747 * Get a subject heading for this share; useful when sharing via email. 748 * 749 * @return The subject heading for this share or null if one was not supplied. 750 * @see Intent#EXTRA_SUBJECT 751 */ 752 public String getSubject() { 753 return mIntent.getStringExtra(Intent.EXTRA_SUBJECT); 754 } 755 756 /** 757 * Get the name of the package that invoked this sharing intent. If the activity 758 * was not started for a result, IntentBuilder will read this from extra metadata placed 759 * in the Intent by ShareBuilder. 760 * 761 * <p><em>Note:</em> This data may have been provided voluntarily by the calling 762 * application. As such it should not be trusted for accuracy in the context of 763 * security or verification.</p> 764 * 765 * @return Name of the package that started this activity or null if unknown 766 * @see Activity#getCallingPackage() 767 * @see ShareCompat#EXTRA_CALLING_PACKAGE 768 */ 769 public String getCallingPackage() { 770 return mCallingPackage; 771 } 772 773 /** 774 * Get the {@link ComponentName} of the Activity that invoked this sharing intent. 775 * If the target sharing activity was not started for a result, IntentBuilder will read 776 * this from extra metadata placed in the intent by ShareBuilder. 777 * 778 * <p><em>Note:</em> This data may have been provided voluntarily by the calling 779 * application. As such it should not be trusted for accuracy in the context of 780 * security or verification.</p> 781 * 782 * @return ComponentName of the calling Activity or null if unknown 783 * @see Activity#getCallingActivity() 784 * @see ShareCompat#EXTRA_CALLING_ACTIVITY 785 */ 786 public ComponentName getCallingActivity() { 787 return mCallingActivity; 788 } 789 790 /** 791 * Get the icon of the calling activity as a Drawable if data about 792 * the calling activity is available. 793 * 794 * <p><em>Note:</em> This data may have been provided voluntarily by the calling 795 * application. As such it should not be trusted for accuracy in the context of 796 * security or verification.</p> 797 * 798 * @return The calling Activity's icon or null if unknown 799 */ 800 public Drawable getCallingActivityIcon() { 801 if (mCallingActivity == null) return null; 802 803 PackageManager pm = mActivity.getPackageManager(); 804 try { 805 return pm.getActivityIcon(mCallingActivity); 806 } catch (NameNotFoundException e) { 807 Log.e(TAG, "Could not retrieve icon for calling activity", e); 808 } 809 return null; 810 } 811 812 /** 813 * Get the icon of the calling application as a Drawable if data 814 * about the calling package is available. 815 * 816 * <p><em>Note:</em> This data may have been provided voluntarily by the calling 817 * application. As such it should not be trusted for accuracy in the context of 818 * security or verification.</p> 819 * 820 * @return The calling application's icon or null if unknown 821 */ 822 public Drawable getCallingApplicationIcon() { 823 if (mCallingPackage == null) return null; 824 825 PackageManager pm = mActivity.getPackageManager(); 826 try { 827 return pm.getApplicationIcon(mCallingPackage); 828 } catch (NameNotFoundException e) { 829 Log.e(TAG, "Could not retrieve icon for calling application", e); 830 } 831 return null; 832 } 833 834 /** 835 * Get the human-readable label (title) of the calling application if 836 * data about the calling package is available. 837 * 838 * <p><em>Note:</em> This data may have been provided voluntarily by the calling 839 * application. As such it should not be trusted for accuracy in the context of 840 * security or verification.</p> 841 * 842 * @return The calling application's label or null if unknown 843 */ 844 public CharSequence getCallingApplicationLabel() { 845 if (mCallingPackage == null) return null; 846 847 PackageManager pm = mActivity.getPackageManager(); 848 try { 849 return pm.getApplicationLabel(pm.getApplicationInfo(mCallingPackage, 0)); 850 } catch (NameNotFoundException e) { 851 Log.e(TAG, "Could not retrieve label for calling application", e); 852 } 853 return null; 854 } 855 } 856} 857