6

According to this solution, I would like to add "copy to clipboard" action in custom share dialog - the same as in the default action share provider.

enter image description here

What I have tried was adding to if clausule statement, word packageName.contains("clipboard") but without success.

String packageName = ri.activityInfo.packageName;
    if(packageName.contains("android.email")) {
        emailIntent.setPackage(packageName);
    } else if(packageName.contains("twitter") || packageName.contains("facebook") || packageName.contains("mms") || packageName.contains("android.gm")) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(packageName, ri.activityInfo.name));
        intent.setAction(Intent.ACTION_SEND);
        intent.setType("text/plain");
        if(packageName.contains("twitter")) {
            intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_twitter));
        } else if(packageName.contains("facebook")) {
            intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_facebook));
        } else if(packageName.contains("mms")) {
            intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_sms));
        } else if(packageName.contains("android.gm")) {
            intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_gmail)));
            intent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject));               
            intent.setType("message/rfc822");
        }

        intentList.add(new LabeledIntent(intent, packageName, ri.loadLabel(pm), ri.icon));
    }

The whole code is used from https://stackoverflow.com/a/18068122/619673 .

adb shell pm list packages returned me list of packagenames but without this phrase.

Can I somehow get packagename of clipboard to add it to my custom list of shared providers?

Here is an example with that "copy to clipboard" option:

enter image description here

Community
  • 1
  • 1
deadfish
  • 11,996
  • 12
  • 87
  • 136
  • `packagename of clipboard` ? Didn't know about a clipboard app. Please explain. – greenapps Jul 14 '14 at 18:09
  • I'm not sure what you're trying to accomplish but definitely you need to check http://developer.android.com/guide/topics/text/copy-paste.html#Clipboard and understand how the cipboard framework works. – IsaacCisneros Jul 17 '14 at 16:34

3 Answers3

12

The trick is that there is actually no built-in package for the clipboard (some apps provide the Copy to Clipboard option system-wide by creating such a package with the appropriate intent-filter).

However, since you're creating the chooser's options manually, you can add your own intent to handle the copy to clipboard operation. For example, like this:

... create the intentList, as before ...

// Add a custom intent to handle the "copy to clipboard" option.
Intent copyToClipboard = new Intent(this, ShareToClipboardActivity.class);
copyToClipboard.putExtra(Intent.EXTRA_TEXT, "text to copy to clipboard");

// Wrap it with a LabeledIntent and add it to the list of choosable ones.
LabeledIntent labeledCopyToClipboard = new LabeledIntent(copyToClipboard, getPackageName(), "Copy!", 0);
intentList.add(labeledCopyToClipboard);

... convert intentList to array and show chooser, as before ...

Where ShareToClipboardActivity is your own activity, which does (at least) this:

public class ShareToClipboardActivity extends Activity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        CharSequence text = getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT);
        ClipboardManager clipboardManager = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
        clipboardManager.setPrimaryClip(ClipData.newPlainText(null, text));
        finish();
    }
}

Note that this is a bare-bones example: you would probably want drawable and string resources for the LabeledIntent, as well as possibly showing a Toast message in ShareToClipboardActivity, use the old ClipboardManager if targeting pre-API 11, &c.

matiash
  • 54,791
  • 16
  • 125
  • 154
6

Update: My solution is dependent on another application package and I realized it might not be the correct approach. Hence would suggest to define your own Activity which will handle copy and paste functionality using ClipboardManager, as suggested in another answer here.

Original Answer

Clipboard activity details:

  • Package name : com.google.android.apps.docs
  • Activity name : com.google.android.apps.docs.app.SendTextToClipboardActivity

Following Intent code will start and execute the clipboard activity.

Intent i = new Intent();
i.setComponent(new ComponentName("com.google.android.apps.docs", "com.google.android.apps.docs.app.SendTextToClipboardActivity"));
i.setAction(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_TEXT, "text to copy to clipboard");
startActivity(i);

You can add appropriate if clause while adding this intent to the intentList.

Community
  • 1
  • 1
