package cri.sanity;
import cri.sanity.util.*;
import java.io.File;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
public class RecService extends Service
{
public static final int NID = 2;
public static final int INCOMING = 1;
public static final int OUTGOING = 2;
public static final int ACT_HEADSET_SKIP = 0;
public static final int ACT_HEADSET_ON = 1;
//public static final int ACT_HEADSET_OFF = 2;
private static final int TASK_EXEC = Task.idNew();
private static final int TASK_LIMIT = Task.idNew();
private static long ts = 0;
private static boolean running = false;
private static boolean autoStart = false;
private static boolean autoStop = false;
private static boolean autoStartSpeaker = false;
private static boolean autoStopSpeaker = false;
private static int autoStartDelay = 0;
private static int autoStopDelay = 0;
private static int autoStopLimit = 0;
private static int autoStartTimes = 0;
private static boolean headsetStart = false;
private static boolean headsetStop = false;
private static boolean headsetOnStart = false;
private static boolean headsetOnStop = false;
private static PhoneListener pl;
private static Rec rec;
private static String notifLimit, notifTitle;
private static Notification notif;
private static PendingIntent notifIntent;
private static Task taskRecStart, taskRecStop, taskRecLimit;
//---- public static api
public static final boolean isRunning() { return running; }
public static final boolean isRecord () { return rec!=null && rec.isStarted(); }
public static final void start(PhoneListener phoneListener) {
if(running) return;
ts = 0;
pl = phoneListener;
rec = new Rec(A.geti(K.REC_SRC), A.geti(K.REC_FMT));
notifLimit = A.is(K.NOTIFY_REC_STOP) ? A.s(A.isFull()? R.string.msg_rec_limit : R.string.msg_rec_free_limit) : null;
autoInit();
buildTasks();
startService();
notifyStatus();
}
public static final void stop() {
if(!running) return;
stopService();
Task.stop(TASK_LIMIT, TASK_EXEC);
if(rec != null) { rec.release(); rec = null; }
if(pl != null) { pl.speakerListener = null; pl = null; }
notif = null;
notifIntent = null;
notifLimit = null;
taskRecStart = null;
taskRecStop = null;
taskRecLimit = null;
//running = false;
A.notifyCanc(NID);
}
public static final void recStart(int delay) { if(taskRecStart != null) taskRecStart.exec(TASK_EXEC, delay); }
public static final void recStop (int delay) { if(taskRecStop != null) taskRecStop .exec(TASK_EXEC, delay); }
public static final void checkAutoRec() {
if(rec==null || rec.isStarted()) return;
final int d = A.geti(K.REC_START_DIR);
if( d == INCOMING) { if( pl.isOutgoing()) noAutoStart(); }
else if(d == OUTGOING) { if(!pl.isOutgoing()) noAutoStart(); }
if(autoStart && !CallFilter.instance().includes(pl.phoneNumber(),"rec",true)) noAutoStart();
setSpeakerListener();
if(!autoStart) return;
if(headsetStart) {
if(headsetOnStart == pl.isHeadsetOn())
recStartOffhook();
}
else if(!autoStartSpeaker || A.audioMan().isSpeakerphoneOn())
recStartOffhook();
}
public static final void updateHeadset(boolean on) {
if(rec == null) return;
if(rec.isStarted()) {
if(!headsetStop || on!=headsetOnStop) return;
recStopAuto();
} else {
if(!headsetStart || on!=headsetOnStart) return;
recStartAuto();
}
}
public static final void cron() {
final int daysLife = A.geti(K.REC_AUTOREMOVE);
if(daysLife <= 0) return;
final long now = A.time();
final long recheck = daysLife>3 ? daysLife>7 ? 86400000*3 : 86400000 : 86400000/2;
try { if(now-A.getl(K.CRON) < recheck) return; } catch(Exception e) {}
final String dir = A.sdcardDir();
if(dir == null) return;
final String prefix = Conf.REC_PREFIX;
final String extprf = Conf.PRF_EXT;
final long threshold = now - ((long)daysLife)*86400000;
for(File f : new File(dir).listFiles()) {
final String name = f.getName();
if(name.startsWith(prefix) && !name.endsWith(extprf) && !name.endsWith(".txt") && f.isFile() && f.lastModified()<threshold)
f.delete();
}
A.putc(K.CRON, now);
}
//---- public Service override
@Override
public IBinder onBind(Intent intent) { return null; }
@Override
public int onStartCommand(Intent i, int flags, int id) {
if(!MainService.isRunning()) return quit();
if(i == null) return START_STICKY;
final long now = SystemClock.elapsedRealtime();
if(now-ts < Conf.SERVICE_TIMEOUT) return START_STICKY;
ts = now;
if(!running) running = true;
else if(rec == null) return quit();
else {
if(rec.isStarted()) recStop (0);
else recStart(0);
try { Dev.iTel().showCallScreen(); } catch(Exception e) {}
}
return START_STICKY;
}
@Override
public void onDestroy() {
A.notifyCanc(NID);
running = false;
super.onDestroy();
}
//---- private api
private int quit() {
A.notifyCanc(NID);
stopSelf();
return START_STICKY;
}
private static void startService() {
final Context ctx = A.app();
ctx.startService(new Intent(ctx, RecService.class));
}
private static void stopService() {
final Context ctx = A.app();
ctx.stopService(new Intent(ctx, RecService.class));
}
private static void recStartAuto() {
if(!autoStart) return;
recStart(autoStartDelay);
autoStart = --autoStartTimes != 0;
}
private static void recStopAuto() {
if(!autoStop) return;
recStop(autoStopDelay);
}
private static void notifyStatus() {
final Context ctx = A.app();
if(notif == null) {
notifIntent = PendingIntent.getService(ctx, 0, new Intent(ctx, RecService.class), 0);
notif = new Notification();
notif.flags = Notification.FLAG_ONGOING_EVENT|Notification.FLAG_NO_CLEAR;
notifTitle = A.s(R.string.msg_rec_title);
}
if(rec == null) {
A.notifyCanc(NID);
return;
}
if(rec.isStarted()) {
notif.icon = R.drawable.ic_rec_bar;
notif.setLatestEventInfo(ctx, notifTitle, A.s(R.string.msg_rec_stop), notifIntent);
} else {
notif.icon = R.drawable.ic_bar;
notif.setLatestEventInfo(ctx, notifTitle, A.s(R.string.msg_rec_start), notifIntent);
}
notif.when = A.time();
A.notifyCanc();
A.notifMan().notify(NID, notif);
}
private static void applyLimit() {
if(taskRecLimit == null) return;
taskRecLimit.exec(TASK_LIMIT, autoStopLimit);
}
// for automatic start recording on offhook
private static void recStartOffhook() {
final int delay = (pl.isOutgoing() ? Conf.FORCE_AUTOSPEAKER_DELAY : 0) + Conf.REC_OFFHOOK_DELAY;
recStart(Math.max(autoStartDelay, delay));
}
// setup auto start/stop when speaker is turned on/off
private static void setSpeakerListener() {
if(!autoStartSpeaker && !autoStopSpeaker)
pl.speakerListener = null;
else
pl.speakerListener = new SpeakerListener() {
@Override
public void onSpeakerChanged(boolean enabled) {
if(enabled) { if(autoStartSpeaker) recStartAuto(); }
else { if(autoStopSpeaker ) recStopAuto (); }
}
};
}
private static void buildTasks() {
taskRecStart = new Task() {
@Override
public void run() {
try {
if(rec==null || rec.isStarted() || !Dev.isOffhook()) return;
if(A.empty(rec.suffix)) {
if(pl == null) { stopService(); return; }
rec.suffix = Conf.REC_SEP + (pl.isOutgoing()? "out" : "in");
final String s = pl.phoneNumber();
if(!A.empty(s)) rec.suffix += Conf.REC_SEP + A.cleanFn(s,true);
}
rec.start();
applyLimit();
notifyStatus();
} catch(Exception e) {}
}
};
taskRecStop = new Task() {
@Override
public void run() {
try {
if(rec==null || !rec.isStarted()) return;
rec.stop();
notifyStatus();
} catch(Exception e) {}
}
};
taskRecLimit = autoStopLimit<=0? null : new Task(){
@Override
public void run() {
try {
if(rec==null || !rec.isStarted()) return;
rec.stop();
if(notifLimit != null) A.notify(notifLimit);
notifyStatus();
} catch(Exception e) {}
}
};
}
private static void autoInit() {
autoStart = A.is(K.REC_START);
autoStop = A.is(K.REC_STOP);
autoStopLimit = A.isFull()? autoStop? A.geti(K.REC_STOP_LIMIT)*60000 : 0 : Conf.REC_FREE_LIMIT;
// setup auto start
if(!autoStart)
noAutoStart();
else {
autoStartDelay = A.geti(K.REC_START_DELAY);
autoStartTimes = A.geti(K.REC_START_TIMES);
autoStartSpeaker = pl.hasAutoSpeaker() && A.is(K.REC_START_SPEAKER);
final int act = A.geti(K.REC_START_HEADSET);
headsetStart = act != ACT_HEADSET_SKIP;
headsetOnStart = act == ACT_HEADSET_ON;
}
// setup auto stop
if(autoStop) {
autoStopDelay = A.geti(K.REC_STOP_DELAY);
autoStopSpeaker = pl.hasAutoSpeaker() && A.is(K.REC_STOP_SPEAKER);
final int act = A.geti(K.REC_STOP_HEADSET);
headsetStop = act != ACT_HEADSET_SKIP;
headsetOnStop = act == ACT_HEADSET_ON;
} else {
autoStopDelay = 0;
autoStopSpeaker = false;
headsetStop = false;
}
}
private static void noAutoStart() {
autoStart = false;
autoStartDelay = 0;
autoStartTimes = 0;
autoStartSpeaker = false;
headsetStart = false;
}
}