package edu.toronto.whimper;
import edu.toronto.whimper.NoiseObjects.NoiseMeter;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
public class NoiseLevel extends Activity {
static private final int PREFERENCES_CALL_CODE = 100;
// ******************************************************************** //
// Activity Lifecycle.
// ******************************************************************** //
/**
* Called when the activity is starting. This is where most
* initialisation should go: calling setContentView(int) to inflate
* the activity's UI, etc.
*
* You can call finish() from within this function, in which case
* onDestroy() will be immediately called without any of the rest of
* the activity lifecycle executing.
*
* Derived classes must call through to the super class's implementation
* of this method. If they do not, an exception will be thrown.
*
* @param icicle If the activity is being re-initialised
* after previously being shut down then this
* Bundle contains the data it most recently
* supplied in onSaveInstanceState(Bundle).
* Note: Otherwise it is null.
*/
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// We don't want a title bar or status bar.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
// We want the audio controls to control our sound volume.
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Get our power manager for wake locks.
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
// Create the application GUI.
//audioInstrument = new InstrumentPanel(this);
//setContentView(audioInstrument);
setContentView(R.layout.noiselevel);
textViewCurrentNoiseLevel = (TextView) findViewById(R.id.textViewCurrentNoiseValue);
textViewAverageNoiseLevel = (TextView) findViewById(R.id.textViewAverageNoiseValue);
textViewSmoothedNoiseLevel = (TextView) findViewById(R.id.textViewSmoothedNoiseValue);
//audioInstrument.appStart();
//audioInstrument.animStart();
// Restore our preferences.
//updatePreferences();
if (icicle == null){
localInit();
//updatePreferences2();
}
}
/**
* Called after {@link #onCreate} or {@link #onStop} when the current
* activity is now being displayed to the user. It will
* be followed by {@link #onRestart}.
*/
@Override
protected void onStart() {
Log.i(TAG, "onStart()");
super.onStart();
//audioInstrument.onStart();
}
/**
* Called after onRestoreInstanceState(Bundle), onRestart(), or onPause(),
* for your activity to start interacting with the user. This is a good
* place to begin animations, open exclusive-access devices (such as the
* camera), etc.
*
* Derived classes must call through to the super class's implementation
* of this method. If they do not, an exception will be thrown.
*/
@Override
protected void onResume() {
Log.i(TAG, "onResume()");
super.onResume();
// First time round, show the EULA.
//showFirstEula();
// Take the wake lock if we want it.
if (wakeLock != null && !wakeLock.isHeld())
wakeLock.acquire();
//audioInstrument.onResume();
// Just start straight away.
//audioInstrument.surfaceStart();
localNoiseMeter.measureStart();
}
/**
* Called to retrieve per-instance state from an activity before being
* killed so that the state can be restored in onCreate(Bundle) or
* onRestoreInstanceState(Bundle) (the Bundle populated by this method
* will be passed to both).
*
* @param outState A Bundle in which to place any state
* information you wish to save.
*/
@Override
public void onSaveInstanceState(Bundle outState) {
Log.i(TAG, "onSaveInstanceState()");
super.onSaveInstanceState(outState);
}
/**
* Called as part of the activity lifecycle when an activity is going
* into the background, but has not (yet) been killed. The counterpart
* to onResume().
*/
@Override
protected void onPause() {
Log.i(TAG, "onPause()");
super.onPause();
//audioInstrument.onPause();
localNoiseMeter.measureStop();
// Let go the wake lock if we have it.
if (wakeLock != null && wakeLock.isHeld())
wakeLock.release();
}
/**
* Called when you are no longer visible to the user. You will next
* receive either {@link #onStart}, {@link #onDestroy}, or nothing,
* depending on later user activity.
*/
@Override
protected void onStop() {
Log.i(TAG, "onStop()");
super.onStop();
//audioInstrument.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
localThreadTicker2.kill();
}
public void noiselevelButtonClickHandler(View clickedButton){
switch(clickedButton.getId()){
case R.id.buttonNLPreferences:
Intent preferencesIntent = new Intent(NoiseLevel.this, Preferences.class);
startActivityForResult(preferencesIntent, PREFERENCES_CALL_CODE);
break;
}
}
/**
* Initialize the contents of the game's options menu by adding items
* to the given menu.
*
* This is only called once, the first time the options menu is displayed.
* To update the menu every time it is displayed, see
* onPrepareOptionsMenu(Menu).
*
* When we add items to the menu, we can either supply a Runnable to
* receive notification of selection, or we can implement the Activity's
* onOptionsItemSelected(Menu.Item) method to handle them there.
*
* @param menu The options menu in which we should
* place our items. We can safely hold on this
* (and any items created from it), making
* modifications to it as desired, until the next
* time onCreateOptionsMenu() is called.
* @return true for the menu to be displayed; false
* to suppress showing it.
*/
/*
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// We must call through to the base implementation.
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
*/
/**
* This hook is called whenever an item in your options menu is selected.
* Derived classes should call through to the base class for it to
* perform the default menu handling. (True?)
*
* @param item The menu item that was selected.
* @return false to have the normal processing happen.
*/
/*
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_prefs:
// Launch the preferences activity as a subactivity, so we
// know when it returns.
Intent pIntent = new Intent();
pIntent.setClass(this, Preferences.class);
startActivityForResult(pIntent, PREFERENCES_CALL_CODE);
break;
case R.id.menu_exit:
finish();
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode){
case PREFERENCES_CALL_CODE:
//updatePreferences();
updatePreferences2();
localNoiseMeter.measureStop();
localNoiseMeter.measureStart();
break;
}
}
// ******************************************************************** //
// Preferences Handling.
// ******************************************************************** //
/**
* Read our application preferences and configure ourself appropriately.
*/
private void updatePreferences2() {
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(this);
// Get the desired sample rate.
int sampleRate = 8000;
try {
String srate = prefs.getString("sampleRate", null);
sampleRate = Integer.valueOf(srate);
} catch (Exception e) {
Log.e(TAG, "Pref: bad sampleRate");
}
if (sampleRate < 8000)
sampleRate = 8000;
Log.i(TAG, "Prefs: sampleRate " + sampleRate);
localNoiseMeter.setSampleRate(sampleRate);
// Get the desired block size.
int blockSize = 256;
try {
String bsize = prefs.getString("blockSize", null);
blockSize = Integer.valueOf(bsize);
} catch (Exception e) {
Log.e(TAG, "Pref: bad blockSize");
}
Log.i(TAG, "Prefs: blockSize " + blockSize);
localNoiseMeter.setBlockSize(blockSize);
// Get the desired decimation.
int decimateRate = 2;
try {
String drate = prefs.getString("decimateRate", null);
decimateRate = Integer.valueOf(drate);
} catch (Exception e) {
Log.e(TAG, "Pref: bad decimateRate");
}
Log.i(TAG, "Prefs: decimateRate " + decimateRate);
localNoiseMeter.setDecimation(decimateRate);
// Get the desired orientation.
int orientMode = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
try {
String omode = prefs.getString("orientationMode", null);
orientMode = Integer.valueOf(omode);
} catch (Exception e) {
Log.e(TAG, "Pref: bad orientationMode");
}
Log.i(TAG, "Prefs: orientationMode " + orientMode);
setRequestedOrientation(orientMode);
boolean keepAwake = false;
try {
keepAwake = prefs.getBoolean("keepAwake", false);
} catch (Exception e) {
Log.e(TAG, "Pref: bad keepAwake");
}
if (keepAwake) {
Log.i(TAG, "Prefs: keepAwake true: take the wake lock");
if (wakeLock == null)
wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
if (!wakeLock.isHeld())
wakeLock.acquire();
} else {
Log.i(TAG, "Prefs: keepAwake false: release the wake lock");
if (wakeLock != null && wakeLock.isHeld())
wakeLock.release();
wakeLock = null;
}
//localNoiseMeter.measureStop();
//localNoiseMeter.measureStart();
}
// ******************************************************************** //
// Class Data.
// ******************************************************************** //
// Debugging tag.
//@SuppressWarnings("unused")
private static final String TAG = "Audalyzer";
// ******************************************************************** //
// Private Data.
// ******************************************************************** //
// Our power manager.
private PowerManager powerManager = null;
// The surface manager for the view.
//private InstrumentPanel audioInstrument = null;
// Wake lock used to keep the screen alive. Null if we aren't going
// to take a lock; non-null indicates that the lock should be taken
// while we're actually running.
private PowerManager.WakeLock wakeLock = null;
public static TextView textViewCurrentNoiseLevel, textViewAverageNoiseLevel, textViewSmoothedNoiseLevel;
///////////////////////////////////////////////////////
//private final AudioAnalyser localAudioAnalyser;
//private PowerGauge localPowerGauge = null;
private NoiseMeter localNoiseMeter = null;
private int animationDelay = 50;
ThreadTicker2 localThreadTicker2 = null;
Handler mainThreadHandler;
public void mainThreadMessageHandler(Message msg){
updateCurrentPower();
}
private void localInit(){
localNoiseMeter = new NoiseMeter();
updatePreferences2();
//localNoiseMeter.measureStart();
mainThreadHandler = new Handler(){
public void handleMessage(Message msg){
mainThreadMessageHandler(msg);
}
};
localThreadTicker2 = new ThreadTicker2();
}
private void updateCurrentPower(){
float currentNoise, averageNoise, smoothedNoise;
localNoiseMeter.doUpdate();
currentNoise = localNoiseMeter.GetCurrentNoise();
averageNoise = localNoiseMeter.GetAverageNoise();
smoothedNoise = localNoiseMeter.GetSmoothedNoise();
//currentNoise = localNoiseMeter.currentPower;
//averageNoise = localNoiseMeter.averagePower;
currentNoise = (float)( (int) (10*currentNoise)) /10;
averageNoise = (float)( (int) (10*averageNoise)) /10;
smoothedNoise = (float)( (int) (10*smoothedNoise)) /10;
textViewCurrentNoiseLevel.setText(currentNoise+" db");
textViewAverageNoiseLevel.setText(averageNoise+" db");
textViewSmoothedNoiseLevel.setText(smoothedNoise+" db");
}
private void tick(){
//updateCurrentPower();
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage());
}
/**
* Thread-based ticker class. This may be faster than LoopTicker.
*/
private class ThreadTicker2
extends Thread
{
// Constructor -- start at once.
private ThreadTicker2() {
super("Surface Runner");
Log.v(TAG, "ThreadTicker: start");
enable = true;
start();
}
// Stop this thread. There will be no new calls to tick() after this.
public void kill() {
Log.v(TAG, "ThreadTicker: kill");
enable = false;
}
// Stop this thread and wait for it to die. When we return, it is
// guaranteed that tick() will never be called again.
//
// Caution: if this is called from within tick(), deadlock is
// guaranteed.
public void killAndWait() {
Log.v(TAG, "ThreadTicker: killAndWait");
if (Thread.currentThread() == this)
throw new IllegalStateException("ThreadTicker.killAndWait()" +
" called from ticker thread");
enable = false;
// Wait for the thread to finish. Ignore interrupts.
if (isAlive()) {
boolean retry = true;
while (retry) {
try {
join();
retry = false;
} catch (InterruptedException e) { }
}
Log.v(TAG, "ThreadTicker: killed");
} else {
Log.v(TAG, "Ticker: was dead");
}
}
// Run method for this thread -- simply call tick() a lot until
// enable is false.
@Override
public void run() {
while (enable) {
tick();
if (animationDelay != 0) try {
sleep(animationDelay);
} catch (InterruptedException e) { }
}
}
// Flag used to terminate this thread -- when false, we die.
private boolean enable = false;
}
}
|