package com.android.alarmclock;
-import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
+import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.view.Window;
+import android.os.Handler;
+import android.os.Message;
import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.Toast;
-import android.widget.TextView;
-
-import java.util.Calendar;
/**
- * Alarm Clock alarm alert: pops visible indicator and plays alarm
- * tone
+ * Full screen alarm alert: pops visible indicator and plays alarm tone. This
+ * activity shows the alert as a dialog.
*/
-public class AlarmAlert extends Activity {
-
- // These defaults must match the values in res/xml/settings.xml
- private static final String DEFAULT_SNOOZE = "10";
- private static final String DEFAULT_VOLUME_BEHAVIOR = "2";
+public class AlarmAlert extends AlarmAlertFullScreen {
- private Alarm mAlarm;
- private int mVolumeBehavior;
+ // If we try to check the keyguard more than 5 times, just launch the full
+ // screen activity.
+ private int mKeyguardRetryCount;
+ private final int MAX_KEYGUARD_CHECKS = 5;
- // Receives the ALARM_KILLED action from the AlarmKlaxon.
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ private final Handler mHandler = new Handler() {
@Override
- public void onReceive(Context context, Intent intent) {
- Alarm alarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
- if (mAlarm.id == alarm.id) {
- dismiss(true);
- }
+ public void handleMessage(Message msg) {
+ handleScreenOff((KeyguardManager) msg.obj);
}
};
+ private final BroadcastReceiver mScreenOffReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ KeyguardManager km =
+ (KeyguardManager) context.getSystemService(
+ Context.KEYGUARD_SERVICE);
+ handleScreenOff(km);
+ }
+ };
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mAlarm = getIntent().getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
-
- // Get the volume/camera button behavior setting
- final String vol =
- PreferenceManager.getDefaultSharedPreferences(this)
- .getString(SettingsActivity.KEY_VOLUME_BEHAVIOR,
- DEFAULT_VOLUME_BEHAVIOR);
- mVolumeBehavior = Integer.parseInt(vol);
-
- requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
- | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
- updateLayout();
-
- // Register to get the alarm killed intent.
- registerReceiver(mReceiver, new IntentFilter(Alarms.ALARM_KILLED));
- }
-
- private void setTitle() {
- String label = mAlarm.getLabelOrDefault(this);
- TextView title = (TextView) findViewById(R.id.alertTitle);
- title.setText(label);
- }
-
- // This method is overwritten in AlarmAlertFullScreen in order to show a
- // full activity with the wallpaper as the background.
- protected View inflateView(LayoutInflater inflater) {
- return inflater.inflate(R.layout.alarm_alert, null);
- }
-
- private void updateLayout() {
- LayoutInflater inflater = LayoutInflater.from(this);
-
- setContentView(inflateView(inflater));
-
- /* set clock face */
- SharedPreferences settings =
- getSharedPreferences(AlarmClock.PREFERENCES, 0);
- int face = settings.getInt(AlarmClock.PREF_CLOCK_FACE, 0);
- if (face < 0 || face >= AlarmClock.CLOCKS.length) {
- face = 0;
- }
- ViewGroup clockView = (ViewGroup) findViewById(R.id.clockView);
- inflater.inflate(AlarmClock.CLOCKS[face], clockView);
- View clockLayout = findViewById(R.id.clock);
- if (clockLayout instanceof DigitalClock) {
- ((DigitalClock) clockLayout).setAnimate();
- }
-
- /* snooze behavior: pop a snooze confirmation view, kick alarm
- manager. */
- Button snooze = (Button) findViewById(R.id.snooze);
- snooze.requestFocus();
- snooze.setOnClickListener(new Button.OnClickListener() {
- public void onClick(View v) {
- snooze();
- }
- });
-
- /* dismiss button: close notification */
- findViewById(R.id.dismiss).setOnClickListener(
- new Button.OnClickListener() {
- public void onClick(View v) {
- dismiss(false);
- }
- });
-
- /* Set the title from the passed in alarm */
- setTitle();
- }
-
- // Attempt to snooze this alert.
- private void snooze() {
- final String snooze =
- PreferenceManager.getDefaultSharedPreferences(this)
- .getString(SettingsActivity.KEY_ALARM_SNOOZE, DEFAULT_SNOOZE);
- int snoozeMinutes = Integer.parseInt(snooze);
-
- final long snoozeTime = System.currentTimeMillis()
- + (1000 * 60 * snoozeMinutes);
- Alarms.saveSnoozeAlert(AlarmAlert.this, mAlarm.id, snoozeTime);
-
- // Get the display time for the snooze and update the notification.
- final Calendar c = Calendar.getInstance();
- c.setTimeInMillis(snoozeTime);
-
- // Append (snoozed) to the label.
- String label = mAlarm.getLabelOrDefault(this);
- label = getString(R.string.alarm_notify_snooze_label, label);
-
- // Notify the user that the alarm has been snoozed.
- Intent cancelSnooze = new Intent(this, AlarmReceiver.class);
- cancelSnooze.setAction(Alarms.CANCEL_SNOOZE);
- cancelSnooze.putExtra(Alarms.ALARM_ID, mAlarm.id);
- PendingIntent broadcast =
- PendingIntent.getBroadcast(this, mAlarm.id, cancelSnooze, 0);
- NotificationManager nm = getNotificationManager();
- Notification n = new Notification(R.drawable.stat_notify_alarm,
- label, 0);
- n.setLatestEventInfo(this, label,
- getString(R.string.alarm_notify_snooze_text,
- Alarms.formatTime(this, c)), broadcast);
- n.deleteIntent = broadcast;
- n.flags |= Notification.FLAG_AUTO_CANCEL;
- nm.notify(mAlarm.id, n);
-
- String displayTime = getString(R.string.alarm_alert_snooze_set,
- snoozeMinutes);
- // Intentionally log the snooze time for debugging.
- Log.v(displayTime);
-
- // Display the snooze minutes in a toast.
- Toast.makeText(AlarmAlert.this, displayTime, Toast.LENGTH_LONG).show();
- stopService(new Intent(Alarms.ALARM_ALERT_ACTION));
- finish();
- }
-
- private NotificationManager getNotificationManager() {
- return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ // Listen for the screen turning off so that when the screen comes back
+ // on, the user does not need to unlock the phone to dismiss the alarm.
+ registerReceiver(mScreenOffReceiver,
+ new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
- // Dismiss the alarm.
- private void dismiss(boolean killed) {
- // The service told us that the alarm has been killed, do not modify
- // the notification or stop the service.
- if (!killed) {
- // Cancel the notification and stop playing the alarm
- NotificationManager nm = getNotificationManager();
- nm.cancel(mAlarm.id);
- stopService(new Intent(Alarms.ALARM_ALERT_ACTION));
- }
- finish();
- }
-
- /**
- * this is called when a second alarm is triggered while a
- * previous alert window is still active.
- */
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
- if (Log.LOGV) Log.v("AlarmAlert.OnNewIntent()");
-
- mAlarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
-
- setTitle();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- // Don't hang around.
- finish();
- }
-
@Override
public void onDestroy() {
super.onDestroy();
- if (Log.LOGV) Log.v("AlarmAlert.onDestroy()");
- // No longer care about the alarm being killed.
- unregisterReceiver(mReceiver);
+ unregisterReceiver(mScreenOffReceiver);
+ // Remove any of the keyguard messages just in case
+ mHandler.removeMessages(0);
}
@Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- // Do this on key down to handle a few of the system keys.
- boolean up = event.getAction() == KeyEvent.ACTION_UP;
- switch (event.getKeyCode()) {
- // Volume keys and camera keys dismiss the alarm
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_CAMERA:
- case KeyEvent.KEYCODE_FOCUS:
- if (up) {
- switch (mVolumeBehavior) {
- case 1:
- snooze();
- break;
+ public void onBackPressed() {
+ finish();
+ }
- case 2:
- dismiss(false);
- break;
+ private boolean checkRetryCount() {
+ if (mKeyguardRetryCount++ >= MAX_KEYGUARD_CHECKS) {
+ Log.e("Tried to read keyguard status too many times, bailing...");
+ return false;
+ }
+ return true;
+ }
- default:
- break;
- }
- }
- return true;
- default:
- break;
+ private void handleScreenOff(final KeyguardManager km) {
+ if (!km.inKeyguardRestrictedInputMode() && checkRetryCount()) {
+ if (checkRetryCount()) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(0, km), 500);
+ }
+ } else {
+ // Launch the full screen activity but do not turn the screen on.
+ Intent i = new Intent(this, AlarmAlertFullScreen.class);
+ i.putExtra(Alarms.ALARM_INTENT_EXTRA, mAlarm);
+ i.putExtra(SCREEN_OFF, true);
+ startActivity(i);
+ finish();
}
- return super.dispatchKeyEvent(event);
}
}
package com.android.alarmclock;
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.view.Window;
import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.Toast;
+import android.widget.TextView;
+
+import java.util.Calendar;
/**
- * Full screen alarm alert: pops visible indicator and plays alarm tone. This
- * activity displays the alert in full screen in order to be secure. The
- * background is the current wallpaper.
+ * Alarm Clock alarm alert: pops visible indicator and plays alarm
+ * tone. This activity is the full screen version which shows over the lock
+ * screen with the wallpaper as the background.
*/
-public class AlarmAlertFullScreen extends AlarmAlert {
+public class AlarmAlertFullScreen extends Activity {
+
+ // These defaults must match the values in res/xml/settings.xml
+ private static final String DEFAULT_SNOOZE = "10";
+ private static final String DEFAULT_VOLUME_BEHAVIOR = "2";
+ protected static final String SCREEN_OFF = "screen_off";
+
+ protected Alarm mAlarm;
+ private int mVolumeBehavior;
+
+ // Receives the ALARM_KILLED action from the AlarmKlaxon.
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Alarm alarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
+ if (alarm != null && mAlarm.id == alarm.id) {
+ dismiss(true);
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
+
+ mAlarm = getIntent().getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
+
+ // Get the volume/camera button behavior setting
+ final String vol =
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .getString(SettingsActivity.KEY_VOLUME_BEHAVIOR,
+ DEFAULT_VOLUME_BEHAVIOR);
+ mVolumeBehavior = Integer.parseInt(vol);
+
+ requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
+
+ final Window win = getWindow();
+ win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ // Turn on the screen unless we are being launched from the AlarmAlert
+ // subclass.
+ if (!getIntent().getBooleanExtra(SCREEN_OFF, false)) {
+ win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+ }
+
+ updateLayout();
+
+ // Register to get the alarm killed intent.
+ registerReceiver(mReceiver, new IntentFilter(Alarms.ALARM_KILLED));
+ }
+
+ private void setTitle() {
+ String label = mAlarm.getLabelOrDefault(this);
+ TextView title = (TextView) findViewById(R.id.alertTitle);
+ title.setText(label);
+ }
+
+ private void updateLayout() {
+ LayoutInflater inflater = LayoutInflater.from(this);
+
+ setContentView(inflater.inflate(R.layout.alarm_alert, null));
+
+ /* set clock face */
+ SharedPreferences settings =
+ getSharedPreferences(AlarmClock.PREFERENCES, 0);
+ int face = settings.getInt(AlarmClock.PREF_CLOCK_FACE, 0);
+ if (face < 0 || face >= AlarmClock.CLOCKS.length) {
+ face = 0;
+ }
+ ViewGroup clockView = (ViewGroup) findViewById(R.id.clockView);
+ inflater.inflate(AlarmClock.CLOCKS[face], clockView);
+ View clockLayout = findViewById(R.id.clock);
+ if (clockLayout instanceof DigitalClock) {
+ ((DigitalClock) clockLayout).setAnimate();
+ }
+
+ /* snooze behavior: pop a snooze confirmation view, kick alarm
+ manager. */
+ Button snooze = (Button) findViewById(R.id.snooze);
+ snooze.requestFocus();
+ snooze.setOnClickListener(new Button.OnClickListener() {
+ public void onClick(View v) {
+ snooze();
+ }
+ });
+
+ /* dismiss button: close notification */
+ findViewById(R.id.dismiss).setOnClickListener(
+ new Button.OnClickListener() {
+ public void onClick(View v) {
+ dismiss(false);
+ }
+ });
+
+ /* Set the title from the passed in alarm */
+ setTitle();
+ }
+
+ // Attempt to snooze this alert.
+ private void snooze() {
+ final String snooze =
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .getString(SettingsActivity.KEY_ALARM_SNOOZE, DEFAULT_SNOOZE);
+ int snoozeMinutes = Integer.parseInt(snooze);
+
+ final long snoozeTime = System.currentTimeMillis()
+ + (1000 * 60 * snoozeMinutes);
+ Alarms.saveSnoozeAlert(AlarmAlertFullScreen.this, mAlarm.id,
+ snoozeTime);
+
+ // Get the display time for the snooze and update the notification.
+ final Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(snoozeTime);
+
+ // Append (snoozed) to the label.
+ String label = mAlarm.getLabelOrDefault(this);
+ label = getString(R.string.alarm_notify_snooze_label, label);
+
+ // Notify the user that the alarm has been snoozed.
+ Intent cancelSnooze = new Intent(this, AlarmReceiver.class);
+ cancelSnooze.setAction(Alarms.CANCEL_SNOOZE);
+ cancelSnooze.putExtra(Alarms.ALARM_ID, mAlarm.id);
+ PendingIntent broadcast =
+ PendingIntent.getBroadcast(this, mAlarm.id, cancelSnooze, 0);
+ NotificationManager nm = getNotificationManager();
+ Notification n = new Notification(R.drawable.stat_notify_alarm,
+ label, 0);
+ n.setLatestEventInfo(this, label,
+ getString(R.string.alarm_notify_snooze_text,
+ Alarms.formatTime(this, c)), broadcast);
+ n.deleteIntent = broadcast;
+ n.flags |= Notification.FLAG_AUTO_CANCEL;
+ nm.notify(mAlarm.id, n);
+
+ String displayTime = getString(R.string.alarm_alert_snooze_set,
+ snoozeMinutes);
+ // Intentionally log the snooze time for debugging.
+ Log.v(displayTime);
+
+ // Display the snooze minutes in a toast.
+ Toast.makeText(AlarmAlertFullScreen.this, displayTime,
+ Toast.LENGTH_LONG).show();
+ stopService(new Intent(Alarms.ALARM_ALERT_ACTION));
+ finish();
+ }
+
+ private NotificationManager getNotificationManager() {
+ return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ }
+
+ // Dismiss the alarm.
+ private void dismiss(boolean killed) {
+ // The service told us that the alarm has been killed, do not modify
+ // the notification or stop the service.
+ if (!killed) {
+ // Cancel the notification and stop playing the alarm
+ NotificationManager nm = getNotificationManager();
+ nm.cancel(mAlarm.id);
+ stopService(new Intent(Alarms.ALARM_ALERT_ACTION));
+ }
+ finish();
+ }
+
+ /**
+ * this is called when a second alarm is triggered while a
+ * previous alert window is still active.
+ */
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if (Log.LOGV) Log.v("AlarmAlert.OnNewIntent()");
+
+ mAlarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
+
+ setTitle();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (!isFinishing()) {
+ // Don't hang around.
+ finish();
+ }
}
@Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (Log.LOGV) Log.v("AlarmAlert.onDestroy()");
+ // No longer care about the alarm being killed.
+ unregisterReceiver(mReceiver);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ // Do this on key down to handle a few of the system keys.
+ boolean up = event.getAction() == KeyEvent.ACTION_UP;
+ switch (event.getKeyCode()) {
+ // Volume keys and camera keys dismiss the alarm
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_FOCUS:
+ if (up) {
+ switch (mVolumeBehavior) {
+ case 1:
+ snooze();
+ break;
+
+ case 2:
+ dismiss(false);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return true;
+ default:
+ break;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
public void onBackPressed() {
- // Don't allow back to dismiss.
+ // Don't allow back to dismiss. This method is overriden by AlarmAlert
+ // so that the dialog is dismissed.
return;
}
}