Manish Mulimani
  • 17,535
  • 2
  • 41
  • 60
  • hod did you find out this? – deadfish Jul 29 '14 at 06:02
  • @deadfish Found following in `logcat` when I selected `Copy to clipboard` in Share feature of Browser application. `07-29 12:28:55.811 909 29901 I ActivityManager: START u0 {act=android.intent.action.SEND typ=text/plain flg=0x3000001 cmp=com.google.android.apps.docs/.app.SendTextToClipboardActivity (has clip) (has extras)} from pid 9525` – Manish Mulimani Jul 29 '14 at 07:01
  • very... very nice +100 is going to you soon – deadfish Jul 29 '14 at 07:36
  • @deadfish This answer is incorrect, as it _requires_ to have the Google Docs apps installed. Otherwise, it will crash -- this is **NOT** a standard package in Android. – matiash Jul 29 '14 at 17:52
  • @matiash I disagree with the app crash, as he will not hardcode the application name instead he will iterate through the package list returned by the `PackageManager`. As per my knowledge, `Google docs` is by default installed on the Android device, after all Android is controlled by Google. Infact I don't have option of uninstalling the app on atleast `Moto G` device. Also all the apps listed in the share list are external apps that are not core of Android platform. – Manish Mulimani Jul 29 '14 at 18:41
  • 1
    @ManishMulimani While Google Docs may be pre-installed on some devices, it is not part of Android per se. And it can certainly be uninstalled, at least on my Nexuses. – matiash Jul 29 '14 at 18:51
  • as long I don't find the real solution, it will be the right answer – deadfish Jul 29 '14 at 19:30
  • @deadfish This will work, only as long as Google Docs is installed -- if that is guaranteed in your use case, then it is indeed a good solution. However to be _sure_ I think you should add your own share target, as I described in the other answer. – matiash Jul 29 '14 at 22:12
  • I also agree on last comment. I've upvoted @matiash answer as it also correct answer :-) – Manish Mulimani Jul 30 '14 at 07:23
  • Thank you @manish-mulimani for the information, how to find out the correct settings. Meanwhile there was a Google Docs Update, and for those interested in the new correct settings to use, you can find them [here](http://puravidaapps.com/snippets.php#2clipboard) – Taifun Aug 21 '15 at 20:52
0

Working Solution

might be quite big but it is quite simple to understand. This solution shows only packages from my list, sort by priority. There is also example how to change text from the list of intents.

Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, mUrl);
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, mTitle);
PackageManager pm = getActivity().getPackageManager();
IntentChoserBuilder.createChoserIntent(this, shareIntent, pm, mUrl, mTitle);

//intent choser class

public class IntentChoserBuilder {

    public static final String TAG = IntentChoserBuilder.class.getSimpleName();
    public static final Map<String, Integer> PRIORITY = new HashMap<String, Integer>();

    public static final String ANDROID_EMAIL = "com.google.android.email";
    public static final String FACEBOOK = "com.facebook.katana";
    public static final String MMS = "com.android.mms";
    public static final String ANDROID_GM = "com.google.android.gm";
    public static final String APPS_PLUS = "com.google.android.apps.plus";
    public static final String TWITTER = "com.twitter.android";
    public static final String CLIPBOARD = "com.google.android.apps.docs";
    public static final String WHATSAPP = "com.whatsapp";

    //static fields for custom sorting
    static {
        PRIORITY.put(CLIPBOARD, 0);//
        PRIORITY.put(FACEBOOK, 1);
        PRIORITY.put(TWITTER, 2);
        PRIORITY.put(APPS_PLUS, 3);
        PRIORITY.put(ANDROID_EMAIL, 4);
        PRIORITY.put(ANDROID_GM, 5);
        PRIORITY.put(MMS, 6);//
        PRIORITY.put(WHATSAPP, 7);
    }

