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.
5 package org.chromium.chrome.browser.share;
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;
26 import org.chromium.base.VisibleForTesting;
27 import org.chromium.chrome.R;
28 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
30 import java.util.Collections;
31 import java.util.List;
34 * A helper class that helps to start an intent to share titles and URLs.
36 public class ShareHelper {
38 private static final String PACKAGE_NAME_KEY = "last_shared_package_name";
39 private static final String CLASS_NAME_KEY = "last_shared_class_name";
42 * Intent extra for sharing screenshots via the Share intent.
44 * Copied from {@link android.provider.Browser} as it is marked as {@literal @hide}.
46 private static final String EXTRA_SHARE_SCREENSHOT = "share_screenshot";
48 private ShareHelper() {}
51 * Creates and shows a share intent picker dialog or starts a share intent directly with the
52 * activity that was most recently used to share based on shareDirectly value.
54 * @param shareDirectly Whether it should share directly with the activity that was most
55 * recently used to share.
56 * @param activity Activity that is used to access package manager.
57 * @param title Title of the page to be shared.
58 * @param url URL of the page to be shared.
59 * @param screenshot Screenshot of the page to be shared.
61 public static void share(boolean shareDirectly, Activity activity, String title, String url,
62 Bitmap screenshot, int extraIntentFlags) {
64 shareWithLastUsed(activity, title, url, screenshot, extraIntentFlags);
66 showShareDialog(activity, title, url, screenshot, extraIntentFlags);
71 * Creates and shows a share intent picker dialog.
73 * @param activity Activity that is used to access package manager.
74 * @param title Title of the page to be shared.
75 * @param url URL of the page to be shared.
76 * @param screenshot Screenshot of the page to be shared.
77 * @param extraIntentFlags Additional flags that should be added to the share intent.
79 private static void showShareDialog(final Activity activity, final String title,
80 final String url, final Bitmap screenshot, final int extraIntentFlags) {
81 Intent intent = getShareIntent(title, url, screenshot, extraIntentFlags);
82 PackageManager manager = activity.getPackageManager();
83 List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent, 0);
84 assert resolveInfoList.size() > 0;
85 if (resolveInfoList.size() == 0) return;
86 Collections.sort(resolveInfoList, new ResolveInfo.DisplayNameComparator(manager));
88 final ShareDialogAdapter adapter =
89 new ShareDialogAdapter(activity, manager, resolveInfoList);
90 AlertDialog.Builder builder = new AlertDialog.Builder(activity);
91 builder.setTitle(activity.getString(R.string.share_link_chooser_title));
92 builder.setAdapter(adapter, null);
94 final AlertDialog dialog = builder.create();
96 dialog.getListView().setOnItemClickListener(new OnItemClickListener() {
98 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
99 ResolveInfo info = adapter.getItem(position);
100 ActivityInfo ai = info.activityInfo;
101 ComponentName component =
102 new ComponentName(ai.applicationInfo.packageName, ai.name);
103 setLastShareComponentName(activity, component);
104 Intent intent = getDirectShareIntentForComponent(title, url, screenshot, component,
106 activity.startActivity(intent);
113 * Starts a share intent with the activity that was most recently used to share.
114 * If there is no most recently used activity, it does nothing.
115 * @param activity Activity that is used to start the share intent.
116 * @param title Title of the page to be shared.
117 * @param url URL of the page to be shared.
118 * @param screenshot Screenshot of the page to be shared.
119 * @param extraIntentFlags Additional flags that should be added to the share intent.
121 private static void shareWithLastUsed(
122 Activity activity, String title, String url, Bitmap screenshot, int extraIntentFlags) {
123 ComponentName component = getLastShareComponentName(activity);
124 if (component == null) return;
125 Intent intent = getDirectShareIntentForComponent(
126 title, url, screenshot, component, extraIntentFlags);
127 activity.startActivity(intent);
131 * Set the icon and the title for the menu item used for direct share.
133 * @param activity Activity that is used to access the package manager.
134 * @param item The menu item that is used for direct share
136 public static void configureDirectShareMenuItem(Activity activity, MenuItem item) {
137 Drawable directShareIcon = null;
138 CharSequence directShareTitle = null;
140 ComponentName component = getLastShareComponentName(activity);
141 if (component != null) {
143 directShareIcon = activity.getPackageManager().getActivityIcon(component);
144 ApplicationInfo ai = activity.getPackageManager().getApplicationInfo(
145 component.getPackageName(), 0);
146 directShareTitle = activity.getPackageManager().getApplicationLabel(ai);
147 } catch (NameNotFoundException exception) {
148 // Use the default null values.
152 item.setIcon(directShareIcon);
153 if (directShareTitle != null) {
154 item.setTitle(activity.getString(R.string.accessibility_menu_share_via,
160 public static Intent getShareIntent(String title, String url, Bitmap screenshot,
161 int extraIntentFlags) {
162 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url);
163 Intent intent = new Intent(Intent.ACTION_SEND);
164 intent.addFlags(extraIntentFlags);
165 intent.setType("text/plain");
166 intent.putExtra(Intent.EXTRA_SUBJECT, title);
167 intent.putExtra(Intent.EXTRA_TEXT, url);
168 if (screenshot != null) intent.putExtra(EXTRA_SHARE_SCREENSHOT, screenshot);
172 private static Intent getDirectShareIntentForComponent(String title, String url,
173 Bitmap screenshot, ComponentName component, int extraIntentFlags) {
174 Intent intent = getShareIntent(title, url, screenshot, extraIntentFlags);
175 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
176 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
177 intent.setComponent(component);
181 private static ComponentName getLastShareComponentName(Context context) {
182 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
183 String packageName = preferences.getString(PACKAGE_NAME_KEY, null);
184 String className = preferences.getString(CLASS_NAME_KEY, null);
185 if (packageName == null || className == null) return null;
186 return new ComponentName(packageName, className);
189 private static void setLastShareComponentName(Context context, ComponentName component) {
190 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
191 SharedPreferences.Editor editor = preferences.edit();
192 editor.putString(PACKAGE_NAME_KEY, component.getPackageName());
193 editor.putString(CLASS_NAME_KEY, component.getClassName());