AlarmActivity.java revision dfd196054474c7f3adf45b9b5253f0120a64c4cf
1/*
2 * Copyright (C) 2013 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
17package com.android.deskclock.alarms;
18
19import android.app.Activity;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.ActivityInfo;
25import android.content.res.Configuration;
26import android.os.Bundle;
27import android.os.Handler;
28import android.os.Message;
29import android.preference.PreferenceManager;
30import android.view.KeyEvent;
31import android.view.LayoutInflater;
32import android.view.View;
33import android.view.Window;
34import android.view.WindowManager;
35import android.widget.TextClock;
36import android.widget.TextView;
37
38import com.android.deskclock.Log;
39import com.android.deskclock.R;
40import com.android.deskclock.SettingsActivity;
41import com.android.deskclock.Utils;
42import com.android.deskclock.provider.AlarmInstance;
43import com.android.deskclock.widget.multiwaveview.GlowPadView;
44
45/**
46 * Alarm activity that pops up a visible indicator when the alarm goes off.
47 */
48public class AlarmActivity extends Activity {
49    // AlarmActivity listens for this broadcast intent, so that other applications
50    // can snooze the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION).
51    public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE";
52
53    // AlarmActivity listens for this broadcast intent, so that other applications
54    // can dismiss the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION).
55    public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS";
56
57    // Controller for GlowPadView.
58    private class GlowPadController extends Handler implements GlowPadView.OnTriggerListener {
59        private static final int PING_MESSAGE_WHAT = 101;
60        private static final long PING_AUTO_REPEAT_DELAY_MSEC = 1200;
61
62        public void startPinger() {
63            sendEmptyMessage(PING_MESSAGE_WHAT);
64        }
65
66        public void stopPinger() {
67            removeMessages(PING_MESSAGE_WHAT);
68        }
69
70        @Override
71        public void handleMessage(Message msg) {
72            ping();
73            sendEmptyMessageDelayed(PING_MESSAGE_WHAT, PING_AUTO_REPEAT_DELAY_MSEC);
74        }
75
76        @Override
77        public void onGrabbed(View v, int handle) {
78            stopPinger();
79        }
80
81        @Override
82        public void onReleased(View v, int handle) {
83            startPinger();
84
85        }
86
87        @Override
88        public void onTrigger(View v, int target) {
89            switch (mGlowPadView.getResourceIdForTarget(target)) {
90                case R.drawable.ic_alarm_alert_snooze:
91                    Log.v("AlarmActivity - GlowPad snooze trigger");
92                    snooze();
93                    break;
94
95                case R.drawable.ic_alarm_alert_dismiss:
96                    Log.v("AlarmActivity - GlowPad dismiss trigger");
97                    dismiss();
98                    break;
99                default:
100                    // Code should never reach here.
101                    Log.e("Trigger detected on unhandled resource. Skipping.");
102            }
103        }
104
105        @Override
106        public void onGrabbedStateChange(View v, int handle) {
107        }
108
109        @Override
110        public void onFinishFinalAnimation() {
111        }
112    }
113
114    private AlarmInstance mInstance;
115    private int mVolumeBehavior;
116    private GlowPadView mGlowPadView;
117    private GlowPadController glowPadController = new GlowPadController();
118    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
119        @Override
120        public void onReceive(Context context, Intent intent) {
121            String action = intent.getAction();
122            Log.v("AlarmActivity - Broadcast Receiver - " + action);
123            if (action.equals(ALARM_SNOOZE_ACTION)) {
124                snooze();
125            } else if (action.equals(ALARM_DISMISS_ACTION)) {
126                dismiss();
127            } else if (action.equals(AlarmService.ALARM_DONE_ACTION)) {
128                finish();
129            } else {
130                Log.i("Unknown broadcast in AlarmActivity: " + action);
131            }
132        }
133    };
134
135    private void snooze() {
136        AlarmStateManager.setSnoozeState(this, mInstance);
137    }
138
139    private void dismiss() {
140        AlarmStateManager.setDismissState(this, mInstance);
141    }
142
143    @Override
144    protected void onCreate(Bundle icicle) {
145        super.onCreate(icicle);
146
147        long instanceId = AlarmInstance.getId(getIntent().getData());
148        mInstance = AlarmInstance.getInstance(this.getContentResolver(), instanceId);
149        if (mInstance != null) {
150            Log.v("Displaying alarm for instance: " + mInstance);
151        } else {
152            // The alarm got deleted before the activity got created, so just finish()
153            Log.v("Error displaying alarm for intent: " + getIntent());
154            finish();
155            return;
156        }
157
158        // Get the volume/camera button behavior setting
159        final String vol =
160                PreferenceManager.getDefaultSharedPreferences(this)
161                .getString(SettingsActivity.KEY_VOLUME_BEHAVIOR,
162                        SettingsActivity.DEFAULT_VOLUME_BEHAVIOR);
163        mVolumeBehavior = Integer.parseInt(vol);
164
165        final Window win = getWindow();
166        win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
167                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
168                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
169                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
170                WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
171
172        // In order to allow tablets to freely rotate and phones to stick
173        // with "nosensor" (use default device orientation) we have to have
174        // the manifest start with an orientation of unspecified" and only limit
175        // to "nosensor" for phones. Otherwise we get behavior like in b/8728671
176        // where tablets start off in their default orientation and then are
177        // able to freely rotate.
178        if (!getResources().getBoolean(R.bool.config_rotateAlarmAlert)) {
179            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
180        }
181        updateLayout();
182
183        // Register to get the alarm done/snooze/dismiss intent.
184        IntentFilter filter = new IntentFilter(AlarmService.ALARM_DONE_ACTION);
185        filter.addAction(ALARM_SNOOZE_ACTION);
186        filter.addAction(ALARM_DISMISS_ACTION);
187        registerReceiver(mReceiver, filter);
188    }
189
190
191    private void updateTitle() {
192        final String titleText = mInstance.getLabelOrDefault(this);
193        TextView tv = (TextView)findViewById(R.id.alertTitle);
194        tv.setText(titleText);
195        super.setTitle(titleText);
196    }
197
198    private void updateLayout() {
199        final LayoutInflater inflater = LayoutInflater.from(this);
200        final View view = inflater.inflate(R.layout.alarm_alert, null);
201        view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
202        setContentView(view);
203        updateTitle();
204        Utils.setTimeFormat((TextClock)(view.findViewById(R.id.digitalClock)),
205                (int)getResources().getDimension(R.dimen.bottom_text_size));
206
207        // Setup GlowPadController
208        mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
209        mGlowPadView.setOnTriggerListener(glowPadController);
210        glowPadController.startPinger();
211    }
212
213    private void ping() {
214        mGlowPadView.ping();
215    }
216
217    @Override
218    public void onConfigurationChanged(Configuration newConfig) {
219        super.onConfigurationChanged(newConfig);
220        updateLayout();
221    }
222
223    @Override
224    protected void onResume() {
225        super.onResume();
226        glowPadController.startPinger();
227    }
228
229    @Override
230    protected void onPause() {
231        super.onPause();
232        glowPadController.stopPinger();
233    }
234
235    @Override
236    public void onDestroy() {
237        super.onDestroy();
238        unregisterReceiver(mReceiver);
239    }
240
241    @Override
242    public void onBackPressed() {
243        // Don't allow back to dismiss.
244    }
245
246    @Override
247    public boolean dispatchKeyEvent(KeyEvent event) {
248        // Do this on key down to handle a few of the system keys.
249        Log.v("AlarmActivity - dispatchKeyEvent - " + event.getKeyCode());
250        switch (event.getKeyCode()) {
251            // Volume keys and camera keys dismiss the alarm
252            case KeyEvent.KEYCODE_POWER:
253            case KeyEvent.KEYCODE_VOLUME_UP:
254            case KeyEvent.KEYCODE_VOLUME_DOWN:
255            case KeyEvent.KEYCODE_VOLUME_MUTE:
256            case KeyEvent.KEYCODE_CAMERA:
257            case KeyEvent.KEYCODE_FOCUS:
258                if (event.getAction() == KeyEvent.ACTION_UP) {
259                    switch (mVolumeBehavior) {
260                        case 1:
261                            snooze();
262                            break;
263
264                        case 2:
265                            dismiss();
266                            break;
267
268                        default:
269                            break;
270                    }
271                }
272                return true;
273            default:
274                break;
275        }
276        return super.dispatchKeyEvent(event);
277    }
278}
279