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