OSDN Git Service

Automated import from //branches/cupcake/...@142047,142047
[android-x86/packages-apps-DeskClock.git] / src / com / android / alarmclock / AlarmAlert.java
1 /*
2  * Copyright (C) 2007 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.alarmclock;
18
19 import android.app.Activity;
20 import android.app.KeyguardManager;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.content.res.Configuration;
25 import android.graphics.PixelFormat;
26 import android.os.Bundle;
27 import android.view.KeyEvent;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.LayoutInflater;
31 import android.view.WindowManager;
32 import android.widget.Button;
33 import android.widget.Toast;
34 import android.widget.TextView;
35
36 import java.util.Calendar;
37
38 /**
39  * Alarm Clock alarm alert: pops visible indicator and plays alarm
40  * tone
41  */
42 public class AlarmAlert extends Activity {
43
44     private static final int SNOOZE_MINUTES = 10;
45     private static final int UNKNOWN = 0;
46     private static final int SNOOZE = 1;
47     private static final int DISMISS = 2;
48     private static final int KILLED = 3;
49
50     private KeyguardManager mKeyguardManager;
51     private KeyguardManager.KeyguardLock mKeyguardLock;
52     private Button mSnoozeButton;
53     private int mState = UNKNOWN;
54
55     private AlarmKlaxon mKlaxon;
56     private int mAlarmId;
57     private String mLabel;
58
59     @Override
60     protected void onCreate(Bundle icicle) {
61         super.onCreate(icicle);
62
63         // Maintain a lock during the playback of the alarm. This lock may have
64         // already been acquired in AlarmReceiver. If the process was killed,
65         // the global wake lock is gone. Acquire again just to be sure.
66         AlarmAlertWakeLock.acquire(this);
67
68         /* FIXME Intentionally verbose: always log this until we've
69            fully debugged the app failing to start up */
70         Log.v("AlarmAlert.onCreate()");
71
72         // Popup alert over black screen
73         WindowManager.LayoutParams lp = getWindow().getAttributes();
74         lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
75         lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
76         // XXX DO NOT COPY THIS!!!  THIS IS BOGUS!  Making an activity have
77         // a system alert type is completely broken, because the activity
78         // manager will still hide/show it as if it is part of the normal
79         // activity stack.  If this is really what you want and you want it
80         // to work correctly, you should create and show your own custom window.
81         lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
82         lp.token = null;
83         getWindow().setAttributes(lp);
84         getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
85
86         mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
87
88         Intent i = getIntent();
89         mAlarmId = i.getIntExtra(Alarms.ID, -1);
90
91         mKlaxon = new AlarmKlaxon();
92         mKlaxon.postPlay(this, mAlarmId);
93
94         /* Set the title from the passed in label */
95         setTitleFromIntent(i);
96
97         /* allow next alarm to trigger while this activity is
98            active */
99         Alarms.disableSnoozeAlert(AlarmAlert.this);
100         Alarms.disableAlert(AlarmAlert.this, mAlarmId);
101         Alarms.setNextAlert(this);
102
103         mKlaxon.setKillerCallback(new AlarmKlaxon.KillerCallback() {
104             public void onKilled() {
105                 if (Log.LOGV) Log.v("onKilled()");
106                 updateSilencedText();
107
108                 /* don't allow snooze */
109                 mSnoozeButton.setEnabled(false);
110
111                 // Dismiss the alarm but mark the state as killed so if the
112                 // config changes, we show the silenced message and disable
113                 // snooze.
114                 dismiss();
115                 mState = KILLED;
116             }
117         });
118
119         updateLayout();
120     }
121
122     private void setTitleFromIntent(Intent i) {
123         mLabel = i.getStringExtra(Alarms.LABEL);
124         if (mLabel == null || mLabel.length() == 0) {
125             mLabel = getString(R.string.default_label);
126         }
127         setTitle(mLabel);
128     }
129
130     private void updateSilencedText() {
131         TextView silenced = (TextView) findViewById(R.id.silencedText);
132         silenced.setText(getString(R.string.alarm_alert_alert_silenced,
133                     AlarmKlaxon.ALARM_TIMEOUT_SECONDS / 60));
134         silenced.setVisibility(View.VISIBLE);
135     }
136
137     private void updateLayout() {
138         setContentView(R.layout.alarm_alert);
139
140         /* set clock face */
141         LayoutInflater mFactory = LayoutInflater.from(this);
142         SharedPreferences settings =
143                 getSharedPreferences(AlarmClock.PREFERENCES, 0);
144         int face = settings.getInt(AlarmClock.PREF_CLOCK_FACE, 0);
145         if (face < 0 || face >= AlarmClock.CLOCKS.length) {
146             face = 0;
147         }
148         View clockLayout =
149                 (View) mFactory.inflate(AlarmClock.CLOCKS[face], null);
150         ViewGroup clockView = (ViewGroup) findViewById(R.id.clockView);
151         clockView.addView(clockLayout);
152         if (clockLayout instanceof DigitalClock) {
153             ((DigitalClock) clockLayout).setAnimate();
154         }
155
156         /* snooze behavior: pop a snooze confirmation view, kick alarm
157            manager. */
158         mSnoozeButton = (Button) findViewById(R.id.snooze);
159         mSnoozeButton.requestFocus();
160         // If this was a configuration change, keep the silenced text if the
161         // alarm was killed.
162         if (mState == KILLED) {
163             updateSilencedText();
164             mSnoozeButton.setEnabled(false);
165         } else {
166             mSnoozeButton.setOnClickListener(new Button.OnClickListener() {
167                 public void onClick(View v) {
168                     snooze();
169                     finish();
170                 }
171             });
172         }
173
174         /* dismiss button: close notification */
175         findViewById(R.id.dismiss).setOnClickListener(
176                 new Button.OnClickListener() {
177                     public void onClick(View v) {
178                         dismiss();
179                         finish();
180                     }
181                 });
182     }
183
184     // Attempt to snooze this alert.
185     private void snooze() {
186         if (mState != UNKNOWN) {
187             return;
188         }
189         // If the next alarm is set for sooner than the snooze interval, don't
190         // snooze. Instead, toast the user that the snooze will not be set.
191         final long snoozeTime = System.currentTimeMillis()
192                 + (1000 * 60 * SNOOZE_MINUTES);
193         final long nextAlarm =
194                 Alarms.calculateNextAlert(AlarmAlert.this).getAlert();
195         String displayTime = null;
196         if (nextAlarm < snoozeTime) {
197             final Calendar c = Calendar.getInstance();
198             c.setTimeInMillis(nextAlarm);
199             displayTime = getString(R.string.alarm_alert_snooze_not_set,
200                     Alarms.formatTime(AlarmAlert.this, c));
201             mState = DISMISS;
202         } else {
203             Alarms.saveSnoozeAlert(AlarmAlert.this, mAlarmId, snoozeTime,
204                     mLabel);
205             Alarms.setNextAlert(AlarmAlert.this);
206             displayTime = getString(R.string.alarm_alert_snooze_set,
207                     SNOOZE_MINUTES);
208             mState = SNOOZE;
209         }
210         // Intentionally log the snooze time for debugging.
211         Log.v(displayTime);
212         // Display the snooze minutes in a toast.
213         Toast.makeText(AlarmAlert.this, displayTime, Toast.LENGTH_LONG).show();
214         mKlaxon.stop(this, mState == SNOOZE);
215         releaseLocks();
216     }
217
218     // Dismiss the alarm.
219     private void dismiss() {
220         if (mState != UNKNOWN) {
221             return;
222         }
223         mState = DISMISS;
224         mKlaxon.stop(this, false);
225         releaseLocks();
226     }
227
228     /**
229      * this is called when a second alarm is triggered while a
230      * previous alert window is still active.
231      */
232     @Override
233     protected void onNewIntent(Intent intent) {
234         super.onNewIntent(intent);
235         if (Log.LOGV) Log.v("AlarmAlert.OnNewIntent()");
236         mState = UNKNOWN;
237         mSnoozeButton.setEnabled(true);
238         disableKeyguard();
239
240         mAlarmId = intent.getIntExtra(Alarms.ID, -1);
241         // Play the new alarm sound.
242         mKlaxon.postPlay(this, mAlarmId);
243
244         setTitleFromIntent(intent);
245
246         /* unset silenced message */
247         TextView silenced = (TextView)findViewById(R.id.silencedText);
248         silenced.setVisibility(View.GONE);
249
250         Alarms.setNextAlert(this);
251         setIntent(intent);
252     }
253
254     @Override
255     protected void onResume() {
256         super.onResume();
257         if (Log.LOGV) Log.v("AlarmAlert.onResume()");
258         disableKeyguard();
259     }
260
261     @Override
262     protected void onStop() {
263         super.onStop();
264         if (Log.LOGV) Log.v("AlarmAlert.onStop()");
265         // As a last resort, try to snooze if this activity is stopped.
266         snooze();
267         // We might have been killed by the KillerCallback so always release
268         // the lock and keyguard.
269         releaseLocks();
270     }
271
272     @Override
273     public void onConfigurationChanged(Configuration config) {
274         super.onConfigurationChanged(config);
275         updateLayout();
276     }
277
278     @Override
279     public boolean dispatchKeyEvent(KeyEvent event) {
280         // Do this on key down to handle a few of the system keys. Only handle
281         // the snooze and dismiss this alert if the state is unknown.
282         boolean up = event.getAction() == KeyEvent.ACTION_UP;
283         boolean dismiss = false;
284         switch (event.getKeyCode()) {
285             case KeyEvent.KEYCODE_DPAD_UP:
286             case KeyEvent.KEYCODE_DPAD_DOWN:
287             case KeyEvent.KEYCODE_DPAD_LEFT:
288             case KeyEvent.KEYCODE_DPAD_RIGHT:
289             case KeyEvent.KEYCODE_DPAD_CENTER:
290             // Ignore ENDCALL because we do not receive the event if the screen
291             // is on. However, we do receive the key up for ENDCALL if the
292             // screen was off.
293             case KeyEvent.KEYCODE_ENDCALL:
294                 break;
295             // Volume keys dismiss the alarm
296             case KeyEvent.KEYCODE_VOLUME_UP:
297             case KeyEvent.KEYCODE_VOLUME_DOWN:
298                 dismiss = true;
299             // All other keys will snooze the alarm
300             default:
301                 // Check for UNKNOWN here so that we intercept both key events
302                 // and prevent the volume keys from triggering their default
303                 // behavior.
304                 if (mState == UNKNOWN && up) {
305                     if (dismiss) {
306                         dismiss();
307                     } else {
308                         snooze();
309                     }
310                     finish();
311                 }
312                 return true;
313         }
314         return super.dispatchKeyEvent(event);
315     }
316
317     private synchronized void enableKeyguard() {
318         if (mKeyguardLock != null) {
319             mKeyguardLock.reenableKeyguard();
320             mKeyguardLock = null;
321         }
322     }
323
324     private synchronized void disableKeyguard() {
325         if (mKeyguardLock == null) {
326             mKeyguardLock = mKeyguardManager.newKeyguardLock(Log.LOGTAG);
327             mKeyguardLock.disableKeyguard();
328         }
329     }
330
331     /**
332      * release wake and keyguard locks
333      */
334     private synchronized void releaseLocks() {
335         AlarmAlertWakeLock.release();
336         enableKeyguard();
337     }
338 }