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 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.share; 6 7 import android.app.Activity; 8 import android.app.AlertDialog; 9 import android.content.ComponentName; 10 import android.content.Context; 11 import android.content.Intent; 12 import android.content.SharedPreferences; 13 import android.content.pm.ActivityInfo; 14 import android.content.pm.ApplicationInfo; 15 import android.content.pm.PackageManager; 16 import android.content.pm.PackageManager.NameNotFoundException; 17 import android.content.pm.ResolveInfo; 18 import android.graphics.Bitmap; 19 import android.graphics.drawable.Drawable; 20 import android.preference.PreferenceManager; 21 import android.view.MenuItem; 22 import android.view.View; 23 import android.widget.AdapterView; 24 import android.widget.AdapterView.OnItemClickListener; 25 26 import org.chromium.chrome.R; 27 28 import java.util.Collections; 29 import java.util.List; 30 31 /** 32 * A helper class that helps to start an intent to share titles and URLs. 33 */ 34 public class ShareHelper { 35 36 private static final String PACKAGE_NAME_KEY = "last_shared_package_name"; 37 private static final String CLASS_NAME_KEY = "last_shared_class_name"; 38 39 /** 40 * Intent extra for sharing screenshots via the Share intent. 41 * 42 * Copied from {@link android.provider.Browser} as it is marked as {@literal @hide}. 43 */ 44 private static final String EXTRA_SHARE_SCREENSHOT = "share_screenshot"; 45 ShareHelper()46 private ShareHelper() {} 47 48 /** 49 * Creates and shows a share intent picker dialog or starts a share intent directly with the 50 * activity that was most recently used to share based on shareDirectly value. 51 * 52 * @param shareDirectly Whether it should share directly with the activity that was most 53 * recently used to share. 54 * @param activity Activity that is used to access package manager. 55 * @param title Title of the page to be shared. 56 * @param url URL of the page to be shared. 57 * @param screenshot Screenshot of the page to be shared. 58 */ share(boolean shareDirectly, Activity activity, String title, String url, Bitmap screenshot)59 public static void share(boolean shareDirectly, Activity activity, String title, String url, 60 Bitmap screenshot) { 61 if (shareDirectly) { 62 shareWithLastUsed(activity, title, url, screenshot); 63 } else { 64 showShareDialog(activity, title, url, screenshot); 65 } 66 } 67 68 /** 69 * Creates and shows a share intent picker dialog. 70 * 71 * @param activity Activity that is used to access package manager. 72 * @param title Title of the page to be shared. 73 * @param url URL of the page to be shared. 74 * @param screenshot Screenshot of the page to be shared. 75 */ showShareDialog(final Activity activity, final String title, final String url, final Bitmap screenshot)76 private static void showShareDialog(final Activity activity, final String title, 77 final String url, final Bitmap screenshot) { 78 Intent intent = getShareIntent(title, url, screenshot); 79 PackageManager manager = activity.getPackageManager(); 80 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent, 0); 81 assert resolveInfoList.size() > 0; 82 if (resolveInfoList.size() == 0) return; 83 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator(manager)); 84 85 final ShareDialogAdapter adapter = 86 new ShareDialogAdapter(activity, manager, resolveInfoList); 87 AlertDialog.Builder builder = new AlertDialog.Builder(activity); 88 builder.setTitle(activity.getString(R.string.share_link_chooser_title)); 89 builder.setAdapter(adapter, null); 90 91 final AlertDialog dialog = builder.create(); 92 dialog.show(); 93 dialog.getListView().setOnItemClickListener(new OnItemClickListener() { 94 @Override 95 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 96 ResolveInfo info = adapter.getItem(position); 97 ActivityInfo ai = info.activityInfo; 98 ComponentName component = 99 new ComponentName(ai.applicationInfo.packageName, ai.name); 100 setLastShareComponentName(activity, component); 101 Intent intent = getDirectShareIntentForComponent(title, url, screenshot, component); 102 activity.startActivity(intent); 103 dialog.dismiss(); 104 } 105 }); 106 } 107 108 /** 109 * Starts a share intent with the activity that was most recently used to share. 110 * If there is no most recently used activity, it does nothing. 111 * @param activity Activity that is used to start the share intent. 112 * @param title Title of the page to be shared. 113 * @param url URL of the page to be shared. 114 * @param screenshot Screenshot of the page to be shared. 115 */ shareWithLastUsed( Activity activity, String title, String url, Bitmap screenshot)116 private static void shareWithLastUsed( 117 Activity activity, String title, String url, Bitmap screenshot) { 118 ComponentName component = getLastShareComponentName(activity); 119 if (component == null) return; 120 Intent intent = getDirectShareIntentForComponent(title, url, screenshot, component); 121 activity.startActivity(intent); 122 } 123 124 /** 125 * Set the icon and the title for the menu item used for direct share. 126 * 127 * @param activity Activity that is used to access the package manager. 128 * @param item The menu item that is used for direct share 129 */ configureDirectShareMenuItem(Activity activity, MenuItem item)130 public static void configureDirectShareMenuItem(Activity activity, MenuItem item) { 131 Drawable directShareIcon = null; 132 CharSequence directShareTitle = null; 133 134 ComponentName component = getLastShareComponentName(activity); 135 if (component != null) { 136 try { 137 directShareIcon = activity.getPackageManager().getActivityIcon(component); 138 ApplicationInfo ai = activity.getPackageManager().getApplicationInfo( 139 component.getPackageName(), 0); 140 directShareTitle = activity.getPackageManager().getApplicationLabel(ai); 141 } catch (NameNotFoundException exception) { 142 // Use the default null values. 143 } 144 } 145 146 item.setIcon(directShareIcon); 147 if (directShareTitle != null) { 148 item.setTitle(activity.getString(R.string.accessibility_menu_share_via, 149 directShareTitle)); 150 } 151 } 152 getShareIntent(String title, String url, Bitmap screenshot)153 private static Intent getShareIntent(String title, String url, Bitmap screenshot) { 154 Intent intent = new Intent(Intent.ACTION_SEND); 155 intent.setType("text/plain"); 156 intent.putExtra(Intent.EXTRA_SUBJECT, title); 157 intent.putExtra(Intent.EXTRA_TEXT, url); 158 if (screenshot != null) intent.putExtra(EXTRA_SHARE_SCREENSHOT, screenshot); 159 return intent; 160 } 161 getDirectShareIntentForComponent(String title, String url, Bitmap screenshot, ComponentName component)162 private static Intent getDirectShareIntentForComponent(String title, String url, 163 Bitmap screenshot, ComponentName component) { 164 Intent intent = getShareIntent(title, url, screenshot); 165 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT 166 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); 167 intent.setComponent(component); 168 return intent; 169 } 170 getLastShareComponentName(Context context)171 private static ComponentName getLastShareComponentName(Context context) { 172 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); 173 String packageName = preferences.getString(PACKAGE_NAME_KEY, null); 174 String className = preferences.getString(CLASS_NAME_KEY, null); 175 if (packageName == null || className == null) return null; 176 return new ComponentName(packageName, className); 177 } 178 setLastShareComponentName(Context context, ComponentName component)179 private static void setLastShareComponentName(Context context, ComponentName component) { 180 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); 181 SharedPreferences.Editor editor = preferences.edit(); 182 editor.putString(PACKAGE_NAME_KEY, component.getPackageName()); 183 editor.putString(CLASS_NAME_KEY, component.getClassName()); 184 editor.apply(); 185 } 186 } 187