Skip to content

Instantly share code, notes, and snippets.

@lidemin
Created February 6, 2015 08:14
Show Gist options
  • Save lidemin/56da411abd9e317e4449 to your computer and use it in GitHub Desktop.
Save lidemin/56da411abd9e317e4449 to your computer and use it in GitHub Desktop.
Android Push Notification Bootstrap
/**
* Created by damon on 30/1/15.
*/
public class GCMReceiver extends WakefulBroadcastReceiver {
public static final String TAG = "GCMReceiver";
@Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GCMService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GCMService.class.getName());
// Start the service, keeping the device awake while it is launching.
Log.i(TAG, "Starting service @ " + SystemClock.elapsedRealtime());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
}
}
/**
* Created by damon on 30/1/15.
*/
public class GCMService extends IntentService {
public static final String TAG = "GCMService";
public static final String KEY_NOTIFICATION_TITLE = "alert";
public static final String KEY_NOTIFICATION_ARTICLE_ID = "articleId";
GoogleCloudMessaging gcm;
//for registration
public static final String KEY_GCM_USER_PREFERENCE = "key_gcm_user_preference";
public static final String KEY_GCM_STATE = "key_gcm_state";
public static final String KEY_GCM_SENDER_ID = "key_gcm_sender_id";
//for showing notification
public static final int NOTIFICATION_ID = 1;
private NotificationManager notificationManager;
NotificationCompat.Builder builder;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*/
public GCMService() {
super("GCMService");
}
@Override
protected void onHandleIntent(Intent intent) {
gcm = GoogleCloudMessaging.getInstance(this);
checkRegisterState();
Bundle bundle = intent.getExtras();
if (bundle != null && !bundle.isEmpty()) {
//process handling notification
processHandleNotification(intent);
}
Log.i(TAG, "Completed service @ " + SystemClock.elapsedRealtime());
GCMReceiver.completeWakefulIntent(intent);
}
private void processHandleNotification(Intent intent) {
if (intent == null) {
return;
}
String messageType = gcm.getMessageType(intent);
if (messageType == null) {
return;
}
if (GoogleCloudMessaging.
MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
Log.e(TAG, "received error:" + intent.getExtras());
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_DELETED.equals(messageType)) {
Log.e(TAG, "deleted messages on server:" + intent.getExtras());
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// If it's a regular GCM message, show message.
// sendNotification();
Bundle bundle = intent.getExtras();
if (bundle != null
&& bundle.containsKey(KEY_NOTIFICATION_TITLE)
&& bundle.containsKey(KEY_NOTIFICATION_ARTICLE_ID)) {
String title = bundle.getString(KEY_NOTIFICATION_TITLE);
String articleId = bundle.getString(KEY_NOTIFICATION_ARTICLE_ID);
sendNotification(title, articleId);
}
Log.i(TAG, "Received: " + intent.getExtras());
} else {
Log.i(TAG, "Received unknown message type: " + intent.getExtras());
}
}
/**
* check local user push notification preference is same as GCM state or not.
*/
private void checkRegisterState() {
if (isUserSwitchOnGCM(this) && !isGCMRegistered(this)) {
//process register
processRegister();
} else if (!isUserSwitchOnGCM(this) && isGCMRegistered(this)) {
processDeregister();
}
}
//todo
private synchronized void processDeregister() {
if (!isGCMRegistered(this)) {
return;
}
//todo
//process fuse api to deregister this sender id
//todo
//update the state in Shared Preference after got response.
}
private synchronized void processRegister() {
if (isGCMRegistered(this)) {
return;
}
String gcmRID = DLAppSession.getInstance(this).getCachedValue(KEY_GCM_SENDER_ID,
String.valueOf(getAppVersion(this)),
String.class);
if (gcmRID == null) {
//request GCM SenderID
if (gcm == null) {
Log.e(TAG, "initialize GCM failed. It might happen which cause app could not get " +
"GCM instance");
return;
}
try {
gcmRID = gcm.register(BuildConfig.GCM_SENDER_ID);
String msg = "Device registered, registration ID=" + gcmRID;
Log.i(TAG, "" + msg);
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Caught error when try to get regid from GCM but ");
return;
}
//save that sender id into sharedpreference after got it with the constraint app
// version.
if (gcmRID != null && !gcmRID.isEmpty()) {
DLAppSession.getInstance(this).cacheValue(KEY_GCM_SENDER_ID, gcmRID, -1, true,
String.valueOf(getAppVersion(this)));
}
} else {
String msg = "Device's registration ID=" + gcmRID;
Log.i(TAG, "" + msg);
}
//process fuse api to register this sender ID
Token token = isAbleToProcessRequest();
if (token == null) {
return;
}
try {
if (Service.getInstance().registerSync(token.getAccessToken(), gcmRID)) {
DLAppSession.getInstance(this).cacheValue(KEY_GCM_STATE, true, true);
} else {
DLAppSession.getInstance(this).cacheValue(KEY_GCM_STATE, false, true);
}
} catch (IOException e) {
e.printStackTrace();
DLAppSession.getInstance(this).cacheValue(KEY_GCM_STATE, false, true);
}
}
/**
* Check user's preference of push notification.
*
* @param context is the context.
* @return true means user switch on push notification in setting page. false means not.
*/
public static boolean isUserSwitchOnGCM(Context context) {
Boolean userChoice = DLAppSession.getInstance(context).getCachedValue(KEY_GCM_USER_PREFERENCE, Boolean.class);
if (userChoice == null || userChoice) {
return true;
} else {
return false;
}
}
/**
* check whether app registered into phoenix or not. This value will be saved in
* SharedPreference and updated every time get the response from Register/Deregister API.
*
* @param context is the context.
* @return true means app has already been registered in phoenix and false means not.
*/
public static boolean isGCMRegistered(Context context) {
Boolean gcmState = DLAppSession.getInstance(context).getCachedValue(KEY_GCM_STATE, Boolean.class);
if (gcmState == null || !gcmState) {
return false;
} else {
return true;
}
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
private static boolean checkPlayServices(Context context) {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
//todo
//broadcast message to show GCM error in current views.
// GooglePlayServicesUtil.getErrorDialog(resultCode, context,
// PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(TAG, "This device is not supported.");
}
return false;
}
return true;
}
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "!!!SHOULD NEVER HAPPEND!!! Could not get package name: " + e);
return 0;
}
}
// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(String title, String articleId) {
Boolean userPerference = DLAppSession.getInstance(this).getCachedValue(KEY_GCM_USER_PREFERENCE,
Boolean.class);
if (userPerference != null && !userPerference) {
//if user switch off push notification in settings page.
//app will not show notification.
return;
}
if (title == null || title.isEmpty()) {
return;
}
notificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(this, BreakingNewsActivity.class);
Bundle bundle = new Bundle();
if (articleId != null && !articleId.isEmpty()) {
bundle.putString(KEY_NOTIFICATION_ARTICLE_ID, articleId);
}
intent.putExtras(bundle);
//different pending intent are still share one Bundle. Don't know why ...
intent.setAction(articleId);
PendingIntent pendingIntent = addBackStack(this, intent);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setTicker(title)
.setContentTitle(getString(R.string.app_name))
.setPriority(android.app.Notification.PRIORITY_HIGH)
.setStyle(new NotificationCompat.BigTextStyle()
.setBigContentTitle(getString(R.string.app_name))
.bigText(title))
.setContentText(title);
mBuilder.setContentIntent(pendingIntent);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
//adding LED lights to notification
notification.defaults |= Notification.DEFAULT_LIGHDL;
notification.defaults |= Notification.DEFAULT_SOUND;
try{
int id = Integer.valueOf(articleId);
//differnt id will create different notification in title bar.
notificationManager.notify(id, notification);
}catch (Exception e){
notificationManager.notify(NOTIFICATION_ID, notification);
}
}
private Token isAbleToProcessRequest() {
Token token = DLAppSession.getInstance(this).getCachedValue(BroadcastActivity.TOKEN, Token.class);
if (token == null) {
Log.e(TAG, "Access token is not available now.");
//broadcast message token is required. maybe redirect user to login or sth else.
return null;
}
//check network.
//if network is not available, service should broadcast message
if (!DLDeviceUtil.isNetworkConnected(this)) {
//broadcast message network is not available.
Log.e(TAG, "Network is not available now.");
// tsBroadcastManager.sendBroadcast(NETWORK_REQUIRED.toString());
return null;
}
return token;
}
public static PendingIntent addBackStack(final Context context, final Intent intent) {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context.getApplicationContext());
stackBuilder.addNextIntentWithParentStack(intent);
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
return stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT);
}
}
<!--push notification-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<!--push notification-->
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>
<activity
android:name=".ResultActivity"
android:screenOrientation="portrait"
android:parentActivityName=".ParentActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ParentActivity"/>
</activity>
<!--For push notification-->
<receiver
android:name=".GCMReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="${applicationId}"/>
</intent-filter>
</receiver>
<service android:name=".GCMService"/>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment