这个录音实现是我在Bus上看到并下载的,他那个源码不完整,再次把我整理完整的代码贴出,源码地址在这:http://download.csdn.net/detail/chaozhung/5618649
Bus上的那个网址找不到了,见谅!!!
下为核心代码:
核心代码1..
package com.lv.reco;import java.io.File;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 HashSetmSavedRecord; 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 (); 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; mMaxFileSize = i.getLongExtra(EXTRA_MAX_BYTES, -1); } if (AUDIO_ANY.equals(mRequestedType)) { mRequestedType = SoundRecorderPreferenceActivity.getRecordType(this); } else if (ANY_ANY.equals(mRequestedType)) { mRequestedType = AUDIO_3GPP; } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); setContentView(R.layout.main); initResourceRefs(); updateUi(false); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mRecorder.sampleLength() == 0) return; Bundle recorderState = new Bundle(); if (mRecorder.state() != Recorder.RECORDING_STATE) { mRecorder.saveState(recorderState); } recorderState.putBoolean(SAMPLE_INTERRUPTED_KEY, mSampleInterrupted); recorderState.putLong(MAX_FILE_SIZE_KEY, mMaxFileSize); outState.putBundle(RECORDER_STATE_KEY, recorderState); } /* * Whenever the UI is re-created (due f.ex. to orientation change) we have * to reinitialize references to the views. */ private void initResourceRefs() { mNewButton = (ImageButton) findViewById(R.id.newButton); mFinishButton = (ImageButton) findViewById(R.id.finishButton); mRecordButton = (ImageButton) findViewById(R.id.recordButton); mStopButton = (ImageButton) findViewById(R.id.stopButton); mPlayButton = (ImageButton) findViewById(R.id.playButton); mPauseButton = (ImageButton) findViewById(R.id.pauseButton); mDeleteButton = (ImageButton) findViewById(R.id.deleteButton); mNewButton.setOnClickListener(this); mFinishButton.setOnClickListener(this); mRecordButton.setOnClickListener(this); mStopButton.setOnClickListener(this); mPlayButton.setOnClickListener(this); mPauseButton.setOnClickListener(this); mDeleteButton.setOnClickListener(this); mWheelLeft = (WheelImageView) findViewById(R.id.wheel_left); mWheelRight = (WheelImageView) findViewById(R.id.wheel_right); mSmallWheelLeft = (WheelImageView) findViewById(R.id.wheel_small_left); mSmallWheelRight = (WheelImageView) findViewById(R.id.wheel_small_right); mFileNameEditText = (RecordNameEditText) findViewById(R.id.file_name); resetFileNameEditText(); mFileNameEditText.setNameChangeListener(new RecordNameEditText.OnNameChangeListener() { @Override public void onNameChanged(String name) { if (!TextUtils.isEmpty(name)) { mRecorder.renameSampleFile(name); } } }); mTimerLayout = (LinearLayout) findViewById(R.id.time_calculator); mVUMeterLayout = (LinearLayout) findViewById(R.id.vumeter_layout); mSeekBarLayout = (LinearLayout) findViewById(R.id.play_seek_bar_layout); mStartTime = (TextView) findViewById(R.id.starttime); mTotalTime = (TextView) findViewById(R.id.totaltime); mPlaySeekBar = (SeekBar) findViewById(R.id.play_seek_bar); mPlaySeekBar.setMax(SEEK_BAR_MAX); mPlaySeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener); mTimerFormat = getResources().getString(R.string.timer_format); if (mShowFinishButton) { mNewButton.setVisibility(View.GONE); mFinishButton.setVisibility(View.VISIBLE); mNewButton = mFinishButton; // use mNewButon variable for left // button in the control panel } mSoundPool = new SoundPool(5, AudioManager.STREAM_SYSTEM, 5); mPlaySound = mSoundPool.load("/system/media/audio/ui/SoundRecorderPlay.ogg", 1); mPauseSound = mSoundPool.load("/system/media/audio/ui/SoundRecorderPause.ogg", 1); mLastClickTime = 0; mLastButtonId = 0; } private void resetFileNameEditText() { String extension = ""; if (AUDIO_AMR.equals(mRequestedType)) { extension = FILE_EXTENSION_AMR; } else if (AUDIO_3GPP.equals(mRequestedType)) { extension = FILE_EXTENSION_3GPP; } // for audio which is used for mms, we can only use english file name // mShowFinishButon indicates whether this is an audio for mms mFileNameEditText.initFileName(mRecorder.getRecordDir(), extension, mShowFinishButton); } private void startRecordPlayingAnimation() { mWheelLeft.startAnimation(WHEEL_SPEED_NORMAL, true); mWheelRight.startAnimation(WHEEL_SPEED_NORMAL, true); mSmallWheelLeft.startAnimation(SMALL_WHEEL_SPEED_NORMAL, true); mSmallWheelRight.startAnimation(SMALL_WHEEL_SPEED_NORMAL, true); } private void stopRecordPlayingAnimation() { stopAnimation(); startRecordPlayingDoneAnimation(); } private void startRecordPlayingDoneAnimation() { mWheelLeft.startAnimation(WHEEL_SPEED_SUPER_FAST, false, 4); mWheelRight.startAnimation(WHEEL_SPEED_SUPER_FAST, false, 4); mSmallWheelLeft.startAnimation(SMALL_WHEEL_SPEED_SUPER_FAST, false, 2); mSmallWheelRight.startAnimation(SMALL_WHEEL_SPEED_SUPER_FAST, false, 2); } private void startForwardAnimation() { mWheelLeft.startAnimation(WHEEL_SPEED_FAST, true); mWheelRight.startAnimation(WHEEL_SPEED_FAST, true); mSmallWheelLeft.startAnimation(SMALL_WHEEL_SPEED_FAST, true); mSmallWheelRight.startAnimation(SMALL_WHEEL_SPEED_FAST, true); } private void startBackwardAnimation() { mWheelLeft.startAnimation(WHEEL_SPEED_FAST, false); mWheelRight.startAnimation(WHEEL_SPEED_FAST, false); mSmallWheelLeft.startAnimation(SMALL_WHEEL_SPEED_FAST, false); mSmallWheelRight.startAnimation(SMALL_WHEEL_SPEED_FAST, false); } private void stopAnimation() { mWheelLeft.stopAnimation(); mWheelRight.stopAnimation(); mSmallWheelLeft.stopAnimation(); mSmallWheelRight.stopAnimation(); } /* * Make sure we're not recording music playing in the background, ask the * MediaPlaybackService to pause playback. */ private void stopAudioPlayback() { // Shamelessly copied from MediaPlaybackService.java, which // should be public, but isn't. Intent i = new Intent("com.android.music.musicservicecommand"); i.putExtra("command", "pause"); sendBroadcast(i); } /* * Handle the buttons. */ public void onClick(View button) { if (System.currentTimeMillis() - mLastClickTime < 300) { // in order to avoid user click bottom too quickly return; } if (!button.isEnabled()) return; if (button.getId() == mLastButtonId && button.getId() != R.id.newButton) { // as the recorder state is async with the UI // we need to avoid launching the duplicated action return; } if (button.getId() == R.id.stopButton && System.currentTimeMillis() - mLastClickTime < 1500) { // it seems that the media recorder is not robust enough // sometime it crashes when stop recording right after starting return; } mLastClickTime = System.currentTimeMillis(); mLastButtonId = button.getId(); switch (button.getId()) { case R.id.newButton: mFileNameEditText.clearFocus(); saveSample(); mRecorder.reset(); resetFileNameEditText(); break; case R.id.recordButton: showOverwriteConfirmDialogIfConflicts(); break; case R.id.stopButton: mRecorder.stop(); break; case R.id.playButton: mRecorder.startPlayback(mRecorder.playProgress()); break; case R.id.pauseButton: mRecorder.pausePlayback(); break; case R.id.finishButton: mRecorder.stop(); saveSample(); finish(); break; case R.id.deleteButton: showDeleteConfirmDialog(); break; } } private void startRecording() { mRemainingTimeCalculator.reset(); if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { mSampleInterrupted = true; mErrorUiMessage = getResources().getString(R.string.insert_sd_card); updateUi(false); } else if (!mRemainingTimeCalculator.diskSpaceAvailable()) { mSampleInterrupted = true; mErrorUiMessage = getResources().getString(R.string.storage_is_full); updateUi(false); } else { stopAudioPlayback(); boolean isHighQuality = SoundRecorderPreferenceActivity.isHighQuality(this); if (AUDIO_AMR.equals(mRequestedType)) { mRemainingTimeCalculator.setBitRate(BITRATE_AMR); int outputfileformat = isHighQuality ? MediaRecorder.OutputFormat.RAW_AMR : MediaRecorder.OutputFormat.RAW_AMR; mRecorder.startRecording(outputfileformat, mFileNameEditText.getText().toString(), FILE_EXTENSION_AMR, isHighQuality, mMaxFileSize); } else if (AUDIO_3GPP.equals(mRequestedType)) { // HACKME: for HD2, there is an issue with high quality 3gpp // use low quality instead if (Build.MODEL.equals("HTC HD2")) { isHighQuality = false; } mRemainingTimeCalculator.setBitRate(BITRATE_3GPP); mRecorder.startRecording(MediaRecorder.OutputFormat.THREE_GPP, mFileNameEditText .getText().toString(), FILE_EXTENSION_3GPP, isHighQuality, mMaxFileSize); } else { throw new IllegalArgumentException("Invalid output file type requested"); } if (mMaxFileSize != -1) { mRemainingTimeCalculator.setFileSizeLimit(mRecorder.sampleFile(), mMaxFileSize); } } } /* * Handle the "back" hardware key. */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { switch (mRecorder.state()) { case Recorder.IDLE_STATE: case Recorder.PLAYING_PAUSED_STATE: if (mRecorder.sampleLength() > 0) saveSample(); finish(); break; case Recorder.PLAYING_STATE: mRecorder.stop(); saveSample(); break; case Recorder.RECORDING_STATE: if (mShowFinishButton) { mRecorder.clear(); } else { finish(); } break; } return true; } else { return super.onKeyDown(keyCode, event); } } @Override protected void onResume() { super.onResume(); String type = SoundRecorderPreferenceActivity.getRecordType(this); if (mCanRequestChanged && !TextUtils.equals(type, mRequestedType)) { saveSample(); mRecorder.reset(); mRequestedType = type; resetFileNameEditText(); } mCanRequestChanged = false; if (!mRecorder.syncStateWithService()) { mRecorder.reset(); resetFileNameEditText(); } if (mRecorder.state() == Recorder.RECORDING_STATE) { String preExtension = AUDIO_AMR.equals(mRequestedType) ? FILE_EXTENSION_AMR : FILE_EXTENSION_3GPP; if (!mRecorder.sampleFile().getName().endsWith(preExtension)) { // the extension is changed need to stop current recording mRecorder.reset(); resetFileNameEditText(); } else { // restore state if (!mShowFinishButton) { String fileName = mRecorder.sampleFile().getName().replace(preExtension, ""); mFileNameEditText.setText(fileName); } if (AUDIO_AMR.equals(mRequestedType)) { mRemainingTimeCalculator.setBitRate(BITRATE_AMR); } else if (AUDIO_3GPP.equals(mRequestedType)) { mRemainingTimeCalculator.setBitRate(BITRATE_3GPP); } } } else { File file = mRecorder.sampleFile(); if (file != null && !file.exists()) { mRecorder.reset(); resetFileNameEditText(); } } IntentFilter filter = new IntentFilter(); filter.addAction(RecorderService.RECORDER_SERVICE_BROADCAST_NAME); registerReceiver(mReceiver, filter); mStopUiUpdate = false; updateUi(true); if (RecorderService.isRecording()) { Intent intent = new Intent(this, RecorderService.class); intent.putExtra(RecorderService.ACTION_NAME, RecorderService.ACTION_DISABLE_MONITOR_REMAIN_TIME); startService(intent); } } @Override protected void onPause() { if (mRecorder.state() != Recorder.RECORDING_STATE || mShowFinishButton || mMaxFileSize != -1) { mRecorder.stop(); saveSample(); mFileNameEditText.clearFocus(); ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)) .cancel(RecorderService.NOTIFICATION_ID); } if (mReceiver != null) { unregisterReceiver(mReceiver); } mCanRequestChanged = true; mStopUiUpdate = true; stopAnimation(); if (RecorderService.isRecording()) { Intent intent = new Intent(this, RecorderService.class); intent.putExtra(RecorderService.ACTION_NAME, RecorderService.ACTION_ENABLE_MONITOR_REMAIN_TIME); startService(intent); } super.onPause(); } @Override protected void onStop() { if (mShowFinishButton) { finish(); } super.onStop(); } /* * If we have just recorded a sample, this adds it to the media data base * and sets the result to the sample's URI. */ private void saveSample() { if (mRecorder.sampleLength() == 0) return; if (!mSavedRecord.contains(mRecorder.sampleFile().getAbsolutePath())) { Uri uri = null; try { uri = this.addToMediaDB(mRecorder.sampleFile()); } catch (UnsupportedOperationException ex) { // Database // manipulation // failure return; } if (uri == null) { return; } mSavedRecord.add(mRecorder.sampleFile().getAbsolutePath()); setResult(RESULT_OK, new Intent().setData(uri)); } } private void showDeleteConfirmDialog() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); dialogBuilder.setIcon(android.R.drawable.ic_dialog_alert); dialogBuilder.setTitle(R.string.delete_dialog_title); dialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mRecorder.delete(); } }); dialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mLastButtonId = 0; } }); dialogBuilder.show(); } private void showOverwriteConfirmDialogIfConflicts() { String fileName = mFileNameEditText.getText().toString() + (AUDIO_AMR.equals(mRequestedType) ? FILE_EXTENSION_AMR : FILE_EXTENSION_3GPP); if (mRecorder.isRecordExisted(fileName) && !mShowFinishButton) { // file already existed and it's not a recording request from other // app AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); dialogBuilder.setIcon(android.R.drawable.ic_dialog_alert); dialogBuilder.setTitle(getString(R.string.overwrite_dialog_title, fileName)); dialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startRecording(); } }); dialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mLastButtonId = 0; } }); dialogBuilder.show(); } else { startRecording(); } } /* * Called on destroy to unregister the SD card mount event receiver. */ @Override public void onDestroy() { if (mSDCardMountEventReceiver != null) { unregisterReceiver(mSDCardMountEventReceiver); mSDCardMountEventReceiver = null; } mSoundPool.release(); super.onDestroy(); } /* * Registers an intent to listen for * ACTION_MEDIA_EJECT/ACTION_MEDIA_UNMOUNTED/ACTION_MEDIA_MOUNTED * notifications. */ private void registerExternalStorageListener() { if (mSDCardMountEventReceiver == null) { mSDCardMountEventReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mSampleInterrupted = false; mRecorder.reset(); resetFileNameEditText(); updateUi(false); } }; IntentFilter iFilter = new IntentFilter(); iFilter.addAction(Intent.ACTION_MEDIA_EJECT); iFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); iFilter.addDataScheme("file"); registerReceiver(mSDCardMountEventReceiver, iFilter); } } /* * A simple utility to do a query into the databases. */ private Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { try { ContentResolver resolver = getContentResolver(); if (resolver == null) { return null; } return resolver.query(uri, projection, selection, selectionArgs, sortOrder); } catch (UnsupportedOperationException ex) { return null; } } /* * Add the given audioId to the playlist with the given playlistId; and * maintain the play_order in the playlist. */ private void addToPlaylist(ContentResolver resolver, int audioId, long playlistId) { String[] cols = new String[] { "count(*)" }; Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); Cursor cur = resolver.query(uri, cols, null, null, null); cur.moveToFirst(); final int base = cur.getInt(0); cur.close(); ContentValues values = new ContentValues(); values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + audioId)); values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); resolver.insert(uri, values); } /* * Obtain the id for the default play list from the audio_playlists table. */ private int getPlaylistId(Resources res) { Uri uri = MediaStore.Audio.Playlists.getContentUri("external"); final String[] ids = new String[] { MediaStore.Audio.Playlists._ID }; final String where = MediaStore.Audio.Playlists.NAME + "=?"; final String[] args = new String[] { res.getString(R.string.audio_db_playlist_name) }; Cursor cursor = query(uri, ids, where, args, null); if (cursor == null) { Log.v(TAG, "query returns null"); } int id = -1; if (cursor != null) { cursor.moveToFirst(); if (!cursor.isAfterLast()) { id = cursor.getInt(0); } cursor.close(); } return id; } /* * Create a playlist with the given default playlist name, if no such * playlist exists. */ private Uri createPlaylist(Resources res, ContentResolver resolver) { ContentValues cv = new ContentValues(); cv.put(MediaStore.Audio.Playlists.NAME, res.getString(R.string.audio_db_playlist_name)); Uri uri = resolver.insert(MediaStore.Audio.Playlists.getContentUri("external"), cv); if (uri == null) { new AlertDialog.Builder(this).setTitle(R.string.app_name) .setMessage(R.string.error_mediadb_new_record) .setPositiveButton(R.string.button_ok, null).setCancelable(false).show(); } return uri; } /* * Adds file and returns content uri. */ private Uri addToMediaDB(File file) { Resources res = getResources(); ContentValues cv = new ContentValues(); long current = System.currentTimeMillis(); long modDate = file.lastModified(); Date date = new Date(current); SimpleDateFormat formatter = new SimpleDateFormat( res.getString(R.string.audio_db_title_format)); String title = formatter.format(date); long sampleLengthMillis = mRecorder.sampleLength() * 1000L; // Lets label the recorded audio file as NON-MUSIC so that the file // won't be displayed automatically, except for in the playlist. cv.put(MediaStore.Audio.Media.IS_MUSIC, "0"); cv.put(MediaStore.Audio.Media.TITLE, title); cv.put(MediaStore.Audio.Media.DATA, file.getAbsolutePath()); cv.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000)); cv.put(MediaStore.Audio.Media.DATE_MODIFIED, (int) (modDate / 1000)); cv.put(MediaStore.Audio.Media.DURATION, sampleLengthMillis); cv.put(MediaStore.Audio.Media.MIME_TYPE, mRequestedType); cv.put(MediaStore.Audio.Media.ARTIST, res.getString(R.string.audio_db_artist_name)); cv.put(MediaStore.Audio.Media.ALBUM, res.getString(R.string.audio_db_album_name)); Log.d(TAG, "Inserting audio record: " + cv.toString()); ContentResolver resolver = getContentResolver(); Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Log.d(TAG, "ContentURI: " + base); Uri result = resolver.insert(base, cv); if (result == null) { Log.w(TAG, getString(R.string.error_mediadb_new_record)); return null; } if (getPlaylistId(res) == -1) { createPlaylist(res, resolver); } int audioId = Integer.valueOf(result.getLastPathSegment()); addToPlaylist(resolver, audioId, getPlaylistId(res)); // Notify those applications such as Music listening to the // scanner events that a recorded audio file just created. sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result)); return result; } private ImageView getTimerImage(char number) { ImageView image = new ImageView(this); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); if (number != ':') { image.setBackgroundResource(R.drawable.background_number); } switch (number) { case '0': image.setImageResource(R.drawable.number_0); break; case '1': image.setImageResource(R.drawable.number_1); break; case '2': image.setImageResource(R.drawable.number_2); break; case '3': image.setImageResource(R.drawable.number_3); break; case '4': image.setImageResource(R.drawable.number_4); break; case '5': image.setImageResource(R.drawable.number_5); break; case '6': image.setImageResource(R.drawable.number_6); break; case '7': image.setImageResource(R.drawable.number_7); break; case '8': image.setImageResource(R.drawable.number_8); break; case '9': image.setImageResource(R.drawable.number_9); break; case ':': image.setImageResource(R.drawable.colon); break; } image.setLayoutParams(lp); return image; } /** * Update the big MM:SS timer. If we are in playback, also update the * progress bar. */ private void updateTimerView() { int state = mRecorder.state(); boolean ongoing = state == Recorder.RECORDING_STATE || state == Recorder.PLAYING_STATE; long time = mRecorder.progress(); String timeStr = String.format(mTimerFormat, time / 60, time % 60); mTimerLayout.removeAllViews(); for (int i = 0; i < timeStr.length(); i++) { mTimerLayout.addView(getTimerImage(timeStr.charAt(i))); } if (state == Recorder.RECORDING_STATE) { updateTimeRemaining(); } if (ongoing) { mHandler.postDelayed(mUpdateTimer, 500); } } private void setTimerView(float progress) { long time = (long) (progress * mRecorder.sampleLength()); String timeStr = String.format(mTimerFormat, time / 60, time % 60); mTimerLayout.removeAllViews(); for (int i = 0; i < timeStr.length(); i++) { mTimerLayout.addView(getTimerImage(timeStr.charAt(i))); } } private void updateSeekBar() { if (mRecorder.state() == Recorder.PLAYING_STATE) { mPlaySeekBar.setProgress((int) (SEEK_BAR_MAX * mRecorder.playProgress())); mHandler.postDelayed(mUpdateSeekBar, 10); } } /* * Called when we're in recording state. Find out how much longer we can go * on recording. If it's under 5 minutes, we display a count-down in the UI. * If we've run out of time, stop the recording. */ private void updateTimeRemaining() { long t = mRemainingTimeCalculator.timeRemaining(); if (t <= 0) { mSampleInterrupted = true; int limit = mRemainingTimeCalculator.currentLowerLimit(); switch (limit) { case RemainingTimeCalculator.DISK_SPACE_LIMIT: mErrorUiMessage = getResources().getString(R.string.storage_is_full); break; case RemainingTimeCalculator.FILE_SIZE_LIMIT: mErrorUiMessage = getResources().getString(R.string.max_length_reached); break; default: mErrorUiMessage = null; break; } mRecorder.stop(); return; } } private void updateVUMeterView() { final int MAX_VU_SIZE = 11; boolean showVUArray[] = new boolean[MAX_VU_SIZE]; if (mVUMeterLayout.getVisibility() == View.VISIBLE && mRecorder.state() == Recorder.RECORDING_STATE) { int vuSize = MAX_VU_SIZE * mRecorder.getMaxAmplitude() / 32768; if (vuSize >= MAX_VU_SIZE) { vuSize = MAX_VU_SIZE - 1; } if (vuSize >= mPreviousVUMax) { mPreviousVUMax = vuSize; } else if (mPreviousVUMax > 0) { mPreviousVUMax--; } for (int i = 0; i < MAX_VU_SIZE; i++) { if (i <= vuSize) { showVUArray[i] = true; } else if (i == mPreviousVUMax) { showVUArray[i] = true; } else { showVUArray[i] = false; } } mHandler.postDelayed(mUpdateVUMetur, 100); } else if (mVUMeterLayout.getVisibility() == View.VISIBLE) { mPreviousVUMax = 0; for (int i = 0; i < MAX_VU_SIZE; i++) { showVUArray[i] = false; } } if (mVUMeterLayout.getVisibility() == View.VISIBLE) { mVUMeterLayout.removeAllViews(); for (boolean show : showVUArray) { ImageView imageView = new ImageView(this); imageView.setBackgroundResource(R.drawable.background_vumeter); if (show) { imageView.setImageResource(R.drawable.icon_vumeter); } imageView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); mVUMeterLayout.addView(imageView); } } } /** * Shows/hides the appropriate child views for the new state. */ private void updateUi(boolean skipRewindAnimation) { switch (mRecorder.state()) { case Recorder.IDLE_STATE: mLastButtonId = 0; case Recorder.PLAYING_PAUSED_STATE: if (mRecorder.sampleLength() == 0) { mNewButton.setEnabled(true); mNewButton.setVisibility(View.VISIBLE); mRecordButton.setVisibility(View.VISIBLE); mStopButton.setVisibility(View.GONE); mPlayButton.setVisibility(View.GONE); mPauseButton.setVisibility(View.GONE); mDeleteButton.setEnabled(false); mRecordButton.requestFocus(); mVUMeterLayout.setVisibility(View.VISIBLE); mSeekBarLayout.setVisibility(View.GONE); } else { mNewButton.setEnabled(true); mNewButton.setVisibility(View.VISIBLE); mRecordButton.setVisibility(View.GONE); mStopButton.setVisibility(View.GONE); mPlayButton.setVisibility(View.VISIBLE); mPauseButton.setVisibility(View.GONE); mDeleteButton.setEnabled(true); mPauseButton.requestFocus(); mVUMeterLayout.setVisibility(View.GONE); mSeekBarLayout.setVisibility(View.VISIBLE); mStartTime.setText(String.format(mTimerFormat, 0, 0)); mTotalTime.setText(String.format(mTimerFormat, mRecorder.sampleLength() / 60, mRecorder.sampleLength() % 60)); } mFileNameEditText.setEnabled(true); mFileNameEditText.clearFocus(); if (mRecorder.sampleLength() > 0) { if (mRecorder.state() == Recorder.PLAYING_PAUSED_STATE) { stopAnimation(); if (SoundRecorderPreferenceActivity.isEnabledSoundEffect(this)) { mSoundPool.play(mPauseSound, 1.0f, 1.0f, 0, 0, 1); } } else { mPlaySeekBar.setProgress(0); if (!skipRewindAnimation) { stopRecordPlayingAnimation(); } else { stopAnimation(); } } } else { stopAnimation(); } // we allow only one toast at one time if (mSampleInterrupted && mErrorUiMessage == null) { Toast.makeText(this, R.string.recording_stopped, Toast.LENGTH_SHORT).show(); } if (mErrorUiMessage != null) { Toast.makeText(this, mErrorUiMessage, Toast.LENGTH_SHORT).show(); } break; case Recorder.RECORDING_STATE: mNewButton.setEnabled(false); mNewButton.setVisibility(View.VISIBLE); mRecordButton.setVisibility(View.GONE); mStopButton.setVisibility(View.VISIBLE); mPlayButton.setVisibility(View.GONE); mPauseButton.setVisibility(View.GONE); mDeleteButton.setEnabled(false); mStopButton.requestFocus(); mVUMeterLayout.setVisibility(View.VISIBLE); mSeekBarLayout.setVisibility(View.GONE); mFileNameEditText.setEnabled(false); startRecordPlayingAnimation(); mPreviousVUMax = 0; break; case Recorder.PLAYING_STATE: mNewButton.setEnabled(false); mNewButton.setVisibility(View.VISIBLE); mRecordButton.setVisibility(View.GONE); mStopButton.setVisibility(View.GONE); mPlayButton.setVisibility(View.GONE); mPauseButton.setVisibility(View.VISIBLE); mDeleteButton.setEnabled(false); mPauseButton.requestFocus(); mVUMeterLayout.setVisibility(View.GONE); mSeekBarLayout.setVisibility(View.VISIBLE); mFileNameEditText.setEnabled(false); if (SoundRecorderPreferenceActivity.isEnabledSoundEffect(this)) { mSoundPool.play(mPlaySound, 1.0f, 1.0f, 0, 0, 1); } startRecordPlayingAnimation(); break; } updateTimerView(); updateSeekBar(); updateVUMeterView(); } /* * Called when Recorder changed it's state. */ public void onStateChanged(int state) { if (state == Recorder.PLAYING_STATE || state == Recorder.RECORDING_STATE) { mSampleInterrupted = false; mErrorUiMessage = null; } updateUi(false); } /* * Called when MediaPlayer encounters an error. */ public void onError(int error) { Resources res = getResources(); String message = null; switch (error) { case Recorder.STORAGE_ACCESS_ERROR: message = res.getString(R.string.error_sdcard_access); break; case Recorder.IN_CALL_RECORD_ERROR: // TODO: update error message to reflect that the recording // could not be // performed during a call. case Recorder.INTERNAL_ERROR: message = res.getString(R.string.error_app_internal); break; } if (message != null) { new AlertDialog.Builder(this).setTitle(R.string.app_name).setMessage(message) .setPositiveButton(R.string.button_ok, null).setCancelable(false).show(); } } @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); if (mRecorder.state() == Recorder.RECORDING_STATE || mRecorder.state() == Recorder.PLAYING_STATE) { return false; } else { getMenuInflater().inflate(R.layout.view_list_menu, menu); return true; } } @Override public boolean onOptionsItemSelected(MenuItem item) { Intent intent; switch (item.getItemId()) { case R.id.menu_fm: saveSample(); intent = new Intent(); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(Uri.parse("file://" + mRecorder.getRecordDir())); startActivity(intent); break; case R.id.menu_setting: intent = new Intent(this, SoundRecorderPreferenceActivity.class); startActivity(intent); break; default: break; } return true; } private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() { private final int DELTA = SEEK_BAR_MAX / 20; private int mProgress = 0; private boolean mPlayingAnimation = false; private boolean mForwardAnimation = true; @Override public void onStopTrackingTouch(SeekBar seekBar) { stopAnimation(); mRecorder.startPlayback((float) seekBar.getProgress() / SEEK_BAR_MAX); } @Override public void onStartTrackingTouch(SeekBar seekBar) { mRecorder.pausePlayback(); mPlayingAnimation = false; } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { if (!mPlayingAnimation) { mForwardAnimation = true; startForwardAnimation(); mPlayingAnimation = true; mProgress = progress; } if (progress >= mProgress + DELTA) { if (!mForwardAnimation) { mForwardAnimation = true; stopAnimation(); startForwardAnimation(); } mProgress = progress; } else if (progress < mProgress - DELTA) { if (mForwardAnimation) { mForwardAnimation = false; stopAnimation(); startBackwardAnimation(); } mProgress = progress; } setTimerView(((float) progress) / SEEK_BAR_MAX); mLastButtonId = 0; } } }; private class RecorderReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(RecorderService.RECORDER_SERVICE_BROADCAST_STATE)) { boolean isRecording = intent.getBooleanExtra( RecorderService.RECORDER_SERVICE_BROADCAST_STATE, false); mRecorder.setState(isRecording ? Recorder.RECORDING_STATE : Recorder.IDLE_STATE); } else if (intent.hasExtra(RecorderService.RECORDER_SERVICE_BROADCAST_ERROR)) { int error = intent.getIntExtra(RecorderService.RECORDER_SERVICE_BROADCAST_ERROR, 0); mRecorder.setError(error); } } }}
核心代码2...
package com.lv.reco;import java.io.File;import java.io.IOException;import android.app.KeyguardManager;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Context;import android.content.Intent;import android.media.AudioManager;import android.media.MediaRecorder;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.PowerManager;import android.os.PowerManager.WakeLock;import android.telephony.PhoneStateListener;import android.telephony.TelephonyManager;public class RecorderService extends Service implements MediaRecorder.OnErrorListener { public final static String ACTION_NAME = "action_type"; public final static int ACTION_INVALID = 0; public final static int ACTION_START_RECORDING = 1; public final static int ACTION_STOP_RECORDING = 2; public final static int ACTION_ENABLE_MONITOR_REMAIN_TIME = 3; public final static int ACTION_DISABLE_MONITOR_REMAIN_TIME = 4; public final static String ACTION_PARAM_FORMAT = "format"; public final static String ACTION_PARAM_PATH = "path"; public final static String ACTION_PARAM_HIGH_QUALITY = "high_quality"; public final static String ACTION_PARAM_MAX_FILE_SIZE = "max_file_size"; public final static String RECORDER_SERVICE_BROADCAST_NAME = "com.android.soundrecorder.broadcast"; public final static String RECORDER_SERVICE_BROADCAST_STATE = "is_recording"; public final static String RECORDER_SERVICE_BROADCAST_ERROR = "error_code"; public final static int NOTIFICATION_ID = 62343234; private static MediaRecorder mRecorder = null; private static String mFilePath = null; private static long mStartTime = 0; private RemainingTimeCalculator mRemainingTimeCalculator; private NotificationManager mNotifiManager; private Notification mLowStorageNotification; private TelephonyManager mTeleManager; private WakeLock mWakeLock; private KeyguardManager mKeyguardManager; private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { if (state != TelephonyManager.CALL_STATE_IDLE) { localStopRecording(); } } }; private final Handler mHandler = new Handler(); private Runnable mUpdateRemainingTime = new Runnable() { public void run() { if (mRecorder != null && mNeedUpdateRemainingTime) { updateRemainingTime(); } } }; private boolean mNeedUpdateRemainingTime; @Override public void onCreate() { super.onCreate(); mRecorder = null; mLowStorageNotification = null; mRemainingTimeCalculator = new RemainingTimeCalculator(); mNeedUpdateRemainingTime = false; mNotifiManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mTeleManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); mTeleManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SoundRecorder"); mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Bundle bundle = intent.getExtras(); if (bundle != null && bundle.containsKey(ACTION_NAME)) { switch (bundle.getInt(ACTION_NAME, ACTION_INVALID)) { case ACTION_START_RECORDING: localStartRecording(bundle.getInt(ACTION_PARAM_FORMAT), bundle.getString(ACTION_PARAM_PATH), bundle.getBoolean(ACTION_PARAM_HIGH_QUALITY), bundle.getLong(ACTION_PARAM_MAX_FILE_SIZE)); break; case ACTION_STOP_RECORDING: localStopRecording(); break; case ACTION_ENABLE_MONITOR_REMAIN_TIME: if (mRecorder != null) { mNeedUpdateRemainingTime = true; mHandler.post(mUpdateRemainingTime); } break; case ACTION_DISABLE_MONITOR_REMAIN_TIME: mNeedUpdateRemainingTime = false; if (mRecorder != null) { showRecordingNotification(); } break; default: break; } return START_STICKY; } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { mTeleManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); if (mWakeLock.isHeld()) { mWakeLock.release(); } super.onDestroy(); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onLowMemory() { localStopRecording(); super.onLowMemory(); } private void localStartRecording(int outputfileformat, String path, boolean highQuality, long maxFileSize) { if (mRecorder == null) { mRemainingTimeCalculator.reset(); if (maxFileSize != -1) { mRemainingTimeCalculator.setFileSizeLimit(new File(path), maxFileSize); } mRecorder = new MediaRecorder(); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); if (outputfileformat == MediaRecorder.OutputFormat.THREE_GPP) { mRemainingTimeCalculator.setBitRate(SoundRecorder.BITRATE_3GPP); mRecorder.setAudioSamplingRate(highQuality ? 44100 : 22050); mRecorder.setOutputFormat(outputfileformat); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); } else { mRemainingTimeCalculator.setBitRate(SoundRecorder.BITRATE_AMR); mRecorder.setAudioSamplingRate(highQuality ? 16000 : 8000); mRecorder.setOutputFormat(outputfileformat); mRecorder.setAudioEncoder(highQuality ? MediaRecorder.AudioEncoder.AMR_NB : MediaRecorder.AudioEncoder.AMR_NB); } mRecorder.setOutputFile(path); mRecorder.setOnErrorListener(this); // Handle IOException try { mRecorder.prepare(); } catch (IOException exception) { sendErrorBroadcast(Recorder.INTERNAL_ERROR); mRecorder.reset(); mRecorder.release(); mRecorder = null; return; } // Handle RuntimeException if the recording couldn't start try { mRecorder.start(); } catch (RuntimeException exception) { AudioManager audioMngr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); boolean isInCall = (audioMngr.getMode() == AudioManager.MODE_IN_CALL); if (isInCall) { sendErrorBroadcast(Recorder.IN_CALL_RECORD_ERROR); } else { sendErrorBroadcast(Recorder.INTERNAL_ERROR); } mRecorder.reset(); mRecorder.release(); mRecorder = null; return; } mFilePath = path; mStartTime = System.currentTimeMillis(); mWakeLock.acquire(); mNeedUpdateRemainingTime = false; sendStateBroadcast(); showRecordingNotification(); } } private void localStopRecording() { if (mRecorder != null) { mNeedUpdateRemainingTime = false; try { mRecorder.stop(); } catch (RuntimeException e) { } mRecorder.release(); mRecorder = null; sendStateBroadcast(); showStoppedNotification(); } stopSelf(); } private void showRecordingNotification() { Notification notification = new Notification(R.drawable.stat_sys_call_record, getString(R.string.notification_recording), System.currentTimeMillis()); notification.flags = Notification.FLAG_ONGOING_EVENT; PendingIntent pendingIntent; pendingIntent = PendingIntent .getActivity(this, 0, new Intent(this, SoundRecorder.class), 0); notification.setLatestEventInfo(this, getString(R.string.app_name), getString(R.string.notification_recording), pendingIntent); startForeground(NOTIFICATION_ID, notification); } private void showLowStorageNotification(int minutes) { if (mKeyguardManager.inKeyguardRestrictedInputMode()) { // it's not necessary to show this notification in lock-screen return; } if (mLowStorageNotification == null) { mLowStorageNotification = new Notification(R.drawable.stat_sys_call_record_full, getString(R.string.notification_recording), System.currentTimeMillis()); mLowStorageNotification.flags = Notification.FLAG_ONGOING_EVENT; } PendingIntent pendingIntent; pendingIntent = PendingIntent .getActivity(this, 0, new Intent(this, SoundRecorder.class), 0); mLowStorageNotification.setLatestEventInfo(this, getString(R.string.app_name), getString(R.string.notification_warning, minutes), pendingIntent); startForeground(NOTIFICATION_ID, mLowStorageNotification); } private void showStoppedNotification() { stopForeground(true); mLowStorageNotification = null; Notification notification = new Notification(R.drawable.stat_sys_call_record, getString(R.string.notification_stopped), System.currentTimeMillis()); notification.flags = Notification.FLAG_AUTO_CANCEL; Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setType("audio/*"); intent.setDataAndType(Uri.fromFile(new File(mFilePath)), "audio/*"); PendingIntent pendingIntent; pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); notification.setLatestEventInfo(this, getString(R.string.app_name), getString(R.string.notification_stopped), pendingIntent); mNotifiManager.notify(NOTIFICATION_ID, notification); } private void sendStateBroadcast() { Intent intent = new Intent(RECORDER_SERVICE_BROADCAST_NAME); intent.putExtra(RECORDER_SERVICE_BROADCAST_STATE, mRecorder != null); sendBroadcast(intent); } private void sendErrorBroadcast(int error) { Intent intent = new Intent(RECORDER_SERVICE_BROADCAST_NAME); intent.putExtra(RECORDER_SERVICE_BROADCAST_ERROR, error); sendBroadcast(intent); } private void updateRemainingTime() { long t = mRemainingTimeCalculator.timeRemaining(); if (t <= 0) { localStopRecording(); return; } else if (t <= 1800 && mRemainingTimeCalculator.currentLowerLimit() != RemainingTimeCalculator.FILE_SIZE_LIMIT) { // less than half one hour showLowStorageNotification((int) Math.ceil(t / 60.0)); } if (mRecorder != null && mNeedUpdateRemainingTime) { mHandler.postDelayed(mUpdateRemainingTime, 500); } } public static boolean isRecording() { return mRecorder != null; } public static String getFilePath() { return mFilePath; } public static long getStartTime() { return mStartTime; } public static void startRecording(Context context, int outputfileformat, String path, boolean highQuality, long maxFileSize) { Intent intent = new Intent(context, RecorderService.class); intent.putExtra(ACTION_NAME, ACTION_START_RECORDING); intent.putExtra(ACTION_PARAM_FORMAT, outputfileformat); intent.putExtra(ACTION_PARAM_PATH, path); intent.putExtra(ACTION_PARAM_HIGH_QUALITY, highQuality); intent.putExtra(ACTION_PARAM_MAX_FILE_SIZE, maxFileSize); context.startService(intent); } public static void stopRecording(Context context) { Intent intent = new Intent(context, RecorderService.class); intent.putExtra(ACTION_NAME, ACTION_STOP_RECORDING); context.startService(intent); } public static int getMaxAmplitude() { return mRecorder == null ? 0 : mRecorder.getMaxAmplitude(); } @Override public void onError(MediaRecorder mr, int what, int extra) { sendErrorBroadcast(Recorder.INTERNAL_ERROR); localStopRecording(); }}
效果图: