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