Java tutorial
// Copyright 2012 (C) Matthew Brejza // // This program 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. // // This program 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. package com.brejza.matt.habmodem; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import rtty.StringRxEvent; import rtty.rtty_receiver; import ukhas.AscentRate; import ukhas.Gps_coordinate; import ukhas.HabitatRxEvent; import ukhas.Habitat_interface; import ukhas.Listener; import ukhas.Payload; import ukhas.TelemetryConfig; import ukhas.Telemetry_string; import android.app.NotificationManager; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Color; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.media.MediaRecorder.AudioSource; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.widget.Toast; public class Dsp_service extends Service implements StringRxEvent, HabitatRxEvent { public final static String TELEM_RX = "com.brejza.matt.habmodem.TELEM_RX"; public final static String CHAR_RX = "com.brejza.matt.habmodem.CHAR_RX"; public final static String CHARS = "com.brejza.matt.habmodem.CHARS"; public final static String FFT_UPDATED = "com.brejza.matt.habmodem.FFT_UPDATED"; public final static String HABITAT_NEW_DATA = "com.brejza.matt.habmodem.HABITAT_NEW_DATA"; public final static String TELEM_STR = "com.brejza.matt.habmodem.TELEM_STR"; public final static String GPS_UPDATED = "com.brejza.matt.habmodem.GPS_UPDATED"; public final static String LOG_EVENT = "com.brejza.matt.habmodem.LOG_EVENT"; public final static String LOG_STR = "com.brejza.matt.habmodem.LOG_STR"; // Binder given to clients private final IBinder mBinder = new LocalBinder(); rtty_receiver rcv = new rtty_receiver(); private AudioRecord mRecorder; private AudioTrack mPlayer; int buffsize; boolean isRecording = false; boolean usingMic = false; HeadsetReceiver headsetReceiver; private int _baud = 300; private int last_colour = 0; Telemetry_string last_str; boolean _enableChase = false; boolean _enablePosition = false; private boolean enableEcho = false; public boolean enableBell = false; public boolean enableUploader = true; private boolean _enableDecoder = false; Timer updateTimer; Timer serviceInactiveTimer; private int lastHabitatFreq = 0; NotificationManager nm; Handler handler; Toast toast; public double currentLatitude = 0; public double currentLongitude = 0; public boolean currentLocationValid = false; private Location_handler loc_han; private LocationManager locationManager; //private long chasecarUpdateSecs = 45; private long lastChasecarUpdate = 0; //moving_average ascent_rates; LoggingQueue log = new LoggingQueue(200); Habitat_interface hab_con; public List<String> listRxStr = Collections.synchronizedList(new ArrayList<String>()); private ConcurrentHashMap<String, Payload> mapPayloads = new ConcurrentHashMap<String, Payload>(); public Dsp_service() { rcv.addStringRecievedListener(this); } @Override public void onCreate() { super.onCreate(); System.out.println("Service started"); } @Override public IBinder onBind(Intent arg0) { if (!isRecording) serviceRestart(); if (serviceInactiveTimer != null) { serviceInactiveTimer.cancel(); serviceInactiveTimer = null; logEvent("Stopping Inactivity Timer", false); } System.out.println("DEBUG : something bound"); handler = new Handler(); //string receiver if (headsetReceiver == null) headsetReceiver = new HeadsetReceiver(); IntentFilter intentFilter1 = new IntentFilter(Intent.ACTION_HEADSET_PLUG); registerReceiver(headsetReceiver, intentFilter1); if (hab_con == null) { String call_u = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()) .getString("pref_callsign", "USER"); hab_con = new Habitat_interface( PreferenceManager.getDefaultSharedPreferences(this).getString("pref_habitat_server", "habitat.habhub.org"), PreferenceManager.getDefaultSharedPreferences(this).getString("pref_habitat_db", "habitat"), new Listener(call_u, new Gps_coordinate(50.2, -0.6, 0), false)); //hab_con.upload_payload_telem(new Telemetry_string("$$ASTRA,12:12:12,5044.11111,-001.00000,1212,34*1234")); hab_con.addGetActiveFlightsTask(); hab_con.addHabitatRecievedListener(this); } if (loc_han == null) { loc_han = new Location_handler(); this.locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); } hab_con.device = android.os.Build.BRAND + " " + android.os.Build.MODEL; hab_con.device_software = android.os.Build.VERSION.RELEASE; hab_con.application = "HAB Modem for Android"; String vers = "unknown"; try { Context cn = getApplicationContext(); vers = cn.getPackageManager().getPackageInfo(cn.getPackageName(), 0).versionName; } catch (NameNotFoundException e) { System.out.println("Cannot get version number - " + e.toString()); } hab_con.application_version = vers; //System.out.println("Starting audio"); return mBinder; } @Override public void onRebind(Intent intent) { if (!isRecording) serviceRestart(); if (serviceInactiveTimer != null) { serviceInactiveTimer.cancel(); serviceInactiveTimer = null; logEvent("Stopping Inactivity Timer", false); } System.out.println("REBOUND"); } @Override public boolean onUnbind(Intent intent) { System.out.println("DEBUG : something unbound"); startInactiveTimer(); return true; } @Override public void onDestroy() { if (headsetReceiver != null) unregisterReceiver(headsetReceiver); disableEcho(); if (mRecorder != null) { mRecorder.stop(); mRecorder.release(); } if (mPlayer != null) { mPlayer.stop(); mPlayer.release(); } nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); nm.cancel(0); System.out.println("Destroying service"); super.onDestroy(); } public class LocalBinder extends Binder { Dsp_service getService() { // Return this instance of LocalService so clients can call public methods return Dsp_service.this; } } public void changeLocationSettings(boolean enablePos, boolean enableChase) { if (!_enablePosition && !_enableChase && (enablePos || enableChase)) enableLocation(); if ((_enablePosition || _enableChase) && !enablePos && !enableChase) disableLocation(); _enablePosition = enablePos; _enableChase = enableChase; //Intent intent = new Intent(this, Map_Activity.class); //PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0); //icon at the bottom if (_enableChase) { } else { nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); nm.cancel(0); } } //doesnt need to be called when service first starts (but can be) public void serviceRestart() { startAudio(); if (countActivePayloads() > 0) { startUpdateTimer(); updateActivePayloadsHabitat(); } logEvent("Service Restarted", false); if (_enablePosition || _enableChase) enableLocation(); } public void servicePause() { isRecording = false; if (updateTimer != null) updateTimer.cancel(); logEvent("Service Paused", false); disableLocation(); } public int countActivePayloads() { int count = 0; for (Map.Entry<String, Payload> entry : mapPayloads.entrySet()) { if (entry.getValue().isActivePayload()) count++; } return count; } private void enableLocation() { //my location part Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); String bestProvider = this.locationManager.getBestProvider(criteria, true); if (bestProvider == null) return; System.out.println("STARTING GPS WITH: " + bestProvider); logEvent("Starting Location with: " + bestProvider, true); this.locationManager.requestLocationUpdates(bestProvider, 2000, 0, this.loc_han); } private void disableLocation() { if (locationManager != null) { locationManager.removeUpdates(this.loc_han); System.out.println("Disabling location"); } } public void startAudio() { if (!_enableDecoder) return; boolean mic = this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE); System.out.println("isRecording: " + isRecording); logEvent("Starting Audio. Mic avaliable: " + mic, false); if (!isRecording) { isRecording = true; buffsize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); buffsize = Math.max(buffsize, 3000); mRecorder = new AudioRecord(AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, buffsize); mPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2 * buffsize, AudioTrack.MODE_STREAM); if (enableEcho) { AudioManager manager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); manager.setMode(AudioManager.MODE_IN_CALL); manager.setSpeakerphoneOn(true); } if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) { mRecorder = new AudioRecord(AudioSource.DEFAULT, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, buffsize); if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) { logEvent("Error - Could not initialise audio", true); return; } logEvent("Using default audio source", false); } mRecorder.startRecording(); System.out.println("STARTING THREAD"); Thread ct = new captureThread(); logEvent("Starting Audio Thread.", false); setDecoderRunningNotification(); ct.start(); } } // public void stopAudio() //{ // isRecording = false; //} private void updateTimerPeriod() { int interval = 3 * 60 * 1000; String inter = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()) .getString("pref_habitat_update_freq", "3"); try { interval = Integer.parseInt(inter) * 60 * 1000; if (interval != lastHabitatFreq && updateTimer != null) { updateTimer.cancel(); updateTimer.purge(); updateTimer = null; startUpdateTimer(); } } catch (Exception e) { } } private void startUpdateTimer() { if (updateTimer == null) { logEvent("Starting Update Timer", false); updateTimer = new Timer(); int interval = 3 * 60 * 1000; String inter = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()) .getString("pref_habitat_update_freq", "3"); try { interval = Integer.parseInt(inter) * 60 * 1000; } catch (Exception e) { interval = 3 * 60 * 1000; } if (interval < 30 * 1000) interval = 30 * 1000; lastHabitatFreq = interval; updateTimer.scheduleAtFixedRate(new UpdateTimerTask(), interval, interval); } } private void startInactiveTimer() { if (serviceInactiveTimer != null) serviceInactiveTimer.cancel(); serviceInactiveTimer = new Timer(); int interval = 20 * 60 * 1000; String sin = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()) .getString("pref_inactive", "20"); try { interval = Integer.parseInt(sin) * 60 * 1000; } catch (Exception e) { interval = 20 * 60 * 1000; } if (interval < 30 * 1000) { interval = 20 * 60 * 1000; } logEvent("Starting Inactivity Timer for " + interval / (60 * 1000) + " Minutes", false); serviceInactiveTimer.schedule(new InactiveTimerTask(), interval); } class UpdateTimerTask extends TimerTask { public void run() { updateActivePayloadsHabitat(); logEvent("Starting Habitat Refresh", true); updateTimerPeriod(); } } class InactiveTimerTask extends TimerTask { public void run() { servicePause(); } } public Telemetry_string getLastString() { return last_str; } public boolean payloadExists(String callsign) { return (mapPayloads.containsKey(callsign.toUpperCase())); } public boolean activePayloadExists(String callsign) { if (mapPayloads.containsKey(callsign.toUpperCase())) { return mapPayloads.get(callsign.toUpperCase()).isActivePayload(); } else return false; } public TreeMap<Long, Telemetry_string> getPayloadData(String callsign) { if (payloadExists(callsign)) return mapPayloads.get(callsign.toUpperCase()).data; else return null; } public double getAscentRate(String callsign) { if (payloadExists(callsign)) return mapPayloads.get(callsign.toUpperCase()).getAscentRate(); else return 0; } public double getMaxAltitude(String callsign) { if (payloadExists(callsign)) return mapPayloads.get(callsign.toUpperCase()).getMaxAltitude(); else return 0; } //public long getLastUpsddate(String callsign){ // if (payloadExists(callsign)) // return mapPayloads.get(callsign.toUpperCase()).getLastUpdated(); // else // return 0; //} //TODO: if already there, update infos /* public void addActivePayload(String call){ String callu = call.toUpperCase(); if (!payloadExists(callu)) mapPayloads.put(callu,new Payload(call,true, 3)); else { Payload p = mapPayloads.get(callu); p.setIsActivePayload(true); } } */ public void addActivePayload(String call, int lookBehind) { startUpdateTimer(); String callu = call.toUpperCase(); if (!payloadExists(callu)) { Payload p = new Payload(call, newColour(), true, lookBehind); mapPayloads.put(callu, p); } else { Payload p = mapPayloads.get(callu); p.setIsActivePayload(true); if (p.colour == 0) p.setNewColour(newColour()); p.setMaxLookBehindSecs(lookBehind); } } public void removeActivePayload(String call) { mapPayloads.get(call.toUpperCase()).clearUserData(); } public double[] getFFT() { return rcv.get_fft(); } public double getFFT(int i) { return rcv.get_fft(i); } public int get_f1_FFTbin() { return (int) (rcv.get_f1() * (rcv.FFT_half_len * 2)); } public int get_f2_FFTbin() { return (int) (rcv.get_f2() * (rcv.FFT_half_len * 2)); } public List<String> getActivePayloadList() { List<String> out = new ArrayList<String>(); for (Map.Entry<String, Payload> entry : mapPayloads.entrySet()) { if (entry.getValue().isActivePayload()) out.add(entry.getValue().callsign); } return out; } public ConcurrentHashMap<String, Payload> getPayloadList() { //check for any new payload data in habitat interface for (Map.Entry<String, String> entry : hab_con.payload_configs.entrySet()) { String call = entry.getKey().toUpperCase(); if (payloadExists(call)) { //update records mapPayloads.get(call).setPayloadID(entry.getValue()); if (hab_con.flight_configs.containsKey(call)) mapPayloads.get(call).setFlightID(hab_con.flight_configs.get(call)); } else { //these payloads are not active if (hab_con.flight_configs.containsKey(entry.getKey().toUpperCase())) mapPayloads.put(call, new Payload(entry.getKey(), hab_con.payload_configs.get(call), hab_con.flight_configs.get(call))); else mapPayloads.put(call, new Payload(entry.getKey(), hab_con.payload_configs.get(call))); } } // out.add(entry.getKey()); return mapPayloads; } public TelemetryConfig getTelemetryConfig(String call) { if (payloadExists(call)) { return mapPayloads.get(call).telemetryConfig; } else return null; } public void enableEcho() { if (isRecording) { AudioManager manager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); manager.setMode(AudioManager.MODE_IN_CALL); manager.setSpeakerphoneOn(true); } enableEcho = true; } public void disableEcho() { AudioManager manager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); manager.setMode(AudioManager.MODE_NORMAL); manager.setSpeakerphoneOn(false); enableEcho = false; } class captureThread extends Thread { public void run() { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); short[] buffer = new short[buffsize]; double[] s = new double[buffsize]; mRecorder.startRecording(); isRecording = true; //AudioManager manager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); boolean lastHead = false; int clippingCount = 0; int samplesSinceToast = 0; logEvent("Starting Audio. Buffer Size: " + buffsize, true); // setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); buffsize = mRecorder.read(buffer, 0, buffsize); mPlayer.write(buffer, 0, buffsize); int readres; while (isRecording && _enableDecoder) { readres = mRecorder.read(buffer, 0, buffsize); if (readres < 10) { _enableDecoder = false; logEvent("Failed to get audio data, code " + readres, true); } else { if (usingMic && enableEcho) { mPlayer.write(buffer, 0, buffsize); if (mPlayer.getPlayState() != AudioTrack.PLAYSTATE_PLAYING && lastHead == true) mPlayer.play(); lastHead = true; } else { if (mPlayer.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { mPlayer.stop(); mPlayer.flush(); } lastHead = false; } if (buffsize >= 512) { int i; s = new double[buffsize]; for (i = 0; i < buffsize; i++) s[i] = (double) buffer[i]; i = 0; clippingCount = 0; while (i < buffsize) { if (buffer[i] > 30000 || buffer[i] < -30000) clippingCount++; i += 10; } if (clippingCount > 10) { if (samplesSinceToast <= 0 || samplesSinceToast > 8000 * 3) { samplesSinceToast = buffsize; System.out.println("Clipping detected"); handler.post(new Runnable() { @Override public void run() { if (toast != null) { toast.cancel(); toast = null; } toast = Toast.makeText(getApplicationContext(), "Clipping Detected", Toast.LENGTH_SHORT); toast.show(); } }); } } samplesSinceToast += buffsize; String rxchar = rcv.processBlock(s, _baud); Intent it = new Intent(CHAR_RX); it.putExtra(CHARS, rxchar); sendBroadcast(it); if (rcv.get_fft_updated()) sendBroadcast(new Intent(FFT_UPDATED)); } } } if (mPlayer != null) { if (mPlayer.getState() != AudioTrack.STATE_UNINITIALIZED) { mPlayer.stop(); mPlayer.release(); } } if (mRecorder != null) { if (mRecorder.getState() != AudioRecord.STATE_UNINITIALIZED) { mRecorder.stop(); mRecorder.release(); } } System.out.println("DONE RECORDING"); logEvent("Stopping Audio", true); isRecording = false; mRecorder = null; mPlayer = null; AudioManager manager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); manager.setMode(AudioManager.MODE_NORMAL); manager.setSpeakerphoneOn(false); nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); nm.cancel(1); } } public void enableDecoder() { _enableDecoder = true; startAudio(); } public void disableDecoder() { _enableDecoder = false; } public boolean getDecoderRunning() { return _enableDecoder; } public void updateActivePayloadsHabitat() { int count = 0; int maxRec = 3000; String smr = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()) .getString("pref_habitat_max_lines", "3000"); try { maxRec = Integer.parseInt(smr); } catch (Exception e) { maxRec = 3000; } if (maxRec < 10 || maxRec > 99999999) { maxRec = 3000; } for (Map.Entry<String, Payload> entry : mapPayloads.entrySet()) { if (entry.getValue().isActivePayload()) { count++; long start = entry.getValue().getUpdateStart(false); if (start + 15 < (System.currentTimeMillis() / 1000L)) { if (entry.getValue().getQueryOngoing() == 0 || entry.getValue().getQueryOngoing() < System.currentTimeMillis() - (60 * 1000)) { hab_con.addDataFetchTask(entry.getValue().callsign, start, (System.currentTimeMillis() / 1000L), maxRec);//entry.getValue().getMaxRecords()); entry.getValue().setQueryOngoing(System.currentTimeMillis()); } } } } if (count < 1) { if (updateTimer != null) { updateTimer.cancel(); logEvent("Cancelling habitat update timer - no active payloads", false); } } } public void StringRx(String str_, boolean checksum) { Telemetry_string str = new Telemetry_string(str_, null); TelemetryConfig tc = getTelemetryConfig(str.callsign); if (tc != null) str = new Telemetry_string(str_, tc); String call = str.callsign.toUpperCase(); if (!checksum && !mapPayloads.containsKey(call)) return; if (last_str == null) last_str = new Telemetry_string("", null); if (!str.raw_64_str().equals(last_str.raw_64_str())) { last_str = str; System.out.println("adding to list: " + str.getSentence().trim()); listRxStr.add(str.getSentence().trim()); logEvent("Decoded String - " + str.getSentence().trim(), true); if (checksum) { if (enableUploader) hab_con.upload_payload_telem(str); //upload received string to server if (serviceInactiveTimer != null) { startInactiveTimer(); } if (mapPayloads.containsKey(call)) { mapPayloads.get(call).setIsActivePayload(true); if (mapPayloads.get(call).colour == 0) mapPayloads.get(call).setNewColour(newColour()); mapPayloads.get(call).putPacket(str); if ((System.currentTimeMillis() / 1000L) - 60 < mapPayloads.get(call).getLastUpdated()) mapPayloads.get(call).setLastUpdatedNow(); //if there are no (big) gaps since last string add current time as last update } else { //first one, dont need to do anything special //TreeMap<Long,Telemetry_string> l = new TreeMap<Long,Telemetry_string>(); //l.put(Long.valueOf(str.time.getTime()),str); //listPayloadData.put(str.callsign.toUpperCase(),l); mapPayloads.put(call, new Payload(str, newColour())); startUpdateTimer(); updateActivePayloadsHabitat(); } if (str.coords != null) { if (str.coords.alt_valid) mapPayloads.get(call).putMaxAltitude(str.coords.altitude); } } else if (str.getSentence().length() > 10 && !payloadExists(str.callsign)) { mapPayloads.put(call, new Payload(call, newColour(), true)); } sendBroadcast(new Intent(TELEM_RX)); } } @Override public void HabitatRx(TreeMap<Long, Telemetry_string> data, boolean success, String callsign, long startTime, long endTime, AscentRate as, double maxAltitude) { mapPayloads.get(callsign.toUpperCase()).setQueryOngoing(0); if (success) { String call = callsign.toUpperCase(); System.out.println("DEBUG: Got " + data.size() + " sentences for payload " + callsign); logEvent("Habitat Query Got " + data.size() + " Sentences For Payload " + callsign, true); if (mapPayloads.containsKey(call)) { Payload p = mapPayloads.get(call); //if havnt already got a telem_config, see if one exists in hab_con if (p.telemetryConfig == null) { if (hab_con.getTelemConfigs().containsKey(call)) { p.telemetryConfig = hab_con.getTelemConfigs().get(call); } } long lt = p.getLastTime(); p.setLastUpdated(endTime); p.putPackets(data); p.setIsActivePayload(true); if (p.colour == 0) p.setNewColour(newColour()); if (data.size() > 0) { if (lt < Long.valueOf(data.lastKey())) { if (as != null) { if (as.valid()) p.ascentRate = as; } } } } else { Payload p = new Payload(callsign, newColour(), true); if (hab_con.getTelemConfigs().containsKey(call)) { p.telemetryConfig = hab_con.getTelemConfigs().get(call); } p.setLastUpdated(endTime); p.data = data; mapPayloads.put(call, p); if (as != null) { if (as.valid()) mapPayloads.get(call).ascentRate = as; } } mapPayloads.get(call).putMaxAltitude(maxAltitude); Intent i = new Intent(HABITAT_NEW_DATA); if (data.size() > 0) i.putExtra(TELEM_STR, data.get(data.lastKey()).getSentence()); sendBroadcast(i); } else { logEvent("Habitat Query Failed - " + callsign, true); } } public void logEvent(String event, boolean broadcast) { SimpleDateFormat sdfDate = new SimpleDateFormat("HH:mm:ss");//dd/MM/yyyy String s = sdfDate.format(new Date()) + " - " + event; if (broadcast) { Intent i = new Intent(LOG_EVENT); i.putExtra(LOG_STR, log.offerAndReturn(s)); sendBroadcast(i); } else log.offer(s); } public String getFromSettingsCallsign() { return PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()) .getString("pref_callsign", "USER"); } private class HeadsetReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { usingMic = false; if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) { //Do stuff if (intent.hasExtra("microphone")) { if (intent.getIntExtra("microphone", 0) == 1) { logEvent("Using Line In", true); usingMic = true; return; } else { logEvent("Not Using Line In", true); usingMic = false; } } else { logEvent("Headset: Not Using Line In", true); usingMic = false; } } } } public void setChaseCarNotification() { String body = "Uploading Chase Car Positions"; String title = "Chase Car"; NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_stat_car).setContentTitle(title).setAutoCancel(true) .setContentText(body); // Creates an explicit intent for an Activity in your app /* Intent resultIntent = new Intent(this, Map_Activity.class); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); // Adds the back stack for the Intent (but not the Intent itself) stackBuilder.addParentStack(Map_Activity.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 ); mBuilder.setContentIntent(resultPendingIntent); */ NotificationManager mNotificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); // mId allows you to update the notification later on. mNotificationManager.notify(0, mBuilder.build()); } public void setDecoderRunningNotification() { String body = "RTTY decoder is processing audio"; String title = "Decoder Running"; NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_stat_decoderrunning).setContentTitle(title).setContentText(body); NotificationManager mNotificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); // mId allows you to update the notification later on. mNotificationManager.notify(1, mBuilder.build()); } private int newColour() { if (last_colour == 0) { last_colour = 0xFFFF0000; return last_colour; } else { float lasthsv[] = new float[3]; Color.colorToHSV(last_colour, lasthsv); lasthsv[0] = (lasthsv[0] + (180 + 33)) % 360; last_colour = Color.HSVToColor(lasthsv); return last_colour; } } private int getChaseCarUpdatePeriod() { int t = 45; String st = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()) .getString("pref_chase_update_freq", "45"); try { t = Integer.parseInt(st); } catch (Exception e) { t = 45; } if (t < 10 || t > 60 * 60 * 24) t = 45; return t; } public class Location_handler implements LocationListener { public Location_handler() { } @Override public void onLocationChanged(Location location) { int chasecarUpdateSecs = getChaseCarUpdatePeriod(); if ((lastChasecarUpdate + chasecarUpdateSecs < System.currentTimeMillis() / 1000L) && _enableChase) { String call_u = getFromSettingsCallsign(); float speed = location.getSpeed(); hab_con.updateChaseCar(new Listener(call_u, new Gps_coordinate(location.getLatitude(), location.getLongitude(), location.getAltitude()), speed, true)); lastChasecarUpdate = System.currentTimeMillis() / 1000L; setChaseCarNotification(); } currentLatitude = location.getLatitude(); currentLongitude = location.getLongitude(); currentLocationValid = true; sendBroadcast(new Intent(GPS_UPDATED)); } @Override public void onProviderDisabled(String provider) { nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); nm.cancel(0); } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } } public boolean getEnableChase() { return _enableChase; } public boolean getEnablePosition() { return _enablePosition; } public boolean getEchoEnabled() { return enableEcho; } public Telemetry_string getMostRecent(String callsign) { if (mapPayloads.containsKey(callsign.toUpperCase())) { return mapPayloads.get(callsign.toUpperCase()).getLastString(); } else return null; } public LoggingQueue getLog() { return log; } public TreeMap<Long, Telemetry_string> getAllData(String callsign) { if (mapPayloads.containsKey(callsign.toUpperCase())) { return mapPayloads.get(callsign.toUpperCase()).data; } else return null; } public void setBaud(int baud) { _baud = baud; } public int getBaud() { return _baud; } public int getPayloadColour(String call) { call = call.toUpperCase(); if (payloadExists(call)) { int i = mapPayloads.get(call).colour; if (i == 0) i = 0xFF000000; return i; } return 0; } }