Change focus sound.

bug:5401870

Change-Id: Ifb5c61ad52489c0b8fb711ba6ada624f20f0e880
diff --git a/res/raw/camera_focus.ogg b/res/raw/camera_focus.ogg
new file mode 100644
index 0000000..0db2683
--- /dev/null
+++ b/res/raw/camera_focus.ogg
Binary files differ
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 74a1b37..8086626 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -356,7 +356,7 @@
         mPreviewFrame.setOnTouchListener(this);
         mFocusIndicator = (RotateLayout) findViewById(R.id.focus_indicator_rotate_layout);
         mFocusManager.initialize(mFocusIndicator, mPreviewFrame, mFaceView, this);
-        mFocusManager.initializeToneGenerator();
+        mFocusManager.initializeSoundPlayer(getResources().openRawResourceFd(R.raw.camera_focus));
         Util.initializeScreenBrightness(getWindow(), getContentResolver());
         installIntentFilter();
         initializeZoom();
@@ -413,7 +413,7 @@
         mLocationManager.recordLocation(recordLocation);
 
         installIntentFilter();
-        mFocusManager.initializeToneGenerator();
+        mFocusManager.initializeSoundPlayer(getResources().openRawResourceFd(R.raw.camera_focus));
         initializeZoom();
         keepMediaProviderInstance();
         checkStorage();
@@ -1262,7 +1262,7 @@
         mLocationManager.recordLocation(false);
         updateExposureOnScreenIndicator(0);
 
-        mFocusManager.releaseToneGenerator();
+        mFocusManager.releaseSoundPlayer();
 
         if (mStorageHint != null) {
             mStorageHint.cancel();
diff --git a/src/com/android/camera/FocusManager.java b/src/com/android/camera/FocusManager.java
index f1b26fb..cf60921 100644
--- a/src/com/android/camera/FocusManager.java
+++ b/src/com/android/camera/FocusManager.java
@@ -20,11 +20,10 @@
 import com.android.camera.ui.FocusIndicator;
 import com.android.camera.ui.FocusIndicatorView;
 
+import android.content.res.AssetFileDescriptor;
 import android.graphics.Rect;
 import android.hardware.Camera.Area;
 import android.hardware.Camera.Parameters;
-import android.media.AudioManager;
-import android.media.ToneGenerator;
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
@@ -55,7 +54,7 @@
 
     private boolean mInitialized;
     private boolean mFocusAreaSupported;
-    private ToneGenerator mFocusToneGenerator;
+    private SoundPlayer mSoundPlayer;
     private View mFocusIndicatorRotateLayout;
     private FocusIndicatorView mFocusIndicator;
     private View mPreviewFrame;
@@ -191,8 +190,8 @@
                 // not do a full scan. The focus callback arrives before doSnap
                 // so the state is always STATE_FOCUSING.
                 if (!Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusMode)
-                        && mFocusToneGenerator != null) {
-                    mFocusToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2);
+                        && mSoundPlayer != null) {
+                    mSoundPlayer.play();
                 }
             } else {
                 mState = STATE_FAIL;
@@ -315,23 +314,17 @@
         }
     }
 
-    public void initializeToneGenerator() {
-        // Initialize focus tone generator.
-        try {
-            mFocusToneGenerator = new ToneGenerator(
-                    AudioManager.STREAM_SYSTEM, FOCUS_BEEP_VOLUME);
-        } catch (Throwable ex) {
-            Log.w(TAG, "Exception caught while creating tone generator: ", ex);
-            mFocusToneGenerator = null;
+    public void initializeSoundPlayer(AssetFileDescriptor fd) {
+        mSoundPlayer = new SoundPlayer(fd);
+    }
+
+    public void releaseSoundPlayer() {
+        if (mSoundPlayer != null) {
+            mSoundPlayer.release();
+            mSoundPlayer = null;
         }
     }
 
-    public void releaseToneGenerator() {
-        if (mFocusToneGenerator != null) {
-            mFocusToneGenerator.release();
-            mFocusToneGenerator = null;
-        }
-    }
 
     // This can only be called after mParameters is initialized.
     public String getFocusMode() {
diff --git a/src/com/android/camera/SoundPlayer.java b/src/com/android/camera/SoundPlayer.java
new file mode 100644
index 0000000..1c2d16b
--- /dev/null
+++ b/src/com/android/camera/SoundPlayer.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera;
+
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Plays an AssetFileDescriptor, but does all the hard work on another thread so
+ * that any slowness with preparing or loading doesn't block the calling thread.
+ */
+public class SoundPlayer implements Runnable {
+    private static final String TAG = "SoundPlayer";
+    private Thread mThread;
+    private MediaPlayer mPlayer;
+    private int mPlayCount = 0;
+    private boolean mExit;
+    private AssetFileDescriptor mAfd;
+
+    @Override
+    public void run() {
+        while(true) {
+            try {
+                if (mPlayer == null) {
+                    MediaPlayer player = new MediaPlayer();
+                    player.setAudioStreamType(AudioManager.STREAM_SYSTEM);
+                    player.setDataSource(mAfd.getFileDescriptor(), mAfd.getStartOffset(),
+                            mAfd.getLength());
+                    player.setLooping(false);
+                    player.prepare();
+                    mPlayer = player;
+                    mAfd.close();
+                    mAfd = null;
+                }
+                synchronized (this) {
+                    while(true) {
+                        if (mExit) {
+                            return;
+                        } else if (mPlayCount <= 0) {
+                            wait();
+                        } else {
+                            mPlayCount--;
+                            break;
+                        }
+                    }
+                }
+                mPlayer.start();
+            } catch (Exception e) {
+                Log.e(TAG, "Error playing sound", e);
+            }
+        }
+    }
+
+    public SoundPlayer(AssetFileDescriptor afd) {
+        mAfd = afd;
+    }
+
+    public void play() {
+        if (mThread == null) {
+            mThread = new Thread(this);
+            mThread.start();
+        }
+        synchronized (this) {
+            mPlayCount++;
+            notifyAll();
+        }
+    }
+
+    public void release() {
+        if (mThread != null) {
+            synchronized (this) {
+                mExit = true;
+                notifyAll();
+            }
+            try {
+                mThread.join();
+            } catch (InterruptedException e) {
+            }
+            mThread = null;
+        }
+        if (mAfd != null) {
+            try {
+                mAfd.close();
+            } catch(IOException e) {
+            }
+            mAfd = null;
+        }
+        if (mPlayer != null) {
+            mPlayer.release();
+            mPlayer = null;
+        }
+    }
+}