net.reichholf.dreamdroid.fragment.SignalFragment.java Source code

Java tutorial

Introduction

Here is the source code for net.reichholf.dreamdroid.fragment.SignalFragment.java

Source

/*  2010 Stephan Reichholf <stephan at reichholf dot net>
 * 
 * Licensed under the Create-Commons Attribution-Noncommercial-Share Alike 3.0 Unported
 * http://creativecommons.org/licenses/by-nc-sa/3.0/
 */

package net.reichholf.dreamdroid.fragment;

import net.reichholf.dreamdroid.R;
import net.reichholf.dreamdroid.fragment.abs.AbstractHttpFragment;
import net.reichholf.dreamdroid.fragment.helper.DreamDroidHttpFragmentHelper;
import net.reichholf.dreamdroid.helpers.ExtendedHashMap;
import net.reichholf.dreamdroid.helpers.enigma2.Signal;
import net.reichholf.dreamdroid.helpers.enigma2.requesthandler.SignalRequestHandler;
import net.reichholf.dreamdroid.loader.AsyncSimpleLoader;
import net.reichholf.dreamdroid.loader.LoaderResult;

import org.codeandmagic.android.gauge.GaugeView;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.ToggleButton;

public class SignalFragment extends AbstractHttpFragment {
    private static final String TAG = SignalFragment.class.getSimpleName();

    private static int sMaxSnrDb = 17;
    private static int sMinSnrDb = 7;

    GaugeView mSnr;
    CheckBox mSound;
    ToggleButton mEnabled;
    TextView mSnrdb;
    TextView mBer;
    TextView mAgc;

    private boolean mIsUpdating = false;
    private double mSnrDb = sMinSnrDb;
    private long mStartTime;

    private Handler mHandler = new Handler();
    private Runnable mPlaySoundTask = new Runnable() {
        public void run() {
            Double freq = (1650 * mSnrDb * mSnrDb) / 1000 + 200;
            playSound(freq);

            Double delay = 100 * (Math.pow(sMaxSnrDb, 3) / Math.pow(mSnrDb, 3));
            delay = delay > 2000 ? 2000 : delay;
            mHandler.postDelayed(this, delay.longValue());
        }
    };

    private Runnable mUpdateTask = new Runnable() {
        public void run() {
            if (!mIsUpdating)
                reload();
            mHandler.postDelayed(this, 50);
        }
    };

    @Override
    public void onResume() {
        super.onResume();
        startPolling();
    }

    @Override
    public void onPause() {
        super.onPause();
        stopPolling();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.signal, container, false);

        mSnr = (GaugeView) view.findViewById(R.id.gauge_view1);

