I have a web view that I want to get the URL when the user long clicks on links. I know I can do this:
// Register the context menu for web view
registerForContextMenu(webView);
And:
#Override
public void onCreateContextMenu(#NonNull ContextMenu menu, #NonNull View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
final WebView.HitTestResult result = webView.getHitTestResult();
Log.i("url is ===" , "result.getExtra()")
}
But this way, In some search engines like Google, Not be return a URL. This is my log when I long clicked on google search results:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA+klEQVR4AWMgBnwr4pRloAR8KuA89KmAK4V8A/LZ1YGGvPiQy65MtCaQjR8LuDxh/M8FXNlAQ078D2VgJs6APE6rjwWcj4CaOkGaIIZybPucz1FHvCuyeYVBmkBhAArIL6XcEiCvfCzkNMOpCeRPoPMXgFyACAPOcnAYFLK7fSrkDAR6rQmnAe/KBfmBNhQCDbkGtP0yyO8gsU+FHLYgL4EClGgvgDR9zudcCrT9PchVX4q49YmKc5AmkLNBsQDyOygsQK4iygCQoo8FHLGg0AcFIDQm3gPpvXg1zlu88j++2ACFPB51CAmgbf9xYcIGEAAEDSAWM1ATAAC4CbdSzzGZLwAAAABJRU5ErkJggg==
I download a web browser open source from GitHub. In this project, the Programmer does this and this is worked:
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// Get link-URL.
String url = (String) msg.getData().get("url");
Log.i("get url" , url);
}
};
So I write this code in my app, But handleMessage not be run. Do I need to do anything else to use handleMessage method?
Do you know another way to get a URL in google search results?
Finally, after days, I found a solution. Please try this way:
#Override
public void onCreateContextMenu(#NonNull ContextMenu menu, #NonNull View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
String url = null, imageUrl = null;
WebView.HitTestResult result = ((WebView) v).getHitTestResult();
switch (result.getType()) {
case WebView.HitTestResult.SRC_ANCHOR_TYPE:
url = result.getExtra();
break;
case WebView.HitTestResult.IMAGE_TYPE:
imageUrl = result.getExtra();
break;
case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
case WebView.HitTestResult.EMAIL_TYPE:
case WebView.HitTestResult.UNKNOWN_TYPE:
Handler handler = new Handler();
Message message = handler.obtainMessage();
((WebView) v).requestFocusNodeHref(message);
url = message.getData().getString("url");
if ("".equals(url)) {
url = null;
}
imageUrl = message.getData().getString("src");
if ("".equals(imageUrl)) {
imageUrl = null;
}
break;
}
showLongPressMenu(url, imageUrl);
}
Related
I want to Create a Context Menu for web view in android. My problem is that I cant get the URL from the clicked link. I write this code for log the clicked link:
webView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(final View v) {
WebView webView1 = (WebView) v;
WebView.HitTestResult hitTestResult = webView1.getHitTestResult();
Log.i("LinkClicked", hitTestResult.getExtra());
return false;
}
});
With this code, when long click on links in websites like stackoverflow, log like this:
https://stackoverflow.com/questions
everything is ok, but when long click on google search results, log like this:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAJFBMVEVHcEz/AAD/AAD/AAD/AAD/AAD/AAD/AAD/g4P/////KCj/7e0I8rGvAAAAB3RSTlMAT0g5Ggp+EilkVQAAAENJREFUGJVjYCAGsDAzggEzC5jLxo4E2BgYWNlRACsDM5jmggkwMzCBaQ5uqBATTICTk4OAAEILhqEY1mI4DNPphAAASIsES4gsgWgAAAAASUVORK5CYII=
it does not return a link. How I can fix this?
public class MainActivity extends AppCompatActivity {
WebView webView;
String URL1 = "https://stackoverflow.com/questions/60577403/how-to-get-url-from-long-click-links-in-a-webview/60577736?noredirect=1#comment107173847_60577736";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webview);
webView.clearHistory();
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
webView.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
}
public void onPageFinished(WebView view, String url) {
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
URL1 = url;
return super.shouldOverrideUrlLoading(view, url);
}
});
webView.loadUrl(URL1);
// Register the context menu for web view
registerForContextMenu(webView);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// Get the web view hit test result
final WebView.HitTestResult result = webView.getHitTestResult();
// If user long press on url
if (result.getType() == WebView.HitTestResult.ANCHOR_TYPE ||
result.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
// Set the title for context menu
menu.setHeaderTitle("\t\t\t\t\t\t\t\t\t\t ◦ ◉ ⦿ Select ⦿ ◉ ◦ \t");
// Add an item to the menu
menu.add(0, 1, 0, " \t \t➤\t Show URL")
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
String Pressed_url = result.getExtra();
Toast.makeText(MainActivity.this, "URL is:-" + Pressed_url,
Toast.LENGTH_SHORT).show();
return false;
}
});
}
}
}
Download Full Code from github.
Output
So, I know that there are plenty of similar questions on Stack; however, none of them managed to solve my issue.
I have a ListActivity activity for displaying a list of usernames;
I created a UserObj class to collect information about each user, i.e., UserObj instance (username, password, etc..).
Now I am showing successfully the username within my ListView and I also managed to show a floating ContextMenu with some items (Delete,ChangeUsername,ChangePassword,ChangeEmail) upon long-clicking on a particular username.
Below I post my ListActivity code:
public class ShowAccountList extends ListActivity {
List<UserObj> Allusers = new ArrayList<>(); // this is required to retrieve users from a local database
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_account_list);
final ListView UserList = (ListView)findViewById(android.R.id.list);
UserList.setLongClickable(true);
/*For completeness: here I fetch users from DB*/
DataBaseUserHelper dbusers = new DataBaseUserHelper(getApplicationContext());
dbusers.CreateTables();
Allusers = dbusers.getAllUsers();
dbusers.closeDB();
/*Let's build a 'username' list to display*/
List<String> namelist = new ArrayList<String>();
for(int i=0 ; i< Allusers.size() ; i++){
String uname = Allusers.get(i).username;
namelist.add(uname);
}
final ArrayAdapter<String> nameadapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,namelist);
UserList.setAdapter(nameadapter);
registerForContextMenu(UserList);
UserList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
openContextMenu(parent);
/*This outputs the CORRECT position*/
System.out.println("Position: " + position + ", id: " + id);
return true;
}
});
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo){
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.user_context_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item){
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int selectedId = info.position; // HERE the problem shows up
// switch statement for debugging purposes
switch (item.getItemId()){
case R.id.DeleteUser:
System.out.println("DELETE USER");
return true;
case R.id.ChangeName:
System.out.println("CHANGE USERNAME");
return true;
case R.id.ChangeEmail:
System.out.println("CHANGE EMAIL");
return true;
case R.id.ChangePassword:
System.out.println("CHANGE PASSWORD");
return true;
default:
return super.onContextItemSelected(item);
}
}
}
However, what I need to do, obviously, is to actually trigger the execution of the 'delete user', 'change email', etc... tasks for the selected user; what I supposed was that the position of the corresponding list item would be required in order to know which user should have undergone these modifications.
So, following the suggestions of the majority of the questions (and of the corresponding answers) on this topic, I casted item.getMenuInfo() to AdapterContextMenuInfo within onContextItemSelected and then I tried to retrieve the position with:
int selectedId = info.position;
The problem is that when I select one menu item (e.g., the one corresponding to 'delete') the ANR dialog shows up and the following exception is reported:
java.lang.NullPointerException: Attempt to read from field 'int android.widget.AdapterView$AdapterContextMenuInfo.position' on a null object reference
What I can understand is that info.position is always null. But why?
What could be the problem in my code?
As you can see from the code above, I tried to see what happened when clicking each single menu item by printing a test string (e.g., "DELETE USER") and actually if I remove int selectedId = info.position; no crash occurs...
Thanks in advance
EDIT
After some diagnosis, I figured out that the menuInfo passed to onCreateContextMenu is NULL. So, I got a little bit closer to the origin of the problem.
Any idea why I am getting a NULL menuInfo?
I faced similar problem. My solution was to register view for context menu inside the adapter using activity.registerForContextMenu(view)
The position of the item or even UserObj can be set as tag in the view.
You can get the tag in the onCreateContextMenu() call and corresponding action could be invoked.
In the best way, you should create custom adapter, then implement custom listener in activity when event occur (onClick, onLongClick...)
About your problem, I think you was wrong when implement #rabhis idea.
Try my solution that I have implemented in my app:
(In my code, I used custom adapter with recycleview, so try to merge to your code)
Class implement:
public class ListHistoryAdapter extends RecyclerView.Adapter<ListHistoryAdapter.HistoryViewHolder> implements View.OnCreateContextMenuListener {
In public void onBindViewHolder method:
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// your code
}
});
holder.itemView.setOnCreateContextMenuListener(this);
holder.itemView.setTag(position);
Override in adapter:
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuItem deleteItem = menu.add(Menu.NONE, 1, 1, "Delete");
final int pos = (int) v.getTag();
deleteItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// your code
return true;
}
});
}
I am creating a quiz to practice Android programming. I am able to run the Android program and it works fine. But now, I have added a ContextMenu. If I click any item, the Activity should restart with a new value. But it does not.
TextView Qsn;
Button TopicTitle;
Button Ybtn;
Button Nbtn;
String check;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.history);
Qsn = (TextView) findViewById(R.id.Question);
TopicTitle = (Button)findViewById(R.id.Topictxt);
Ybtn = (Button)findViewById(R.id.Yesbtn);
Nbtn = (Button)findViewById(R.id.Nobtn);
Intent intent = getIntent();
Bundle bundle =intent.getExtras();
check=bundle.getString("Bundlekey") ;
TopicTitle.setText(check);
Toast.makeText(getApplicationContext(), check, Toast.LENGTH_SHORT) .show();
registerForContextMenu(TopicTitle);
if (check.matches("History")) {
....
}
}
The code check what topic has been selected and it works fine till here. But now I've added a ContextMenu so if the user wants to change the topic he can long-press on the button and select the topic and change his new topic for a new question.
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.topic_selection_in_question, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
String Value_from_item ;
Value_from_item = (String) item.getTitle();
check = Value_from_item;
Intent intent = getIntent(); finish(); startActivity(intent);
return super.onContextItemSelected(item);
}
Where did I make the mistake? Is there an error in the logic? I do not get a runtime error. Everything works fine. I would be glad if you can help me out. Thanks in advance.
Instead of this code
Intent intent = getIntent(); finish(); startActivity(intent);
Use
Intent intent = new Intent(youractivity.this, Youractivity.class);
finish();
startActivity(intent);
I am able to select text when long pressed but when longClick on image its not showing save as option.? Tried all solutions but not getting results. I have tried solution on stackoverflow.com but not working for me.
I have tried below stuff
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
// Confirm the view is a webview
if (v instanceof WebView) {
WebView.HitTestResult result = ((WebView) v).getHitTestResult();
if (result != null) {
int type = result.getType();
// Confirm type is an image
if (type == WebView.HitTestResult.IMAGE_TYPE || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
String imageUrl = result.getExtra();
Toast.makeText(this, imageUrl, Toast.LENGTH_LONG).show();
}
}
}
}
are u use registerForContextMenu()?
try this
activity.registerForContextMenu(webView);
actually i got a problem while creating my project. I am having one list view in one screen where data comes from database & binds to it. I created one context menu here with two menus (view & delete). The problem i am facing is when i make a long click context menu occur & when i click on anyone of the menu it navigates to another screen. here i want the listview(which was clicked) item data to pass to next screen. By i am not getting it. This is the following code...
Main.java
/*******some code****/
DbHandler dbh=new DbHandler(GroupName.this);
ast=dbh.selectgroupnam(s);
//here "ast" is of ArrayList defined globally
ArrayAdapter<String> adp=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,ast);
lv.setAdapter(adp);
registerForContextMenu(lv);
lv.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> arg0, View v, int p, long arg3) {
// TODO Auto-generated method stub
TextView tv=(TextView)v;
String gnam=tv.getText().toString();
}});
}//on create
//context menu code
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, v.getId(), 0, "View");
menu.add(0, v.getId(), 0, "Delete");
}
#Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "group name" + gnam,30).show();
if (item.getTitle() == "Delete") {
Toast.makeText(getApplicationContext(), "selected group" + gnam, 30).show();
startActivity(new Intent(GroupName.this,GroupEdit.class));
}
else
{
startActivity(new Intent(GroupName.this,GroupEdit.class));
}
return super.onContextItemSelected(item);
}
As per the following code how to get the list view data (which was long clicked for context menu) & pass the data to GroupEdit.class.
Waiting for reply......
So you start activity startActivity(new Intent(GroupName.this,GroupEdit.class))
but any data you are adding to intent.
So try it with putExtra(<key>,<data>) or if you want to use Bundle so putExtras(<bundle>)
You should to it like this:
Intent i = new Intent(GroupName.this,GroupEdit.class);
i.putExtra("key", <data>);
startActivity(i);
Then in new Activity GroupEdit you get this data with getIntent() method that return the intent that started this activity and getExtras() with it you retrieve a map of extended data from the intent.
So in GroupEdit String text = getIntent().getExtras().getString("keyOfField")
Of you will use Bundle so
Intent i = new Intent(GroupName.this,GroupEdit.class);
i.putExtras(bundle);
startActivity(i);
in GroupEdit you retrieve data with Bundle data = getIntent().getExtras()
Regards