Show dialog alert from a non-activity class in android - android

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);
}

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" />

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

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.

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();
}

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");

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 );
}
}
}

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.
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.
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 :)

Related

handleWindowVisibility: no activity for token android.os.BinderProxy in second run

I am making a simple app to download video from a website using volley.
So when i opened my app for first time everything was fine but when i opened app second time after closing app with back button , then i got a error or warning.
Now i can't use alertDialogs ( process dialogs are working fine) because of it ( app crashed if i did)
i am using singleton class AlertUser for AlertDialogs
public class AlertUser {
private static final AlertUser AlertUserInstance = new AlertUser();
private Context ActivityContext = null;
private AlertUser() { }
public static AlertUser getInstance() {
return AlertUserInstance;
}
public void init(Context ctx) {
if (ActivityContext == null)
ActivityContext = ctx;
}
public void alertUser(String msg) {
if (!((AppCompatActivity)ActivityContext).isFinishing()) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityContext);
alertDialogBuilder.setTitle(R.string.app_name);
alertDialogBuilder.setMessage(msg);
alertDialogBuilder.setPositiveButton("Got it!",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
}
}
Here is some code from MainActivity
public class MainActivity extends AppCompatActivity {
private RequestQueue queue;
private AlertUser alert = AlertUser.getInstance();
ProgressDialog progressDialog;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
Log.d("Main","onCreate");
alert.init(MainActivity.this);
queue = new Volley().newRequestQueue(MainActivity.this);
}
}
Edit : Now i am using System.exit(0) and now it's working in every run after being killed but i don't think its good solution and still i am unaware from exact problem.

Unable to dismiss dialog in runOnUiThread

I'm scanning QR code using Google's Vision. I got help from this link. I want to show AlertDialog after getting the value from QR code. If I directly show alertdialog inside receiveDetections() method I'm getting "Can't create looper" error. So I called the alertdialog inside runOnUiThread(). But now I'm unable to dismiss the dialog. Would like to know what's the reason for this.
#Override
public void receiveDetections(Detector.Detections<Barcode> detections){
final SparseArray<Barcode> barcodes = detections.getDetectedItems();
if (barcodes.size() != 0) {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
String val = barcodes.valueAt(0).displayValue;
showAlert(val);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void showAlert(String val){
try {
if (!val.equals("")) {
AlertDialog.Builder builder = new AlertDialog.Builder(ScannedBarcodeActivity.this);
builder.setTitle(emp.getName())
.setPositiveButton(newStatus, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
emp.setStatus(newStatus);
viewModel.updateEmployee(emp);
dialog.dismiss();
}
})
.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
}
}catch (Exception e){
e.printStackTrace();
}
}
Even though now the alertdialog is showing, when I click CANCEL button, the alert does not gets dismissed.
I think receiveDetections is being called more than once, which is resulting in multiple instances of AlertDialog. So when you press CANCEL button you might be cancelling only one of those multiple opened dialogs.
You can add logs to see how many times receiveDetections is being called, or just hit CANCEL button multiple times and all the previously opened alerts will be cancelled
*Possible Reason:
receiveDetections will be executed every-time your camera passes image to QRScanner,
and as your camera is continuously streaming images, QRScanner is calling receiveDetections again and again.
The reason why you alert dialog is not dismissing because you are new object of AlertDialog each time when receiveDetections called and in your case receiveDetections multiple time.
You have to create a Singleton class object:
public class singleTonDialogExample {
static TextToSpeech t1;
private static singleTonExample ourInstance = new singleTonDialogExample();
private Context appContext;
private ICallBack iCallBack;
public interface ICallBack{
void onYesPressed();
void onNoPressed();
}
private singleTonDialogExample() { }
public static Context get() {
return getInstance().getContext();
}
public static synchronized singleTonDialogExample getInstance() {
return ourInstance;
}
public void init(Context context) {
if (appContext = = null) {
this.appContext = context;
}
}
private Context getContext() {
return appContext;
}
public void setICallBack(ICallBack callBack){
this.iCallBack=callBack;
}
public void AlertDialog(final MainActivity mainActivity,String title,String message) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mainActivity);
alertDialogBuilder.setMessage(message);
alertDialogBuilder.setPositiveButton("yes",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
iCallBack.onYesPressed();
}
});
alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
iCallBack.onNoPressed();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
}
Create the Dialog in Activity like this:
singleTonDialogExample dialog;
dialog = singleTonExample.getInstance();
dialog.init(getApplicationContext());
dialog.setICallBack(this);
dialog.AlertDialog(MainActivity.this,"Title","This is message");
Also implement the ICallBack interface in your activity or fragment.

