Get the FULL version

Android: Creating a two color LED notification

Android: Creating a two color LED notification thumbnail

Another programming tutorial, this time, showing how to make the built-in notification LED on a Android device continuously alternate between two colors. That said, by the time this article is being written, it’s recommended to try this code on a real Android device that has a notification LED instead of running the application on the emulator. Also, the Activity featured below has been created to work on devices with Android 2.0 or later. All code featured in this article is available for download at the end of the post.

To continuously change the colors of the LED, it’s necessary to create and initialize a Notification object that changes the LED colors and post this notification using a handle to the system’s notification service (using a instance of the NotificationManager class). The notification is then canceled, its LED color is changed and the notification is posted again and the process is repeated over and over making the colors swap back and forth. Since this code is going to run continuously, it’s better to place it inside an AsyncTask. Then, all pending notifications must be cancelled and the AsyncTask background code execution must be stopped if the user presses the back button. Here’s the code:

package fortyonepost.com.twocolorledblinker;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;

public class TwoColorLEDblinkerActivity extends Activity
{
	//An object that acts as a handle to the system notification service
	private NotificationManager notificationManager;
	//The object responsible for sending a notification
	private Notification notification;
	//Sets whether the LED should blink indeterminately or at fixed rate
	private boolean indeterminate = true;
	//The time (in milliseconds) that each color remains active
	private int msInterval = 850;
	//The number of times that colors are swapped
	private int transitions = 4;

	//User interface elements
	private Button startBT;
	private Button stopBT;
	private CheckBox indeterminateCB;

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

		//Get a handle to the system's notification service
		notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

		//Create a new notification
		notification = new Notification();
		//The notification should turn on the device's notification LED
		notification.flags = Notification.FLAG_SHOW_LIGHTS;

		//Initialize the user interface buttons and the check box
		startBT = (Button) findViewById(R.id.startBT);
		stopBT = (Button) findViewById(R.id.stopBT);
		indeterminateCB = (CheckBox) findViewById(R.id.inteterminateCB);

		//Set what happens when the start button is pressed
		startBT.setOnClickListener(new OnClickListener()
		{

			@Override
			public void onClick(View v)
			{
				//Instantiate a TwoColorBlink AsynkTask object and call the execute() method
				new TwoColorBlink().execute();		

				//LED is blinking, disable the 'Start' button
				startBT.setEnabled(false);
				//Enable 'Stop' button
				stopBT.setEnabled(true);
				//Disable the 'Indeterminate' check box
				indeterminateCB.setEnabled(false);
			}
		});

		//Set what happens when the stop button is pressed
		stopBT.setOnClickListener(new OnClickListener()
		{

			@Override
			public void onClick(View v)
			{
				//Set the indeterminate variable to false.
				indeterminate = false;
				//Cancel the notification
				notificationManager.cancel(0);

				//LED isn't blinking, enable start button
				startBT.setEnabled(true);
				//Disable 'Stop' button
				stopBT.setEnabled(false);
				//Disable the 'Indeterminate' check box
				indeterminateCB.setEnabled(true);
			}
		});
	}

	@Override
	protected void onPause()
	{
		//Set the indeterminate variable to false.
		indeterminate = false;
		//Cancel the notification
		notificationManager.cancel(0);
		super.onPause();
	}

	private class TwoColorBlink extends AsyncTask<Void, Void, Void>
	{
		//Initialize an integer (that will act as a counter) to zero
		private int counter = 0;

		@Override
		protected void onPreExecute()
		{
			//Set 'indeterminate' boolean according to the check box
			if(indeterminateCB.isChecked())
			{
				indeterminate = true;
			}
			else
			{
				indeterminate = false;
			}
		}

		@Override
		protected Void doInBackground(Void... arg0)
		{
			try
			{
				// Get the current background thread's token
				synchronized (this)
				{
					//Set the initial LED color to red
					notification.ledARGB = 0xFFFF0000;

					//Check if the indeterminate boolean is true
					if (TwoColorLEDblinkerActivity.this.indeterminate)
					{
						while(indeterminate)
						{
							//Post the notification
							notificationManager.notify(0, notification);
							//Wait the number of milliseconds defined by 'msInterval'
							this.wait(msInterval);
							//Cancel the notification
							notificationManager.cancel(0);
							//Add one to the counter while obtaining the remaining part of its division by 2 and checking if it's equal to zero
							if (counter++ % 2 == 0)
							{
								//Change color to green
								notification.ledARGB = 0xFF00FF00;
							}
							else
							{
								//Change color to red
								notification.ledARGB = 0xFFFF0000;
							}
						}

					}
					else //Notification LED should blink a predefined number of times
					{
						//While the counter is smaller or equal to the number of transitions
						while (counter <= transitions)
						{
							//Post the notification
							notificationManager.notify(0, notification);
							//Wait the number of milliseconds defined by 'msInterval'
							this.wait(msInterval);
							//Cancel the notification
							notificationManager.cancel(0);

							if (counter % 2 == 0)
							{
								// Change color to green
								notification.ledARGB = 0xFF00FF00;
							}
							else
							{
								// Change color to red
								notification.ledARGB = 0xFFFF0000;
							}

							//Add one to the counter
							counter++;
						}
					}
				}
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result)
		{
			//Cancel the notification
			notificationManager.cancel(0);
			//Reset the counter to zero
			counter = 0;
			//Enable the 'Start' button and the 'Indeterminate' check box...
			startBT.setEnabled(true);
			indeterminateCB.setEnabled(true);
			//... and disable the 'Stop' button.
			stopBT.setEnabled(false);
		}

	}
}

