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