Merge branch 'master' of https://github.com/google/iosched
diff --git a/android/src/main/java/com/google/samples/apps/iosched/service/SessionAlarmService.java b/android/src/main/java/com/google/samples/apps/iosched/service/SessionAlarmService.java
index 948e97f..8e2fada 100644
--- a/android/src/main/java/com/google/samples/apps/iosched/service/SessionAlarmService.java
+++ b/android/src/main/java/com/google/samples/apps/iosched/service/SessionAlarmService.java
@@ -48,9 +48,11 @@
import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.google.samples.apps.iosched.util.LogUtils.LOGD;
+import static com.google.samples.apps.iosched.util.LogUtils.LOGE;
import static com.google.samples.apps.iosched.util.LogUtils.makeLogTag;
/**
@@ -140,6 +142,10 @@
scheduleAllStarredBlocks();
scheduleAllStarredSessionFeedbacks();
return;
+ } else if (ACTION_NOTIFY_SESSION_FEEDBACK.equals(action)) {
+ LOGD(TAG, "Showing session feedback notification.");
+ notifySessionFeedback(DEBUG_SESSION_ID.equals(intent.getStringExtra(EXTRA_SESSION_ID)));
+ return;
}
final long sessionEnd = intent.getLongExtra(SessionAlarmService.EXTRA_SESSION_END,
@@ -155,30 +161,17 @@
LOGD(TAG, "Session alarm offset is: " + sessionAlarmOffset);
// Feedback notifications have a slightly different set of extras.
- if (ACTION_SCHEDULE_FEEDBACK_NOTIFICATION.equals(action) ||
- ACTION_NOTIFY_SESSION_FEEDBACK.equals(action)) {
+ if (ACTION_SCHEDULE_FEEDBACK_NOTIFICATION.equals(action)) {
final String sessionId = intent.getStringExtra(SessionAlarmService.EXTRA_SESSION_ID);
final String sessionTitle = intent.getStringExtra(
SessionAlarmService.EXTRA_SESSION_TITLE);
- final String sessionRoom = intent.getStringExtra(
- SessionAlarmService.EXTRA_SESSION_ROOM);
- final String sessionSpeakers = intent.getStringExtra(
- SessionAlarmService.EXTRA_SESSION_SPEAKERS);
if (sessionTitle == null || sessionEnd == UNDEFINED_VALUE ||
sessionId == null) {
- Log.e(TAG,
- "Attempted to schedule or notify for feedback without providing extras.");
+ LOGE(TAG, "Attempted to schedule for feedback without providing extras.");
return;
}
- if (ACTION_SCHEDULE_FEEDBACK_NOTIFICATION.equals(action)) {
- LOGD(TAG, "Scheduling feedback alarm for session: " + sessionTitle);
- scheduleFeedbackAlarm(sessionId, sessionEnd, sessionAlarmOffset, sessionTitle,
- sessionRoom, sessionSpeakers);
- } else {
- LOGD(TAG, "Notifying for feedback on session: " + sessionTitle);
- notifySessionFeedback(sessionId, sessionEnd, sessionTitle, sessionRoom,
- sessionSpeakers);
- }
+ LOGD(TAG, "Scheduling feedback alarm for session: " + sessionTitle);
+ scheduleFeedbackAlarm(sessionEnd, sessionAlarmOffset, sessionTitle);
return;
}
@@ -204,9 +197,8 @@
}
}
- public void scheduleFeedbackAlarm(final String sessionId, final long sessionEnd,
- final long alarmOffset, final String sessionTitle, String sessionRoom,
- String sessionSpeakers) {
+ public void scheduleFeedbackAlarm(final long sessionEnd,
+ final long alarmOffset, final String sessionTitle) {
// By default, feedback alarms fire 5 minutes before session end time. If alarm offset is
// provided, alarm is set to go off that much time from now (useful for testing).
long alarmTime;
@@ -219,24 +211,12 @@
LOGD(TAG, "Scheduling session feedback alarm for session '" + sessionTitle + "'");
LOGD(TAG, " -> end time: " + sessionEnd + " = " + (new Date(sessionEnd)).toString());
LOGD(TAG, " -> alarm time: " + alarmTime + " = " + (new Date(alarmTime)).toString());
- LOGD(TAG, " -> room name: " + sessionRoom);
- LOGD(TAG, " -> speakers: " + sessionSpeakers);
final Intent feedbackIntent = new Intent(
ACTION_NOTIFY_SESSION_FEEDBACK,
null,
this,
SessionAlarmService.class);
- feedbackIntent.setData(
- new Uri.Builder().authority("com.google.samples.apps.iosched")
- .path(sessionId).build()
- );
- feedbackIntent.putExtra(SessionAlarmService.EXTRA_SESSION_END, sessionEnd);
- feedbackIntent.putExtra(SessionAlarmService.EXTRA_SESSION_ALARM_OFFSET, alarmOffset);
- feedbackIntent.putExtra(SessionAlarmService.EXTRA_SESSION_ID, sessionId);
- feedbackIntent.putExtra(SessionAlarmService.EXTRA_SESSION_TITLE, sessionTitle);
- feedbackIntent.putExtra(SessionAlarmService.EXTRA_SESSION_SPEAKERS, sessionSpeakers);
- feedbackIntent.putExtra(SessionAlarmService.EXTRA_SESSION_ROOM, sessionRoom);
PendingIntent pi = PendingIntent.getService(
this, 1, feedbackIntent, PendingIntent.FLAG_CANCEL_CURRENT);
final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
@@ -296,84 +276,120 @@
// A starred session is about to end; notify the user to provide session feedback.
// Constructs and triggers a system notification. Does nothing if the session has already
// concluded.
- private void notifySessionFeedback(final String sessionId, final long sessionEnd,
- final String sessionTitle, final String sessionRoom, final String sessionSpeakers) {
- LOGD(TAG, "Considering firing notification for feedback for session: " + sessionTitle);
- boolean isDebug = DEBUG_SESSION_ID.equals(sessionId);
+ private void notifySessionFeedback(boolean debug) {
+ LOGD(TAG, "Considering firing notification for session feedback.");
- if (isDebug) {
+ if (debug) {
LOGD(TAG, "Note: this is a debug notification.");
}
// Don't fire notification if this feature is disabled in settings
if (!PrefUtils.shouldShowSessionFeedbackReminders(this)) {
- LOGD(TAG, "Skipping session feedback notification for session " + sessionId + " ("
- + sessionTitle + "). Disabled in settings.");
+ LOGD(TAG, "Skipping session feedback notification. Disabled in settings.");
return;
}
- // Avoid repeated notifications.
- if (!isDebug && UIUtils.isFeedbackNotificationFiredForSession(this, sessionId)) {
- LOGD(TAG, "Skipping repeated session feedback notification for session '"
- + sessionTitle + "'");
- return;
- }
-
- // If the session is no longer is MY_SCHEDULE, don't notify for it.
- final Uri myScheduleUri = ScheduleContract.MySchedule.buildMyScheduleUri(this);
final Cursor c = getContentResolver().query(
- myScheduleUri, MySessionsExistenceQuery.PROJECTION,
- MySessionsExistenceQuery.WHERE_CLAUSE, new String[]{sessionId}, null);
- if (!isDebug && (c == null || !c.moveToFirst())) {
- // no longer in MY_SCHEDULE
+ ScheduleContract.Sessions.CONTENT_MY_SCHEDULE_URI,
+ SessionsNeedingFeedbackQuery.PROJECTION,
+ SessionsNeedingFeedbackQuery.WHERE_CLAUSE, null, null);
+ if (c == null) {
return;
}
- LOGD(TAG, "Going forward with session feedback notification for: " + sessionTitle);
- final Uri sessionUri = ScheduleContract.Sessions.buildSessionUri(sessionId);
+ List<String> needFeedbackIds = new ArrayList<String>();
+ List<String> needFeedbackTitles = new ArrayList<String>();
+ while (c.moveToNext()) {
+ String sessionId = c.getString(SessionsNeedingFeedbackQuery.SESSION_ID);
+ String sessionTitle = c.getString(SessionsNeedingFeedbackQuery.SESSION_TITLE);
+
+ // Avoid repeated notifications.
+ if (UIUtils.isFeedbackNotificationFiredForSession(this, sessionId)) {
+ LOGD(TAG, "Skipping repeated session feedback notification for session '"
+ + sessionTitle + "'");
+ continue;
+ }
+
+ needFeedbackIds.add(sessionId);
+ needFeedbackTitles.add(sessionTitle);
+ }
+
+ if (needFeedbackIds.size() == 0) {
+ // the user has already been notified of all sessions needing feedback
+ return;
+ }
+
+ LOGD(TAG, "Going forward with session feedback notification for "
+ + needFeedbackIds.size() + " session(s).");
final Resources res = getResources();
- String contentText = res.getString(R.string.session_feedback_notification_text,
- sessionTitle);
-
- PendingIntent pi = TaskStackBuilder.create(this)
- .addNextIntent(new Intent(this, MyScheduleActivity.class))
- .addNextIntent(new Intent(Intent.ACTION_VIEW, sessionUri, this,
- SessionFeedbackActivity.class))
- .getPendingIntent(1, PendingIntent.FLAG_CANCEL_CURRENT);
// this is used to synchronize deletion of notifications on phone and wear
Intent dismissalIntent = new Intent(ACTION_NOTIFICATION_DISMISSAL);
- dismissalIntent.putExtra(KEY_SESSION_ID, sessionId);
+ // TODO: fix Wear dismiss integration
+ //dismissalIntent.putExtra(KEY_SESSION_ID, sessionId);
PendingIntent dismissalPendingIntent = PendingIntent
.getService(this, (int) new Date().getTime(), dismissalIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
+ String provideFeedbackTicker = res.getString(R.string.session_feedback_notification_ticker);
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(this)
- .setContentTitle(sessionTitle)
- .setContentText(contentText)
//.setColor(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.
- .setTicker(res.getString(R.string.session_feedback_notification_ticker))
- .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
+ .setContentText(provideFeedbackTicker)
+ .setTicker(provideFeedbackTicker)
.setLights(
SessionAlarmService.NOTIFICATION_ARGB_COLOR,
SessionAlarmService.NOTIFICATION_LED_ON_MS,
SessionAlarmService.NOTIFICATION_LED_OFF_MS)
.setSmallIcon(R.drawable.ic_stat_notification)
- .setContentIntent(pi)
- .setPriority(Notification.PRIORITY_MAX)
+ .setPriority(Notification.PRIORITY_LOW)
.setLocalOnly(true) // make it local to the phone
+ .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
.setDeleteIntent(dismissalPendingIntent)
.setAutoCancel(true);
+
+ if (needFeedbackIds.size() == 1) {
+ // Only 1 session needs feedback
+ Uri sessionUri = ScheduleContract.Sessions.buildSessionUri(needFeedbackIds.get(0));
+ PendingIntent pi = TaskStackBuilder.create(this)
+ .addNextIntent(new Intent(this, MyScheduleActivity.class))
+ .addNextIntent(new Intent(Intent.ACTION_VIEW, sessionUri, this,
+ SessionFeedbackActivity.class))
+ .getPendingIntent(1, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ notifBuilder.setContentTitle(needFeedbackTitles.get(0))
+ .setContentIntent(pi);
+ } else {
+ // Show information about several sessions that need feedback
+ PendingIntent pi = TaskStackBuilder.create(this)
+ .addNextIntent(new Intent(this, MyScheduleActivity.class))
+ .getPendingIntent(1, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
+ inboxStyle.setBigContentTitle(provideFeedbackTicker);
+ for (String title : needFeedbackTitles) {
+ inboxStyle.addLine(title);
+ }
+
+ notifBuilder.setContentTitle(
+ getResources().getQuantityString(R.plurals.session_plurals,
+ needFeedbackIds.size(), needFeedbackIds.size()))
+ .setStyle(inboxStyle)
+ .setContentIntent(pi);
+ }
+
NotificationManager nm = (NotificationManager) getSystemService(
Context.NOTIFICATION_SERVICE);
LOGD(TAG, "Now showing session feedback notification!");
- nm.notify(sessionId, FEEDBACK_NOTIFICATION_ID, notifBuilder.build());
- setupNotificationOnWear(sessionId, sessionRoom, sessionTitle, sessionSpeakers);
+ nm.notify(FEEDBACK_NOTIFICATION_ID, notifBuilder.build());
+
+ for (int i = 0; i < needFeedbackIds.size(); i++) {
+ setupNotificationOnWear(needFeedbackIds.get(i), null, needFeedbackTitles.get(i), null);
+ }
}
/**
@@ -596,12 +612,9 @@
// TODO: Should we also check that SESSION_IN_MY_SCHEDULE is true?
final Cursor c = cr.query(ScheduleContract.Sessions.CONTENT_MY_SCHEDULE_URI,
new String[]{
- ScheduleContract.Sessions.SESSION_ID,
ScheduleContract.Sessions.SESSION_TITLE,
ScheduleContract.Sessions.SESSION_END,
ScheduleContract.Sessions.SESSION_IN_MY_SCHEDULE,
- ScheduleContract.Sessions.ROOM_NAME,
- ScheduleContract.Sessions.SESSION_SPEAKER_NAMES,
},
null,
null,
@@ -611,13 +624,9 @@
return;
}
while (c.moveToNext()) {
- final String sessionId = c.getString(0);
- final String sessionTitle = c.getString(1);
- final long sessionEnd = c.getLong(2);
- final String sessionRoom = c.getString(3);
- final String sessionSpeakers = c.getString(4);
- scheduleFeedbackAlarm(sessionId, sessionEnd, UNDEFINED_ALARM_OFFSET, sessionTitle,
- sessionRoom, sessionSpeakers);
+ final String sessionTitle = c.getString(0);
+ final long sessionEnd = c.getLong(1);
+ scheduleFeedbackAlarm(sessionEnd, UNDEFINED_ALARM_OFFSET, sessionTitle);
}
}
@@ -635,16 +644,19 @@
int ROOM_ID = 2;
}
- public interface MySessionsExistenceQuery {
-
+ public interface SessionsNeedingFeedbackQuery {
String[] PROJECTION = {
- ScheduleContract.MySchedule.SESSION_ID
+ ScheduleContract.Sessions.SESSION_ID,
+ ScheduleContract.Sessions.SESSION_TITLE,
+ ScheduleContract.Sessions.SESSION_IN_MY_SCHEDULE,
+ ScheduleContract.Sessions.HAS_GIVEN_FEEDBACK,
};
int SESSION_ID = 0;
+ int SESSION_TITLE = 1;
public static final String WHERE_CLAUSE =
- ScheduleContract.MySchedule.SESSION_ID + "=?";
+ ScheduleContract.Sessions.HAS_GIVEN_FEEDBACK + "=0";
}
@Override
diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml
index 4a8438d..6f11514 100644
--- a/android/src/main/res/values/strings.xml
+++ b/android/src/main/res/values/strings.xml
@@ -32,6 +32,12 @@
<item quantity="other">%d sessions are about to start.</item>
</plurals>
+ <!-- Indicates a certain number of sessions. -->
+ <plurals name="session_plurals">
+ <item quantity="one">1 session</item>
+ <item quantity="other">%1$d sessions</item>
+ </plurals>
+
<!-- Title for the notification that alerts the user that some of their sessions are about to begin. -->
<plurals name="session_notification_title">
<item quantity="one">1 session is starting in <xliff:g id="remaining_time">%1$d</xliff:g> min.</item>