am be2f475f: Lift the upperbound of the up-scaling when view image.

Merge commit 'be2f475fe49538e38753ad391fb3176f9b0d1c69' into eclair-mr2

* commit 'be2f475fe49538e38753ad391fb3176f9b0d1c69':
  Lift the upperbound of the up-scaling when view image.
diff --git a/res/layout/camera.xml b/res/layout/camera.xml
index 2a60de5..d644d5d 100644
--- a/res/layout/camera.xml
+++ b/res/layout/camera.xml
@@ -80,7 +80,7 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:id="@+id/flash_icon"
-                        camera:modes="@array/pref_camera_flashmode_entryvalues"
+                        camera:modes="@array/flash_modes"
                         camera:icons="@array/flash_icons"
                         android:visibility="visible"/>
             </com.android.camera.EvenlySpacedLayout>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 4022919..c9bc8ae 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -89,8 +89,8 @@
     <string name="pref_gallery_sort_summary" msgid="6644398051645595214">"사진 및 동영상 정렬 순서 선택"</string>
     <string name="pref_gallery_sort_dialogtitle" msgid="5787417105532562739">"사진 정렬"</string>
   <string-array name="pref_gallery_sort_choices">
-    <item msgid="5546009539334018063">"가장 최근 사진 먼저"</item>
-    <item msgid="7931283047572866748">"가장 오래된 사진 먼저"</item>
+    <item msgid="5546009539334018063">"최근 사진부터"</item>
+    <item msgid="7931283047572866748">"오래된 사진부터"</item>
   </string-array>
     <string name="pref_gallery_slideshow_interval_title" msgid="6534904787962619832">"슬라이드쇼 간격"</string>
     <string name="pref_gallery_slideshow_interval_summary" msgid="329876327077905033">"쇼에서 각 슬라이드를 표시할 시간 선택"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2908b9e..876d46c 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -102,7 +102,7 @@
   </string-array>
     <string name="pref_gallery_slideshow_transition_title" msgid="3235158556228218846">"Lysbildeovergang"</string>
     <string name="pref_gallery_slideshow_transition_summary" msgid="2390320265891546846">"Velg effekten som skal brukes mellom lysbilder"</string>
-    <string name="pref_gallery_slideshow_transition_dialogtitle" msgid="5483406447721500371">"Lysbildevergang"</string>
+    <string name="pref_gallery_slideshow_transition_dialogtitle" msgid="5483406447721500371">"Lysbildeovergang"</string>
   <string-array name="pref_gallery_slideshow_transition_choices">
     <item msgid="2825716730899894863">"Ton inn og ut"</item>
     <item msgid="403116336404005687">"Skli venstre - høyre"</item>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index e498c13..83a16a3 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -92,26 +92,26 @@
     <item msgid="5546009539334018063">"O mais recente primeiro"</item>
     <item msgid="7931283047572866748">"O mais recente por último"</item>
   </string-array>
-    <string name="pref_gallery_slideshow_interval_title" msgid="6534904787962619832">"Intervalo da apresentação de slides"</string>
-    <string name="pref_gallery_slideshow_interval_summary" msgid="329876327077905033">"Selecione a duração de exibição de cada slide na apresentação."</string>
+    <string name="pref_gallery_slideshow_interval_title" msgid="6534904787962619832">"Intervalo dos slides"</string>
+    <string name="pref_gallery_slideshow_interval_summary" msgid="329876327077905033">"Selecione a duração de exibição de cada slide na apresentação de slides."</string>
     <string name="pref_gallery_slideshow_interval_dialogtitle" msgid="6775543119826248900">"Intervalo da apresentação de slides"</string>
   <string-array name="pref_gallery_slideshow_interval_choices">
     <item msgid="3089037742117543119">"2 segundos"</item>
     <item msgid="738579316565625730">"3 segundos"</item>
     <item msgid="5670078787463530498">"4 segundos"</item>
   </string-array>
-    <string name="pref_gallery_slideshow_transition_title" msgid="3235158556228218846">"Transição da apresentação de slides"</string>
+    <string name="pref_gallery_slideshow_transition_title" msgid="3235158556228218846">"Transição dos slides"</string>
     <string name="pref_gallery_slideshow_transition_summary" msgid="2390320265891546846">"Selecione o efeito usado ao passar de um slide para o próximo."</string>
     <string name="pref_gallery_slideshow_transition_dialogtitle" msgid="5483406447721500371">"Transição da apresentação de slides"</string>
   <string-array name="pref_gallery_slideshow_transition_choices">
-    <item msgid="2825716730899894863">"Aparecimento/desaparecimento gradual (fade in/out)"</item>
+    <item msgid="2825716730899894863">"Aparecimento/desaparecimento"</item>
     <item msgid="403116336404005687">"Deslizar para a esquerda - direita"</item>
     <item msgid="4901733079450971731">"Deslizar para cima - para baixo"</item>
     <item msgid="9006732482485375438">"Seleção aleatória"</item>
   </string-array>