        mEnabled = (ToggleButton) view.findViewById(R.id.toggle_enabled);
        mEnabled.setChecked(true);
        mEnabled.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    startPolling();
                } else {
                    stopPolling();
                }
            }
        });

        mSound = (CheckBox) view.findViewById(R.id.check_accoustic_feedback);
        mSound.setChecked(false);
        mSound.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    if (mEnabled.isChecked()) {
                        mHandler.removeCallbacks(mPlaySoundTask);
                        mHandler.post(mPlaySoundTask);
                    }
                } else {
                    mHandler.removeCallbacks(mPlaySoundTask);
                }
            }
        });

        mSnrdb = (TextView) view.findViewById(R.id.text_snrdb);
        mBer = (TextView) view.findViewById(R.id.text_ber);
        mAgc = (TextView) view.findViewById(R.id.text_agc);
        return view;
    }

    @Override
    public Loader<LoaderResult<ExtendedHashMap>> onCreateLoader(int id, Bundle args) {
        AsyncSimpleLoader loader = new AsyncSimpleLoader(getActionBarActivity(), new SignalRequestHandler(), args);
        mIsUpdating = true;
        return loader;
    }

    @Override
    public void onLoadFinished(Loader<LoaderResult<ExtendedHashMap>> loader, LoaderResult<ExtendedHashMap> result) {
        if (result.isError()) {
            mEnabled.setChecked(false);
        }
        super.onLoadFinished(loader, result);
    }

    @Override
    public void applyData(int loaderId, ExtendedHashMap content) {
        long stopTime = System.currentTimeMillis();
        long time = stopTime - mStartTime;
        Log.w(TAG, "requets & parsing took: " + time + "ms");

        if (!mEnabled.isChecked())
            return;
        String _snr = content.getString(Signal.KEY_SNR).replace("%", "").trim();

        int snr = 0;
        try {
            snr = Integer.parseInt(_snr);
        } catch (NumberFormatException ex) {
        }

        try {
            mSnrDb = Double.parseDouble(content.getString(Signal.KEY_SNRDB, "7").replaceAll("(?i)dB", "").trim());
        } catch (NumberFormatException ex) {
            mSnrDb = sMinSnrDb;
        }

        mSnr.setTargetValue(snr);
        mSnrdb.setText(content.getString(Signal.KEY_SNRDB, "-").trim());
        mBer.setText(content.getString(Signal.KEY_BER, "-").trim());
        mAgc.setText(content.getString(Signal.KEY_AGC, "-").trim());

        mIsUpdating = false;
        reload();
    }

    protected void reload() {
        mStartTime = System.currentTimeMillis();
        if (!"".equals(getBaseTitle().trim()))
            setCurrentTitle(getBaseTitle() + " - " + getString(R.string.loading));

        getActionBarActivity().setTitle(getCurrentTitle());
        getLoaderManager().restartLoader(0, getLoaderBundle(DreamDroidHttpFragmentHelper.LOADER_DEFAULT_ID), this);
    }

    private void startPolling() {
        mIsUpdating = false;
        if (mEnabled.isChecked()) {
            reload();
            // mHandler.removeCallbacks(mUpdateTask);
            // mHandler.post(mUpdateTask);
            if (mSound.isChecked()) {
                mHandler.removeCallbacks(mPlaySoundTask);
                mHandler.post(mPlaySoundTask);
            }
        }
    }

    private void stopPolling() {
        mHandler.removeCallbacks(mPlaySoundTask);
        mHandler.removeCallbacks(mUpdateTask);
        mSnr.setTargetValue(0);
        mSnrdb.setText("-");
        mBer.setText("-");
        mAgc.setText("-");
    }

    void playSound(double freqOfTone) {
        double duration = 0.1; // seconds
        int sampleRate = 8000; // a number

        double dnumSamples = duration * sampleRate;
        dnumSamples = Math.ceil(dnumSamples);
        int numSamples = (int) dnumSamples;
        double sample[] = new double[numSamples];
        byte generatedSnd[] = new byte[2 * numSamples];

        for (int i = 0; i < numSamples; ++i) { // Fill the sample array
            sample[i] = Math.sin(freqOfTone * 2 * Math.PI * i / (sampleRate));
        }

        // convert to 16 bit pcm sound array
        // assumes the sample buffer is normalized.
        int idx = 0;
        int i = 0;

        int ramp = numSamples / 20; // Amplitude ramp as a percent of sample
        // count

        for (i = 0; i < numSamples; ++i) { // Ramp amplitude up (to avoid
            // clicks)
            if (i < ramp) {
                double dVal = sample[i];
                // Ramp up to maximum
                final short val = (short) ((dVal * 32767 * i / ramp));
                // in 16 bit wav PCM, first byte is the low order byte
                generatedSnd[idx++] = (byte) (val & 0x00ff);
                generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
            } else if (i < numSamples - ramp) {
                // Max amplitude for most of the samples
                double dVal = sample[i];
                // scale to maximum amplitude
                final short val = (short) ((dVal * 32767));
                // in 16 bit wav PCM, first byte is the low order byte
                generatedSnd[idx++] = (byte) (val & 0x00ff);
                generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
            } else {
                double dVal = sample[i];
                // Ramp down to zero
                final short val = (short) ((dVal * 32767 * (numSamples - i) / ramp));
                // in 16 bit wav PCM, first byte is the low order byte
                generatedSnd[idx++] = (byte) (val & 0x00ff);
                generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
            }
        }

        AudioTrack audioTrack = null; // Get audio track
        try {
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_OUT_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, (int) numSamples * 2, AudioTrack.MODE_STATIC);
            // Load the track
            audioTrack.write(generatedSnd, 0, generatedSnd.length);
            audioTrack.play(); // Play the track
        } catch (Exception e) {
        }

        int x = 0;
        do { // Montior playback to find when done
            if (audioTrack != null)
                x = audioTrack.getPlaybackHeadPosition();
            else
                x = numSamples;
        } while (x < numSamples);

        if (audioTrack != null)
            audioTrack.release(); // Track play done. Release track.
    }
}