how to show alert dialog on top of any activity in an application android

I want to display an alert dialog. And this alert dialog is created in one activity. But Problem is i want to display this dialog on top of any activity in an application when i get some response from server
Yes i got the solution....
first i created a class for displaying alert dialog.
upon receiving a response from server calling a method to display alert dialog by passing application context
package io.omoto.omotokairaliapp.Utls;
import android.content.Context;
import android.view.WindowManager;
import com.gitonway.lee.niftymodaldialogeffects.lib.NiftyDialogBuilder;
import io.omoto.omotokairaliapp.Constants.Constants;
/**
* Created by ${venkie} on ${28/1/16}.
*/
public class DisplayRegisteredMessage {
Context context;
private NiftyDialogBuilder dialogBuilder;
public DisplayRegisteredMessage(Context context) {
this.context = context;
}
public void displayMessage() {
if (Constants.FLAG == 1) {
Constants.FLAG = 0;
dialogBuilder = NiftyDialogBuilder.getInstance(context);
dialogBuilder
.withTitle("Response is already registered")
.withMessage("For this Customer we have already taken response Sorry!!");
dialogBuilder.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialogBuilder.show();
} else {
}
}
}
The above code displays alert dialog
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
super.onSuccess(statusCode, headers, response);
Log.e("response page", response.toString());
try {
if (response.getString(Constants.STATUS).equalsIgnoreCase("SUCCESS"))
p7.deleterecord(p7b.getFlowid());
p7.deleteRows();
Constants.FLAG = 1;
DisplayRegisteredMessage displayRegisteredMessage = new DisplayRegisteredMessage(mContext);
displayRegisteredMessage.displayMessage();
} catch (JSONException e) {
e.printStackTrace();
}
Log.e("Page 6", p7b.getFlowid());
}
Create alert dialog in other class (not activity) as shown below code in static method & call this method using UDF.showAlertDialog(activity) where you want to show dialog.
public class UDF {
public static void showAlertDialog(
String warning,
DialogInterface.OnClickListener positiveClickListener,
DialogInterface.OnClickListener negativeClickListener,
Context context) {
AlertDialog.Builder alertdialog = new AlertDialog.Builder(context);
alertdialog.setMessage(warning);
alertdialog.setPositiveButton("Ok", positiveClickListener);
alertdialog.setNegativeButton("Cancel", negativeClickListener);
alertdialog.show();
}
}
Edit : set this
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
and add permission in menifest.xml
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
& pass getApplicationContext() while creating dialog instade of activity or context
Here is a workaround that worked for me:
Suppose you have 4 activities in total:
MainActivity
OtherActivity1
OtherActivity2
OtherActivity3
I had the code for the alert dialog in the MainActivity and I wanted the alert dialog to display in all activities. I did the following:
Make other activities extend the main activity.
public class OtherActivity1 extends MainActivity{
}
public class OtherActivity2 extends MainActivity{
}
public class OtherActivity3 extends MainActivity{
}
In your Main activity, save the context in a variable.
public class MainActivity extends AppCompatActivity{
public static Context contextMain;
#Override
protected void onCreate(Bundle savedInstanceState) {
contextMain = MainActivity.this;
}
}
And wherever you are trying to call your alert dialog in the MainActivity just pass contextMain as the context.
final AlertDialog.Builder dialog = new AlertDialog.Builder(contextMain)

Android testing that an alertDialog is shown in an activity

