1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.deskclock.data; 18 19 import android.app.Notification; 20 import android.app.NotificationChannel; 21 import android.app.PendingIntent; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.res.Resources; 25 import android.os.SystemClock; 26 import androidx.annotation.DrawableRes; 27 import androidx.annotation.StringRes; 28 import androidx.core.app.NotificationCompat; 29 import androidx.core.app.NotificationCompat.Action; 30 import androidx.core.app.NotificationCompat.Builder; 31 import androidx.core.app.NotificationManagerCompat; 32 import androidx.core.content.ContextCompat; 33 import android.widget.RemoteViews; 34 35 import com.android.deskclock.R; 36 import com.android.deskclock.Utils; 37 import com.android.deskclock.events.Events; 38 import com.android.deskclock.stopwatch.StopwatchService; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 43 import static android.view.View.GONE; 44 import static android.view.View.VISIBLE; 45 46 /** 47 * Builds notification to reflect the latest state of the stopwatch and recorded laps. 48 */ 49 class StopwatchNotificationBuilder { 50 51 /** 52 * Notification channel containing all stopwatch notifications. 53 */ 54 private static final String STOPWATCH_NOTIFICATION_CHANNEL_ID = "StopwatchNotification"; 55 buildChannel(Context context, NotificationManagerCompat notificationManager)56 public void buildChannel(Context context, NotificationManagerCompat notificationManager) { 57 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 58 NotificationChannel channel = new NotificationChannel( 59 STOPWATCH_NOTIFICATION_CHANNEL_ID, 60 context.getString(R.string.default_label), 61 NotificationManagerCompat.IMPORTANCE_DEFAULT); 62 notificationManager.createNotificationChannel(channel); 63 } 64 } 65 build(Context context, NotificationModel nm, Stopwatch stopwatch)66 public Notification build(Context context, NotificationModel nm, Stopwatch stopwatch) { 67 @StringRes final int eventLabel = R.string.label_notification; 68 69 // Intent to load the app when the notification is tapped. 70 final Intent showApp = new Intent(context, StopwatchService.class) 71 .setAction(StopwatchService.ACTION_SHOW_STOPWATCH) 72 .putExtra(Events.EXTRA_EVENT_LABEL, eventLabel); 73 74 final PendingIntent pendingShowApp = PendingIntent.getService(context, 0, showApp, 75 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); 76 77 // Compute some values required below. 78 final boolean running = stopwatch.isRunning(); 79 final String pname = context.getPackageName(); 80 final Resources res = context.getResources(); 81 final long base = SystemClock.elapsedRealtime() - stopwatch.getTotalTime(); 82 83 final RemoteViews content = new RemoteViews(pname, R.layout.chronometer_notif_content); 84 content.setChronometer(R.id.chronometer, base, null, running); 85 86 final List<Action> actions = new ArrayList<>(2); 87 88 if (running) { 89 // Left button: Pause 90 final Intent pause = new Intent(context, StopwatchService.class) 91 .setAction(StopwatchService.ACTION_PAUSE_STOPWATCH) 92 .putExtra(Events.EXTRA_EVENT_LABEL, eventLabel); 93 94 @DrawableRes final int icon1 = R.drawable.ic_pause_24dp; 95 final CharSequence title1 = res.getText(R.string.sw_pause_button); 96 final PendingIntent intent1 = Utils.pendingServiceIntent(context, pause); 97 actions.add(new Action.Builder(icon1, title1, intent1).build()); 98 99 // Right button: Add Lap 100 if (DataModel.getDataModel().canAddMoreLaps()) { 101 final Intent lap = new Intent(context, StopwatchService.class) 102 .setAction(StopwatchService.ACTION_LAP_STOPWATCH) 103 .putExtra(Events.EXTRA_EVENT_LABEL, eventLabel); 104 105 @DrawableRes final int icon2 = R.drawable.ic_sw_lap_24dp; 106 final CharSequence title2 = res.getText(R.string.sw_lap_button); 107 final PendingIntent intent2 = Utils.pendingServiceIntent(context, lap); 108 actions.add(new Action.Builder(icon2, title2, intent2).build()); 109 } 110 111 // Show the current lap number if any laps have been recorded. 112 final int lapCount = DataModel.getDataModel().getLaps().size(); 113 if (lapCount > 0) { 114 final int lapNumber = lapCount + 1; 115 final String lap = res.getString(R.string.sw_notification_lap_number, lapNumber); 116 content.setTextViewText(R.id.state, lap); 117 content.setViewVisibility(R.id.state, VISIBLE); 118 } else { 119 content.setViewVisibility(R.id.state, GONE); 120 } 121 } else { 122 // Left button: Start 123 final Intent start = new Intent(context, StopwatchService.class) 124 .setAction(StopwatchService.ACTION_START_STOPWATCH) 125 .putExtra(Events.EXTRA_EVENT_LABEL, eventLabel); 126 127 @DrawableRes final int icon1 = R.drawable.ic_start_24dp; 128 final CharSequence title1 = res.getText(R.string.sw_start_button); 129 final PendingIntent intent1 = Utils.pendingServiceIntent(context, start); 130 actions.add(new Action.Builder(icon1, title1, intent1).build()); 131 132 // Right button: Reset (dismisses notification and resets stopwatch) 133 final Intent reset = new Intent(context, StopwatchService.class) 134 .setAction(StopwatchService.ACTION_RESET_STOPWATCH) 135 .putExtra(Events.EXTRA_EVENT_LABEL, eventLabel); 136 137 @DrawableRes final int icon2 = R.drawable.ic_reset_24dp; 138 final CharSequence title2 = res.getText(R.string.sw_reset_button); 139 final PendingIntent intent2 = Utils.pendingServiceIntent(context, reset); 140 actions.add(new Action.Builder(icon2, title2, intent2).build()); 141 142 // Indicate the stopwatch is paused. 143 content.setTextViewText(R.id.state, res.getString(R.string.swn_paused)); 144 content.setViewVisibility(R.id.state, VISIBLE); 145 } 146 147 final Builder notification = new NotificationCompat.Builder( 148 context, STOPWATCH_NOTIFICATION_CHANNEL_ID) 149 .setLocalOnly(true) 150 .setOngoing(running) 151 .setCustomContentView(content) 152 .setContentIntent(pendingShowApp) 153 .setAutoCancel(stopwatch.isPaused()) 154 .setPriority(Notification.PRIORITY_MAX) 155 .setSmallIcon(R.drawable.stat_notify_stopwatch) 156 .setStyle(new NotificationCompat.DecoratedCustomViewStyle()) 157 .setColor(ContextCompat.getColor(context, R.color.default_background)); 158 159 if (Utils.isNOrLater()) { 160 notification.setGroup(nm.getStopwatchNotificationGroupKey()); 161 } 162 163 for (Action action : actions) { 164 notification.addAction(action); 165 } 166 167 return notification.build(); 168 } 169 } 170