-    <string name="pref_gallery_slideshow_repeat_title" msgid="6512135022461429738">"Repetir apresentação de slides"</string>
+    <string name="pref_gallery_slideshow_repeat_title" msgid="6512135022461429738">"Repetir apresentação"</string>
     <string name="pref_gallery_slideshow_repeat_summary" msgid="8289230397431855268">"Reproduzir apresentação de slides mais de uma vez"</string>
-    <string name="pref_gallery_slideshow_shuffle_title" msgid="3677508579783015598">"Reproduzir slides aleatoriamente"</string>
+    <string name="pref_gallery_slideshow_shuffle_title" msgid="3677508579783015598">"Reproduzir aleatoriamente"</string>
     <string name="pref_gallery_slideshow_shuffle_summary" msgid="8566948749149325715">"Mostrar imagens em ordem aleatória"</string>
     <!-- no translation found for pref_camera_recordlocation_title (371208839215448917) -->
     <skip />
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 331e25a..695bda5 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -19,7 +19,7 @@
     <string name="cannot_connect_camera" msgid="8029009101380114174">"Не удается подключиться к камере."</string>
     <string name="all_images" msgid="1195501551939178807">"Все картинки"</string>
     <string name="all_videos" msgid="3380966619230896013">"Все видео"</string>
-    <string name="camera_label" msgid="6346560772074764302">"Фотографии"</string>
+    <string name="camera_label" msgid="6346560772074764302">"Фотокамера"</string>
     <string name="video_camera_label" msgid="2899292505526427293">"Видеокамера"</string>
     <string name="gallery_picker_label" msgid="3080425245006492787">"Фотоальбом"</string>
     <!-- no translation found for gallery_label (7119609703856708011) -->
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 42b0076..a2b67c6 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -106,7 +106,7 @@
   <string-array name="pref_gallery_slideshow_transition_choices">
     <item msgid="2825716730899894863">"Tonas fram och bort"</item>
     <item msgid="403116336404005687">"Skjuts åt vänster eller höger"</item>
-    <item msgid="4901733079450971731">"Skjuts upp och ner"</item>
+    <item msgid="4901733079450971731">"Skjuts upp och ned"</item>
     <item msgid="9006732482485375438">"Slumpmässigt urval"</item>
   </string-array>
     <string name="pref_gallery_slideshow_repeat_title" msgid="6512135022461429738">"Upprepa bildspel"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 02d7cdf..22b3100 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -51,7 +51,7 @@
     <string name="crop_save_text" msgid="8140440041190264400">"保存"</string>
     <string name="crop_discard_text" msgid="5303657888280340603">"舍弃"</string>
     <string name="confirm_delete_title" msgid="263478358046514887">"删除"</string>
-    <string name="confirm_delete_message" msgid="4161389939579284604">"将会删除此照片。"</string>
+    <string name="confirm_delete_message" msgid="4161389939579284604">"将会删除此图片。"</string>
     <string name="confirm_delete_video_message" msgid="5796154324948010221">"将会删除视频。"</string>
     <string name="confirm_delete_multiple_message" msgid="5962369828035778779">"此时将删除这些媒体文件。"</string>
     <string name="review_toss" msgid="7255331999518617841">"删除"</string>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index b6cb407..026ed71 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -134,9 +134,17 @@
         <item>@string/pref_camera_recordlocation_entry_on</item>
     </array>
 
+    <string-array name="flash_modes" translatable="false">
+        <item>auto</item>
+        <item>on</item>
+        <item>off</item>
+        <item>no_flash</item>
+    </string-array>
+
     <array name="flash_icons">
         <item>@drawable/ic_viewfinder_flash_auto</item>
         <item>@drawable/ic_viewfinder_flash_on</item>
+        <item>@drawable/ic_viewfinder_flash_off</item>
         <item>@drawable/ic_viewfinder_empty</item>
     </array>
 
diff --git a/src/com/android/camera/BitmapManager.java b/src/com/android/camera/BitmapManager.java
index 36c7ec1..3ae6b93 100644
--- a/src/com/android/camera/BitmapManager.java
+++ b/src/com/android/camera/BitmapManager.java
@@ -16,8 +16,11 @@
 
 package com.android.camera;
 
+import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Video;
 import android.util.Log;
 
 import java.io.FileDescriptor;
