SoundRecorder.java revision 6c9130ef3893f6cff60148009e0c2ba0b0327da5
1f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch/*
2f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * Copyright (C) 2011 The Android Open Source Project
3f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch *
4f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * Licensed under the Apache License, Version 2.0 (the "License");
5f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * you may not use this file except in compliance with the License.
6f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * You may obtain a copy of the License at
7f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch *
8f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch *      http://www.apache.org/licenses/LICENSE-2.0
9f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch *
10f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * Unless required by applicable law or agreed to in writing, software
11f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * distributed under the License is distributed on an "AS IS" BASIS,
12f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * See the License for the specific language governing permissions and
14f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch * limitations under the License.
15f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch */
16f2ef799d0826b6d4f9bb3727f7878545b3ad29b9Ben Murdoch
1745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectpackage com.android.soundrecorder;
1845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
1945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport java.io.File;
2045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport java.text.SimpleDateFormat;
2145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport java.util.Date;
2245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
2345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.app.Activity;
2445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.app.AlertDialog;
2545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.ContentResolver;
2645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.ContentValues;
2745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.Intent;
2845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.Context;
2945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.IntentFilter;
3045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.BroadcastReceiver;
3145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.res.Configuration;
3245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.content.res.Resources;
3345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.database.Cursor;
346c9130ef3893f6cff60148009e0c2ba0b0327da5Marco Nelissenimport android.media.AudioManager;
3545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.media.MediaRecorder;
3645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.net.Uri;
3745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.os.Bundle;
3845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.os.Environment;
3945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.os.Handler;
4045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.os.PowerManager;
4145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.os.StatFs;
4245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.os.PowerManager.WakeLock;
4345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.provider.MediaStore;
4445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.util.Log;
4545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.view.KeyEvent;
4645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.view.View;
4745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.widget.Button;
4845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.widget.ImageButton;
4945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.widget.ImageView;
5045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.widget.LinearLayout;
5145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.widget.ProgressBar;
5245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectimport android.widget.TextView;
5345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
5445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project/**
5545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project * Calculates remaining recording time based on available disk space and
5645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project * optionally a maximum recording file size.
5745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project *
5845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project * The reason why this is not trivial is that the file grows in blocks
5945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project * every few seconds or so, while we want a smooth countdown.
6045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project */
6145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
6245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectclass RemainingTimeCalculator {
6345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public static final int UNKNOWN_LIMIT = 0;
6445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public static final int FILE_SIZE_LIMIT = 1;
6545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public static final int DISK_SPACE_LIMIT = 2;
6645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
6745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    // which of the two limits we will hit (or have fit) first
6845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private int mCurrentLowerLimit = UNKNOWN_LIMIT;
6945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
7045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private File mSDCardDirectory;
7145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
7245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     // State for tracking file size of recording.
7345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private File mRecordingFile;
7445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private long mMaxBytes;
7545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
7645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    // Rate at which the file grows
7745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private int mBytesPerSecond;
7845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
7945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    // time at which number of free blocks last changed
8045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private long mBlocksChangedTime;
8145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    // number of available blocks at that time
8245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private long mLastBlocks;
8345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
8445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    // time at which the size of the file has last changed
8545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private long mFileSizeChangedTime;
8645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    // size of the file at that time
8745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private long mLastFileSize;
8845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
8945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public RemainingTimeCalculator() {
9045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mSDCardDirectory = Environment.getExternalStorageDirectory();
9145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
9245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
9345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
9445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * If called, the calculator will return the minimum of two estimates:
9545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * how long until we run out of disk space and how long until the file
9645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * reaches the specified size.
9745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     *
9845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * @param file the file to watch
9945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * @param maxBytes the limit
10045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
10145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
10245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void setFileSizeLimit(File file, long maxBytes) {
10345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecordingFile = file;
10445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mMaxBytes = maxBytes;
10545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
10645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
10745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
10845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Resets the interpolation.
10945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
11045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void reset() {
11145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mCurrentLowerLimit = UNKNOWN_LIMIT;
11245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mBlocksChangedTime = -1;
11345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mFileSizeChangedTime = -1;
11445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
11545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
11645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
11745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Returns how long (in seconds) we can continue recording.
11845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
11945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public long timeRemaining() {
12045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // Calculate how long we can record based on free disk space
12145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
12245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        StatFs fs = new StatFs(mSDCardDirectory.getAbsolutePath());
12345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long blocks = fs.getAvailableBlocks();
12445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long blockSize = fs.getBlockSize();
12545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long now = System.currentTimeMillis();
12645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
12745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (mBlocksChangedTime == -1 || blocks != mLastBlocks) {
12845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mBlocksChangedTime = now;
12945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mLastBlocks = blocks;
13045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
13145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
13245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        /* The calculation below always leaves one free block, since free space
13345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project           in the block we're currently writing to is not added. This
13445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project           last block might get nibbled when we close and flush the file, but
13545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project           we won't run out of disk. */
13645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
13745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // at mBlocksChangedTime we had this much time
13845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long result = mLastBlocks*blockSize/mBytesPerSecond;
13945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // so now we have this much time
14045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        result -= (now - mBlocksChangedTime)/1000;
14145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
14245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (mRecordingFile == null) {
14345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mCurrentLowerLimit = DISK_SPACE_LIMIT;
14445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return result;
14545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
14645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
14745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // If we have a recording file set, we calculate a second estimate
14845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // based on how long it will take us to reach mMaxBytes.
14945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
15045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecordingFile = new File(mRecordingFile.getAbsolutePath());
15145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long fileSize = mRecordingFile.length();
15245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (mFileSizeChangedTime == -1 || fileSize != mLastFileSize) {
15345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mFileSizeChangedTime = now;
15445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mLastFileSize = fileSize;
15545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
15645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
15745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long result2 = (mMaxBytes - fileSize)/mBytesPerSecond;
15845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        result2 -= (now - mFileSizeChangedTime)/1000;
15945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        result2 -= 1; // just for safety
16045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
16145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mCurrentLowerLimit = result < result2
16245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            ? DISK_SPACE_LIMIT : FILE_SIZE_LIMIT;
16345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
16445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        return Math.min(result, result2);
16545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
16645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
16745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
16845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Indicates which limit we will hit (or have hit) first, by returning one
16945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * of FILE_SIZE_LIMIT or DISK_SPACE_LIMIT or UNKNOWN_LIMIT. We need this to
17045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * display the correct message to the user when we hit one of the limits.
17145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
17245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public int currentLowerLimit() {
17345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        return mCurrentLowerLimit;
17445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
17545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
17645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
17745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Is there any point of trying to start recording?
17845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
17945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public boolean diskSpaceAvailable() {
18045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        StatFs fs = new StatFs(mSDCardDirectory.getAbsolutePath());
18145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // keep one free block
18245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        return fs.getAvailableBlocks() > 1;
18345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
18445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
18545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
18645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Sets the bit rate used in the interpolation.
18745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     *
18845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * @param bitRate the bit rate to set in bits/sec.
18945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
19045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void setBitRate(int bitRate) {
19145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mBytesPerSecond = bitRate/8;
19245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
19345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project}
19445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
19545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Projectpublic class SoundRecorder extends Activity
19645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        implements Button.OnClickListener, Recorder.OnStateChangedListener {
19745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String TAG = "SoundRecorder";
19845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String STATE_FILE_NAME = "soundrecorder.state";
19945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String RECORDER_STATE_KEY = "recorder_state";
20045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String SAMPLE_INTERRUPTED_KEY = "sample_interrupted";
20145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String MAX_FILE_SIZE_KEY = "max_file_size";
20245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
20345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String AUDIO_3GPP = "audio/3gpp";
20445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String AUDIO_AMR = "audio/amr";
20545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final String AUDIO_ANY = "audio/*";
2069a879fc7b23550a6b1d84535df02528ed0f49f27Gloria Wang    static final String ANY_ANY = "*/*";
20745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
20845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final int BITRATE_AMR =  5900; // bits/sec
20945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    static final int BITRATE_3GPP = 5900;
21045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
21145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    WakeLock mWakeLock;
21245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    String mRequestedType = AUDIO_ANY;
21345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    Recorder mRecorder;
21445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    boolean mSampleInterrupted = false;
21545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    String mErrorUiMessage = null; // Some error messages are displayed in the UI,
21645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                                   // not a dialog. This happens when a recording
21745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                                   // is interrupted for some reason.
21845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
21945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    long mMaxFileSize = -1;        // can be specified in the intent
22045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    RemainingTimeCalculator mRemainingTimeCalculator;
22145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
22245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    String mTimerFormat;
22345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    final Handler mHandler = new Handler();
22445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    Runnable mUpdateTimer = new Runnable() {
22545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        public void run() { updateTimerView(); }
22645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    };
22745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
22845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    ImageButton mRecordButton;
22945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    ImageButton mPlayButton;
23045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    ImageButton mStopButton;
23145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
23245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    ImageView mStateLED;
23345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    TextView mStateMessage1;
23445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    TextView mStateMessage2;
23545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    ProgressBar mStateProgressBar;
23645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    TextView mTimerView;
23745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
23845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    LinearLayout mExitButtons;
23945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    Button mAcceptButton;
24045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    Button mDiscardButton;
24145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    VUMeter mVUMeter;
24245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private BroadcastReceiver mSDCardMountEventReceiver = null;
24345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
24445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    @Override
24545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void onCreate(Bundle icycle) {
24645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        super.onCreate(icycle);
24745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
24845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Intent i = getIntent();
24945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (i != null) {
25045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            String s = i.getType();
2519a879fc7b23550a6b1d84535df02528ed0f49f27Gloria Wang            if (AUDIO_AMR.equals(s) || AUDIO_3GPP.equals(s) || AUDIO_ANY.equals(s)
2529a879fc7b23550a6b1d84535df02528ed0f49f27Gloria Wang                    || ANY_ANY.equals(s)) {
25345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRequestedType = s;
25445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            } else if (s != null) {
25545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                // we only support amr and 3gpp formats right now
25645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                setResult(RESULT_CANCELED);
25745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                finish();
25845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                return;
25945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            }
26045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
26145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            final String EXTRA_MAX_BYTES
26245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                = android.provider.MediaStore.Audio.Media.EXTRA_MAX_BYTES;
26345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mMaxFileSize = i.getLongExtra(EXTRA_MAX_BYTES, -1);
26445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
26545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
2669a879fc7b23550a6b1d84535df02528ed0f49f27Gloria Wang        if (AUDIO_ANY.equals(mRequestedType) || ANY_ANY.equals(mRequestedType)) {
26745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mRequestedType = AUDIO_3GPP;
26845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
26945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
27045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        setContentView(R.layout.main);
27145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
27245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecorder = new Recorder();
27345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecorder.setOnStateChangedListener(this);
27445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRemainingTimeCalculator = new RemainingTimeCalculator();
27545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
27645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        PowerManager pm
27745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            = (PowerManager) getSystemService(Context.POWER_SERVICE);
27845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
27945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                                    "SoundRecorder");
28045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
28145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        initResourceRefs();
28245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
28345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        setResult(RESULT_CANCELED);
28445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        registerExternalStorageListener();
28545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (icycle != null) {
28645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            Bundle recorderState = icycle.getBundle(RECORDER_STATE_KEY);
28745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            if (recorderState != null) {
28845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecorder.restoreState(recorderState);
28945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mSampleInterrupted = recorderState.getBoolean(SAMPLE_INTERRUPTED_KEY, false);
29045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mMaxFileSize = recorderState.getLong(MAX_FILE_SIZE_KEY, -1);
29145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            }
29245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
29345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
29445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        updateUi();
29545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
29645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
29745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    @Override
29845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void onConfigurationChanged(Configuration newConfig) {
29945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        super.onConfigurationChanged(newConfig);
30045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
30145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        setContentView(R.layout.main);
30245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        initResourceRefs();
30345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        updateUi();
30445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
30545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
30645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    @Override
30745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    protected void onSaveInstanceState(Bundle outState) {
30845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        super.onSaveInstanceState(outState);
30945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
31045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (mRecorder.sampleLength() == 0)
31145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return;
31245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
31345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Bundle recorderState = new Bundle();
31445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
31545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecorder.saveState(recorderState);
31645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        recorderState.putBoolean(SAMPLE_INTERRUPTED_KEY, mSampleInterrupted);
31745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        recorderState.putLong(MAX_FILE_SIZE_KEY, mMaxFileSize);
31845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
31945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        outState.putBundle(RECORDER_STATE_KEY, recorderState);
32045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
32145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
32245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
32345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Whenever the UI is re-created (due f.ex. to orientation change) we have
32445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * to reinitialize references to the views.
32545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
32645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void initResourceRefs() {
32745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecordButton = (ImageButton) findViewById(R.id.recordButton);
32845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mPlayButton = (ImageButton) findViewById(R.id.playButton);
32945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mStopButton = (ImageButton) findViewById(R.id.stopButton);
33045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
33145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mStateLED = (ImageView) findViewById(R.id.stateLED);
33245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mStateMessage1 = (TextView) findViewById(R.id.stateMessage1);
33345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mStateMessage2 = (TextView) findViewById(R.id.stateMessage2);
33445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mStateProgressBar = (ProgressBar) findViewById(R.id.stateProgressBar);
33545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mTimerView = (TextView) findViewById(R.id.timerView);
33645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
33745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mExitButtons = (LinearLayout) findViewById(R.id.exitButtons);
33845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mAcceptButton = (Button) findViewById(R.id.acceptButton);
33945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mDiscardButton = (Button) findViewById(R.id.discardButton);
34045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mVUMeter = (VUMeter) findViewById(R.id.uvMeter);
34145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
34245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecordButton.setOnClickListener(this);
34345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mPlayButton.setOnClickListener(this);
34445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mStopButton.setOnClickListener(this);
34545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mAcceptButton.setOnClickListener(this);
34645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mDiscardButton.setOnClickListener(this);
34745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
34845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mTimerFormat = getResources().getString(R.string.timer_format);
34945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
35045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mVUMeter.setRecorder(mRecorder);
35145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
35245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
35345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
35445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Make sure we're not recording music playing in the background, ask
35545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * the MediaPlaybackService to pause playback.
35645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
35745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void stopAudioPlayback() {
3586c9130ef3893f6cff60148009e0c2ba0b0327da5Marco Nelissen        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
3596c9130ef3893f6cff60148009e0c2ba0b0327da5Marco Nelissen        am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
36045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
36145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
36245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
36345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Handle the buttons.
36445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
36545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void onClick(View button) {
36645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (!button.isEnabled())
36745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return;
36845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
36945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        switch (button.getId()) {
37045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case R.id.recordButton:
37145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRemainingTimeCalculator.reset();
37245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
37345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mSampleInterrupted = true;
37445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mErrorUiMessage = getResources().getString(R.string.insert_sd_card);
37545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    updateUi();
37645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                } else if (!mRemainingTimeCalculator.diskSpaceAvailable()) {
37745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mSampleInterrupted = true;
37845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mErrorUiMessage = getResources().getString(R.string.storage_is_full);
37945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    updateUi();
38045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                } else {
38145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    stopAudioPlayback();
38245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
38345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    if (AUDIO_AMR.equals(mRequestedType)) {
38445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        mRemainingTimeCalculator.setBitRate(BITRATE_AMR);
385615384c62e2906613590e6f33a37f7dfe4276a59Jean-Michel Trivi                        mRecorder.startRecording(MediaRecorder.OutputFormat.AMR_NB, ".amr", this);
38645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    } else if (AUDIO_3GPP.equals(mRequestedType)) {
38745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        mRemainingTimeCalculator.setBitRate(BITRATE_3GPP);
388615384c62e2906613590e6f33a37f7dfe4276a59Jean-Michel Trivi                        mRecorder.startRecording(MediaRecorder.OutputFormat.THREE_GPP, ".3gpp",
389615384c62e2906613590e6f33a37f7dfe4276a59Jean-Michel Trivi                                this);
39045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    } else {
39145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        throw new IllegalArgumentException("Invalid output file type requested");
39245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    }
39345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
39445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    if (mMaxFileSize != -1) {
39545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        mRemainingTimeCalculator.setFileSizeLimit(
39645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                                mRecorder.sampleFile(), mMaxFileSize);
39745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    }
39845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                }
39945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
40045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case R.id.playButton:
40145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecorder.startPlayback();
40245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
40345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case R.id.stopButton:
40445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecorder.stop();
40545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
40645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case R.id.acceptButton:
40745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecorder.stop();
40845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                saveSample();
40945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                finish();
41045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
41145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case R.id.discardButton:
41245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecorder.delete();
41345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                finish();
41445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
41545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
41645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
41745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
41845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
41945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Handle the "back" hardware key.
42045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
42145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    @Override
42245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
42345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (keyCode == KeyEvent.KEYCODE_BACK) {
42445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            switch (mRecorder.state()) {
42545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                case Recorder.IDLE_STATE:
42645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    if (mRecorder.sampleLength() > 0)
42745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        saveSample();
42845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    finish();
42945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    break;
43045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                case Recorder.PLAYING_STATE:
43145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mRecorder.stop();
43245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    saveSample();
43345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    break;
43445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                case Recorder.RECORDING_STATE:
43545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mRecorder.clear();
43645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    break;
43745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            }
43845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return true;
43945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        } else {
44045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return super.onKeyDown(keyCode, event);
44145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
44245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
44345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
44445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    @Override
44545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void onStop() {
44645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecorder.stop();
44745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        super.onStop();
44845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
44945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
45045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    @Override
45145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    protected void onPause() {
45245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mSampleInterrupted = mRecorder.state() == Recorder.RECORDING_STATE;
45345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mRecorder.stop();
45445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
45545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        super.onPause();
45645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
45745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
45845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
45945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * If we have just recorded a smaple, this adds it to the media data base
46045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * and sets the result to the sample's URI.
46145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
46245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void saveSample() {
46345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (mRecorder.sampleLength() == 0)
46445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return;
46545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Uri uri = null;
46645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        try {
46745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            uri = this.addToMediaDB(mRecorder.sampleFile());
46845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        } catch(UnsupportedOperationException ex) {  // Database manipulation failure
46945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return;
47045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
47145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (uri == null) {
47245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return;
47345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
47445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        setResult(RESULT_OK, new Intent().setData(uri));
47545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
47645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
47745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
47845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Called on destroy to unregister the SD card mount event receiver.
47945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
48045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    @Override
48145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void onDestroy() {
48245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (mSDCardMountEventReceiver != null) {
48345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            unregisterReceiver(mSDCardMountEventReceiver);
48445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mSDCardMountEventReceiver = null;
48545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
48645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        super.onDestroy();
48745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
48845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
48945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
49045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Registers an intent to listen for ACTION_MEDIA_EJECT/ACTION_MEDIA_MOUNTED
49145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * notifications.
49245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
49345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void registerExternalStorageListener() {
49445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (mSDCardMountEventReceiver == null) {
49545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mSDCardMountEventReceiver = new BroadcastReceiver() {
49645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                @Override
49745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                public void onReceive(Context context, Intent intent) {
49845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    String action = intent.getAction();
49945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
50045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        mRecorder.delete();
50145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
50245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        mSampleInterrupted = false;
50345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        updateUi();
50445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    }
50545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                }
50645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            };
50745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            IntentFilter iFilter = new IntentFilter();
50845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
50945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
51045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            iFilter.addDataScheme("file");
51145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            registerReceiver(mSDCardMountEventReceiver, iFilter);
51245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
51345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
51445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
51545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
51645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * A simple utility to do a query into the databases.
51745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
51845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
51945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        try {
52045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            ContentResolver resolver = getContentResolver();
52145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            if (resolver == null) {
52245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                return null;
52345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            }
52445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
52545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project         } catch (UnsupportedOperationException ex) {
52645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return null;
52745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
52845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
52945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
53045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
53145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Add the given audioId to the playlist with the given playlistId; and maintain the
53245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * play_order in the playlist.
53345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
53445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void addToPlaylist(ContentResolver resolver, int audioId, long playlistId) {
53545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        String[] cols = new String[] {
53645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                "count(*)"
53745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        };
53845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
53945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Cursor cur = resolver.query(uri, cols, null, null, null);
54045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cur.moveToFirst();
54145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        final int base = cur.getInt(0);
54245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cur.close();
54345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        ContentValues values = new ContentValues();
54445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + audioId));
54545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId);
54645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        resolver.insert(uri, values);
54745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
54845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
54945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
55045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Obtain the id for the default play list from the audio_playlists table.
55145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
55245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private int getPlaylistId(Resources res) {
55345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Uri uri = MediaStore.Audio.Playlists.getContentUri("external");
55445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        final String[] ids = new String[] { MediaStore.Audio.Playlists._ID };
55545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        final String where = MediaStore.Audio.Playlists.NAME + "=?";
55645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        final String[] args = new String[] { res.getString(R.string.audio_db_playlist_name) };
55745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Cursor cursor = query(uri, ids, where, args, null);
55845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (cursor == null) {
55945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            Log.v(TAG, "query returns null");
56045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
56145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        int id = -1;
56245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (cursor != null) {
56345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            cursor.moveToFirst();
56445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            if (!cursor.isAfterLast()) {
56545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                id = cursor.getInt(0);
56645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            }
56745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
56845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cursor.close();
56945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        return id;
57045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
57145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
57245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
57345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Create a playlist with the given default playlist name, if no such playlist exists.
57445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
57545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private Uri createPlaylist(Resources res, ContentResolver resolver) {
57645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        ContentValues cv = new ContentValues();
57745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Playlists.NAME, res.getString(R.string.audio_db_playlist_name));
57845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Uri uri = resolver.insert(MediaStore.Audio.Playlists.getContentUri("external"), cv);
57945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (uri == null) {
58045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            new AlertDialog.Builder(this)
58145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setTitle(R.string.app_name)
58245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setMessage(R.string.error_mediadb_new_record)
58345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setPositiveButton(R.string.button_ok, null)
58445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setCancelable(false)
58545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .show();
58645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
58745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        return uri;
58845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
58945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
59045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
59145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Adds file and returns content uri.
59245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
59345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private Uri addToMediaDB(File file) {
59445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Resources res = getResources();
59545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        ContentValues cv = new ContentValues();
59645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long current = System.currentTimeMillis();
59745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long modDate = file.lastModified();
59845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Date date = new Date(current);
59945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        SimpleDateFormat formatter = new SimpleDateFormat(
60045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                res.getString(R.string.audio_db_title_format));
60145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        String title = formatter.format(date);
6020508261c0f215eaa82a161158404cb317727b3f8Sahil Verma        long sampleLengthMillis = mRecorder.sampleLength() * 1000L;
60345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
60445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // Lets label the recorded audio file as NON-MUSIC so that the file
60545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // won't be displayed automatically, except for in the playlist.
60645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.IS_MUSIC, "0");
60745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
60845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.TITLE, title);
60945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.DATA, file.getAbsolutePath());
61045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
61145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.DATE_MODIFIED, (int) (modDate / 1000));
6120508261c0f215eaa82a161158404cb317727b3f8Sahil Verma        cv.put(MediaStore.Audio.Media.DURATION, sampleLengthMillis);
61345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.MIME_TYPE, mRequestedType);
61445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.ARTIST,
61545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                res.getString(R.string.audio_db_artist_name));
61645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        cv.put(MediaStore.Audio.Media.ALBUM,
61745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                res.getString(R.string.audio_db_album_name));
61845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Log.d(TAG, "Inserting audio record: " + cv.toString());
61945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        ContentResolver resolver = getContentResolver();
62045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
62145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Log.d(TAG, "ContentURI: " + base);
62245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Uri result = resolver.insert(base, cv);
62345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (result == null) {
62445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            new AlertDialog.Builder(this)
62545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setTitle(R.string.app_name)
62645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setMessage(R.string.error_mediadb_new_record)
62745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setPositiveButton(R.string.button_ok, null)
62845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setCancelable(false)
62945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .show();
63045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return null;
63145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
63245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (getPlaylistId(res) == -1) {
63345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            createPlaylist(res, resolver);
63445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
63545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        int audioId = Integer.valueOf(result.getLastPathSegment());
63645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        addToPlaylist(resolver, audioId, getPlaylistId(res));
63745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
63845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // Notify those applications such as Music listening to the
63945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        // scanner events that a recorded audio file just created.
64045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
64145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        return result;
64245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
64345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
64445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
64545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Update the big MM:SS timer. If we are in playback, also update the
64645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * progress bar.
64745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
64845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void updateTimerView() {
64945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Resources res = getResources();
65045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        int state = mRecorder.state();
65145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
65245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        boolean ongoing = state == Recorder.RECORDING_STATE || state == Recorder.PLAYING_STATE;
65345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
65445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long time = ongoing ? mRecorder.progress() : mRecorder.sampleLength();
65545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        String timeStr = String.format(mTimerFormat, time/60, time%60);
65645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mTimerView.setText(timeStr);
65745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
65845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (state == Recorder.PLAYING_STATE) {
65945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mStateProgressBar.setProgress((int)(100*time/mRecorder.sampleLength()));
66045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        } else if (state == Recorder.RECORDING_STATE) {
66145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            updateTimeRemaining();
66245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
66345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
66445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (ongoing)
66545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mHandler.postDelayed(mUpdateTimer, 1000);
66645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
66745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
66845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
66945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Called when we're in recording state. Find out how much longer we can
67045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * go on recording. If it's under 5 minutes, we display a count-down in
67145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * the UI. If we've run out of time, stop the recording.
67245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
67345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void updateTimeRemaining() {
67445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        long t = mRemainingTimeCalculator.timeRemaining();
67545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
67645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (t <= 0) {
67745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mSampleInterrupted = true;
67845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
67945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            int limit = mRemainingTimeCalculator.currentLowerLimit();
68045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            switch (limit) {
68145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                case RemainingTimeCalculator.DISK_SPACE_LIMIT:
68245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mErrorUiMessage
68345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        = getResources().getString(R.string.storage_is_full);
68445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    break;
68545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                case RemainingTimeCalculator.FILE_SIZE_LIMIT:
68645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mErrorUiMessage
68745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                        = getResources().getString(R.string.max_length_reached);
68845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    break;
68945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                default:
69045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mErrorUiMessage = null;
69145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    break;
69245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            }
69345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
69445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mRecorder.stop();
69545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            return;
69645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
69745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
69845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Resources res = getResources();
69945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        String timeStr = "";
70045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
70145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (t < 60)
70245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            timeStr = String.format(res.getString(R.string.sec_available), t);
70345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        else if (t < 540)
70445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            timeStr = String.format(res.getString(R.string.min_available), t/60 + 1);
70545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
70645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mStateMessage1.setText(timeStr);
70745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
70845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
70945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /**
71045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Shows/hides the appropriate child views for the new state.
71145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
71245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    private void updateUi() {
71345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Resources res = getResources();
71445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
71545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        switch (mRecorder.state()) {
71645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case Recorder.IDLE_STATE:
71745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                if (mRecorder.sampleLength() == 0) {
71845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mRecordButton.setEnabled(true);
71945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mRecordButton.setFocusable(true);
72045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mPlayButton.setEnabled(false);
72145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mPlayButton.setFocusable(false);
72245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStopButton.setEnabled(false);
72345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStopButton.setFocusable(false);
72445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mRecordButton.requestFocus();
72545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
72645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateMessage1.setVisibility(View.INVISIBLE);
7279913636a48ba71e91d45e6805bfe3e41ac877263Ben Murdoch                    mStateLED.setVisibility(View.INVISIBLE);
7289913636a48ba71e91d45e6805bfe3e41ac877263Ben Murdoch                    mStateMessage2.setVisibility(View.INVISIBLE);
72945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
73045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mExitButtons.setVisibility(View.INVISIBLE);
73145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mVUMeter.setVisibility(View.VISIBLE);
73245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
73345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateProgressBar.setVisibility(View.INVISIBLE);
73445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
73545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    setTitle(res.getString(R.string.record_your_message));
73645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                } else {
73745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mRecordButton.setEnabled(true);
73845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mRecordButton.setFocusable(true);
73945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mPlayButton.setEnabled(true);
74045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mPlayButton.setFocusable(true);
74145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStopButton.setEnabled(false);
74245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStopButton.setFocusable(false);
74345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
74445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateMessage1.setVisibility(View.INVISIBLE);
74545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateLED.setVisibility(View.INVISIBLE);
74645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateMessage2.setVisibility(View.INVISIBLE);
74745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
74845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mExitButtons.setVisibility(View.VISIBLE);
74945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mVUMeter.setVisibility(View.INVISIBLE);
75045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
75145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateProgressBar.setVisibility(View.INVISIBLE);
75245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
75345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    setTitle(res.getString(R.string.message_recorded));
75445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                }
75545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
75645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                if (mSampleInterrupted) {
75745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateMessage2.setVisibility(View.VISIBLE);
75845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateMessage2.setText(res.getString(R.string.recording_stopped));
7599913636a48ba71e91d45e6805bfe3e41ac877263Ben Murdoch                    mStateLED.setVisibility(View.INVISIBLE);
76045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                }
76145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
76245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                if (mErrorUiMessage != null) {
76345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateMessage1.setText(mErrorUiMessage);
76445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                    mStateMessage1.setVisibility(View.VISIBLE);
76545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                }
76645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
76745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
76845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case Recorder.RECORDING_STATE:
76945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecordButton.setEnabled(false);
77045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecordButton.setFocusable(false);
77145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mPlayButton.setEnabled(false);
77245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mPlayButton.setFocusable(false);
77345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStopButton.setEnabled(true);
77445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStopButton.setFocusable(true);
77545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
77645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateMessage1.setVisibility(View.VISIBLE);
77745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateLED.setVisibility(View.VISIBLE);
77845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateLED.setImageResource(R.drawable.recording_led);
77945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateMessage2.setVisibility(View.VISIBLE);
78045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateMessage2.setText(res.getString(R.string.recording));
78145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
78245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mExitButtons.setVisibility(View.INVISIBLE);
78345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mVUMeter.setVisibility(View.VISIBLE);
78445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
78545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateProgressBar.setVisibility(View.INVISIBLE);
78645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
78745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                setTitle(res.getString(R.string.record_your_message));
78845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
78945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
79045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
79145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case Recorder.PLAYING_STATE:
79245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecordButton.setEnabled(true);
79345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mRecordButton.setFocusable(true);
79445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mPlayButton.setEnabled(false);
79545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mPlayButton.setFocusable(false);
79645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStopButton.setEnabled(true);
79745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStopButton.setFocusable(true);
79845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
79945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateMessage1.setVisibility(View.INVISIBLE);
80045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateLED.setVisibility(View.INVISIBLE);
80145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateMessage2.setVisibility(View.INVISIBLE);
80245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
80345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mExitButtons.setVisibility(View.VISIBLE);
80445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mVUMeter.setVisibility(View.INVISIBLE);
80545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
80645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mStateProgressBar.setVisibility(View.VISIBLE);
80745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
80845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                setTitle(res.getString(R.string.review_message));
80945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
81045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
81145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
81245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
81345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        updateTimerView();
81445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        mVUMeter.invalidate();
81545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
81645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
81745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
81845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Called when Recorder changed it's state.
81945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
82045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void onStateChanged(int state) {
82145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (state == Recorder.PLAYING_STATE || state == Recorder.RECORDING_STATE) {
82245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mSampleInterrupted = false;
82345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            mErrorUiMessage = null;
8248eced4bcd84e4006672dc9512f06e7f553c410c1Eva            mWakeLock.acquire(); // we don't want to go to sleep while recording or playing
82545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        } else {
82645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            if (mWakeLock.isHeld())
82745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                mWakeLock.release();
82845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
82945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
83045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        updateUi();
83145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
83245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
83345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    /*
83445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     * Called when MediaPlayer encounters an error.
83545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project     */
83645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    public void onError(int error) {
83745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        Resources res = getResources();
83845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project
83945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        String message = null;
84045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        switch (error) {
84145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case Recorder.SDCARD_ACCESS_ERROR:
84245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                message = res.getString(R.string.error_sdcard_access);
84345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
844615384c62e2906613590e6f33a37f7dfe4276a59Jean-Michel Trivi            case Recorder.IN_CALL_RECORD_ERROR:
845615384c62e2906613590e6f33a37f7dfe4276a59Jean-Michel Trivi                // TODO: update error message to reflect that the recording could not be
846615384c62e2906613590e6f33a37f7dfe4276a59Jean-Michel Trivi                //       performed during a call.
84745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            case Recorder.INTERNAL_ERROR:
84845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                message = res.getString(R.string.error_app_internal);
84945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                break;
85045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
85145fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        if (message != null) {
85245fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project            new AlertDialog.Builder(this)
85345fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setTitle(R.string.app_name)
85445fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setMessage(message)
85545fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setPositiveButton(R.string.button_ok, null)
85645fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .setCancelable(false)
85745fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project                .show();
85845fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project        }
85945fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project    }
86045fd319136b87911aae50269618b51c4a5902ad9The Android Open Source Project}
861