/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.soundrecorder;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaRecorder;
import android.media.SoundPool;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
public class SoundRecorder extends Activity implements Button.OnClickListener,
Recorder.OnStateChangedListener {
private static final String TAG = "SoundRecorder";
private static final String RECORDER_STATE_KEY = "recorder_state";
private static final String SAMPLE_INTERRUPTED_KEY = "sample_interrupted";
private static final String MAX_FILE_SIZE_KEY = "max_file_size";
private static final String AUDIO_3GPP = "audio/3gpp";
private static final String AUDIO_AMR = "audio/amr";
private static final String AUDIO_ANY = "audio/*";
private static final String ANY_ANY = "*/*";
private static final String FILE_EXTENSION_AMR = ".amr";
private static final String FILE_EXTENSION_3GPP = ".3gpp";
public static final int BITRATE_AMR = 2 * 1024 * 8; // bits/sec
public static final int BITRATE_3GPP = 20 * 1024 * 8; // bits/sec
private static final int SEEK_BAR_MAX = 10000;
private static final long WHEEL_SPEED_NORMAL = 1800;
private static final long WHEEL_SPEED_FAST = 300;
private static final long WHEEL_SPEED_SUPER_FAST = 100;
private static final long SMALL_WHEEL_SPEED_NORMAL = 900;
private static final long SMALL_WHEEL_SPEED_FAST = 200;
private static final long SMALL_WHEEL_SPEED_SUPER_FAST = 200;
private String mRequestedType = AUDIO_ANY;
private boolean mCanRequestChanged = false;
private Recorder mRecorder;
private RecorderReceiver mReceiver;
private boolean mSampleInterrupted = false;
private boolean mShowFinishButton = false;
private String mErrorUiMessage = null; // Some error messages are displayed
// in the UI, not a dialog. This
// happens when a recording
// is interrupted for some reason.
private long mMaxFileSize = -1; // can be specified in the intent
private RemainingTimeCalculator mRemainingTimeCalculator;
private String mTimerFormat;
private SoundPool mSoundPool;
private int mPlaySound;
private int mPauseSound;
private HashSet<String> mSavedRecord;
private long mLastClickTime;
private int mLastButtonId;
private final Handler mHandler = new Handler();
private Runnable mUpdateTimer = new Runnable() {
public void run() {
if (!mStopUiUpdate) {
updateTimerView();
}
}
};
private Runnable mUpdateSeekBar = new Runnable() {
@Override
public void run() {
if (!mStopUiUpdate) {
updateSeekBar();
}
}
};
private Runnable mUpdateVUMetur = new Runnable() {
@Override
public void run() {
if (!mStopUiUpdate) {
updateVUMeterView();
}
}
};
private ImageButton mNewButton;
private ImageButton mFinishButton;
private ImageButton mRecordButton;
private ImageButton mStopButton;
private ImageButton mPlayButton;
private ImageButton mPauseButton;
private ImageButton mDeleteButton;
private WheelImageView mWheelLeft;
private WheelImageView mWheelRight;
private WheelImageView mSmallWheelLeft;
private WheelImageView mSmallWheelRight;
private RecordNameEditText mFileNameEditText;
private LinearLayout mTimerLayout;
private LinearLayout mVUMeterLayout;
private LinearLayout mSeekBarLayout;
private TextView mStartTime;
private TextView mTotalTime;
private SeekBar mPlaySeekBar;
private BroadcastReceiver mSDCardMountEventReceiver = null;
private int mPreviousVUMax;
private boolean mStopUiUpdate;
@Override
public void onCreate(Bundle icycle) {
super.onCreate(icycle);
initInternalState(getIntent());
setContentView(R.layout.main);
mRecorder = new Recorder(this);
mRecorder.setOnStateChangedListener(this);
mReceiver = new RecorderReceiver();
mRemainingTimeCalculator = new RemainingTimeCalculator();
mSavedRecord = new HashSet<String>();
initResourceRefs();
setResult(RESULT_CANCELED);
registerExternalStorageListener();
if (icycle != null) {
Bundle recorderState = icycle.getBundle(RECORDER_STATE_KEY);
if (recorderState != null) {
mRecorder.restoreState(recorderState);
mSampleInterrupted = recorderState.getBoolean(SAMPLE_INTERRUPTED_KEY, false);
mMaxFileSize = recorderState.getLong(MAX_FILE_SIZE_KEY, -1);
}
}
setVolumeControlStream(AudioManager.STREAM_MUSIC);
if (mShowFinishButton) {
// reset state if it is a recording request
mRecorder.reset();
resetFileNameEditText();
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
boolean preShowFinishButton = mShowFinishButton;
initInternalState(intent);
if (mShowFinishButton || preShowFinishButton != mShowFinishButton) {
// reset state if it is a recording request or state is changed
mRecorder.reset();
resetFileNameEditText();
}
}
private void initInternalState(Intent i) {
mRequestedType = AUDIO_ANY;
mShowFinishButton = false;
if (i != null) {
String s = i.getType();
if (AUDIO_AMR.equals(s) || AUDIO_3GPP.equals(s) || AUDIO_ANY.equals(s)
|| ANY_ANY.equals(s)) {
mRequestedType = s;
mShowFinishButton = true;
} else if (s != null) {
// we only support amr and 3gpp formats right now
setResult(RESULT_CANCELED);
finish();
return;
}
final String EXTRA_MAX_BYTES = android.provider.MediaStore.Audio.Media.EXTRA_MAX_BYTES;