1

I'm using Firebase to send messages to my Android app. After this messages has been received (which works) - I want to open an AlertDialog.

From what I understood so far, receiving the message happens in a worker thread, so I need to hook into the main thread again. I build Handler with a Runnable for this. How can I retrieve my MainActivity context inside the runnable? I looked up solutions like that Context inside a Runnable

But the MainActivity is not the outer class when Firebase sends the messages. Here is my setup

MainActivity

package com.example.xhallix.passamessage;


import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.example.xhallix.passamessage.notifications.FireBaseMessagingServiceManager;
import com.example.xhallix.passamessage.notifications.MyApplication;
import com.example.xhallix.passamessage.notifications.NotificationManager;

public class MainActivity extends AppCompatActivity {

    private static final String LOG_TAG = "CustomLog";

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

    }
}

FireBaseMessagingServiceManager

package com.example.xhallix.passamessage.notifications;

import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.util.Log;


import com.example.xhallix.passamessage.MainActivity;
import com.example.xhallix.passamessage.R;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

import android.os.Handler;

public class FireBaseMessagingServiceManager extends FirebaseMessagingService {

    private static final String LOG_TAG = "CustomLog";

    private Context context;

    public FireBaseMessagingServiceManager(){
        retrieveCurrentToken();
        // this is called when firebase is sending data
    }

    public FireBaseMessagingServiceManager(Context context){
        this.context = context; // this was just a test - this is not called when firebase sends the message again , so this.context will be null in onMessageReceive
    }


    /**
     * Get the Token of GoogleFirebase for that device
     */
    private void retrieveCurrentToken() {
        FirebaseInstanceId.getInstance().getInstanceId()
                .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
                    @Override
                    public void onComplete(@NonNull Task<InstanceIdResult> task) {
                        if (!task.isSuccessful()) {
                            Log.w(LOG_TAG, "getInstanceId failed", task.getException());
                            return;
                        }

                        // Get new Instance ID token
                        String token = task.getResult().getToken();

                        Log.d(LOG_TAG, token);
                    }
                });
    }


    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.d(LOG_TAG, remoteMessage.getFrom());
        Log.d(LOG_TAG,"Notification Message Body: " + remoteMessage.getNotification().getBody());
        createAlert();
    }


    @Override
    public void onNewToken(String token) {
        Log.d(LOG_TAG, "Refreshed token: " + token);
    }


    protected void createAlert() {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(**???**); // HOW TO RETRIEvE THE CONTEXT FROM MainActivity
                builder.setMessage(R.string.alert_dialog_msg);
                builder.setTitle(R.string.alert_dialog_title);
                builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Log.d(LOG_TAG, "Accepted Dialog");
                    }
                });

                builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Log.d(LOG_TAG, "NOT Accepted Dialog");
                    }
                });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });
    }
}
xhallix
  • 2,919
  • 5
  • 37
  • 55
  • 1
    Well, a `Service` is a `Context`, but you can't really show a `Dialog` from a `Service` without some hacky fiddling. An alternative would be to start an `Activity` that uses a `Dialog` theme, but, in either case, suddenly popping something to the foreground isn't very user-friendly, especially if they're not even in your app. Have you considered showing a `Notification` instead? – Mike M. Jul 22 '18 at 06:42
  • @MikeM. yes I'm considering it right now because as you set, it seems very hacky. I'm pretty new to android so I was not sure if that is really tricky or if I'm just doing a lot of things wrong here. User friendly is not an issue here, it is just a prototype:) – xhallix Jul 22 '18 at 06:45
  • Yeah, if this is just for testing/prototyping, I'd say use a `Notification`. It'll be much easier and straightforward to get that going, rather than try to implement one of the `Dialog` hacks. If you do really want a windowed UI, I suppose the `Dialog`-themed `Activity` isn't too involved, either (maybe even a little simpler, depending). It'd just be a separate `Activity` class, its layout, a `Theme.Dialog` in the manifest, and a `startActivity()` call. Whichever would be easier for ya. – Mike M. Jul 22 '18 at 06:51

1 Answers1

1

How can I retrieve my MainActivity context inside the runnable?

You cannot get the MainActivity context because it has no relation to the service you're running it.

If you really really want to show the dialog directly in response to the push notification, you would explicitly launch a dialog themed Activity. Something like:

protected void createAlert() {
    startActivity(new Intent(this, DialogThemedActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
dominicoder
  • 9,338
  • 1
  • 26
  • 32
  • This is more like an alerting. If we receive a message from push then something happens. So I want the most disturbing thing to be displayed. From what I see, notifications are far away from disturbing, what would you suggest? – xhallix Jul 22 '18 at 07:07
  • Can you elaborate on your use case? Deliberately disturbing the user with a popup dialog regardless of what they are doing in the moment seems extremely aggressive and not something the average app should be doing. A phone call or alarm, which is as "disturbing" as you can get, use notifications with the "urgent" importance: https://developer.android.com/guide/topics/ui/notifiers/notifications#importance. I'd hope that will work for you as well. – dominicoder Jul 22 '18 at 07:18
  • For the use case : Its some inner company app, which should alert if some system is going down – xhallix Jul 22 '18 at 07:20