/*
This file is part of BeepMe.
BeepMe is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
BeepMe is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BeepMe. If not, see <http://www.gnu.org/licenses/>.
Copyright 2012-2014 Michael Glanznig
http://beepme.yourexp.at
*/
package com.glanznig.beepme;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.ref.WeakReference;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import com.glanznig.beepme.data.PreferenceHandler;
import com.glanznig.beepme.data.Sample;
import com.glanznig.beepme.data.TimerProfile;
import com.glanznig.beepme.db.SampleTable;
import com.glanznig.beepme.db.ScheduledBeepTable;
import com.glanznig.beepme.db.StorageHandler;
import com.glanznig.beepme.db.TimerProfileTable;
import com.glanznig.beepme.db.UptimeTable;
import com.glanznig.beepme.helper.AsyncImageScaler;
import com.glanznig.beepme.helper.PhotoUtils;
import com.glanznig.beepme.view.BeepActivity;
import com.glanznig.beepme.view.ExportActivity;
import com.glanznig.beepme.view.MainActivity;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Application;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;
public class BeeperApp extends Application { //implements SharedPreferences.OnSharedPreferenceChangeListener {
private PreferenceHandler preferences = null;
private TimerProfile timerProfile;
private BeeperApp.CallStateListener callStateListener;
private static final int ALARM_INTENT_ID = 5332;
private static final int NOTIFICATION_ID = 1283;
private static final String TAG = "BeeperApp";
public static final int BEEPER_INACTIVE = 0;
public static final int BEEPER_ACTIVE = 1;
public static final int BEEPER_INACTIVE_AFTER_CALL = 2;
public PreferenceHandler getPreferences() {
if (preferences == null) {
preferences = new PreferenceHandler(this.getApplicationContext());
//preferences.registerOnPreferenceChangeListener(BeeperApp.this);
}
return preferences;
}
public boolean isBeeperActive() {
int active = getPreferences().getBeeperActive();
if (active == BEEPER_ACTIVE) {
return true;
}
return false;
}
public void setBeeperActive(int active) {
UptimeTable uptimeTbl = new UptimeTable(this.getApplicationContext(), timerProfile);
getPreferences().setBeeperActive(active);
if (active == BEEPER_ACTIVE) {
getPreferences().setUptimeId(uptimeTbl.startUptime(Calendar.getInstance().getTime()));
createNotification();
}
else {
long uptimeId = getPreferences().getUptimeId();
if (uptimeId != 0L) {
uptimeTbl.endUptime(uptimeId, Calendar.getInstance().getTime());
getPreferences().setUptimeId(0L);
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(TAG, NOTIFICATION_ID);
}
}
}
private void createNotification() {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
if (this.getPreferences().isTestMode()) {
notificationBuilder.setSmallIcon(R.drawable.ic_stat_notify_testmode);
notificationBuilder.setContentTitle(getString(R.string.notify_title_testmode));
}
else {
notificationBuilder.setSmallIcon(R.drawable.ic_stat_notify);
notificationBuilder.setContentTitle(getString(R.string.notify_title));
}
notificationBuilder.setContentText(getString(R.string.notify_content));
//set as ongoing, so it cannot be cleared
notificationBuilder.setOngoing(true);
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(resultPendingIntent);
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
// notification_id allows you to update the notification later on.
manager.notify(TAG, NOTIFICATION_ID, notificationBuilder.build());
}
@Override
public void onCreate() {
super.onCreate();
getPreferences();
setTimerProfile();
onAppUpdate(getPreferences().getAppVersion());
// save thumbnail sizes
DisplayMetrics metrics = this.getResources().getDisplayMetrics();
int screenDpWidth = (int)(metrics.widthPixels / metrics.density + 0.5f);
int[] sizes = {48, 64, screenDpWidth};
getPreferences().setThumbnailSizes(sizes);
// listen to call events
if (callStateListener == null) {
callStateListener = new CallStateListener(BeeperApp.this);
}
TelephonyManager telManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telManager.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
//set export running to false
getPreferences().setExportRunningSince(0L);
UptimeTable uptimeTbl = new UptimeTable(this.getApplicationContext(), timerProfile);
if (isBeeperActive()) {
long scheduledBeepId = getPreferences().getScheduledBeepId();
//is there a scheduled beep, if no, create one, if yes and it is expired, create a new one
if (scheduledBeepId != 0L) {
ScheduledBeepTable sbt = new ScheduledBeepTable(this.getApplicationContext());
if (sbt.getStatus(scheduledBeepId) != 3 && sbt.isExpired(scheduledBeepId)) {
expireTimer();
setTimer();
}
}
else {
setTimer();
}
//is there a notification, if no, create one
//cannot check if there is a notification or not, so call create, it will be replaced
createNotification();
//is there a open uptime interval, if no, create one
long uptimeId = getPreferences().getUptimeId();
if (uptimeId == 0L) {
getPreferences().setUptimeId(uptimeTbl.startUptime(Calendar.getInstance().getTime()));
}
}
else {
long scheduledBeepId = getPreferences().getScheduledBeepId();
//is there a scheduled beep, if yes, cancel it
if (scheduledBeepId != 0L) {
cancelTimer();
}
//cancel notifications
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(TAG, NOTIFICATION_ID);
manager.cancel(TAG, ExportActivity.EXPORT_RUNNING_NOTIFICATION);
//is there a open uptime interval, if yes, end it
long uptimeId = getPreferences().getUptimeId();
if (uptimeId != 0L) {
uptimeTbl.endUptime(uptimeId, Calendar.getInstance().getTime());
getPreferences().setUptimeId(0L);
}
}
}
public void setTimerProfile() {
//long profileId = preferences.getTimerProfileId();
long profileId = 1;
timerProfile = new TimerProfileTable(this.getApplicationContext()).getTimerProfile(profileId);
}
public TimerProfile getTimerProfile() {
return timerProfile;
}
public void setTimer() {
if (isBeeperActive()) {
Calendar alarmTime = Calendar.getInstance();
Calendar alarmTimeUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
if (timerProfile == null) {
setTimerProfile();
}
long timer = timerProfile.getTimer(this.getApplicationContext());
alarmTime.add(Calendar.SECOND, (int)timer);
//Log.i(TAG, "alarm in " + timer + " seconds.");
alarmTimeUTC.add(Calendar.SECOND, (int)timer);
getPreferences().setScheduledBeepId(new ScheduledBeepTable(
this.getApplicationContext()).addScheduledBeep(alarmTime.getTimeInMillis(),
getPreferences().getUptimeId()));
Intent intent = new Intent(this, BeepActivity.class);
PendingIntent alarmIntent = PendingIntent.getActivity(this, ALARM_INTENT_ID, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager manager = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
manager.set(AlarmManager.RTC_WAKEUP, alarmTimeUTC.getTimeInMillis(), alarmIntent);
}
}
public void declineTimer() {
updateTimer(4);
}
public void acceptTimer() {
updateTimer(3);
}
public void expireTimer() {
updateTimer(2);
}
public void cancelTimer() {
updateTimer(1);
}
public void updateTimer(int status) {
if (status != 3 || status != 4) {
Intent intent = new Intent(this, BeepActivity.class);
PendingIntent alarmIntent = PendingIntent.getActivity(this, ALARM_INTENT_ID, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
alarmIntent.cancel();
}
new ScheduledBeepTable(this.getApplicationContext()).updateStatus(getPreferences().getScheduledBeepId(), status);
if (status != 3) {
getPreferences().setScheduledBeepId(0L);
}
}
public void beep() {
if (isBeeperActive()) {
Intent beep = new Intent(BeeperApp.this, BeepActivity.class);
beep.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(beep);
}
}
/*@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(PreferenceHandler.KEY_TIMER_PROFILE_ID)) {
if (isBeeperActive()) {
setBeeperActive(BEEPER_INACTIVE);
setTimerProfile();
setBeeperActive(BEEPER_ACTIVE);
}
else {
setTimerProfile();
}
}
}*/
private void onAppUpdate(int oldVersion) {
try {
PackageInfo packageInfo = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
int newVersion = packageInfo.versionCode;
//if (oldVersion > 0 && oldVersion != newVersion) {
// if should be above line, change in future versions
if (oldVersion < newVersion) {
for (int mVers = oldVersion; mVers < newVersion; mVers++) {
switch (mVers) {
case 16:
String dbName;
String picDirName;
if (getPreferences().isTestMode()) {
dbName = StorageHandler.getTestModeDatabaseName();
picDirName = PhotoUtils.TEST_MODE_DIR;
}
else {
dbName = StorageHandler.getProductionDatabaseName();
picDirName = PhotoUtils.NORMAL_MODE_DIR;
}
// rename the database
if (!dbName.equals(StorageHandler.DB_OLD_NAME)) {
File oldDb = getDatabasePath(StorageHandler.DB_OLD_NAME);
File newDb = new File(oldDb.getParentFile(), dbName);
oldDb.renameTo(newDb);
}
// move pictures
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File oldDir = this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File newDir = new File(oldDir.getAbsolutePath(), picDirName);
if (!newDir.exists()) {
newDir.mkdirs();
}
File[] picFiles = oldDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".jpg");
}
});
for (int i = 0; i < picFiles.length; i++) {
picFiles[i].renameTo(new File(newDir, picFiles[i].getName()));
}
SampleTable st = new SampleTable(this);
List<Sample> list = st.getSamples();
for (int i = 0; i < list.size(); i++) {
Sample s = list.get(i);
String uri = s.getPhotoUri();
if (uri != null) {
File pic = new File(uri);
s.setPhotoUri(pic.getParent() + File.separator + picDirName + File.separator + pic.getName());
st.editSample(s);
}
}
}
break;
}
}
} // else we would have a new install or the data had been deleted
getPreferences().setAppVersion(newVersion);
}
catch(PackageManager.NameNotFoundException nnfe) {}
}
private static class CallStateListener extends PhoneStateListener {
private WeakReference<BeeperApp> appRef;
public CallStateListener(BeeperApp app) {
appRef = new WeakReference<BeeperApp>(app);
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (appRef != null && appRef.get() != null) {
BeeperApp app = appRef.get();
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
app.getPreferences().setCall(false);
// beeper was paused by call, reactivate it
if (app.getPreferences().getBeeperActive() == BeeperApp.BEEPER_INACTIVE_AFTER_CALL) {
app.setBeeperActive(BeeperApp.BEEPER_ACTIVE);
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
app.getPreferences().setCall(true);
break;
case TelephonyManager.CALL_STATE_RINGING:
app.getPreferences().setCall(true);
break;
}
}
}
}
}