    public static void createChoserIntent(Fragment fragment, Intent prototype, final PackageManager pm, String EXTRA_TEXT, String EXTRA_SUBJECT) {

        String[] forbiddenChoices = new String[]{CLIPBOARD, FACEBOOK, TWITTER, APPS_PLUS, ANDROID_EMAIL, ANDROID_GM, MMS, WHATSAPP};

        List<Intent> targetedShareIntents = new ArrayList<Intent>();
        List<HashMap<String, String>> intentMetaInfo = new ArrayList<HashMap<String, String>>();
        Intent chooserIntent = null;

        Intent dummy = new Intent(prototype.getAction());
        dummy.setType(prototype.getType());
        List<ResolveInfo> resInfo = pm.queryIntentActivities(dummy, 0);

        if (!resInfo.isEmpty()) {
            for (ResolveInfo resolveInfo : resInfo) {
                if (!Arrays.asList(forbiddenChoices).contains(resolveInfo.activityInfo.packageName))
                    continue;

                //todo hack to ignore word DYSK (remove duplicated option `copy to clipboard`, working for PL language)
                if (String.valueOf(resolveInfo.activityInfo.loadLabel(pm)).equals("Dysk"))
                    continue;

                HashMap<String, String> info = new HashMap<String, String>();
                info.put("packageName", resolveInfo.activityInfo.packageName);
                info.put("className", resolveInfo.activityInfo.name);
                info.put("simpleName", String.valueOf(resolveInfo.activityInfo.loadLabel(pm)));

                intentMetaInfo.add(info);
            }

            if (!intentMetaInfo.isEmpty()) {
                Collections.sort(intentMetaInfo, new Comparator<HashMap<String, String>>() {
                    @Override
                    public int compare(HashMap<String, String> map1, HashMap<String, String> map2) {
                        int m1 = getLabeledIntentPriority(map1.get("packageName"));
                        int m2 = getLabeledIntentPriority(map2.get("packageName"));

                        if (m1 < m2)
                            return -1;
                        else if (m1 > m2)
                            return 1;
                        else
                            return 0;
                    }
                });

                for (HashMap<String, String> metaInfo : intentMetaInfo) {
                    Intent targetedShareIntent = (Intent) prototype.clone();
                    if (metaInfo.get("packageName").equals(CLIPBOARD)) {
                        targetedShareIntent.setPackage(metaInfo.get("packageName"));
                        targetedShareIntent.setClassName(metaInfo.get("packageName"), metaInfo.get("className"));
                        LabeledIntent labeledIntent = new LabeledIntent(targetedShareIntent, fragment.getActivity().getPackageName(), "Example how to change text for for copy link", R.drawable.launcher_copy_link);
                        targetedShareIntents.add(labeledIntent);
                    } else {
                        targetedShareIntent.setPackage(metaInfo.get("packageName"));
                        targetedShareIntent.setClassName(metaInfo.get("packageName"), metaInfo.get("className"));
                        targetedShareIntents.add(targetedShareIntent);
                    }

                }

                chooserIntent = Intent.createChooser(targetedShareIntents.remove(targetedShareIntents.size() - 1), fragment.getString(R.string.sharee));
                chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{}));
            }
        }
        fragment.startActivity(Intent.createChooser(chooserIntent, fragment.getString(R.string.podziel_sie)));

    }

    private static int getLabeledIntentPriority(String packageName) {
        if (packageName.equalsIgnoreCase(ANDROID_EMAIL))
            return PRIORITY.get(ANDROID_EMAIL);
        else if (packageName.equalsIgnoreCase(FACEBOOK))
            return PRIORITY.get(FACEBOOK);
        else if (packageName.equalsIgnoreCase(MMS))
            return PRIORITY.get(MMS);
        else if (packageName.equalsIgnoreCase(ANDROID_GM))
            return PRIORITY.get(ANDROID_GM);
        else if (packageName.equalsIgnoreCase(APPS_PLUS))
            return PRIORITY.get(APPS_PLUS);
        else if (packageName.equalsIgnoreCase(TWITTER))
            return PRIORITY.get(TWITTER);
        else if (packageName.equalsIgnoreCase(WHATSAPP))
            return PRIORITY.get(WHATSAPP);
        else if (packageName.equalsIgnoreCase(CLIPBOARD))
            return PRIORITY.get(CLIPBOARD);
        else
            return 1000;//none
    }
}

Based on: https://gist.github.com/mediavrog/5625602

deadfish
  • 11,996
  • 12
  • 87
  • 136