How to show an AlertDialog from any Activity in my application.

Hello Friends,

I hope my previous posts might have helped you.This time I want to do experiment with Service,AlertDialog and Notifications and BroadcastReciever.
As you all know “A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application.”

To know more about service you can see Service.

And Broadcast receivers: A broadcast receiver is a component that responds to system-wide broadcast announcements.

And for notifying user for anything there are Toast,Status Bar Notification and Dialogs.Like you have some process is running in background and you want to notify user about its completion so you can use one of these.

    * A Toast Notification, for brief messages that come from the background.
    * A Dialog Notification, for Activity-related notifications.
    * A Status Bar Notification, for persistent reminders that come from the background and request the user’s response.

You can learn more from here about Notification from here.

Now what is today’s experiment is to use all these together in an one more innovative way.This came to my mind when I was facing a problem during one of my project.

In my project I was using a Service and in that service I was checking messages coming from a server.What I wanted is whenever a message comes I should check it and if it is worth of then notify the user.And for project it was mandatory for me that a user must see the message.So in this case Toast notification was not proper way because Toast notification pops up for some time only and disappears so there are chances my user miss the message (and that I don’t want).

So for this I used Dialog (or specifically AlertDialog).By using AlertDialog you can force user to see its message and also there you can add buttons.A very good example that nobody want in there app is ForceClose.

But there is still a problem with AlertDialog.Dialogs are specific to Activities so if you have used Dialog for one activity and your user is on another activity,So again user can miss your message.

So for solution of these there is a third kind of notifications ie called “Status Bar Notification”.

A status bar notification adds an icon to the system’s status bar (with an optional ticker-text message) and an expanded message in the “Notifications” window.
By expanding it user can see the message and also you can set Intent.
When the user selects the expanded message, Android fires an Intent that is defined by the notification (usually to launch an Activity).

You can also configure the notification to alert the user with a sound, a vibration, and flashing lights on the device.
This is a good way of notifying user when you are using Service.

After all this I thought I have found solutions for my problem and definitely I had.But then from where it is “innovative”, it is a usual way of using it.

So I thoght how can I make it innovative and then I tried to solve the problem with Dialogs.

“Dialogs are specific to Activities so if you have used Dialog for one activity and your user is on another activity then user can miss your message.”

Then I decided that I will show the AlertDialog along with message on every activity in my application and if my application is minimized and another application is runninng in foreground then I will show Status Bar Notification.

For this I thought I will show dialog from my Service itself but “You cannot display a dialog from a Service or BroadcastReceiver”.

Now I had to do something else.So lets try it..

First of all I created a Service which does my main task to get message from server.But in this example I am not interacting with server instead that I am using an counter and incrementing it.on incrementing counter I am checking its value in service(in background) and whenever it meets my condition I notify user with a message.

TestService.java

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.widget.Toast;

public class TestService extends Service
{
    final static String TAG = “TestService”;
    private final Handler handler = new Handler();
    public static final String BROADCAST_ACTION = “com.ab1209.broadcast.testservice”;
    public static int COUNTER = 0;
    Intent intent;
    Ringtone ringtone;

    @Override
    public IBinder onBind(Intent arg0)
    {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate()
    {
        // TODO Auto-generated method stub
        super.onCreate();
//        alertSound();
        intent = new Intent(BROADCAST_ACTION);
    }

    @Override
    public void onStart(Intent intent, int startId)
    {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);
        Toast.makeText(getApplicationContext(), “Serivce Started”, Toast.LENGTH_SHORT).show();
        
        handler.removeCallbacks(sendAlertRunnable);
        handler.postDelayed(sendAlertRunnable, 1000);
    }

    private Runnable sendAlertRunnable = new Runnable()
    {
        @Override
        public void run()
        {
            // TODO Auto-generated method stub
            new TraceTask().execute();
            handler.postDelayed(this, 1000);
        }
    };

    public void onDestroy()
    {
        Toast.makeText(getApplicationContext(), “Serivce Stopped”, Toast.LENGTH_SHORT).show();
        handler.removeCallbacks(sendAlertRunnable);
        super.onDestroy();
    };

    private class TraceTask extends AsyncTask<String, String, String>
    {
        @Override
        protected void onPreExecute()
        {
            // TODO Auto-generated method stub
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String… params)
        {
            // TODO Auto-generated method stub
            SystemClock.sleep(1000);
            COUNTER++;
            return null;
        }

        @Override
        protected void onPostExecute(String result)
        {
            // TODO Auto-generated method stub
            super.onPostExecute(result);

            if (COUNTER % 5 == 0)
                sendAlert();
            if (COUNTER > 50)
            {
                stopSelf();
                sendAlert();
            }
        }
    }

