Home » Android » Show dialog alert from a non-activity class in android

Show dialog alert from a non-activity class in android

Posted by: admin May 14, 2020 Leave a comment

Questions:

I want to show an Alert Dialog via AlertDialogManager class to a non-activity class DeviceAdminReceiverSample‘s method onDisabled, but whenever I call alertDialog via that method it generates error with following text

Error

06-12 12:01:19.923: E/AndroidRuntime(468): FATAL EXCEPTION: main
06-12 12:01:19.923: E/AndroidRuntime(468): java.lang.RuntimeException: Unable to start           
receiver com.android.remotewipedata.DeviceAdminReceiverSample:   
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not   
for an application

I know the issue is with context thing but I don’t know what to put there so that it work, I tried this, getApplicationContext() but all vain. My code for both classes is below

AlertDialogManager

public class AlertDialogManager {

public void showAlertDialog(Context context, String title, String message,
        Boolean status) {
    final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
    alertDialog.setTitle(title);
    alertDialog.setMessage(message);

    if (status != null)
        alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                alertDialog.dismiss();
            }
        });
    alertDialog.show();
}

}

DeviceAdminReceiverSample

public class DeviceAdminReceiverSample extends DeviceAdminReceiver {
static final String TAG = "DeviceAdminReceiver";
AlertDialogManager alert = new AlertDialogManager();

/** Called when this application is no longer the device administrator. */
@Override
public void onDisabled(Context context, Intent intent) {
    super.onDisabled(context, intent);
    Toast.makeText(context, R.string.device_admin_disabled,
            Toast.LENGTH_LONG).show();
    // intent.putExtra("dialogMessage", "Device admin has been disabled");
    // intent.setClass(context, DialogActivity.class);
    // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    // context.startActivity(intent);
    alert.showAlertDialog(context, "Alert",
            "Device admin has been disabled", true);
}
How to&Answers:

The problem is ‘You can show AlertDialogs from Activity only‘. This is not an issue of context.

Although this is not a good idea to show dialog from receiver (better is to use Notification), But if you want to do so you can create an Activity as dialog and show

Answer:

Just add this before your alertDialog.show();

alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

or try following if above didn’t work:

alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL); 

and use this permission:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

Answer:

If you always want to get the current activity from anywhere in the app you can register an ActivityLifecycleCallback on your Application instance.

Here’s an untested implementation that might get you closer.

public class TestApp extends Application {

    private WeakReference<Activity> mActivity = null;

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                mActivity = new WeakReference<Activity>(activity);
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
                mActivity.clear();
            }

            /** Unused implementation **/
            @Override
            public void onActivityStarted(Activity activity) {}

            @Override
            public void onActivityResumed(Activity activity) {}
            @Override
            public void onActivityPaused(Activity activity) {}

            @Override
            public void onActivityStopped(Activity activity) {}

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
        });
    }

    public Activity getCurrentActivity() {
        return mActivity.get();
    }

}

Then to use this throughout your app you would do some call like this …

Activity activity = ((TestApp)getApplicationContext()).getCurrentActivity(); 

The advantages are you can always keep track of your current activity, however its a little too overkill for just handling Dialogs from within the Activity.

Answer:

call this method in activity class

public static void showAlert(Activity activity, String message) {

        TextView title = new TextView(activity);
        title.setText("Title");
        title.setPadding(10, 10, 10, 10);
        title.setGravity(Gravity.CENTER);
        title.setTextColor(Color.WHITE);
        title.setTextSize(20);

        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        // builder.setTitle("Title");
        builder.setCustomTitle(title);
        // builder.setIcon(R.drawable.alert_36);

        builder.setMessage(message);

        builder.setCancelable(false);
        builder.setNegativeButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();

            }

        });

        AlertDialog alert = builder.create();
        alert.show();
    }

Answer:

As AJAY suggested, the best way is to work with the ‘Activity’ in parameter instead of using the ‘context’.

In your personal class, just ask for the activity in its constructor as a mandatory parameter => public void constructorOfTheClass(Activity activity){…}.

When you call the constructor in your Activity, just indicate this parameter and you’ll be able to work with it inside the class directly.

Then you can use this ‘activity’ information in your AlertDialog method within your class as SUNIL noticed to be prompted correctly in the desired Activity.

Hope it helps… and be sure it will work ! ;o)

Answer:

Here’s what I made and use:

myDialog.java:

import android.app.Activity;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class myDialog {
    private Activity mActivity;

    myDialog(Activity a) {
        this.mActivity = a;
    }

    @SuppressWarnings("InflateParams")
    public void build(String title, String msg) {
        LayoutInflater inflater = LayoutInflater.from(mActivity);
        View subView = inflater.inflate(R.layout.dialog_box_text, null);
        final TextView message = subView.findViewById(R.id.message);
        message.setText(msg);
        AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
        builder.setTitle(title);
        builder.setView(subView);
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        AlertDialog alert = builder.create();
        alert.show();
    }
}

dialog_box_text.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="1"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="  "
        android:maxLines="1"
        android:textColor="@color/colorBlack" />
</LinearLayout>

Example code:

public class MainActivity extends AppCompatActivity {
    private myDialog md;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        md = new myDialog(this);

...

        md.build("Title", "Message");

Answer:

Here’s a quick method of properly performing this task that has done the job for me. Basically, what you would do is just create a new thread.

  1. Declare a public and static variable with a type that matches the original activity class.

    public static Activity1 activity;

Activity1 is the class that the variable resides in.


  1. Upon calling the method onCreate();, set the variable to be equal to the context of the activity, otherwise known as this.

Example:

@Override 
    protected void onCreate( Bundle savedInstanceState ) {
    super.onCreate( savedInstanceState );
    activity = this;
}

3. Since we now have the context of the activity, we can use it to create a function with an alert dialog by using the runOnUiThread(); method inside of the function that will call the alert dialog. We would use a new Runnable() for the runnable action required for runOnUiThread();, and to have the alert dialog actually open, we would override the run function of a runnable item and place the code for the alert dialog in there.

Example function:

public static void exampleDialog(){
Activity1.activity.runOnUiThread(new Runnable){
@Override
    public void run(){
    //alert dialog code goes here.  For the context, use the activity variable from Activity1.
        }
    }
}

Hope this helps 🙂

Answer:

You can define a public Context var in the MainActivity with initial value (this); As show here:

public class MainActivity< alertdail > extends AppCompatActivity {

    ////////////////////////////////////////////////////////////
    //Public var refers to Main Activity:
    Context mainActivity = this;
    ////////////////////////////////////////////////////////////

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate ( savedInstanceState );
        setContentView ( R.layout.activity_main );
        AlertDialogManager alert  =new AlertDialogManager ();
alert.showAlertDialog ( this,"Title","Message",true );


     }


    public class AlertDialogManager {

        public void showAlertDialog(Context context, String title, String message,
                                    Boolean status) {
            final AlertDialog alertDialog = new AlertDialog.Builder ( mainActivity ).create ( );
            alertDialog.setTitle ( title );
            alertDialog.setMessage ( message );

            if (status != null)
                alertDialog.setButton ( "OK", new DialogInterface.OnClickListener ( ) {
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialog.dismiss ( );
                    }
                } );
            alertDialog.show ( );
        }

        public void showAlertDialog(Context c) {
        }
    }


    public class DeviceAdminReceiverSample extends DeviceAdminReceiver {
        static final String TAG = "DeviceAdminReceiver";
        AlertDialogManager alert = new AlertDialogManager ( );

        /**
         * Called when this application is no longer the device administrator.
         */
        @Override
        public void onDisabled(Context context, Intent intent) {
            super.onDisabled ( context, intent );
            Toast.makeText ( context, R.string.device_admin_disabled,
                    Toast.LENGTH_LONG ).show ( );
            // intent.putExtra("dialogMessage", "Device admin has been disabled");
            // intent.setClass(context, DialogActivity.class);
            // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // context.startActivity(intent);
            alert.showAlertDialog ( context, "Alert",
                    "Device admin has been disabled", true );
        }
    }
}