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 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