/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.iosched.gcm.command;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import com.google.samples.apps.iosched.R;
import com.google.samples.apps.iosched.gcm.GCMCommand;
import com.google.samples.apps.iosched.settings.SettingsUtils;
import com.google.samples.apps.iosched.myschedule.MyScheduleActivity;
import com.google.samples.apps.iosched.util.TimeUtils;
import com.google.gson.Gson;
import java.util.Date;
import static com.google.samples.apps.iosched.util.LogUtils.*;
public class NotificationCommand extends GCMCommand {
private static final String TAG = makeLogTag("NotificationCommand");
private static class NotificationCommandModel {
String format;
String audience;
String minVersion;
String maxVersion;
String title;
String message;
String expiry;
String dialogTitle;
String dialogText;
String dialogYes;
String dialogNo;
String url;
}
@Override
public void execute(Context context, String type, String payload) {
LOGI(TAG, "Received GCM message: " + type);
LOGI(TAG, "Parsing GCM notification command: " + payload);
Gson gson = new Gson();
NotificationCommandModel command;
try {
command = gson.fromJson(payload, NotificationCommandModel.class);
if (command == null) {
LOGE(TAG, "Failed to parse command (gson returned null).");
return;
}
LOGD(TAG, "Format: " + command.format);
LOGD(TAG, "Audience: " + command.audience);
LOGD(TAG, "Title: " + command.title);
LOGD(TAG, "Message: " + command.message);
LOGD(TAG, "Expiry: " + command.expiry);
LOGD(TAG, "URL: " + command.url);
LOGD(TAG, "Dialog title: " + command.dialogTitle);
LOGD(TAG, "Dialog text: " + command.dialogText);
LOGD(TAG, "Dialog yes: " + command.dialogYes);
LOGD(TAG, "Dialog no: " + command.dialogNo);
LOGD(TAG, "Min version code: " + command.minVersion);
LOGD(TAG, "Max version code: " + command.maxVersion);
} catch (Exception ex) {
ex.printStackTrace();
LOGE(TAG, "Failed to parse GCM notification command.");
return;
}
LOGD(TAG, "Processing notification command.");
processCommand(context, command);
}
private void processCommand(Context context, NotificationCommandModel command) {
// Check format
if (!"1.0.00".equals(command.format)) {
LOGW(TAG, "GCM notification command has unrecognized format: " + command.format);
return;
}
// Check app version
if (!TextUtils.isEmpty(command.minVersion) || !TextUtils.isEmpty(command.maxVersion)) {
LOGD(TAG, "Command has version range.");
int minVersion = 0;
int maxVersion = Integer.MAX_VALUE;
try {
if (!TextUtils.isEmpty(command.minVersion)) {
minVersion = Integer.parseInt(command.minVersion);
}
if (!TextUtils.isEmpty(command.maxVersion)) {
maxVersion = Integer.parseInt(command.maxVersion);
}
LOGD(TAG, "Version range: " + minVersion + " - " + maxVersion);
PackageInfo pinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
LOGD(TAG, "My version code: " + pinfo.versionCode);
if (pinfo.versionCode < minVersion) {
LOGD(TAG, "Skipping command because our version is too old, "
+ pinfo.versionCode + " < " + minVersion);
return;
}
if (pinfo.versionCode > maxVersion) {
LOGD(TAG, "Skipping command because our version is too new, "
+ pinfo.versionCode + " > " + maxVersion);
return;
}
} catch (NumberFormatException ex) {
LOGE(TAG, "Version spec badly formatted: min=" + command.minVersion
+ ", max=" + command.maxVersion);
return;
} catch (Exception ex) {
LOGE(TAG, "Unexpected problem doing version check.", ex);
return;
}
}
// Check if we are the right audience
LOGD(TAG, "Checking audience: " + command.audience);
if ("remote".equals(command.audience)) {
if (SettingsUtils.isAttendeeAtVenue(context)) {
LOGD(TAG, "Ignoring notification because audience is remote and attendee is on-site");
return;
} else {
LOGD(TAG, "Relevant (attendee is remote).");
}
} else if ("local".equals(command.audience)) {
if (!SettingsUtils.isAttendeeAtVenue(context)) {
LOGD(TAG, "Ignoring notification because audience is on-site and attendee is remote.");
return;
} else {
LOGD(TAG, "Relevant (attendee is local).");
}
} else if ("all".equals(command.audience)) {
LOGD(TAG, "Relevant (audience is 'all').");
} else {
LOGE(TAG, "Invalid audience on GCM notification command: " + command.audience);
return;
}
// Check if it expired
Date expiry = command.expiry == null ? null : TimeUtils.parseTimestamp(command.expiry);
if (expiry == null) {
LOGW(TAG, "Failed to parse expiry field of GCM notification command: " + command.expiry);
return;
} else if (expiry.getTime() < TimeUtils.getCurrentTime(context)) {
LOGW(TAG, "Got expired GCM notification command. Expiry: " + expiry.toString());
return;
} else {
LOGD(TAG, "Message is still valid (expiry is in the future: " + expiry.toString() + ")");
}
// decide the intent that will be fired when the user clicks the notification
Intent intent;
if (TextUtils.isEmpty(command.dialogText)) {
// notification leads directly to the URL, no dialog
if (TextUtils.isEmpty(command.url)) {
intent = new Intent(context, MyScheduleActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
} else {
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(command.url));
}
} else {
// use a dialog
intent = new Intent(context, MyScheduleActivity.class).setFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP |
Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(MyScheduleActivity.EXTRA_DIALOG_TITLE,
command.dialogTitle == null ? "" : command.dialogTitle);
intent.putExtra(MyScheduleActivity.EXTRA_DIALOG_MESSAGE,
command.dialogText == null ? "" : command.dialogText);
intent.putExtra(MyScheduleActivity.EXTRA_DIALOG_YES,
command.dialogYes == null ? "OK" : command.dialogYes);
intent.putExtra(MyScheduleActivity.EXTRA_DIALOG_NO,
command.dialogNo == null ? "" : command.dialogNo);
intent.putExtra(MyScheduleActivity.EXTRA_DIALOG_URL,
command.url == null ? "" : command.url);
}
final String title = TextUtils.isEmpty(command.title) ?
context.getString(R.string.app_name) : command.title;
final String message = TextUtils.isEmpty(command.message) ? "" : command.message;
// fire the notification
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(0, new NotificationCompat.Builder(context)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_stat_notification)
.setTicker(command.message)
.setContentTitle(title)
.setContentText(message)
//.setColor(context.getResources().getColor(R.color.theme_primary))
// Note: setColor() is available in the support lib v21+.
// We commented it out because we want the source to compile
// against support lib v20. If you are using support lib
// v21 or above on Android L, uncomment this line.
.setContentIntent(PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT))
.setAutoCancel(true)
.build());
}
}