DEV Community

Cover image for Providing Custom Text Selection Actions in Android
Arooran Thanabalasingam
Arooran Thanabalasingam

Posted on

Providing Custom Text Selection Actions in Android

I recently came across the app Text Infinity. It offers additional actions for selected text in Android. So I asked myself how can I create an app that provides additional actions.
Text Infinity(source: Google Play)

Table of Contents

How it works

Since Android 6.0 a floating text selection toolbar will appear when the text is selected. By default, the common actions like cut, copy and paste are displayed. The best part is that any app can provide custom actions for the text selection toolbar.

Basically, your activity must listen to the implicit intent ACTION_PROCESS_TEXT. For that you have to add an intent filter inside an activity in the manifest as shown below:

<activity
    android:name=".UppercaseActivity"
    android:label="@string/action_uppercase"
    >
    <intent-filter>
        <action android:name="android.intent.action.PROCESS_TEXT" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

The EXTRA_PROCESS_TEXT parameter contains the highlighted text:

val text = intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT)

There is one more parameter EXTRA_PROCESS_TEXT_READONLY. It can be used to check if the action was triggered from an editable field like EditText. So you can return a modified version of text when it is not readonly.

val readonly = intent.getBooleanExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, false)

Usually my mind understands a concept better when I see the complete code. Therefore, here is a potential implementation how it could look like:

class UppercaseActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val text = intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT)
        val readonly = intent.getBooleanExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, false)

        if(!readonly && text != null){

            val outgoingIntent = Intent()
            outgoingIntent.putExtra(Intent.EXTRA_PROCESS_TEXT, text.toString().toUpperCase())
            setResult(Activity.RESULT_OK, outgoingIntent)

        } else {
            Toast.makeText(this, "Text cannot be modified", Toast.LENGTH_SHORT).show()
        }

        finish()
    }
}

So let's have look at our example:
working example

Further cases

Multiple actions

In case you want to deploy multiple actions with a single app, each text selection action requires a separate activity.

<activity
    android:name=".UppercaseActivity"
    android:label="@string/action_uppercase"
    >
    <intent-filter>
        <action android:name="android.intent.action.PROCESS_TEXT" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>
<activity
    android:name=".LowercaseActivity"
    android:label="@string/action_lowercase"
    >
    <intent-filter>
        <action android:name="android.intent.action.PROCESS_TEXT" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>
<activity
    android:name=".ReverseActivity"
    android:label="@string/action_reverse"
    >
    <intent-filter>
        <action android:name="android.intent.action.PROCESS_TEXT" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

Starting a service

For the intent ACTION_PROCESS_TEXT , the Android system looks only for activities. In other words, a service cannot be directly started by this intent. However, your activity could simply start a service subsequently.

Listening to certain types of text

Maybe you have wondered whether your action can only be triggered for certain types of text such as phone numbers, links and etc. Unfortunately there is no way to do that within the Android system. In other words, your action will always appear. So you need to validate the user input before processing it.

Watch out: launchMode singleTop

If your activity is configured as launchMode=”singleTop”, then you must also handle the text selection action within the onNewIntent() method. (For more information about launchMode, see Tasks)

References

Top comments (2)

Collapse
 
tuabali profile image
tuabali

this is not working on redmi devices, custom text selection not working on redmi device. but its working fine on other devices. can you share the solution for redmi devices?

Collapse
 
filipebatista profile image
Filipe Baptista • Edited

Nice article. Did you manage a way to associate an icon to the action like the app of google contacts/messages does?