116

I want to show a custom popup menu when the user clicks on a floating icon

the floating icon create with service and i have no activity

this is my floating icon code

public class copy_actions_service extends Service
{
    ImageView copy_ImageView;
    WindowManager windowManager;
    WindowManager.LayoutParams layoutParams;

    @Override
    public IBinder onBind(Intent arg0)
    {
        // TODO Auto-generated method stub
        return null;
    }
    
    @Override
    
    public void onCreate()
    {
        windowManager=(WindowManager)getSystemService(WINDOW_SERVICE);
        
        copy_ImageView=new ImageView(this);
        copy_ImageView.setImageResource(R.drawable.ic_launcher);
        copy_ImageView.setAlpha(245);
        copy_ImageView.setOnClickListener(new OnClickListener()
        {
            
            @Override
            public void onClick(View arg0)
            {
                showCustomPopupMenu();
            }
        });
        
        layoutParams=new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);
        
        layoutParams.gravity=Gravity.TOP|Gravity.CENTER;
        layoutParams.x=0;
        layoutParams.y=100;
        
        windowManager.addView(copy_ImageView, layoutParams);

    }
    
    private void showCustomPopupMenu()
    {
        LayoutInflater layoutInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view=layoutInflater.inflate(R.layout.xxact_copy_popupmenu, null);
        
        PopupWindow popupWindow=new PopupWindow();
        popupWindow.setContentView(view);
        popupWindow.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
        popupWindow.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
        popupWindow.setFocusable(true);

        popupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, 0);             
    }
}

everything fine but when i click on the float button app stop and this error is shown on logcat :(

11-23 02:18:58.217: E/AndroidRuntime(3231): android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

but I have no activity?

I want to popup menu show after user click on float icon; but popup menu only can show text;

how can I show a popup menu with icons?

HamidTB
  • 1,381
  • 3
  • 11
  • 15

11 Answers11

255

If you're using getApplicationContext() as Context in Activity for the dialog like this

Dialog dialog = new Dialog(getApplicationContext());

then use YourActivityName.this

Dialog dialog = new Dialog(YourActivityName.this);
Kishan Solanki
  • 13,761
  • 4
  • 85
  • 82
  • 16
    The solution above is not relevant. We are looking for context when there is no activity. This solution requires an activity, which is definitely not what we are looking for. – Prakash Sep 12 '19 at 19:14
  • 5
    What if am using a Fragment – Flash Oct 15 '19 at 14:41
  • 2
    @Flash then you can use requireActivity() in Fragment – Kishan Solanki Jun 23 '20 at 10:09
  • I got this error when trying to build/show an AlertDialog, but I was passing in the appContext for my app/activity. Switching to passing in .this fixed the problem immediately. – alesplin Jan 14 '21 at 19:19
  • 2
    If you are wondering why `YourActivityName.this` works but `getApplicationContext()` does not, see this answer https://stackoverflow.com/a/22967165/5460959 – McFizz May 21 '21 at 19:57
  • 1
    This works for my case when I try to pop out an AlertDialog. I think this is a Android API internal issue, quite stupid bug right? – xuancong84 Jan 21 '22 at 07:38
30

This error happens when you are trying to show pop-up window too early, to fix it, give Id to the main layout as main_layout and use the below code:

Java:

 findViewById(R.id.main_layout).post(new Runnable() {
   public void run() {
       popupWindow.showAtLocation(findViewById(R.id.main_layout), Gravity.CENTER, 0, 0);
   }
});

Kotlin:

 main_layout.post {
      popupWindow?.showAtLocation(main_layout, Gravity.CENTER, 0, 0)
    }

Credit to @kordzik

Manohar
  • 22,116
  • 9
  • 108
  • 144
20

I had the same problem as you, it looks like you used the tutorial from http://www.piwai.info/chatheads-basics like I did. The problem is that you cannot reliably pass the current activity to the popup window, because you have no control over the current activity. It looks like there might be a unreliable way to get the current activity, but I don't recommend that.

The way I fixed it for my app was to not use the popup window, but instead make my own through the window manager.

private void showCustomPopupMenu()
{
    windowManager2 = (WindowManager)getSystemService(WINDOW_SERVICE);
    LayoutInflater layoutInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view=layoutInflater.inflate(R.layout.xxact_copy_popupmenu, null);
    params=new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.TYPE_PHONE,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT
    );

    params.gravity=Gravity.CENTER|Gravity.CENTER;
    params.x=0;
    params.y=0;
    windowManager2.addView(view, params);  
}

