Context Menu/Window in WebView inside PopupWindow crashes the app?
android, android-contextmenu, android-webview
Solution
As commented above in my answer you can use Custom dialog for your requirement.. i have created a sample PopupDialog.. please check and let me know..if it solve your purpose.. Autocomplete and ContextMenus will work as expected..
MyActivity.java
package com.example.testapp;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button btnOpenPopup = (Button) findViewById(R.id.openpopup);
btnOpenPopup.setOnClickListener(new Button.OnClickListener() {
@SuppressLint("NewApi")
@Override
public void onClick(View arg0) {
final PopupDialog popupDialog = new PopupDialog(MyActivity.this);
popupDialog.setContentView(R.layout.popup);
WebView popupWebview = (WebView) popupDialog.findViewById(R.id.webviewActionView);
popupWebview.setWebChromeClient(new WebChromeClient());
popupWebview.setWebViewClient(new WebViewClient());
popupWebview.loadUrl("http://m.facebook.com");
Button btnDismiss = (Button) popupDialog
.findViewById(R.id.dismiss);
btnDismiss.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
popupDialog.dismiss();
}
});
// popupDialog.showAtLocation(50,50);
popupDialog.showAsDropDown(findViewById(R.id.openpopup));
}
});
}
}
PopupDialog.java
package com.example.testapp;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class PopupDialog extends Dialog{
private final Context mContext;
public PopupDialog(Context context) {
super(context);
mContext=context;
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
public void showAtLocation(int x,int y)
{
WindowManager.LayoutParams wmlp = getWindow().getAttributes();
wmlp.gravity = Gravity.TOP | Gravity.LEFT;
wmlp.x = x;
wmlp.y = y;
show();
}
public void showAsDropDown(View view)
{
float density = mContext.getResources().getDisplayMetrics().density;
WindowManager.LayoutParams wmlp = getWindow().getAttributes();
int[] location = new int[2];
view.getLocationInWindow(location);
wmlp.gravity = Gravity.TOP | Gravity.LEFT;
wmlp.x = location[0]+(int)(view.getWidth()/density);
wmlp.y = location[1]+(int)(view.getHeight()/density);
show();
}
}
edit: added popup.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:minHeight="400dp"
android:minWidth="200dp"
android:background="@android:color/background_light"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="vertical" >
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="20dp"
android:orientation="vertical" >
<WebView
xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:id="@+id/webviewActionView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="200dp"
android:minWidth="200dp"
android:scrollbars="none" >
</WebView>
<Button
android:id="@+id/dismiss"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Dismiss" />
</LinearLayout>
</LinearLayout>
Problem
I have an app with PopupWindow containing WebView that opens Facebook's page, any context menu like: the Autocomplete on text fields in the WebView or even the Long Press that should display options for the user to copy/paste/cut crashes the app right away with the follow error: ``` FATAL EXCEPTION: main android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@418cdab0 is not valid; is your activity running? at android.view.ViewRootImpl.setView(ViewRootImpl.java:700) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:345) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224) at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149) at android.view.Window$LocalWindowManager.addView(Window.java:554) at android.widget.PopupWindow.invokePopup(PopupWindow.java:1013) at android.widget.PopupWindow.showAtLocation(PopupWindow.java:856) at android.widget.PopupWindow.showAtLocation(PopupWindow.java:820) at android.webkit.WebViewClassic$PastePopupWindow.show(WebViewClassic.java:971) at android.webkit.WebViewClassic.showPasteWindow(WebViewClassic.java:7037) at android.webkit.WebViewClassic.access$10300(WebViewClassic.java:235) at android.webkit.WebViewClassic$PrivateHandler.handleMessage(WebViewClassic.java:11376) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4921) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794) at dalvik.system.NativeStart.main(Native Method) ``` Notice: my understanding of the problem is that the context menu/window are shown actually in the scope of the app itself not inside the WebView using another PopWindow (Auto generated by the Core WebView Class) this class references the context incorrectly. My Code is as follows: Main.xml ``` <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/openpopup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Open Popup Window" /> </LinearLayout> ``` Popup.xml ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/background_light" android:orientation="vertical" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_margin="1dp" android:background="@android:color/darker_gray" android:orientation="vertical" > > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_margin="20dp" android:orientation="vertical" > <WebView xmlns:ptr="http://schemas.android.com/apk/res-auto" android:id="@+id/webviewActionView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:minHeight="200dp" android:minWidth="200dp" android:scrollbars="none" > </WebView> <Button android:id="@+id/dismiss" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Dismiss" /> </LinearLayout> </LinearLayout> </LinearLayout> ``` MainActivity.java ``` import android.os.Bundle; import android.annotation.SuppressLint; import android.app.Activity; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Button; import android.widget.PopupWindow; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final Button btnOpenPopup = (Button) findViewById(R.id.openpopup); btnOpenPopup.setOnClickListener(new Button.OnClickListener() { @SuppressLint("NewApi") @Override public void onClick(View arg0) { LayoutInflater layoutInflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE); View popupView = layoutInflater.inflate(R.layout.popup, null); final PopupWindow popupWindow = new PopupWindow(popupView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); popupWindow.setTouchable(true); popupWindow.setFocusable(true); WebView popupWebview = (WebView) popupView.findViewById(R.id.webviewActionView); popupWebview.loadUrl("https://m.facebook.com"); Button btnDismiss = (Button) popupView .findViewById(R.id.dismiss); btnDismiss.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub popupWindow.dismiss(); } }); popupWindow.showAsDropDown(btnOpenPopup, 50, -30); } }); } } ```