Getting selected text in a WebView via a contextual action bar - android

It's known to be difficult to get selected text in a WebView because WebView text selection is actually handled by a private class, WebTextView.
However, with the recently released Android 4.0 Design guidelines, there seems to be a glimmer of hope of achieving this through contextual action bars (CABs). It says:
Use CABs whenever you allow the user to select data via long press. You can control the action content of a CAB in order to insert the actions you would like the user to be able to perform.
Am I misinterpreting this? Is there a way to retrieve selected text from a WebView via a CAB?
After a long click and text selection mode begins, I can currently detect when the ActionMode starts and modify the original copy/paste Menu; however, I can't quite figure out how to actually retrieve the selected text.

You can't do that yet with the current API.
I filed a feature request for this - Issue 24841: WebView should allow applications to supply a custom Contextual Action Bar http://code.google.com/p/android/issues/detail?id=24841
Basically, WebView in 4.0 has hardcoded its own Contextual Action Bar (CAB). That CAB has a reference back to the WebView and with that reference, it can get the selected text. I'm not sure how you were able to detect the ActionMode starting and modify the menu, but if you were able to do all of that, then you are stuck because getSelection() is package-private currently. I filed that as a separate issue and linked it to the previous issue above.

You can use javascript to get the selected text: window.getSelection(), and use WebView's addJavascriptInterface function to return the result.

thanks for your information, I have solved a hard issue..
I just want to add some function into the actionmode.
The following is my code, May be helpful to others.
#Override
public ActionMode onWindowStartingActionMode(Callback callback) {
// TODO Auto-generated method stub
ActionMode mode = super.onWindowStartingActionMode(callback);
mode.getMenuInflater().inflate(R.menu.actions, mode.getMenu());
mode.getMenu().findItem(R.id.action_add).setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
Log.i("", "onMenuItemClick add ");
return false;
}
});
return mode;
}

Related

How to programmaticallly remove submenu from navigation drawer in Android?

I am developing an Android app. Firstly, let me tell you that I am not professional. What I am doing now is I am adding submenu to menu depending on a condition. But I need to do it very often in my app. But my problem is I added a submenu to the menu as first time.
But second time when I update menu depending on condition, existing submenu is not removed and new submenu is appended to navigation drawer. How can I remove submenu that is programmatically added to menu? Why my code is not removing it?
Here is my code
public void updateAuthUI()
{
isLoggedIn = tempStorage.getBoolean(getResources().getString(R.string.pref_is_logged_in),false);
Menu menu = leftDrawer.getMenu();
menu.removeItem(getResources().getInteger(R.integer.logout_item_id));
menu.removeItem(getResources().getInteger(R.integer.login_item_id));
menu.removeItem(getResources().getInteger(R.integer.register_item_id));
SubMenu authSubMenu = menu.addSubMenu("Auth");
if(isLoggedIn)
{
authSubMenu.add(1,getResources().getInteger(R.integer.logout_item_id),99,"Sign out");
}
else{
authSubMenu.add(1,getResources().getInteger(R.integer.register_item_id),97,"Register");
authSubMenu.add(1,getResources().getInteger(R.integer.login_item_id),98,"Sign in").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
openLoginActivity();
item.setChecked(true);
return true;
}
});
}
}
Here is the screenshot of my problem
As you can see Auth submenu is appended without removing existing one.
Try
authSubMenu.clear();
before your first
authSubMenu.add();
I just used SubMenu.clear() in an Android app where I was using a third-party library, and I needed to clear out an unwanted submenu from the action bar. (I actually wanted to remove the submenu completely, and this was the only way I could find to do it. It seemed to work.)
That's different from your situation, where authSubMenu is a menu you just added via menu.addSubMenu("Auth"), so you would expect it to be empty. But, as you've seen, it apparently isn't empty: rather, addSubMenu("Auth") returns the existing submenu of that title. (I can't find documentation to that effect; I'm just going by the results you've reported.)
If that really is the case, as it appears to be, then authSubMenu.clear() will remove all existing items from the submenu.
As #slymm said in a comment you can remove all menu and submenu items using
navigationView.getMenu().clear();
This can be used to remove submenu (and menu elements) and then recreate them with the new required items

Android Espresso onData strange behavior

I have an Activity with ListView (id: android.R.id.list). The ListView shows information from a custom adapter, and I want to use Espresso to click on a specific view in a specific item: I want to click the view with id R.id.continueButton in the item that shows information from the object testOrder.
My test is:
onData(is(sameAsOrder(testOrder)))
.onChildView(withId(R.id.continueButton))
.inAdapterView(withId(android.R.id.list))
.perform(click());
where sameAsOrder() is:
public static Matcher<Object> sameAsOrder(final Order order) {
assertNotNull(order);
return new BoundedMatcher<Object, Order>(Order.class) {
#Override
public boolean matchesSafely(Order myOrder) {
return myOrder.getId().equals(order.getId());
}
#Override
public void describeTo(Description description) {
description.appendText(" with id '" + order.getId() + "'");
}
};
}
I run the tests on my device, but when I load my Order objects from a online server the click happens on the action bar menu, as if I run the Espresso command
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());
When using dummy data it clicks on the correct list item. Moreover, when using dummy data on the emulator it also clicks on the action bar menu.
If I remove the menu, the test passes without nothing being clicked (as far as I can tell...)
Does anybody have an ideia why that strange behavior happens?
Thanks!
I got it! The strange behavior has nothing to do with onData(). I am using action bar overlay mode. Due to difference on screen sizes from my device to the emulator, and due to different data being used to fill the list (dummy vs. loaded from server), sometimes the item that I want to click on is getting below the action bar. When Espresso tries to click on it, it clicks on the action bar...