    void sendAlert()
    {
        if (MainActivity.STATE == MainActivity.RUNNING)
        {
            String message = “Message from Broadcast ” + COUNTER;
            if (COUNTER > 50)
                message = “Service Stopped”;

            intent.putExtra(“MESSAGE”, message);
//            ringtone.play();
            
            sendBroadcast(intent);
        } else if (MainActivity.STATE == MainActivity.PAUSED)
        {
            showNotification();
        }
    }

    void showNotification()
    {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        Notification notification = new Notification(R.drawable.ic_launcher, “TestService Notification”, 1000);

        Context context = getApplicationContext();
        Intent intent = new Intent(this, Activity2.class);

        String message = “Message from Notification ” + COUNTER;
        intent.putExtra(“MESSAGE”, message);
        if (COUNTER > 50)
            message = “Service Stopped”;

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        notification.setLatestEventInfo(context, “Test Service”, message, pendingIntent);
        notification.flags = Notification.FLAG_AUTO_CANCEL;
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        notification.defaults |= Notification.DEFAULT_SOUND;
        
        notificationManager.notify(R.drawable.ic_launcher, notification);
    }
    
    void alertSound()
    {
        Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        ringtone = RingtoneManager.getRingtone(getApplicationContext(), notification);
    }

}

For incrementing and checking counter value I am using AsyncTask and its doInBackground() method (Where I interct with server).
Method sendAlert() is for notifying user.The interesting thing I have done here is if my Activity is paused (ie in background) then I will show a Status Bar Notification and if it is on foreground so I will show a AlertDialog.

For this I have used three static variables STATE,PAUSED and RUNNING.So whenver my Activity is paused I set STATE = PAUSED and if on foreground I set STATE = RUNNING.
By checking STATE value I decide when to show AlertDialog or Status Bar Notification.

for showing AlertDialog I have used Broadcasting intent using

public static final String BROADCAST_ACTION = “com.ab1209.broadcast.testservice”;
Intent intent = new Intent(BROADCAST_ACTION);
 
After completion of one AsyncTask I am starting it again by
private Runnable sendAlertRunnable = new Runnable()
    {
        @Override
        public void run()
        {
            // TODO Auto-generated method stub
            new TraceTask().execute();
            handler.postDelayed(this, 1000);
        }
    };

One more thing if you want to notify user with sound and vibration so in Status Bar Notification you can do it easily using

notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.defaults |= Notification.DEFAULT_SOUND;

but adding sound for AlertDialog you can try this

void alertSound()
    {
        Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        ringtone = RingtoneManager.getRingtone(getApplicationContext(), notification);
    }

and use
ringtone.play();
and then send message using
sendBroadcast(intent);

On testing on emulator you may get an NullPointerException on ringtone.play(); so first you will have to set an ringtone to you emulator also.
for this you can check http://yenliangl.blogspot.in/2009/12/no-ringtones-in-android-emulator.html.

You must add Service in your AndoroidManifest.xml and also VIBRATE permission if you want to alert with vibration also.

Now its time for my Activity from where I will start Service, show AlertDialog when recieving broadcasts.

MainActivity.java

package com.test.dialog;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity
{
    Intent intentService;
    Button btn;

    public final static int RUNNING = 1209;
    public final static int PAUSED = 9021;
    public static int STATE = RUNNING;

    AlertDialog alertDialog;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Toast.makeText(getApplicationContext(), “onCreate”, Toast.LENGTH_SHORT).show();
        initParameters();
        getNotificationIntent();
    }

    void getNotificationIntent()
    {
        String message = getIntent().getStringExtra(“MESSAGE”);
        if(message!=null)
        showAlertDialog(message);
    }
    void initParameters()
    {
        prepareAlertDialog();
        intentService = new Intent(this, TestService.class);
        registerReceiver(broadcastReceiverTestService, new IntentFilter(TestService.BROADCAST_ACTION));
    }

    private BroadcastReceiver broadcastReceiverTestService = new BroadcastReceiver()
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            String message = intent.getStringExtra(“MESSAGE”);
            showAlertDialog(message);
        }
    };

    void prepareAlertDialog()
    {
        alertDialog = new AlertDialog.Builder(MainActivity.this).create();
        alertDialog.setButton(“OK”, new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
            }
        });
    }
    
    void showAlertDialog(String message)
    {
        alertDialog.setMessage(message);
        alertDialog.show();
    }

    @Override
    protected void onPause()
    {
        // TODO Auto-generated method stub
        super.onPause();
        STATE = PAUSED;
    }

    @Override
    protected void onResume()
    {
        // TODO Auto-generated method stub
        super.onResume();
        STATE = RUNNING;
    }

}

