/*
* Copyright (C) 2010 Enrique Lara (enrique.posix2.lara@gmail.com)
*
* 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 app.timetogo;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Vibrator;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import app.timetogo.model.Alarm;
import app.timetogo.provider.Projections;
public final class Klaxon extends Service {
private static final String TAG = "Klaxon";
/** Play alarm up to 10 minutes before silencing */
private static final int ALARM_TIMEOUT_SECONDS = 10 * 60;
private Ringtone ringtone = null;
private Vibrator vibrator = null;
private Alarm mCurrentAlarm = null;
private TelephonyManager telephonyManager;
private int mInitialCallState;
public Klaxon() {
}
@Override
public IBinder onBind(final Intent intent) {
return mBinder;
}
private final IBinder mBinder = new LocalBinder();
public final class LocalBinder extends Binder {
Klaxon getService() {
return Klaxon.this;
}
}
// Internal messages
private static final int KILLER = 1000;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(final Message msg) {
switch (msg.what) {
case KILLER:
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "*********** Alarm killer triggered ***********");
}
sendKillBroadcast((Alarm) msg.obj);
stopSelf();
break;
default:
}
}
};
private final PhoneStateListener phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(final int state, final String ignored) {
// The user might already be in a call when the alarm fires. When
// we register onCallStateChanged, we get the initial in-call state
// which kills the alarm. Check against the initial call state so
// we don't kill the alarm during a call.
if ((state != TelephonyManager.CALL_STATE_IDLE) && (state != mInitialCallState)) {
sendKillBroadcast(mCurrentAlarm);
stopSelf();
}
}
};
@Override
public void onCreate() {
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
// Listen for incoming calls to kill the alarm.
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
AlertWakeLock.acquireCpuWakeLock(this);
}
@Override
public void onDestroy() {
stop();
// Stop listening for incoming calls.
telephonyManager.listen(phoneStateListener, 0);
AlertWakeLock.releaseCpuLock();
}
@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
// No intent, tell the system not to restart us.
if (intent == null) {
stopSelf();
return START_NOT_STICKY;
}
final Uri uri = intent.getData();
final Cursor cursor = getContentResolver().query(uri, Projections.AlarmsAll.PROJECTION, null, null, null);
Alarm a = null;
if ((cursor != null) && cursor.moveToFirst()) {
a = new Alarm(uri, this);
a.init(cursor);
if (!a.isSilent()) {
final Uri ringtoneUri = Uri.parse(a.getRingtone());
ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
}
} else {
Log.d(TAG, "Klaxon failed intialize alarm from the intent");
stopSelf();
return START_NOT_STICKY;
}
if (mCurrentAlarm != null) {
sendKillBroadcast(mCurrentAlarm);
}
play(a);
mCurrentAlarm = a;
// Record the initial call state here so that the new alarm has the newest state.
mInitialCallState = telephonyManager.getCallState();
return START_STICKY;
}
private void play(final Alarm a) {
if (a.isVibrate()) {
vibrator.vibrate(Settings.getVibratePattern(), 0);
} else {
vibrator.cancel();
}
if (!a.isSilent() && (ringtone != null)) {
ringtone.play();
}
enableKiller(a);
// mPlaying = true;
}
protected void stop() {
vibrator.cancel();
if (ringtone != null) {
ringtone.stop();
}
disableKiller();
}
private void sendKillBroadcast(final Alarm alarm) {
//XXX n/s what to sendKillBroadcast for/to.
// long millis = System.currentTimeMillis() - mStartTime;
// int minutes = (int) Math.round(millis / 60000.0);
// Intent alarmKilled = new Intent(Alarms.ALARM_KILLED);
// alarmKilled.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
// alarmKilled.putExtra(Alarms.ALARM_KILLED_TIMEOUT, minutes);
// sendBroadcast(alarmKilled);
}
private void enableKiller(final Alarm alarm) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(KILLER, alarm), 1000 * ALARM_TIMEOUT_SECONDS);
}
private void disableKiller() {
mHandler.removeMessages(KILLER);
}
}
|