If you want this to look like a popup window, just add a transparent gray view as the background and add a onClickListener to it to remove the view from the windowManager object.

I know this isn't as convenient as a popup, but from my experience, it is the most reliable way.

and don't forget to add permission in your manifest file

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
skit456
  • 250
  • 1
  • 4
  • how to dismiss this windowmanager when user click outside this view? – nidhi May 07 '18 at 11:27
  • @nidhi use `windowManager2.removeViewImmediate(view);` but make your inflated view a global variable `private View view;` – Pierre Feb 18 '20 at 08:19
  • 3
    this error happens at `windowManager.addView(view, params)` as well - `Caused by android.view.WindowManager$BadTokenException Unable to add window -- token null is not valid; is your activity running?` – user924 May 19 '21 at 11:10
  • it works for Android 8+ but not on Android 6-7 – user924 Apr 30 '23 at 10:04
11

You need to pass your activity in the constructor

 PopupWindow popupWindow = new PopupWindow(YourActivity.this)
SacreDeveloper
  • 1,253
  • 1
  • 9
  • 16
10

If you use another view make sure to use view.getContext() instead of this or getApplicationContext()

Mohamed Ben Romdhane
  • 1,005
  • 3
  • 11
  • 22
4

In my case, I was inflating a PopupMenu at the very beginning of the activity i.e on onCreate()... I fixed it by putting it in a Handler

  new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                PopupMenu popuMenu=new PopupMenu(SplashScreen.this,binding.progressBar);
                popuMenu.inflate(R.menu.bottom_nav_menu);
                popuMenu.show();
            }
        },100);
AgentP
  • 6,261
  • 2
  • 31
  • 52
3
  • If you coding on Kotlin and using Viewbinding system.
  • Try so: binding.root.context.
  • It helped me to run AlertDialog.
Stanislav
  • 191
  • 1
  • 5
1

PopupWindow can only be attached to an Activity. In your case you are trying to add PopupWindow to service which is not right.

To solve this problem you can use a blank and transparent Activity. On click of floating icon, launch the Activity and on onCreate of Activity show the PopupWindow.

On dismiss of PopupWindow, you can finish the transparent Activity. Hope this helps you.

rafsanahmad007
  • 23,683
  • 6
  • 47
  • 62
KR_Android
  • 1,149
  • 9
  • 19
  • i want show popup menu after click on float icon; i can do this but popup menu only show text not icon; how i can make an custom popup menu with icon ? – HamidTB Nov 23 '14 at 11:07
1

I was getting this error while trying to show DatePicker from Fragment.

I changed

val datePickerDialog = DatePickerDialog(activity!!.applicationContext, ...)

to

val datePickerDialog = DatePickerDialog(requireContext(), ...)

and it worked just fine.

Ananth
  • 2,597
  • 1
  • 29
  • 39
0

You should not put the windowManager.addView in onCreate

Try to call the windowManager.addView after onWindowFocusChanged and the status of hasFoucus is true.

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    //code here
    //that you can add a flag that you can call windowManager.addView now.
}
adiga
  • 34,372
  • 9
  • 61
  • 83
Bruce
  • 1,688
  • 1
  • 12
  • 12
  • This solution almost worked for me, in the sense that it did not make crash the application, but the problem is that also when you dismiss the window the `onWindowFocusChanged` is called again thus showing the window repeatedly – Tiziano Mischi Aug 25 '20 at 16:34
0

In a case that use a dialog in a class might be happened, so in Kotlin like this:

 cContext = activity.applicationContext
  val dialog = Dialog(cContext)

doesn't work and change it to

 showErrorDialog(this) // a method in the activity
 cContext=context
 val dialog = Dialog(cContext)

use direct Context from the current activity , shortly

val dialog = Dialog(activity.applicationContext) 

change context to

val dialog = Dialog(this)
Mori
  • 2,653
  • 18
  • 24