As I mentioned in In-place DOM manipulation: Thorny as ever, text selection in browsers can get tricky fast. For poketto.me, the challenge was even bigger: the web app runs inside a hosted WebView in an Android app.
Mobile text selection already behaves differently from desktop, and the embedding scenario didn’t make things easier. After wrestling with a few awkward bugs, though, I found an elegant solution.
On the web, when a user finishes selecting text, poketto.me immediately converts the selection into a highlight (default color). On Android, however, a tiny system context menu pops up with entries like Copy, Select All, Web Search, etc. At first this got in the way—but it turns out you can customize this menu on a per-activity basis!
All you need to do is override onActionModeStarted(...) and add/remove/reshuffle items as needed:
@Override
public void onActionModeStarted(ActionMode mode) {
Menu menu = mode.getMenu();
MenuItem highlight = mode.getMenu().add(Menu.NONE, R.id.highlight_menu_item, 0, \"Highlight\");
highlight.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
highlight.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(@NonNull MenuItem item) {
MainActivity.this.evaluateJavascript(\"window.dispatchEvent(new Event(\'androidHighlight\'))\");
return false;
}
});
mode.hide(1); // more on this below 👇
super.onActionModeStarted(mode);
}
In poketto.me’s main activity, I injected a “Highlight” menu item that calls back into the web app, telling it to highlight the selected text. From then on, it works just like on the web.
💡 PS: What’s mode.hide(1)? That’s one of those awkward bugs: without it, the menu doesn’t reliably work. Calling hide(1) tells Android to hide the menu for 1 millisecond, forcing a re-render—including my custom menu item.