Why does findViewById(R.android.id.home) always return null?

I'm using AppCompat and trying to recall the ImageView for the up/back button belonging to the toolbar.
I know R.android.id.home exists, because I can manage its click as a Menu item:
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
//this works
}
return super.onOptionsItemSelected(item);
}
Apart from that, whenever I try to call findViewById(android.R.id.home) - be it onCreate, be it onClick of a custom button - I get null.
I even get null if, in the sample above, I call findViewById(item.getItemId()).
Why is it?
This question has been asked before here, most times regarding ActionBarSherlock (which I am not using). Another time it was suggested to use:
getWindow().getDecorView().findViewById(android.R.id.home)
But it isn't working. In that question the OP also says findViewById(android.R.id.home) works on API>3.0, but that's not true for me. Any ideas?
Whether or not the "home" icon is a widget, and what class of widget it is, and what its ID is (if any), is up to the implementation of the action bar. The native action bar may do this differently for different API levels, and all of that may be different than the way appcompat-v7 does it. Let alone ActionBarSherlock or other action bar implementations.
Specifically, android.R.id.home is a menu ID, which is why you can use it in places like onOptionsItemSelected(). It is not necessarily a widget ID, which is why it may or may not work with findViewById().
Ideally, you do not attempt to mess with the internal implementation of a UI that you did not construct yourself.
do one really has to make his own Up button to style it?
I do not know, as I have never tried to style it.
As CommonsWare said android.R.id.home is a menu ID, not a widget ID. But if you want to access this home button you could do it. For example I needed it to highlight home button in in-app tutorial:
fun AppCompatActivity.getToolbarHomeIcon(): View? =
this.findViewById<Toolbar?>(R.id.toolbar)?.let { toolbar ->
val contentDescription: CharSequence = toolbar.navigationContentDescription.let {
if (it.isNullOrEmpty()) {
this.getString(R.string.abc_action_bar_up_description)
} else {
it
}
}
// Here home button should be created even if it doesn't exist before
toolbar.navigationContentDescription = contentDescription
ArrayList<View>().let { potentialViews ->
toolbar.findViewsWithText(
potentialViews,
contentDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION
)
potentialViews.getOrNull(0)
}
}

master/detail template with action menu - right way to show both

Beginner here, targetting sdk v14 and v17 for my learning...no need for older support.
I am using the master/detail template and trying to get an action menu (for SEARCH) to show up both in phone and tablet view. Actually I can get it to work, but I have to duplicate up my code in both ItemDetailActivity.java and ItemListActivity.java
These are the methods that I have to have in both for SEARCH to work:
public boolean onQueryTextChange(String newText) {
public boolean onQueryTextSubmit (String query) {
public boolean onClose () {
I only want to search the "detail", not the "list".
So my question: is there a way to associate the action bar with only the list fragment? That way I can keep the search functions in 1 file.
Thanks!
I'll go ahead and answer what I (think) I know as I don't want to leave this question open.
From tracing in the debugger, it looks to me like the phone activity and the tablet activity are separate and if you want to hook up an actionmenu, you have to hook it up to both separately.

Android ListView: mouseover action

I am new to Android application Development.
How can I identify the mouseover action for a list box? On mouse over of a particular cell I want to highlight that cell or change the background color.
Please help me regarding this.
There isn't a concept of MouseOver in Android, at least one that I know of - user interaction is done through hardware/virtual keyboard and touchscreen.
ListView automatically highlights the current selection, so when you use the up and down DPad keys, you may get the effect you want.
I know this is old but my queries kept returning to this original post so I wanted to share it here.
For what it is worth, implementing the state_hovered in your selector will NOT work for list views on mouse over events.
You can achieve this event using custom array adapter.
*This assumes you know how to create your own selector and ArrayAdapter. If not, you can find those in other Stack Overflow posts.
Create your own array adapter.
Implement View.OnHoverListener in the adapter
Override the 'onHover'method:
#Override
public boolean onHover(View arg0, MotionEvent arg1) {
int ev = arg1.getActionMasked();
switch (ev) {
case MotionEvent.ACTION_HOVER_ENTER:
arg0.setHovered(true);
arg0.setSelected(true);
return true;
case MotionEvent.ACTION_HOVER_EXIT:
arg0.setHovered(false);
arg0.setSelected(false);
return true;
}
return false;
}

Categories

Resources