Created
February 6, 2015 08:14
-
-
Save lidemin/56da411abd9e317e4449 to your computer and use it in GitHub Desktop.
Android Push Notification Bootstrap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--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