Hello and thank you for taking the time to read this question.
I am trying to write an instrumentation test for an activity. The scenario is the following:
If on create of the activity the GPS is not enabled, an alertDialog should be shown to the user to suggest turning on the sensor. The check is performed by an utility class that checks the connectivity and shows the alertDialog if necessary. I want to be able to test in my class if the dialog is shown to the user.
Now for some code:
The activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
Utils.checkGPSProvider(this);
}
The Utility class:
public final class Utils {
private Utils() {
}
private static void createAlertDialog(final Context context, final String message, final String intentAction) {
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
final Intent callSettingIntent = new Intent(intentAction);
alertDialogBuilder.setMessage(message).setPositiveButton(POSITIVE_BUTTON,
new DialogInterface.OnClickListener() {
#Override
public void onClick(final DialogInterface dialog, final int id) {
context.startActivity(callSettingIntent);
}
});
alertDialogBuilder.setNegativeButton(NEGATIVE_BUTTON, new DialogInterface.OnClickListener() {
#Override
public void onClick(final DialogInterface dialog, final int id) {
dialog.cancel();
}
});
final AlertDialog alert = alertDialogBuilder.create();
alert.show();
}
public static void checkGPSProvider(final Context context) {
String message;
message = "GPS message";
final LocationManager mlocManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (!mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
createAlertDialog(context, message, android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
}
}
}
The test class:
public class UtilsTest extends ActivityInstrumentationTestCase2<MyActivity> {
private MyActivity activity;
#Mock
LocationManager mlocManager;
public UtilsTest() {
super(MyActivity.class);
}
public UtilsTest(Class<MyActivity> activityClass) {
super(activityClass);
}
#Override
public void setUp() throws Exception {
super.setUp();
activity = getActivity();
MockitoAnnotations.initMocks(this);
}
public void testWhenGPSIsDisabled_ShouldShowAlertDialog() {
when(mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)).thenReturn(false);
if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Assert.fail("GPS should be disabled");
}
(insert code here that should test that the alertDialog is shown)
}
}
I know that the Dialog class has an isShown() method but I do not know how to get the dialog reference to test the isShown method.
If there is any other necessary information I will try to provide it to you.
Thank you.
You can return the reference of the AlertDialog from the method createAlertDialog
example:
private static AlertDialog createAlertDialog(final Context context, final String message, final String intentAction)
When you call this method you can then get the return reference value of the method same as your checkGPSProvider should also return AlertDialog.
sample:
public static AlertDialog checkGPSProvider(final Context context) {
String message;
message = "GPS message";
final LocationManager mlocManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (!mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
return createAlertDialog(context, message, android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
}
}
And in your oncreate method of the activity create a Field for AlertDialog and instantiate with the Utils.checkGPSProvider(this);
solution:
your_alert_dialog = Utils.checkGPSProvider(this);

Android: Trying to create a dialog within a AsyncTask<String object

I'm using a AsyncTask
I use parent to create the intent no errors.
The line to creat a dialog gives a
parent cannot be resolved to a ye.
new parent.AlertDialog.Builder(this)
The error I get is that parent does not exist, but I use parent in the same methed to call the intent
code block
private class SendTextOperation extends AsyncTask {
#Override
protected void onPreExecute() {
//Update UI here
}
#Override
protected String doInBackground(String... params) {
// Talk to server here to avoid Ui hanging
rt=TalkToServer("http://besttechsolutions.biz/projects/bookclub/login.php");
return(rt);
}
#Override
protected void onPostExecute(String result) {
if (rt.contains("ok"))
{
Intent i = new Intent(parent, cChat.class);
startActivity(i);
}
else
{
new parent.AlertDialog.Builder(this)
.setTitle("Game Over")
.setMessage("Your time is up, You saved "
+" Million more people!!")
.setNeutralButton("Try Again",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dlg, int i)
{
}} ).show();
}
}
}
For showing AlertDialog from non Activity you will need to pass Current Activity Context to non Activity class in your case to SendTextOperation class.
Create an Constructor for SendTextOperation as :
public class SendTextOperation extends AsyncTask<String,Void,String>{
Context context;
public SendTextOperation(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
//Update UI here
}
#Override
protected String doInBackground(String... params) {
// Talk to server here to avoid Ui hanging
rt=TalkToServer("http://besttechsolutions.biz/projects/bookclub/login.php");
return(rt);
}
#Override
protected void onPostExecute(String result) {
if (rt.contains("ok"))
{
Intent i = new Intent(context, cChat.class);
startActivity(i);
}
else
{
new context.AlertDialog.Builder(context)
.setTitle("Game Over")
.setMessage("Your time is up, You saved "
+" Million more people!!")
.setNeutralButton("Try Again",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dlg, int i)
{
}} ).show();
}
}
}
and start SendTextOperation AsyncTask as :
SendTextOperation sendtxtasyncTask = new SendTextOperation(CurrentActivity.this);
sendtxtasyncTask.execute("");
Lets say you have that class declared inside a class named MyActivity
Then use instead of this, MyActivity.this when creating the Dialog.
It looks like you should be calling it like this:
final AlertDialog.Builder builder = new AlertDialog.Builder(_context);
builder.setMessage(_context.getString(R.string.error) + ": " + _errorMessage)
.setTitle(_context.getString(R.string.loginError))
.setIcon(android.R.drawable.ic_dialog_alert)
.setCancelable(true)
.setPositiveButton(_context.getString(R.string.ok), null);
final AlertDialog alert = builder.create();
alert.show();
(My own sample code)
It looks like your error is trying to do parent.AlertDialog.Builder(this), where you need to use new AlertDialog.Builder(parent), if parent is your context.

Categories

Resources