blob: 8f1582ce15ce916a2e70f3a885637d741f3bc245 [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.deskclock;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import com.android.deskclock.widget.multiwaveview.GlowPadView;
import java.util.Calendar;
/**
* 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 Activity implements GlowPadView.OnTriggerListener {
private final boolean LOG = true;
// These defaults must match the values in res/xml/settings.xml
private static final String DEFAULT_SNOOZE = "10";
protected static final String SCREEN_OFF = "screen_off";
protected Alarm mAlarm;
private int mVolumeBehavior;
boolean mFullscreenStyle;
private GlowPadView mGlowPadView;
private boolean mIsDocked = false;
// Parameters for the GlowPadView "ping" animation; see triggerPing().
private static final int PING_MESSAGE_WHAT = 101;
private static final boolean ENABLE_PING_AUTO_REPEAT = true;
private static final long PING_AUTO_REPEAT_DELAY_MSEC = 1200;
private boolean mPingEnabled = true;
// Receives the ALARM_KILLED action from the AlarmKlaxon,
// and also ALARM_SNOOZE_ACTION / ALARM_DISMISS_ACTION from other applications
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (LOG) {
Log.v("AlarmAlertFullScreen - onReceive " + action);
}
if (action.equals(Alarms.ALARM_SNOOZE_ACTION)) {
snooze();
} else if (action.equals(Alarms.ALARM_DISMISS_ACTION)) {
dismiss(false, false);
} else {
Alarm alarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
boolean replaced = intent.getBooleanExtra(Alarms.ALARM_REPLACED, false);
if (alarm != null && mAlarm.id == alarm.id) {
dismiss(true, replaced);
}
}
}
};
private final Handler mPingHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case PING_MESSAGE_WHAT:
triggerPing();
break;
}
}
};
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mAlarm = getIntent().getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
if (LOG) {
Log.v("AlarmAlertFullScreen - onCreate");
if (mAlarm != null) {
Log.v("AlarmAlertFullScreen - Alarm Id " + mAlarm.toString());
}
}
// Get the volume/camera button behavior setting
final String vol =
PreferenceManager.getDefaultSharedPreferences(this)
.getString(SettingsActivity.KEY_VOLUME_BEHAVIOR,
SettingsActivity.DEFAULT_VOLUME_BEHAVIOR);
mVolumeBehavior = Integer.parseInt(vol);
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 as a result of the screen turning off.
if (!getIntent().getBooleanExtra(SCREEN_OFF, false)) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
}
updateLayout();
// Check the docking status , if the device is docked , do not limit rotation
IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
Intent dockStatus = registerReceiver(null, ifilter);
if (dockStatus != null) {
mIsDocked = dockStatus.getIntExtra(Intent.EXTRA_DOCK_STATE, -1)
!= Intent.EXTRA_DOCK_STATE_UNDOCKED;
}
// Register to get the alarm killed/snooze/dismiss intent.
IntentFilter filter = new IntentFilter(Alarms.ALARM_KILLED);
filter.addAction(Alarms.ALARM_SNOOZE_ACTION);
filter.addAction(Alarms.ALARM_DISMISS_ACTION);
registerReceiver(mReceiver, filter);
}
private void setTitle() {
final String titleText = mAlarm.getLabelOrDefault(this);
TextView tv = (TextView) findViewById(R.id.alertTitle);
tv.setText(titleText);
setTitle(titleText);
}
protected int getLayoutResId() {
return R.layout.alarm_alert;
}
private void updateLayout() {
if (LOG) {
Log.v("AlarmAlertFullScreen - updateLayout");
}
final LayoutInflater inflater = LayoutInflater.from(this);
final View view = inflater.inflate(getLayoutResId(), null);
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
setContentView(view);
/* Set the title from the passed in alarm */
setTitle();
mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
mGlowPadView.setOnTriggerListener(this);
triggerPing();
}
private void triggerPing() {
if (mPingEnabled) {
mGlowPadView.ping();
if (ENABLE_PING_AUTO_REPEAT) {
mPingHandler.sendEmptyMessageDelayed(PING_MESSAGE_WHAT, PING_AUTO_REPEAT_DELAY_MSEC);
}
}
}
// Attempt to snooze this alert.
private void snooze() {
if (LOG) {
Log.v("AlarmAlertFullScreen - 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);
String snoozeTimeStr = Alarms.formatTime(this, c);
String label = mAlarm.getLabelOrDefault(this);
// Notify the user that the alarm has been snoozed.
Intent dismissIntent = new Intent(this, AlarmReceiver.class);
dismissIntent.setAction(Alarms.CANCEL_SNOOZE);
dismissIntent.putExtra(Alarms.ALARM_INTENT_EXTRA, mAlarm);
Intent openAlarm = new Intent(this, DeskClock.class);
openAlarm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
openAlarm.putExtra(Alarms.ALARM_INTENT_EXTRA, mAlarm);
openAlarm.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.CLOCK_TAB_INDEX);
NotificationManager nm = getNotificationManager();
Notification notif = new Notification.Builder(getApplicationContext())
.setContentTitle(label)
.setContentText(getResources().getString(R.string.alarm_alert_snooze_until, snoozeTimeStr))
.setSmallIcon(R.drawable.stat_notify_alarm)
.setOngoing(true)
.setAutoCancel(false)
.setPriority(Notification.PRIORITY_MAX)
.setWhen(0)
.addAction(android.R.drawable.ic_menu_close_clear_cancel,
getResources().getString(R.string.alarm_alert_dismiss_text),
PendingIntent.getBroadcast(this, mAlarm.id, dismissIntent, 0))
.build();
notif.contentIntent = PendingIntent.getActivity(this, mAlarm.id, openAlarm, 0);
nm.notify(mAlarm.id, notif);
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, boolean replaced) {
if (LOG) {
Log.v("AlarmAlertFullScreen - dismiss");
}
Log.i("Alarm id=" + mAlarm.id + (killed ? (replaced ? " replaced" : " killed") : " dismissed by user"));
// 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));
}
if (!replaced) {
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) Log.v("AlarmAlert.OnNewIntent()");
mAlarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
setTitle();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (LOG) {
Log.v("AlarmAlertFullScreen - onConfigChanged");
}
updateLayout();
super.onConfigurationChanged(newConfig);
}
@Override
protected void onResume() {
super.onResume();
if (LOG) {
Log.v("AlarmAlertFullScreen - onResume");
}
// If the alarm was deleted at some point, disable snooze.
if (Alarms.getAlarm(getContentResolver(), mAlarm.id) == null) {
mGlowPadView.setTargetResources(R.array.dismiss_drawables);
mGlowPadView.setTargetDescriptionsResourceId(R.array.dismiss_descriptions);
mGlowPadView.setDirectionDescriptionsResourceId(R.array.dismiss_direction_descriptions);
}
// The activity is locked to the default orientation as a default set in the manifest
// Override this settings if the device is docked or config set it differently
if (getResources().getBoolean(R.bool.config_rotateAlarmAlert) || mIsDocked) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (LOG) Log.v("AlarmAlertFullScreen.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;
if (LOG) {
Log.v("AlarmAlertFullScreen - dispatchKeyEvent " + event.getKeyCode());
}
switch (event.getKeyCode()) {
// Volume keys and camera keys dismiss the alarm
case KeyEvent.KEYCODE_POWER:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:
case KeyEvent.KEYCODE_CAMERA:
case KeyEvent.KEYCODE_FOCUS:
if (up) {
switch (mVolumeBehavior) {
case 1:
snooze();
break;
case 2:
dismiss(false, false);
break;
default:
break;
}
}
return true;
default:
break;
}
return super.dispatchKeyEvent(event);
}
@Override
public void onBackPressed() {
// Don't allow back to dismiss. This method is overriden by AlarmAlert
// so that the dialog is dismissed.
if (LOG) {
Log.v("AlarmAlertFullScreen - onBackPressed");
}
return;
}
@Override
public void onGrabbed(View v, int handle) {
mPingEnabled = false;
}
@Override
public void onReleased(View v, int handle) {
mPingEnabled = true;
triggerPing();
}
@Override
public void onTrigger(View v, int target) {
final int resId = mGlowPadView.getResourceIdForTarget(target);
switch (resId) {
case R.drawable.ic_alarm_alert_snooze:
snooze();
break;
case R.drawable.ic_alarm_alert_dismiss:
dismiss(false, false);
break;
default:
// Code should never reach here.
Log.e("Trigger detected on unhandled resource. Skipping.");
}
}
@Override
public void onGrabbedStateChange(View v, int handle) {
}
@Override
public void onFinishFinalAnimation() {
}
}