1 /* 2 * Copyright (C) 2009 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; 18 19 import android.app.Activity; 20 import android.app.Notification; 21 import android.app.NotificationManager; 22 import android.app.PendingIntent; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.os.Bundle; 28 import android.preference.PreferenceManager; 29 import android.view.KeyEvent; 30 import android.view.LayoutInflater; 31 import android.view.View; 32 import android.view.Window; 33 import android.view.WindowManager; 34 import android.widget.Button; 35 import android.widget.TextView; 36 import android.widget.Toast; 37 38 import java.util.Calendar; 39 40 /** 41 * Alarm Clock alarm alert: pops visible indicator and plays alarm 42 * tone. This activity is the full screen version which shows over the lock 43 * screen with the wallpaper as the background. 44 */ 45 public class AlarmAlertFullScreen extends Activity { 46 47 // These defaults must match the values in res/xml/settings.xml 48 private static final String DEFAULT_SNOOZE = "10"; 49 private static final String DEFAULT_VOLUME_BEHAVIOR = "2"; 50 protected static final String SCREEN_OFF = "screen_off"; 51 52 protected Alarm mAlarm; 53 private int mVolumeBehavior; 54 boolean mFullscreenStyle; 55 56 // Receives the ALARM_KILLED action from the AlarmKlaxon, 57 // and also ALARM_SNOOZE_ACTION / ALARM_DISMISS_ACTION from other applications 58 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 59 @Override 60 public void onReceive(Context context, Intent intent) { 61 String action = intent.getAction(); 62 if (action.equals(Alarms.ALARM_SNOOZE_ACTION)) { 63 snooze(); 64 } else if (action.equals(Alarms.ALARM_DISMISS_ACTION)) { 65 dismiss(false); 66 } else { 67 Alarm alarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA); 68 if (alarm != null && mAlarm.id == alarm.id) { 69 dismiss(true); 70 } 71 } 72 } 73 }; 74 75 @Override 76 protected void onCreate(Bundle icicle) { 77 super.onCreate(icicle); 78 79 mAlarm = getIntent().getParcelableExtra(Alarms.ALARM_INTENT_EXTRA); 80 81 // Get the volume/camera button behavior setting 82 final String vol = 83 PreferenceManager.getDefaultSharedPreferences(this) 84 .getString(SettingsActivity.KEY_VOLUME_BEHAVIOR, 85 DEFAULT_VOLUME_BEHAVIOR); 86 mVolumeBehavior = Integer.parseInt(vol); 87 88 final Window win = getWindow(); 89 win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED 90 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); 91 // Turn on the screen unless we are being launched from the AlarmAlert 92 // subclass as a result of the screen turning off. 93 if (!getIntent().getBooleanExtra(SCREEN_OFF, false)) { 94 win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 95 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON 96 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON); 97 } 98 99 updateLayout(); 100 101 // Register to get the alarm killed/snooze/dismiss intent. 102 IntentFilter filter = new IntentFilter(Alarms.ALARM_KILLED); 103 filter.addAction(Alarms.ALARM_SNOOZE_ACTION); 104 filter.addAction(Alarms.ALARM_DISMISS_ACTION); 105 registerReceiver(mReceiver, filter); 106 } 107 108 private void setTitle() { 109 final String titleText = mAlarm.getLabelOrDefault(this); 110 111 setTitle(titleText); 112 } 113 114 protected int getLayoutResId() { 115 return R.layout.alarm_alert_fullscreen; 116 } 117 118 private void updateLayout() { 119 LayoutInflater inflater = LayoutInflater.from(this); 120 121 setContentView(inflater.inflate(getLayoutResId(), null)); 122 123 /* snooze behavior: pop a snooze confirmation view, kick alarm 124 manager. */ 125 Button snooze = (Button) findViewById(R.id.snooze); 126 snooze.requestFocus(); 127 snooze.setOnClickListener(new Button.OnClickListener() { 128 public void onClick(View v) { 129 snooze(); 130 } 131 }); 132 133 /* dismiss button: close notification */ 134 findViewById(R.id.dismiss).setOnClickListener( 135 new Button.OnClickListener() { 136 public void onClick(View v) { 137 dismiss(false); 138 } 139 }); 140 141 /* Set the title from the passed in alarm */ 142 setTitle(); 143 } 144 145 // Attempt to snooze this alert. 146 private void snooze() { 147 // Do not snooze if the snooze button is disabled. 148 if (!findViewById(R.id.snooze).isEnabled()) { 149 dismiss(false); 150 return; 151 } 152 final String snooze = 153 PreferenceManager.getDefaultSharedPreferences(this) 154 .getString(SettingsActivity.KEY_ALARM_SNOOZE, DEFAULT_SNOOZE); 155 int snoozeMinutes = Integer.parseInt(snooze); 156 157 final long snoozeTime = System.currentTimeMillis() 158 + (1000 * 60 * snoozeMinutes); 159 Alarms.saveSnoozeAlert(AlarmAlertFullScreen.this, mAlarm.id, 160 snoozeTime); 161 162 // Get the display time for the snooze and update the notification. 163 final Calendar c = Calendar.getInstance(); 164 c.setTimeInMillis(snoozeTime); 165 166 // Append (snoozed) to the label. 167 String label = mAlarm.getLabelOrDefault(this); 168 label = getString(R.string.alarm_notify_snooze_label, label); 169 170 // Notify the user that the alarm has been snoozed. 171 Intent cancelSnooze = new Intent(this, AlarmReceiver.class); 172 cancelSnooze.setAction(Alarms.CANCEL_SNOOZE); 173 cancelSnooze.putExtra(Alarms.ALARM_INTENT_EXTRA, mAlarm); 174 PendingIntent broadcast = 175 PendingIntent.getBroadcast(this, mAlarm.id, cancelSnooze, 0); 176 NotificationManager nm = getNotificationManager(); 177 Notification n = new Notification(R.drawable.stat_notify_alarm, 178 label, 0); 179 n.setLatestEventInfo(this, label, 180 getString(R.string.alarm_notify_snooze_text, 181 Alarms.formatTime(this, c)), broadcast); 182 n.flags |= Notification.FLAG_AUTO_CANCEL 183 | Notification.FLAG_ONGOING_EVENT; 184 nm.notify(mAlarm.id, n); 185 186 String displayTime = getString(R.string.alarm_alert_snooze_set, 187 snoozeMinutes); 188 // Intentionally log the snooze time for debugging. 189 Log.v(displayTime); 190 191 // Display the snooze minutes in a toast. 192 Toast.makeText(AlarmAlertFullScreen.this, displayTime, 193 Toast.LENGTH_LONG).show(); 194 stopService(new Intent(Alarms.ALARM_ALERT_ACTION)); 195 finish(); 196 } 197 198 private NotificationManager getNotificationManager() { 199 return (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 200 } 201 202 // Dismiss the alarm. 203 private void dismiss(boolean killed) { 204 Log.i(killed ? "Alarm killed" : "Alarm dismissed by user"); 205 // The service told us that the alarm has been killed, do not modify 206 // the notification or stop the service. 207 if (!killed) { 208 // Cancel the notification and stop playing the alarm 209 NotificationManager nm = getNotificationManager(); 210 nm.cancel(mAlarm.id); 211 stopService(new Intent(Alarms.ALARM_ALERT_ACTION)); 212 } 213 finish(); 214 } 215 216 /** 217 * this is called when a second alarm is triggered while a 218 * previous alert window is still active. 219 */ 220 @Override 221 protected void onNewIntent(Intent intent) { 222 super.onNewIntent(intent); 223 224 if (Log.LOGV) Log.v("AlarmAlert.OnNewIntent()"); 225 226 mAlarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA); 227 228 setTitle(); 229 } 230 231 @Override 232 protected void onResume() { 233 super.onResume(); 234 // If the alarm was deleted at some point, disable snooze. 235 if (Alarms.getAlarm(getContentResolver(), mAlarm.id) == null) { 236 Button snooze = (Button) findViewById(R.id.snooze); 237 snooze.setEnabled(false); 238 } 239 } 240 241 @Override 242 public void onDestroy() { 243 super.onDestroy(); 244 if (Log.LOGV) Log.v("AlarmAlert.onDestroy()"); 245 // No longer care about the alarm being killed. 246 unregisterReceiver(mReceiver); 247 } 248 249 @Override 250 public boolean dispatchKeyEvent(KeyEvent event) { 251 // Do this on key down to handle a few of the system keys. 252 boolean up = event.getAction() == KeyEvent.ACTION_UP; 253 switch (event.getKeyCode()) { 254 // Volume keys and camera keys dismiss the alarm 255 case KeyEvent.KEYCODE_VOLUME_UP: 256 case KeyEvent.KEYCODE_VOLUME_DOWN: 257 case KeyEvent.KEYCODE_VOLUME_MUTE: 258 case KeyEvent.KEYCODE_CAMERA: 259 case KeyEvent.KEYCODE_FOCUS: 260 if (up) { 261 switch (mVolumeBehavior) { 262 case 1: 263 snooze(); 264 break; 265 266 case 2: 267 dismiss(false); 268 break; 269 270 default: 271 break; 272 } 273 } 274 return true; 275 default: 276 break; 277 } 278 return super.dispatchKeyEvent(event); 279 } 280 281 @Override 282 public void onBackPressed() { 283 // Don't allow back to dismiss. This method is overriden by AlarmAlert 284 // so that the dialog is dismissed. 285 return; 286 } 287 } 288