In MainActivity I have used three static variables STATE,PAUSED and RUNNING and in Service I check this variable and decide how to notify user (by AlertDialog or Status Bar Notification).
I am changing variable STATE value in onPause() and onResume() methods.

@Override
    protected void onPause()
    {
        // TODO Auto-generated method stub
        super.onPause();
        STATE = PAUSED;
    }

    @Override
    protected void onResume()
    {
        // TODO Auto-generated method stub
        super.onResume();
        STATE = RUNNING;
    }

A my AlertDialog is only related to MainActivity only so if I will switch to other Activity then I want be able to see AlertDialog(Althogh I will be able to see Status Bar Notification).But as “innovative” way I have to show AlertDialog at every Activity of my app and that will not happen in this case.

For implementing this what I have done is
First thing I haven’t use setContentView() ie there is no View set to this MainActivity and second I have created two more activites (you can create as many as you want) Activity1 and Activity2.
These two activity Activity1 and Activity2 extends my MainActivity and by extending this they have got all the properties of it and of course with their own.So now both activities can start and stop Service from MainActivity and show AlertDialog.

Here are my two sub activities
 
Activity1.java

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;

public class Activity1 extends MainActivity implements OnClickListener
{
    Button btn;
    Button btnStartService;
    Button btnStopService;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1);
        initViews();
    }

    void initViews()
    {
        btnStartService = (Button) findViewById(R.id.button_start_service);
        btnStartService.setOnClickListener(this);

        btnStopService = (Button) findViewById(R.id.button_stop_service);
        btnStopService.setVisibility(LinearLayout.GONE);
        btnStopService.setOnClickListener(this);

        btn = (Button) findViewById(R.id.button_act1);
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v)
    {
        // TODO Auto-generated method stub

        switch (v.getId())
        {
        case R.id.button_act1:
            Intent intent = new Intent(this, Activity2.class);
            startActivity(intent);
            break;

        case R.id.button_start_service:
            startService(intentService);

            btnStopService.setVisibility(LinearLayout.VISIBLE);
            btnStartService.setVisibility(LinearLayout.GONE);
            break;
        case R.id.button_stop_service:
            stopService(intentService);

            btnStartService.setVisibility(LinearLayout.VISIBLE);
            btnStopService.setVisibility(LinearLayout.GONE);
            break;
        }

    }
}

Layout for Activity1 is activity1.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    android:orientation=”vertical” >

    <Button
        android:id=”@+id/button_start_service”
        android:layout_width=”fill_parent”
        android:layout_height=”wrap_content”
        android:text=”Start Service” />

    <Button
        android:id=”@+id/button_stop_service”
        android:layout_width=”fill_parent”
        android:layout_height=”wrap_content”
        android:text=”Stop Service” />

    <Button
        android:id=”@+id/button_act1″
        android:layout_width=”fill_parent”
        android:layout_height=”wrap_content”
        android:text=”To Activity 2″ />

    <TextView
        android:layout_width=”fill_parent”
        android:layout_height=”fill_parent”
        android:gravity=”center”
        android:text=”ACTIVITY 1″
        android:textColor=”#FFF”
        android:textSize=”20dip”
        android:textStyle=”bold” />

</LinearLayout>

and Activity2.java

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Activity2 extends MainActivity implements OnClickListener
{
    Button btn;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity2);
        btn = (Button) findViewById(R.id.button_act2);
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v)
    {
        // TODO Auto-generated method stub
        Intent intent = new Intent(this, Activity1.class);
        startActivity(intent);
    }
}

Layout for Activity1 is activity2.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    android:orientation=”vertical” >

    <Button
        android:id=”@+id/button_act2″
        android:layout_width=”fill_parent”
        android:layout_height=”wrap_content”
        android:text=”To Activity 1″ />

    <TextView
        android:layout_width=”fill_parent”
        android:layout_height=”fill_parent”
        android:gravity=”center”
        android:text=”ACTIVITY 2″
        android:textColor=”#FFF”
        android:textSize=”20dip”
        android:textStyle=”bold” />

</LinearLayout>
 

My first activity is Activity1 and I can start and stop Service from here and also can switch from other activity Activity2.So if you will switch to any activity you will see an message through same AlertDialog and if your application is in background you will recieve Status Bar Notification.

And this is how I solved my problem in innovative way.Hope you will try and let me know about your views about it.

For getting basic idea of how to use Service and BroadcastReceiver together you can check here.

So that’s all for today from my side.Soon I will be back with something more interesting thing.

Thanks

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s