OSDN Git Service

Switch from dialog to fullscreen when the keyguard is showing.
authorPatrick Scott <phanna@android.com>
Mon, 5 Oct 2009 13:00:14 +0000 (09:00 -0400)
committerPatrick Scott <phanna@android.com>
Mon, 5 Oct 2009 15:09:40 +0000 (11:09 -0400)
Make AlarmAlert derive from AlarmAlertFullScreen. This looks like a massive
change but it is mostly a rename. Use a broadcast receiver to listen for the
screen turning off. Attempt to read the keyguard status up to 5 times in order
to launch the fullscreen activity. Add "screen_off" to the intent extras to
indicate that the intent is from the screen_off broadcast and to not wake the
screen.

The overall goal of this is that if the alarm fires while the device is on and
the user turns the screen off and then on, the full screen alert will show so
that the user can dismiss the alert.

src/com/android/alarmclock/AlarmAlert.java
src/com/android/alarmclock/AlarmAlertFullScreen.java

index 89a866a..0039ca8 100644 (file)
 
 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);
     }
 }
index c00ffce..08c13f0 100644 (file)
 
 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;
     }
 }