Intents, Notifications and External Applications
Android Intents
What is an Intent?
An Intent is a specific command in Android that allows you to send a command to the Android OS to do something specific. Think of it like an action that needs to take place. There are many actions that can be done such as sending an email, or attaching a photo to an email or even launching an application.
The logical workflow of creating an intent is usually as follows:
a. Create the Intent
b. Add Intent options -> Ex. what type of intent we are sending to the OS or any attributes associated with that intent, such as a text string or something being passed along with the intent
c. RUN the Intent
Real Life Example: Let’s say I wake up in the morning and I “INTEND” to go to the washroom. I will first have to THINK about going to the washroom, but that DOESN’T really get me to the washroom. I will then have to tell my brain to get out of bed first, then walk to the washroom, and then release, then go and wash my hands, then go and wipe my hands. Once I know where I’m going I SEND the command to begin and my body takes action.
Pending Intents
Continuing from the real life example, let’s say I want to take a shower but I want to shower AFTER I brush my teeth and eat breakfast. So I know I won’t be showering until at least 30-40 minutes. I still have in my head that I need to prepare my clothes, and then walk up the stairs back to the bathroom, then undress and then shower. However this will not happen until 30-40 minutes have passed. I now have a PENDING intent to shower. It is PENDING for 30-40 minutes.
That is pretty much the difference between a Pending Intent and a Regular Intent. Regular Intents can be created without a Pending Intent, however in order to create a Pending Intent you need to have a Regular Intent setup first. In short:
Regular Intent -> DOES NOT REQUIRE PENDING INTENT TO BE MADE
Pending Intent -> REQUIRES A REGULAR INTENT TO BE CREATED
Android Notifications
For this Tutorial, we want to create a NOTIFICATION at a specific time in Android and FORCE screen on if it is not on. NOTE: This solution will only set a notification in the notification bar WHEN the user is OUTSIDE of your app. That’s the point of notifications, to tell the user something when they are NOT inside of your app. It will NOT send a notification while INSIDE your app. So to TEST the code, you need to exit out of your app in order to see the notification pop up. It’s better to set a PREDEFINED TIME in the future for the notification to pop up, for example we have it set to 300 seconds.
This code will FORCE the Android device to wake up from sleep mode as well. The user will then have to unlock their keyboard or phone in order to see the notification.
Creating a Notification
- First create a function in ShiVa to send a notification (TEXT) through a function. Something like “onCreateNotification ( sText )”
- Complete the entire Hooks and Callbacks tutorial with this new function only and go all the way until you reach the JAVA file section. We are assuming you called the JAVA function “CallJAVANotification” (you will require to pass a STRING so make sure you pass a string through in the C++ portion of the code).
- Copy and Paste this function below into the JAVA file at approx. line 505 before the “public void onLowMemory ( )” function:
public static int CallJAVANotification ( String sText ) { // Create a new double variable called nSeconds. THIS IS WHERE YOU EDIT HOW LONG BEFORE THE NOTIFICATION IS SHOWN TO THE USER. double nSeconds = 300.0; // Create a new AlarmManager called am AlarmManager am; // Set am to ALARM_SERVICE am = (AlarmManager) oThis.getSystemService(Context.ALARM_SERVICE); // Create REGULAR INTENT based on the Alarm Receiver class Intent intent = new Intent(oThis.getBaseContext(), AlarmReceiver.class); // Pass along the string data with the intent intent.putExtra("sText", sText); // Create a PENDING INTENT which is based on the REGULAR INTENT above and make sure it happens ONLY ONCE PendingIntent pendingIntent = PendingIntent.getBroadcast(oThis.getBaseContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT); // Cancel ALL other previous PENDING INTENTS that were called using the same ID of 0 in this case am.cancel(pendingIntent); // Set the Alarm Manager to run the PENDING INTENT IMMEDIATELY as our nSeconds is set to 0. (In future we can set this to a specific time ahead) am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (long) (nSeconds * 1000), pendingIntent); // Return return 0; }
- NEXT we need to create a BroadcastReceiver in a new Activity class. In your Package Explorer window in Eclipse, click on the arrow next to src and then right click on the package folder (will look like: com.yourcompany.yourappname) and then click on New->Class.
- Name the class “AlarmReceiver” without the quotes and hit the Finish button.
- Now copy the code below into it and REPLACE the first line (package com.yourcompany.yourappname) with your own package name:
// REPLACE LINE BELOW package com.yourcompany.yourappname; import android.app.Activity; import android.app.KeyguardManager; import android.app.KeyguardManager.KeyguardLock; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.PowerManager; import android.view.Window; import android.view.WindowManager; public class AlarmReceiver extends BroadcastReceiver { // Create a new Notification Manager called nm NotificationManager nm; // Create a new Power Manager called pm PowerManager pm; // Main function for activity @Override public void onReceive(Context context, Intent intent) { // Set pm to Power Service so that we can access the power options on device pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); // Set WHERE the notification is coming 'from' (You can place your app name here if you wish) CharSequence from = "YourAppNameHere"; // Check if the screen itself is off or not. If it is then this code below will FORCEFULLY wake up the device even if it is put into sleep mode by user if(pm.isScreenOn() == false) { PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "MyLock"); wl.acquire(10000); PowerManager.WakeLock wl_cpu = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyCpuLock"); wl_cpu.acquire(10000); } // Set the notification manager to Notification Service nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); // Get the text we passed in from ShiVa and place that text here in the message we are going to display to user CharSequence message = intent.getCharSequenceExtra("sText"); // Create a new pending intent called contentIntent PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(), 0); // Create a new notification which will include YOUR APP ICON Notification notif = new Notification(R.drawable.app_icon, message, System.currentTimeMillis()); // Setup the notification window notif.setLatestEventInfo(context, from, message, contentIntent); // This flag here will INSISTENTLY send the notification to the user until the user ACKNOWLEDGES the notification by clicking on it notif.flags = Notification.FLAG_INSISTENT; // This actually runs the notification command itself nm.notify(1, notif); } }
- Now save that file and open up the AndroidManifest.xml file by double clicking on AndroidManifest.xml in your Package Explorer window on the left.
- Inside the AndroidManifest.xml file, we need to tell our app that we are using a Broadcast Receiver and where to find the AlarmReceiver file. Right after the activity end tag on approx. line 17-18, paste the following code AND REPLACE THE PACKAGE INFO like this -> com.yourcompany.yourapp.AlarmReceiver :
- This next item to add into the AndroidManifest.xml file I believe is needed, but never really knew why, but in any case just add it in as this is what worked for me lol. In any case you MAY NOT need this step but just incase it wont hurt to add it in, you can remove it if you find it will work without it or if you dont want it.
Go to line approx. 25, right at the very end of the ‘‘ tags and add the following code: - Save the file and compile and test, you should now see your notifications running.
Running an External Application from Code
- Finish tutorial above so that you now have an “AlarmReceiver.java” class file
- Open the AlarmReceiver.java file and at approx. line 50. Under the ‘nm.notify(1, notif);’ line, add the following code:
// Create a new intent based on the MAIN ACTION Intent i = new Intent(Intent.ACTION_MAIN); // Create a new Package Manager called manager PackageManager manager = context.getPackageManager(); // Set the intent to launch the package of the name com.appcompany.appyouwanttolaunch <- REPLACE THAT WITH THE APP PACKAGE YOU WANT TO LAUNCH i = manager.getLaunchIntentForPackage("com.appcompany.appyouwanttolaunch"); // Set the intent category to launcher to be able to launch an app i.addCategory(Intent.CATEGORY_LAUNCHER); // Send the command to start the intent context.startActivity(i);
- Now you should be able to launch apps right from Android code, congratulations!
Complete Example
COMPLETED CODE BELOW FOR AlarmReceiver.java:
// REPLACE LINE BELOW
package com.yourcompany.yourappname;
import android.app.Activity;
import android.app.KeyguardManager;
import android.app.KeyguardManager.KeyguardLock;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.view.Window;
import android.view.WindowManager;
public class AlarmReceiver extends BroadcastReceiver {
// Create a new Notification Manager called nm
NotificationManager nm;
// Create a new Power Manager called pm
PowerManager pm;
// Main function for activity
@Override
public void onReceive(Context context, Intent intent) {
// Set pm to Power Service so that we can access the power options on device
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
// Set WHERE the notification is coming 'from' (You can place your app name here if you wish)
CharSequence from = "YourAppNameHere";
// Check if the screen itself is off or not. If it is then this code below will FORCEFULLY wake up the device even if it is put into sleep mode by user
if(pm.isScreenOn() == false)
{
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "MyLock");
wl.acquire(10000);
PowerManager.WakeLock wl_cpu = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyCpuLock");
wl_cpu.acquire(10000);
}
// Set the notification manager to Notification Service
nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Get the text we passed in from ShiVa and place that text here in the message we are going to display to user
CharSequence message = intent.getCharSequenceExtra("sText");
// Create a new pending intent called contentIntent
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
// Create a new notification which will include YOUR APP ICON
Notification notif = new Notification(R.drawable.app_icon, message, System.currentTimeMillis());
// Setup the notification window
notif.setLatestEventInfo(context, from, message, contentIntent);
// This flag here will INSISTENTLY send the notification to the user until the user ACKNOWLEDGES the notification by clicking on it
notif.flags = Notification.FLAG_INSISTENT;
// This actually runs the notification command itself
nm.notify(1, notif);
// Create a new intent based on the MAIN ACTION
Intent i = new Intent(Intent.ACTION_MAIN);
// Create a new Package Manager called manager
PackageManager manager = context.getPackageManager();
// Set the intent to launch the package of the name com.appcompany.appyouwanttolaunch <- REPLACE THAT WITH THE APP PACKAGE YOU WANT TO LAUNCH
i = manager.getLaunchIntentForPackage("com.appcompany.appyouwanttolaunch");
// Set the intent category to launcher to be able to launch an app
i.addCategory(Intent.CATEGORY_LAUNCHER);
// Send the command to start the intent
context.startActivity(i);
}
}
Further Reading
Resources:
http://smartandroidians.blogspot.ca/2010/04/alarmmanager-and-notification-in.html
http://www.anddev.org/other-coding-problems-f5/acquire-causes-wakeup-not-working-on-some-devices-t48434.html
http://stackoverflow.com/questions/9631869/light-up-screen-when-notification-received-android
http://forum.xda-developers.com/showthread.php?t=1134978
http://stackoverflow.com/questions/2780102/open-another-application-from-your-own-intent