Java tutorial
/* * Copyright (C) 2016 The Android Open Source Project * * 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.android.deskclock.data; import android.app.AlarmManager; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.SystemClock; import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; import android.support.annotation.VisibleForTesting; import android.support.v4.app.NotificationCompat; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import com.android.deskclock.HandleDeskClockApiCalls; import com.android.deskclock.R; import com.android.deskclock.Utils; import com.android.deskclock.timer.ExpiredTimersActivity; import com.android.deskclock.timer.TimerService; import java.util.List; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; /** * Builds KK, L, or M-style notifications to reflect the latest state of the unexpired timers. */ class TimerNotificationBuilderPreN implements TimerModel.NotificationBuilder { @Override public Notification build(Context context, NotificationModel nm, List<Timer> unexpired) { final Timer timer = unexpired.get(0); final long remainingTime = timer.getRemainingTime(); // Generate some descriptive text, a title, and some actions based on timer states. final String contentText; final String contentTitle; @DrawableRes int firstActionIconId, secondActionIconId = 0; @StringRes int firstActionTitleId, secondActionTitleId = 0; Intent firstActionIntent, secondActionIntent = null; if (unexpired.size() == 1) { contentText = formatElapsedTimeUntilExpiry(context, remainingTime); if (timer.isRunning()) { // Single timer is running. if (TextUtils.isEmpty(timer.getLabel())) { contentTitle = context.getString(R.string.timer_notification_label); } else { contentTitle = timer.getLabel(); } firstActionIconId = R.drawable.ic_pause_24dp; firstActionTitleId = R.string.timer_pause; firstActionIntent = new Intent(context, TimerService.class) .setAction(HandleDeskClockApiCalls.ACTION_PAUSE_TIMER) .putExtra(HandleDeskClockApiCalls.EXTRA_TIMER_ID, timer.getId()); secondActionIconId = R.drawable.ic_add_24dp; secondActionTitleId = R.string.timer_plus_1_min; secondActionIntent = new Intent(context, TimerService.class) .setAction(HandleDeskClockApiCalls.ACTION_ADD_MINUTE_TIMER) .putExtra(HandleDeskClockApiCalls.EXTRA_TIMER_ID, timer.getId()); } else { // Single timer is paused. contentTitle = context.getString(R.string.timer_paused); firstActionIconId = R.drawable.ic_start_24dp; firstActionTitleId = R.string.sw_resume_button; firstActionIntent = new Intent(context, TimerService.class) .setAction(HandleDeskClockApiCalls.ACTION_START_TIMER) .putExtra(HandleDeskClockApiCalls.EXTRA_TIMER_ID, timer.getId()); secondActionIconId = R.drawable.ic_reset_24dp; secondActionTitleId = R.string.sw_reset_button; secondActionIntent = new Intent(context, TimerService.class) .setAction(HandleDeskClockApiCalls.ACTION_RESET_TIMER) .putExtra(HandleDeskClockApiCalls.EXTRA_TIMER_ID, timer.getId()); } } else { if (timer.isRunning()) { // At least one timer is running. final String timeRemaining = formatElapsedTimeUntilExpiry(context, remainingTime); contentText = context.getString(R.string.next_timer_notif, timeRemaining); contentTitle = context.getString(R.string.timers_in_use, unexpired.size()); } else { // All timers are paused. contentText = context.getString(R.string.all_timers_stopped_notif); contentTitle = context.getString(R.string.timers_stopped, unexpired.size()); } firstActionIconId = R.drawable.ic_reset_24dp; firstActionTitleId = R.string.timer_reset_all; firstActionIntent = TimerService.createResetUnexpiredTimersIntent(context); } // Intent to load the app and show the timer when the notification is tapped. final Intent showApp = new Intent(context, HandleDeskClockApiCalls.class) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setAction(HandleDeskClockApiCalls.ACTION_SHOW_TIMERS) .putExtra(HandleDeskClockApiCalls.EXTRA_TIMER_ID, timer.getId()) .putExtra(HandleDeskClockApiCalls.EXTRA_EVENT_LABEL, R.string.label_notification); final PendingIntent pendingShowApp = PendingIntent.getActivity(context, 0, showApp, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); final NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setOngoing(true) .setLocalOnly(true).setShowWhen(false).setAutoCancel(false).setContentText(contentText) .setContentTitle(contentTitle).setContentIntent(pendingShowApp) .setSmallIcon(R.drawable.stat_notify_timer).setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_ALARM).setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setColor(ContextCompat.getColor(context, R.color.default_background)); final PendingIntent action1 = Utils.pendingServiceIntent(context, firstActionIntent); final String action1Title = context.getString(firstActionTitleId); builder.addAction(firstActionIconId, action1Title, action1); if (secondActionIntent != null) { final PendingIntent action2 = Utils.pendingServiceIntent(context, secondActionIntent); final String action2Title = context.getString(secondActionTitleId); builder.addAction(secondActionIconId, action2Title, action2); } final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); final Intent updateNotification = TimerService.createUpdateNotificationIntent(context); if (timer.isRunning() && remainingTime > MINUTE_IN_MILLIS) { // Schedule a callback to update the time-sensitive information of the running timer. final PendingIntent pi = PendingIntent.getService(context, 0, updateNotification, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); final long nextMinuteChange = remainingTime % MINUTE_IN_MILLIS; final long triggerTime = SystemClock.elapsedRealtime() + nextMinuteChange; TimerModel.schedulePendingIntent(am, triggerTime, pi); } else { // Cancel the update notification callback. final PendingIntent pi = PendingIntent.getService(context, 0, updateNotification, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE); if (pi != null) { am.cancel(pi); pi.cancel(); } } return builder.build(); } @Override public Notification buildHeadsUp(Context context, List<Timer> expired) { // Generate some descriptive text, a title, and an action name based on the timer count. final int timerId; final String contentText; final String contentTitle; final String resetActionTitle; final int count = expired.size(); if (count == 1) { final Timer timer = expired.get(0); timerId = timer.getId(); resetActionTitle = context.getString(R.string.timer_stop); contentText = context.getString(R.string.timer_times_up); final String label = timer.getLabel(); if (TextUtils.isEmpty(label)) { contentTitle = context.getString(R.string.timer_notification_label); } else { contentTitle = label; } } else { timerId = -1; contentText = context.getString(R.string.timer_multi_times_up, count); contentTitle = context.getString(R.string.timer_notification_label); resetActionTitle = context.getString(R.string.timer_stop_all); } // Content intent shows the expired timers full screen when clicked. final Intent content = new Intent(context, ExpiredTimersActivity.class); final PendingIntent pendingContent = Utils.pendingActivityIntent(context, content); // Full screen intent has flags so it is different than the content intent. final Intent fullScreen = new Intent(context, ExpiredTimersActivity.class) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION); final PendingIntent pendingFullScreen = Utils.pendingActivityIntent(context, fullScreen); // Left button: Reset timer / Reset all timers final Intent reset = TimerService.createResetExpiredTimersIntent(context); final PendingIntent pendingReset = Utils.pendingServiceIntent(context, reset); final NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setOngoing(true) .setLocalOnly(true).setShowWhen(false).setAutoCancel(false).setContentText(contentText) .setContentTitle(contentTitle).setContentIntent(pendingContent) .setColor(ContextCompat.getColor(context, R.color.default_background)) .setSmallIcon(R.drawable.stat_notify_timer).setFullScreenIntent(pendingFullScreen, true) .setPriority(NotificationCompat.PRIORITY_MAX).setDefaults(NotificationCompat.DEFAULT_LIGHTS) .addAction(R.drawable.ic_stop_24dp, resetActionTitle, pendingReset); // Add a second action if only a single timer is expired. if (count == 1) { // Right button: Add minute final Intent addMinute = TimerService.createAddMinuteTimerIntent(context, timerId); final PendingIntent pendingAddMinute = Utils.pendingServiceIntent(context, addMinute); final String addMinuteTitle = context.getString(R.string.timer_plus_1_min); builder.addAction(R.drawable.ic_add_24dp, addMinuteTitle, pendingAddMinute); } return builder.build(); } /** * Format "7 hours 52 minutes remaining" */ @VisibleForTesting static String formatElapsedTimeUntilExpiry(Context context, long remainingTime) { final int hours = (int) remainingTime / (int) HOUR_IN_MILLIS; final int minutes = (int) remainingTime / ((int) MINUTE_IN_MILLIS) % 60; String minSeq = Utils.getNumberFormattedQuantityString(context, R.plurals.minutes, minutes); String hourSeq = Utils.getNumberFormattedQuantityString(context, R.plurals.hours, hours); // The verb "remaining" may have to change tense for singular subjects in some languages. final String verb = context.getString( (minutes > 1 || hours > 1) ? R.string.timer_remaining_multiple : R.string.timer_remaining_single); final boolean showHours = hours > 0; final boolean showMinutes = minutes > 0; int formatStringId; if (showHours) { if (showMinutes) { formatStringId = R.string.timer_notifications_hours_minutes; } else { formatStringId = R.string.timer_notifications_hours; } } else if (showMinutes) { formatStringId = R.string.timer_notifications_minutes; } else { formatStringId = R.string.timer_notifications_less_min; } return String.format(context.getString(formatStringId), hourSeq, minSeq, verb); } }