The first couple of member variables being declared at the above Activity are a NotificationManager object and a Notification object. The latter is the notification itself, the one that will actually turn on the LED at the desired color. The former, as previously stated, is a handle to the system’s notification service (lines 16 and 18). Then, there’s the indeterminate boolean, that flags if the LED should change colors indefinitely or if it should swap colors a predefined number of times (line 20).

The amount of time each color should be displayed and the number of times that the colors should change are defined by the msInterval and transitions variables, declared and initialized at lines 22 and 24. The last three variables being declared are just three View elements that are there to allow the user some control over the application by adding a pair of buttons to start or stop the two color blinking notifications and a check box to set if the blinking should change colors indefinitely (lines 27 through 29).

Finally, inside the onCreate() method where the NotificationManager object is initialized by obtaining a handle to the system’s notification service (line 39). The Notification object is also initialized and configured to use only the device’s LED (lines 42 and 44).

Also, all three View elements are being inflated from the main.xml file (lines 47 through 49). The last two blocks of code inside the onCreate() method define what should these buttons do when they are pressed (lines 53 through 90).

The stopBT button just cancels the notification, sets the indeterminate boolean to false and enables the start button and the indeterminate’ check box. In other words: it cancels any pending notifications making the LED stop change colors (if it’s already doing so) and sets the user interface elements.

The startBT button does almost the opposite: it disables the user interface elements and initializes and calls the execute() method of the TwoColorBlink asynchronous task, that’s later defined in the code (line 60).

This inner class is a child of AsyncTask and is responsible for making the LED blink in two different colors using a background thread, releasing the UI thread from a continuous code execution, avoiding a ‘Application not Responding‘ error. This child class has only a single member: the counter integer. As the name suggests, it’s a variable that gets incremented and it’s value is later read to make the LED change between two colors (line 106).

The first method being overridden in this class is the onPreExecute(). As the name suggests, this method runs before the background thread code execution is started. There, a if statement tests whether the check box is marked and updates the value of the indeterminate boolean accordingly (lines 110 through 121).

The doInBackground() method is where the code that needs to be executed on a background thread is placed. In this case, the code that makes the LED switch between two different colors. It works by first setting the initial color of the LED, which is done at line 132. The color is a integer composed of four hexadecimal pairs in the ARGB format. The first two values correspond to the alpha channel, the other three value pairs are, respectively, the red, green and blue color channels. That said, the 0xFFFF0000 value is: 255 (FF) alpha, 255 (FF) red, 0 (00) green and 0 (00) blue.

After defining the initial color, the if statement checks the value of the indeterminate variable. If it’s true, a while loop condition is set with that variable, meaning that it will run indeterminately until indeterminate is changed to false (line 137). Inside this loop, the notification is posted by calling the notify() method from the notificationManager (line 140). It takes two arguments: the notification ID and a Notification object. These parameters are filled with 0 (zero) for the ID and the object notification for the Notification.

To make the LED temporarily light up in a certain color, the background thread is set to wait the amount of milliseconds defined by the msInterval variable (ine 142). Since the color of the LED can’t be changed after the notification has been posted, the notification must be canceled (line 144), the LED color is changed to different one, and the notification is posted again using the NotificationManager.

To achieve this alternate color change, the thread execution resumes after the specified amount of time, the counter variable is incremented, and the rest of its division by two is compared to zero. Case this computed value is zero, the LED color changes to green, if it isn’t the color changes to red again (lines 146 through 155). The code executes over and over again, posting the notification, cancelling it after a certain amount of time swapping the colors and posting it again, effectively making the LED alternate between two colors.

If the indeterminate variable is false, basically the same code is executed, except that the while checks whether the counter is smaller or equal to the value of the transitions variable. This makes the code change the LED color the exact number of times defined by the transitions variable. For example, in the above code, the LED color will change four times after it’s set to the initial color (lines 159 through 184).

Finally, the code on the onPostExecute() method runs after the background thread execution and it resets the View elements, cancels the notification (if it hasn’t been already cancelled) and makes counter equal to zero.

That’s it for the TwoColorBlink inner class. Now back to the Activity, the onPause() has to be overridden, so that any pending notifications and the indeterminate boolean can be set to false, if the user quits the application.

That’s it! Here’s a video of the application in action:

Downloads

4 Comments to “Android: Creating a two color LED notification”

  1. You don’t need to call notificationManager.cancel(0) in every iteration in the loop, notify will do the job of changing the led color just fine.
    Call cancel on post execute (which you do)

    Besides that, replace the counter with a boolean value in the case of intermediate, as the counter might over lap, which will cause the crash of your application:

    private boolean changeColor = false;

    and change it’s value in every loop, like that:
    changeColor = !changeColor;
    if(changeColor)
    notification.ledARGB = 0xFF00FF00;
    else
    notification.ledARGB = 0xFFFF0000;

  2. Quang says:

    Hi DimasTheDriver, this tutorial is very usefull. But when i run this, led in my device not light.My devices has support led(Google Nexus).Please tell me why? Thank you very much!

    • DimasTheDriver says:

      Hey Quang,

      I don’t know why this doesn’t work on the Nexus. Unfortunately, I don’t have a Nexus, so I can’t test this code.

      Have you tried different ARGB hex colors than the ones described on the post?

    • Oby says:

      Hi
      LED lights work on Google Nexus only then if screen is off (tested my self). So try to run blink code with some delay (so you have time to turn of screen) or put blinker code in OnCreate method and execute app from your developer IDE while your phones screen is off.

Leave a Reply to DimasTheDriver

Post Comments RSS