@@ -38,7 +41,7 @@
     private static class ThreadStatus {
         public State mState = State.ALLOW;
         public BitmapFactory.Options mOptions;
-
+        public boolean mThumbRequesting;
         @Override
         public String toString() {
             String s;
@@ -107,7 +110,7 @@
         getOrCreateThreadStatus(t).mState = State.ALLOW;
     }
 
-    public synchronized void cancelThreadDecoding(Thread t) {
+    public synchronized void cancelThreadDecoding(Thread t, ContentResolver cr) {
         ThreadStatus status = getOrCreateThreadStatus(t);
         status.mState = State.CANCEL;
         if (status.mOptions != null) {
@@ -116,6 +119,49 @@
 
         // Wake up threads in waiting list
         notifyAll();
+
+        // Since our cancel request can arrive MediaProvider earlier than getThumbnail request,
+        // we use mThumbRequesting flag to make sure our request does cancel the request.
+        try {
+            synchronized (status) {
+                while (status.mThumbRequesting) {
+                    Images.Thumbnails.cancelThumbnailRequest(cr, -1, t.getId());
+                    Video.Thumbnails.cancelThumbnailRequest(cr, -1, t.getId());
+                    status.wait(200);
+                }
+            }
+        } catch (InterruptedException ex) {
+            // ignore it.
+        }
+    }
+
+    public Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
+            BitmapFactory.Options options, boolean isVideo) {
+        Thread t = Thread.currentThread();
+        ThreadStatus status = getOrCreateThreadStatus(t);
+
+        if (!canThreadDecoding(t)) {
+            Log.d(TAG, "Thread " + t + " is not allowed to decode.");
+            return null;
+        }
+
+        try {
+            synchronized (status) {
+                status.mThumbRequesting = true;
+            }
+            if (isVideo) {
+                return Video.Thumbnails.getThumbnail(cr, origId, t.getId(),
+                        kind, null);
+            } else {
+                return Images.Thumbnails.getThumbnail(cr, origId, t.getId(),
+                        kind, null);
+            }
+        } finally {
+            synchronized (status) {
+                status.mThumbRequesting = false;
+                status.notifyAll();
+            }
+        }
     }
 
     public static synchronized BitmapManager instance() {
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 3aee44f..a2d916d 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -84,13 +84,16 @@
 /**
  * Activity of the Camera which used to see preview and take pictures.
  */
-public class Camera extends Activity implements View.OnClickListener,
+public class Camera extends NoSearchActivity implements View.OnClickListener,
         ShutterButton.OnShutterButtonListener, SurfaceHolder.Callback,
         Switcher.OnSwitchListener, OnScreenSettings.OnVisibilityChangedListener,
         OnSharedPreferenceChangeListener {
 
     private static final String TAG = "camera";
 
+    // This value must be as same as the item value of the string array
+    // "flash_mode" in file "res/values/arrays.xml".
+    private static final String NO_FLASH_MODE = "no_flash";
     private static final int CROP_MSG = 1;
     private static final int FIRST_TIME_INIT = 2;
     private static final int RESTART_PREVIEW = 3;
@@ -116,7 +119,7 @@
     public static final String ZOOM_SPEED = "99";
 
     private Parameters mParameters;
-    private Parameters mInitialParameters;
+    private Parameters mInitialParams;
 
     // The non-standard parameter strings to communicate with camera driver.
     // This will be removed in the future.
@@ -984,7 +987,7 @@
             mSettings = new OnScreenSettings(
                     findViewById(R.id.camera_preview));
             CameraSettings helper =
-                    new CameraSettings(this, mInitialParameters);
+                    new CameraSettings(this, mInitialParams);
             mSettings.setPreferenceScreen(helper
                     .getPreferenceScreen(R.xml.camera_preferences));
             mSettings.setOnVisibilityChangedListener(this);
@@ -1111,8 +1114,8 @@
                 newExtras.putBoolean("return-data", true);
             }
 
-            Intent cropIntent = new Intent();
-            cropIntent.setClass(this, CropImage.class);
+            Intent cropIntent = new Intent("com.android.camera.action.CROP");
+
             cropIntent.setData(tempUri);
             cropIntent.putExtras(newExtras);
 
@@ -1514,7 +1517,7 @@
     private void ensureCameraDevice() throws CameraHardwareException {
         if (mCameraDevice == null) {
             mCameraDevice = CameraHolder.instance().open();
-            mInitialParameters = mCameraDevice.getParameters();
+            mInitialParams = mCameraDevice.getParameters();
         }
     }
 
@@ -1673,6 +1676,28 @@
     private void setCameraParameters() {
         mParameters = mCameraDevice.getParameters();
 
+        // Since change scene mode may change supported values,
+        // Set scene mode first,
+        String sceneMode = mPreferences.getString(
+                CameraSettings.KEY_SCENE_MODE,
+                getString(R.string.pref_camera_scenemode_default));
+        if (isSupported(sceneMode, mParameters.getSupportedSceneModes())) {
+            if (!mParameters.getSceneMode().equals(sceneMode)) {
+                mParameters.setSceneMode(sceneMode);
+                mCameraDevice.setParameters(mParameters);
+
+                // Setting scene mode will change the settings of flash mode, white
+                // balance, and focus mode. So read back here, so that we know
+                // what're the settings
+                mParameters = mCameraDevice.getParameters();
+            }
+        } else {
+            sceneMode = mParameters.getSceneMode();
+            if (sceneMode == null) {
+                sceneMode = Parameters.SCENE_MODE_AUTO;
+            }
+        }
+
         // Reset preview frame rate to the maximum because it may be lowered by
         // video camera application.
         List<Integer> frameRates = mParameters.getSupportedPreviewFrameRates();
@@ -1724,31 +1749,11 @@
             mParameters.setColorEffect(colorEffect);
         }
 
-        // Set scene mode.
-        String sceneMode = mPreferences.getString(
-                CameraSettings.KEY_SCENE_MODE,
-                getString(R.string.pref_camera_scenemode_default));
-        if (isSupported(sceneMode, mParameters.getSupportedSceneModes())) {
-            mParameters.setSceneMode(sceneMode);
-        } else {
-            sceneMode = mParameters.getSceneMode();
-            if (sceneMode == null) {
-                sceneMode = Parameters.SCENE_MODE_AUTO;
-            }
-        }
-
         // If scene mode is set, we cannot set flash mode, white balance, and
         // focus mode, instead, we read it from driver
         String flashMode;
         String whiteBalance;
-
         if (!Parameters.SCENE_MODE_AUTO.equals(sceneMode)) {
-            mCameraDevice.setParameters(mParameters);
-
-            // Setting scene mode will change the settings of flash mode, white
-            // balance, and focus mode. So read back here, so that we know
-            // what's the settings
-            mParameters = mCameraDevice.getParameters();
             flashMode = mParameters.getFlashMode();
             whiteBalance = mParameters.getWhiteBalance();
             mFocusMode = mParameters.getFocusMode();
@@ -1778,7 +1783,7 @@
             } else {
                 flashMode = mParameters.getFlashMode();
                 if (flashMode == null) {
-                    flashMode = Parameters.FLASH_MODE_OFF;
+                    flashMode = NO_FLASH_MODE;
                 }
             }
 
@@ -1786,7 +1791,8 @@
             whiteBalance = mPreferences.getString(
                     CameraSettings.KEY_WHITE_BALANCE,
                     getString(R.string.pref_camera_whitebalance_default));
-            if (isSupported(whiteBalance, mParameters.getSupportedWhiteBalance())) {
+            if (isSupported(whiteBalance,
+                    mParameters.getSupportedWhiteBalance())) {
                 mParameters.setWhiteBalance(whiteBalance);
             } else {
                 whiteBalance = mParameters.getWhiteBalance();
diff --git a/src/com/android/camera/CameraButtonIntentReceiver.java b/src/com/android/camera/CameraButtonIntentReceiver.java
index 0d9c4fb..4153104 100644
--- a/src/com/android/camera/CameraButtonIntentReceiver.java
+++ b/src/com/android/camera/CameraButtonIntentReceiver.java
@@ -21,8 +21,6 @@
 import android.content.Intent;
 
 public class CameraButtonIntentReceiver extends BroadcastReceiver {
-    public CameraButtonIntentReceiver() {
-    }
 
     @Override
     public void onReceive(Context context, Intent intent) {
@@ -35,8 +33,9 @@
         holder.release();
         Intent i = new Intent(Intent.ACTION_MAIN);
         i.setClass(context, Camera.class);
-        i.addCategory("android.intent.category.LAUNCHER");
-        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        i.addCategory(Intent.CATEGORY_LAUNCHER);
+        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         context.startActivity(i);
     }
 }
diff --git a/src/com/android/camera/DeleteImage.java b/src/com/android/camera/DeleteImage.java
index 1c1b07e..78ffe8a 100644
--- a/src/com/android/camera/DeleteImage.java
+++ b/src/com/android/camera/DeleteImage.java
@@ -28,7 +28,7 @@
 
 import java.util.ArrayList;
 
-public class DeleteImage extends Activity {
+public class DeleteImage extends NoSearchActivity {
 
     @SuppressWarnings("unused")
     private static final String TAG = "DeleteImage";
diff --git a/src/com/android/camera/GalleryPicker.java b/src/com/android/camera/GalleryPicker.java
index 33101fd..2f29691 100644
--- a/src/com/android/camera/GalleryPicker.java
+++ b/src/com/android/camera/GalleryPicker.java
@@ -69,7 +69,7 @@
 /**
  * The GalleryPicker activity.
  */
-public class GalleryPicker extends Activity {
+public class GalleryPicker extends NoSearchActivity {
     private static final String TAG = "GalleryPicker";
 
     Handler mHandler = new Handler();  // handler for the main thread
@@ -312,8 +312,7 @@
 
     private void abortWorker() {
         if (mWorkerThread != null) {
-            BitmapManager.instance().cancelThreadDecoding(mWorkerThread);
-            MediaStore.Images.Thumbnails.cancelThumbnailRequest(getContentResolver(), -1);
+            BitmapManager.instance().cancelThreadDecoding(mWorkerThread, getContentResolver());
             mAbort = true;
             try {
                 mWorkerThread.join();
@@ -333,7 +332,6 @@
 
     // This is run in the worker thread.
     private void workerRun() {
-
         // We collect items from checkImageList() and checkBucketIds() and
         // put them in allItems. Later we give allItems to checkThumbBitmap()
         // and generated thumbnail bitmaps for each item. We do this instead of
diff --git a/src/com/android/camera/ImageGallery.java b/src/com/android/camera/ImageGallery.java
index e62c05b..eaca3c9 100644
--- a/src/com/android/camera/ImageGallery.java
+++ b/src/com/android/camera/ImageGallery.java
@@ -64,7 +64,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 
-public class ImageGallery extends Activity implements
+public class ImageGallery extends NoSearchActivity implements
         GridViewSpecial.Listener, GridViewSpecial.DrawAdapter {
     private static final String STATE_SCROLL_POSITION = "scroll_position";
     private static final String STATE_SELECTED_INDEX = "first_index";
@@ -941,6 +941,7 @@
     }
 
     private void onShareMultipleClicked() {
+        if (mMultiSelected == null) return;
         if (mMultiSelected.size() > 1) {
             Intent intent = new Intent();
             intent.setAction(Intent.ACTION_SEND_MULTIPLE);
@@ -980,6 +981,7 @@
     }
 
     private void onDeleteMultipleClicked() {
+        if (mMultiSelected == null) return;
         Runnable action = new Runnable() {
             public void run() {
                 ArrayList<Uri> uriList = new ArrayList<Uri>();
diff --git a/src/com/android/camera/ImageGetter.java b/src/com/android/camera/ImageGetter.java
index 08c9370..72228da 100644
--- a/src/com/android/camera/ImageGetter.java
+++ b/src/com/android/camera/ImageGetter.java
@@ -234,8 +234,7 @@
     public synchronized void cancelCurrent() {
         Util.Assert(mGetterThread != null);
         mCancel = true;
-        BitmapManager.instance().cancelThreadDecoding(mGetterThread);
-        MediaStore.Images.Thumbnails.cancelThumbnailRequest(mCr, -1);
+        BitmapManager.instance().cancelThreadDecoding(mGetterThread, mCr);
     }
 
     // Cancels current loading (with waiting).
diff --git a/src/com/android/camera/ImageLoader.java b/src/com/android/camera/ImageLoader.java
index c4d211f..a394508 100644
--- a/src/com/android/camera/ImageLoader.java
+++ b/src/com/android/camera/ImageLoader.java
@@ -163,8 +163,7 @@
         if (mDecodeThread != null) {
             try {
                 Thread t = mDecodeThread;
-                BitmapManager.instance().cancelThreadDecoding(t);
-                MediaStore.Images.Thumbnails.cancelThumbnailRequest(mCr, -1);
+                BitmapManager.instance().cancelThreadDecoding(t, mCr);
                 t.join();
                 mDecodeThread = null;
             } catch (InterruptedException ex) {
diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java
index a5d50eb..055025a 100644
--- a/src/com/android/camera/MenuHelper.java
+++ b/src/com/android/camera/MenuHelper.java
@@ -593,11 +593,11 @@
                     return;
                 }
 
-                Intent cropIntent = new Intent();
-                cropIntent.setClass(activity, CropImage.class);
+                Intent cropIntent = new Intent(
+                        "com.android.camera.action.CROP");
                 cropIntent.setData(u);
-                activity.startActivityForResult(cropIntent,
-                        RESULT_COMMON_MENU_CROP);
+                activity.startActivityForResult(
+                        cropIntent, RESULT_COMMON_MENU_CROP);
             }
         });
         return true;
diff --git a/src/com/android/camera/MonitoredActivity.java b/src/com/android/camera/MonitoredActivity.java
index 94c163f..4c8f77d 100644
--- a/src/com/android/camera/MonitoredActivity.java
+++ b/src/com/android/camera/MonitoredActivity.java
@@ -21,7 +21,7 @@
 
 import java.util.ArrayList;
 
-public class MonitoredActivity extends Activity {
+public class MonitoredActivity extends NoSearchActivity {
 
     private final ArrayList<LifeCycleListener> mListeners =
             new ArrayList<LifeCycleListener>();
diff --git a/src/com/android/camera/MovieView.java b/src/com/android/camera/MovieView.java
index 57e62ba..ea4676e 100644
--- a/src/com/android/camera/MovieView.java
+++ b/src/com/android/camera/MovieView.java
@@ -30,11 +30,14 @@
 /**
  * This activity plays a video from a specified URI.
  */
-public class MovieView extends Activity  {
+public class MovieView extends NoSearchActivity  {
     private static final String TAG = "MovieView";
 
     private MovieViewControl mControl;
     private boolean mFinishOnCompletion;
+    private boolean mResumed = false;  // Whether this activity has been resumed.
+    private boolean mFocused = false;  // Whether this window has focus.
+    private boolean mControlResumed = false;  // Whether the MovieViewControl is resumed.
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -64,15 +67,30 @@
 
     @Override
     public void onPause() {
-        mControl.onPause();
         super.onPause();
+        mResumed = false;
+        if (mControlResumed) {
+            mControl.onPause();
+            mControlResumed = false;
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mResumed = true;
+        if (mFocused && mResumed && !mControlResumed) {
+            mControl.onResume();
+            mControlResumed = true;
+        }
     }
 
     @Override
     public void onWindowFocusChanged(boolean hasFocus) {
-        if (hasFocus) {
-            Log.v(TAG, "hasFocus");
+        mFocused = hasFocus;
+        if (mFocused && mResumed && !mControlResumed) {
             mControl.onResume();
+            mControlResumed = true;
         }
     }
 }
diff --git a/src/com/android/camera/NoSearchActivity.java b/src/com/android/camera/NoSearchActivity.java
new file mode 100644
index 0000000..f859ce9
--- /dev/null
+++ b/src/com/android/camera/NoSearchActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2009 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.app.Activity;
+
+public class NoSearchActivity extends Activity {
+    @Override
+    public boolean onSearchRequested() {
+        return false;
+    }
+}
diff --git a/src/com/android/camera/PhotoAppWidgetBind.java b/src/com/android/camera/PhotoAppWidgetBind.java
index 628fdc6..5c2aa50 100644
--- a/src/com/android/camera/PhotoAppWidgetBind.java
+++ b/src/com/android/camera/PhotoAppWidgetBind.java
@@ -28,7 +28,7 @@
 
 import java.util.ArrayList;
 
-class PhotoAppWidgetBind extends Activity {
+class PhotoAppWidgetBind extends NoSearchActivity {
     private static final String TAG = "PhotoAppWidgetBind";
     private static final String EXTRA_APPWIDGET_BITMAPS =
             "com.android.camera.appwidgetbitmaps";
diff --git a/src/com/android/camera/PhotoAppWidgetConfigure.java b/src/com/android/camera/PhotoAppWidgetConfigure.java
index 1755a71..76174c7 100644
--- a/src/com/android/camera/PhotoAppWidgetConfigure.java
+++ b/src/com/android/camera/PhotoAppWidgetConfigure.java
@@ -26,7 +26,7 @@
 import android.util.DisplayMetrics;
 import android.widget.RemoteViews;
 
-public class PhotoAppWidgetConfigure extends Activity {
+public class PhotoAppWidgetConfigure extends NoSearchActivity {
 
     @SuppressWarnings("unused")
     private static final String TAG = "PhotoAppWidgetConfigure";
diff --git a/src/com/android/camera/ReviewImage.java b/src/com/android/camera/ReviewImage.java
index ef629da..b87cca0 100644
--- a/src/com/android/camera/ReviewImage.java
+++ b/src/com/android/camera/ReviewImage.java
@@ -50,7 +50,7 @@
 // the user view one image at a time, and can click "previous" and "next"
 // button to see the previous or next image. In slide show mode it shows one
 // image after another, with some transition effect.
-public class ReviewImage extends Activity implements View.OnClickListener {
+public class ReviewImage extends NoSearchActivity implements View.OnClickListener {
     private static final String STATE_URI = "uri";
     private static final String TAG = "ReviewImage";
     private static final double ASPECT_RATIO = 4.0 / 3.0;
@@ -283,6 +283,7 @@
         @Override
         public boolean onScroll(MotionEvent e1, MotionEvent e2,
                 float distanceX, float distanceY) {
+            if (mPaused) return false;
             ImageViewTouch2 imageView = mImageView;
             if (imageView.getScale() > 1F) {
                 imageView.postTranslateCenter(-distanceX, -distanceY);
@@ -292,6 +293,7 @@
 
         @Override
         public boolean onSingleTapConfirmed(MotionEvent e) {
+            if (mPaused) return false;
             showOnScreenControls();
             scheduleDismissOnScreenControls();
             return true;
@@ -299,6 +301,7 @@
 
         @Override
         public boolean onDoubleTap(MotionEvent e) {
+            if (mPaused) return false;
             ImageViewTouch2 imageView = mImageView;
 
             // Switch between the original scale and 3x scale.
diff --git a/src/com/android/camera/Switcher.java b/src/com/android/camera/Switcher.java
index ba205a8..cb0d4f1 100644
--- a/src/com/android/camera/Switcher.java
+++ b/src/com/android/camera/Switcher.java
@@ -41,6 +41,7 @@
     private boolean mSwitch = false;
     private int mPosition = 0;
     private long mAnimationStartTime = 0;
+    private int mAnimationStartPosition;
     private OnSwitchListener mListener;
 
     public Switcher(Context context, AttributeSet attrs) {
@@ -108,6 +109,7 @@
 
     private void startParkingAnimation() {
         mAnimationStartTime = AnimationUtils.currentAnimationTimeMillis();
+        mAnimationStartPosition = mPosition;
     }
 
     private void trackTouchEvent(MotionEvent event) {
@@ -138,14 +140,14 @@
             final int available = getHeight() - mPaddingTop - mPaddingBottom
                     - drawableHeight;
             long time = AnimationUtils.currentAnimationTimeMillis();
-            long deltaTime = time - mAnimationStartTime;
-            mPosition += ANIMATION_SPEED
-                    * (mSwitch ? deltaTime : -deltaTime) / 1000;
-            mAnimationStartTime = time;
+            int deltaTime = (int)(time - mAnimationStartTime);
+            mPosition = mAnimationStartPosition +
+                    ANIMATION_SPEED * (mSwitch ? deltaTime : -deltaTime) / 1000;
             if (mPosition < 0) mPosition = 0;
             if (mPosition > available) mPosition = available;
-            if (mPosition != 0 && mPosition != available) {
-                postInvalidate();
+            boolean done = (mPosition == (mSwitch ? available : 0));
+            if (!done) {
+                invalidate();
             } else {
                 mAnimationStartTime = NO_ANIMATION;
             }
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index 0786fa5..c9dc27f 100644
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -83,7 +83,7 @@
 /**
  * The Camcorder activity.
  */
-public class VideoCamera extends Activity implements View.OnClickListener,
+public class VideoCamera extends NoSearchActivity implements View.OnClickListener,
         ShutterButton.OnShutterButtonListener, SurfaceHolder.Callback,
         MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener,
         Switcher.OnSwitchListener, OnSharedPreferenceChangeListener,
@@ -391,6 +391,7 @@
             }
             case R.id.review_thumbnail: {
                 stopVideoRecordingAndShowReview();
+                initializeRecorder();
                 break;
             }
         }
@@ -1384,13 +1385,6 @@
             mRecordingTimeView.setTextColor(color);
         }
 
-        // Work around a limitation of the T-Mobile G1: The T-Mobile
-        // hardware blitter can't pixel-accurately scale and clip at the
-        // same time, and the SurfaceFlinger doesn't attempt to work around
-        // this limitation. In order to avoid visual corruption we must
-        // manually refresh the entire surface view when changing any
-        // overlapping view's contents.
-        mVideoPreview.invalidate();
         mHandler.sendEmptyMessageDelayed(
                 UPDATE_RECORD_TIME, next_update_delay);
     }
diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java
index 2992f7a..0443d02 100644
--- a/src/com/android/camera/ViewImage.java
+++ b/src/com/android/camera/ViewImage.java
@@ -55,7 +55,7 @@
 // the user view one image at a time, and can click "previous" and "next"
 // button to see the previous or next image. In slide show mode it shows one
 // image after another, with some transition effect.
-public class ViewImage extends Activity implements View.OnClickListener {
+public class ViewImage extends NoSearchActivity implements View.OnClickListener {
     private static final String PREF_SLIDESHOW_REPEAT =
             "pref_gallery_slideshow_repeat_key";
     private static final String PREF_SHUFFLE_SLIDESHOW =
@@ -329,6 +329,7 @@
         @Override
         public boolean onScroll(MotionEvent e1, MotionEvent e2,
                 float distanceX, float distanceY) {
+            if (mPaused) return false;
             ImageViewTouch imageView = mImageView;
             if (imageView.getScale() > 1F) {
                 imageView.postTranslateCenter(-distanceX, -distanceY);
@@ -338,12 +339,14 @@
 
         @Override
         public boolean onSingleTapUp(MotionEvent e) {
+            if (mPaused) return false;
             setMode(MODE_NORMAL);
             return true;
         }
 
         @Override
         public boolean onSingleTapConfirmed(MotionEvent e) {
+            if (mPaused) return false;
             showOnScreenControls();
             scheduleDismissOnScreenControls();
             return true;
@@ -351,6 +354,7 @@
 
         @Override
         public boolean onDoubleTap(MotionEvent e) {
+            if (mPaused) return false;
             ImageViewTouch imageView = mImageView;
 
             // Switch between the original scale and 3x scale.
@@ -402,8 +406,12 @@
                         Uri uri = image.fullSizeImageUri();
                         cb.run(uri, image);
 
-                        mImageView.clear();
-                        setImage(mCurrentPosition, false);
+                        // We might have deleted all images in the callback, so
+                        // call setImage() only if we still have some images.
+                        if (mAllImages.getCount() > 0) {
+                            mImageView.clear();
+                            setImage(mCurrentPosition, false);
+                        }
                     }
                 });
 
@@ -897,6 +905,7 @@
     private Uri getCurrentUri() {
         if (mAllImages.getCount() == 0) return null;
         IImage image = mAllImages.getImageAt(mCurrentPosition);
+        if (image == null) return null;
         return image.fullSizeImageUri();
     }
 
diff --git a/src/com/android/camera/Wallpaper.java b/src/com/android/camera/Wallpaper.java
index 2d533b5..a715958 100644
--- a/src/com/android/camera/Wallpaper.java
+++ b/src/com/android/camera/Wallpaper.java
@@ -25,7 +25,7 @@
  * Wallpaper picker for the camera application. This just redirects to the
  * standard pick action.
  */
-public class Wallpaper extends Activity {
+public class Wallpaper extends NoSearchActivity {
     @SuppressWarnings("unused")
     private static final String TAG = "Wallpaper";
     private static final int PHOTO_PICKED = 1;
diff --git a/src/com/android/camera/gallery/BaseImage.java b/src/com/android/camera/gallery/BaseImage.java
index 6607b08..6e2f8f1 100644
--- a/src/com/android/camera/gallery/BaseImage.java
+++ b/src/com/android/camera/gallery/BaseImage.java
@@ -181,8 +181,8 @@
         Bitmap b = null;
         try {
             long id = mId;
-            b = Images.Thumbnails.getThumbnail(mContentResolver, id,
-                    Images.Thumbnails.MICRO_KIND, null);
+            b = BitmapManager.instance().getThumbnail(mContentResolver, id,
+                    Images.Thumbnails.MICRO_KIND, null, false);
         } catch (Throwable ex) {
             Log.e(TAG, "miniThumbBitmap got exception", ex);
             return null;
diff --git a/src/com/android/camera/gallery/Image.java b/src/com/android/camera/gallery/Image.java
index 6190706..78ec382 100644
--- a/src/com/android/camera/gallery/Image.java
+++ b/src/com/android/camera/gallery/Image.java
@@ -16,6 +16,7 @@
 
 package com.android.camera.gallery;
 
+import com.android.camera.BitmapManager;
 import com.android.camera.Util;
 
 import android.content.ContentResolver;
@@ -152,8 +153,8 @@
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inDither = false;
         options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        bitmap = Images.Thumbnails.getThumbnail(
-                    mContentResolver, mId, Images.Thumbnails.MINI_KIND, options);
+        bitmap = BitmapManager.instance().getThumbnail(mContentResolver, mId,
+                Images.Thumbnails.MINI_KIND, options, false);
 
         if (bitmap != null && rotateAsNeeded) {
             bitmap = Util.rotate(bitmap, getDegreesRotated());
diff --git a/src/com/android/camera/gallery/VideoObject.java b/src/com/android/camera/gallery/VideoObject.java
index 8e3b60e..589e42f 100644
--- a/src/com/android/camera/gallery/VideoObject.java
+++ b/src/com/android/camera/gallery/VideoObject.java
@@ -16,10 +16,13 @@
 
 package com.android.camera.gallery;
 
+import com.android.camera.BitmapManager;
+
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.media.ThumbnailUtil;
 import android.net.Uri;
+import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Video;
 import android.util.Log;
 
@@ -110,8 +113,8 @@
     public Bitmap miniThumbBitmap() {
         try {
             long id = mId;
-            return Video.Thumbnails.getThumbnail(mContentResolver, id,
-                    Video.Thumbnails.MICRO_KIND, null);
+            return BitmapManager.instance().getThumbnail(mContentResolver,
+                    id, Images.Thumbnails.MICRO_KIND, null, true);
         } catch (Throwable ex) {
             Log.e(TAG, "miniThumbBitmap got exception", ex);
             return null;
diff --git a/tests/src/com/android/camera/BitmapManagerUnitTests.java b/tests/src/com/android/camera/BitmapManagerUnitTests.java
index fc1ade1..7878b74 100644
--- a/tests/src/com/android/camera/BitmapManagerUnitTests.java
+++ b/tests/src/com/android/camera/BitmapManagerUnitTests.java
@@ -75,7 +75,7 @@
         assertTrue(mBitmapManager.canThreadDecoding(t));
 
         // Disallow thread t to decode.
-        mBitmapManager.cancelThreadDecoding(t);
+        mBitmapManager.cancelThreadDecoding(t, mContext.getContentResolver());
         assertFalse(mBitmapManager.canThreadDecoding(t));
 
         // Allow thread t to decode again.
@@ -96,7 +96,7 @@
 
     public void testCancelDecoding() {
         DecodeThread t = new DecodeThread();
-        mBitmapManager.cancelThreadDecoding(t);
+        mBitmapManager.cancelThreadDecoding(t, mContext.getContentResolver());
         try {
             t.start();
             t.join();
@@ -108,7 +108,7 @@
 
     public void testAllowDecoding() {
         DecodeThread t = new DecodeThread();
-        mBitmapManager.cancelThreadDecoding(t);
+        mBitmapManager.cancelThreadDecoding(t, mContext.getContentResolver());
         mBitmapManager.allowThreadDecoding(t);
         try {
             t.start();
@@ -123,7 +123,7 @@
         DecodeThread t1 = new DecodeThread();
         DecodeThread t2 = new DecodeThread();
         mBitmapManager.allowThreadDecoding(t1);
-        mBitmapManager.cancelThreadDecoding(t2);
+        mBitmapManager.cancelThreadDecoding(t2, mContext.getContentResolver());
         t1.start();
         t2.start();