Merge "bugfix 5422126 Panorama needs to load the thumbnail from the file"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 61088ec..23114db 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -65,6 +65,7 @@
             </intent-filter>
         </activity>
         <activity android:name="com.android.camera.panorama.PanoramaActivity"
+                android:label="@string/pano_dialog_title"
                 android:configChanges="orientation|screenSize|keyboardHidden"
                 android:screenOrientation="landscape"
                 android:clearTaskOnLaunch="true"
diff --git a/res/drawable-hdpi/dialog_full_holo_dark.9.png b/res/drawable-hdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..79e56f5
--- /dev/null
+++ b/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_pressed_holo.9.png b/res/drawable-hdpi/list_pressed_holo.9.png
deleted file mode 100644
index 9eae8f4..0000000
--- a/res/drawable-hdpi/list_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/dialog_full_holo_dark.9.png b/res/drawable-mdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..fb3660e
--- /dev/null
+++ b/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_pressed_holo.9.png b/res/drawable-mdpi/list_pressed_holo.9.png
deleted file mode 100644
index e3344b6..0000000
--- a/res/drawable-mdpi/list_pressed_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/dialog_full_holo_dark.9.png b/res/drawable-xhdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..f4970ad
--- /dev/null
+++ b/res/drawable-xhdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/res/drawable/border_preview.xml b/res/drawable/border_preview.xml
index 8cac1fc..5835e2f 100644
--- a/res/drawable/border_preview.xml
+++ b/res/drawable/border_preview.xml
@@ -16,6 +16,6 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_activated="true" android:drawable="@drawable/ic_snapshot_border" />
-    <item android:drawable="@android:color/transparent" />
+    <item android:drawable="@android:color/black" />
 </selector>
 
diff --git a/res/drawable/setting_picker.xml b/res/drawable/setting_picker.xml
index de225e3..a286d09 100644
--- a/res/drawable/setting_picker.xml
+++ b/res/drawable/setting_picker.xml
@@ -16,6 +16,6 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_activated="true"
-              android:drawable="@drawable/list_pressed_holo" />
+              android:drawable="@drawable/list_pressed_holo_light" />
     <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/res/layout/bg_replacement_training_message.xml b/res/layout/bg_replacement_training_message.xml
new file mode 100644
index 0000000..ee0464e
--- /dev/null
+++ b/res/layout/bg_replacement_training_message.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/bg_replace_message_frame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        android:onClick="onProtectiveCurtainClick"
+        android:background="#77000000">
+    <com.android.camera.ui.RotateLayout
+            android:id="@+id/bg_replace_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true">
+        <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:background="@drawable/dialog_full_holo_dark">
+            <TextView
+                    android:layout_width="300dp"
+                    android:layout_height="wrap_content"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:text="@string/bg_replacement_message"
+                    android:padding="32dp" />
+
+            <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1px"
+                    android:background="#aaaaaa" />
+
+            <Button android:id="@+id/bg_replace_cancel_button"
+                    android:layout_width="match_parent"
+                    android:layout_height="48dip"
+                    android:layout_gravity="center"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    style="?android:attr/borderlessButtonStyle"
+                    android:text="@android:string/cancel"
+                    android:onClick="onCancelBgTraining"/>
+        </LinearLayout>
+    </com.android.camera.ui.RotateLayout>
+</RelativeLayout>
diff --git a/res/layout/camera_control.xml b/res/layout/camera_control.xml
index 6aba493..366393d 100644
--- a/res/layout/camera_control.xml
+++ b/res/layout/camera_control.xml
@@ -29,6 +29,7 @@
             android:scaleType="center"
             android:clickable="true"
             android:focusable="true"
+            android:contentDescription="@string/accessibility_shutter_button"
             android:background="@drawable/btn_shutter" />
     <include layout="@layout/mode_picker" />
 </com.android.camera.ui.ControlPanelLayout>
diff --git a/res/layout/indicator_bar.xml b/res/layout/indicator_bar.xml
index 4fe6d45..764d6d6 100644
--- a/res/layout/indicator_bar.xml
+++ b/res/layout/indicator_bar.xml
@@ -41,6 +41,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_alignParentBottom="true"
+                    android:contentDescription="@string/accessibility_second_level_indicators"
                     android:src="@drawable/ic_settings_holo_light" />
         </com.android.camera.ui.IndicatorControlBar>
 
@@ -63,6 +64,12 @@
                     android:layout_height="0dp"
                     android:background="@color/mode_selection_border"
                     android:visibility="gone" />
+            <com.android.camera.ui.ColorFilterImageView
+                    android:id="@+id/back_to_first_level"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:contentDescription="@string/accessibility_back_to_first_level"
+                    android:src="@drawable/btn_close_settings" />
         </com.android.camera.ui.SecondLevelIndicatorControlBar>
 
     </RelativeLayout>
diff --git a/res/layout/mode_picker.xml b/res/layout/mode_picker.xml
index 5cbc882..12c9618 100644
--- a/res/layout/mode_picker.xml
+++ b/res/layout/mode_picker.xml
@@ -24,12 +24,14 @@
             android:layout_alignBottom="@+id/mode_selection"
             android:layout_width="match_parent"
             android:layout_height="55dp"
+            android:contentDescription="@string/accessibility_mode_picker"
             android:background="@drawable/bg_mode_picker">
         <View android:layout_width="match_parent"
                 android:layout_height="1dp"
                 android:background="@android:color/white"/>
         <RelativeLayout
                 android:orientation="horizontal"
+                android:contentDescription="@string/empty"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent">
             <com.android.camera.ui.RotateImageView android:id="@+id/mode_0"
@@ -39,12 +41,14 @@
                     android:layout_alignParentLeft="true"
                     android:layout_marginLeft="8dp"
                     android:scaleType="fitCenter"
+                    android:contentDescription="@string/empty"
                     android:src="@drawable/ic_switch_video_holo_light" />
             <com.android.camera.ui.RotateImageView android:id="@+id/mode_1"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:layout_centerInParent="true"
                     android:scaleType="fitCenter"
+                    android:contentDescription="@string/empty"
                     android:src="@drawable/ic_switch_camera_holo_light" />
             <com.android.camera.ui.RotateImageView android:id="@+id/mode_2"
                     android:layout_width="32dp"
@@ -53,6 +57,7 @@
                     android:layout_alignParentRight="true"
                     android:layout_marginRight="8dp"
                     android:scaleType="fitCenter"
+                    android:contentDescription="@string/empty"
                     android:src="@drawable/ic_switch_pan_holo_light" />
         </RelativeLayout>
     </RelativeLayout>
@@ -72,6 +77,7 @@
                 android:layout_height="wrap_content"
                 android:layout_centerVertical="true">
             <com.android.camera.ui.RotateImageView android:id="@+id/mode_camera"
+                    android:contentDescription="@string/switch_to_camera_label"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginBottom="10dp"
@@ -79,6 +85,7 @@
                     android:background="@drawable/bg_pressed"
                     android:src="@drawable/ic_switch_camera_holo_light" />
             <com.android.camera.ui.RotateImageView android:id="@+id/mode_video"
+                    android:contentDescription="@string/switch_to_video_label"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginBottom="10dp"
@@ -86,6 +93,7 @@
                     android:background="@drawable/bg_pressed"
                     android:src="@drawable/ic_switch_video_holo_light" />
             <com.android.camera.ui.RotateImageView android:id="@+id/mode_panorama"
+                    android:contentDescription="@string/switch_to_panorama_label"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:scaleType="center"
diff --git a/res/layout/preview_frame_video.xml b/res/layout/preview_frame_video.xml
index c2823ee..5e27169 100644
--- a/res/layout/preview_frame_video.xml
+++ b/res/layout/preview_frame_video.xml
@@ -44,16 +44,6 @@
                 android:src="@drawable/ic_gallery_play"
                 android:visibility="gone"
                 android:onClick="onReviewPlayClicked"/>
-        <TextView android:id="@+id/bg_replace_message"
-                android:layout_width="300dp"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                android:padding="32dp"
-                android:layout_margin="24dp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:background="@drawable/bg_text_on_preview"
-                android:visibility="gone"
-                android:text="@string/bg_replacement_message" />
     </com.android.camera.PreviewFrameLayout>
 
     <!-- Fill up the space below preview frame with black. -->
diff --git a/res/layout/review_thumbnail.xml b/res/layout/review_thumbnail.xml
index 1d80687..1f94e27 100644
--- a/res/layout/review_thumbnail.xml
+++ b/res/layout/review_thumbnail.xml
@@ -21,5 +21,6 @@
         android:clickable="true"
         android:focusable="false"
         android:visibility="gone"
+        android:contentDescription="@string/accessibility_review_thumbnail"
         android:background="@drawable/border_last_picture">
 </com.android.camera.ui.RotateImageView>
diff --git a/res/layout/video_camera.xml b/res/layout/video_camera.xml
index c8c24c2..809c7a5 100644
--- a/res/layout/video_camera.xml
+++ b/res/layout/video_camera.xml
@@ -14,12 +14,17 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:camera="http://schemas.android.com/apk/res/com.android.camera"
         android:id="@+id/app_root"
-        android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-    <include layout="@layout/preview_frame_video"/>
-    <include layout="@layout/camera_control"/>
-</LinearLayout>
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <include layout="@layout/preview_frame_video"/>
+        <include layout="@layout/camera_control"/>
+    </LinearLayout>
+    <include layout="@layout/bg_replacement_training_message"/>
+</RelativeLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0bdb819..7cc61f4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -329,4 +329,28 @@
 
     <!-- Title of category for background replacement effects. [CHAR LIMIT=26] -->
     <string name="effect_background">Background</string>
+
+    <!-- The shutter button. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_shutter_button">Shutter button</string>
+    <!-- The button to review the thumbnail. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_review_thumbnail">Most recent photo</string>
+    <!-- The front/back camera switch. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_camera_picker">Front and back camera switch</string>
+    <!-- The mode picker to switch between camera, video and panorama. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_mode_picker">Camera, video or panorama selector</string>
+    <!-- The button to switch to the second-level indicators of the camera settings. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_second_level_indicators">More setting controls</string>
+    <!-- The button to back to the first-level indicators of the camera settings. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_back_to_first_level">Close setting controls</string>
+    <!-- The zoom control button. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_zoom_control">Zoom control</string>
+    <!-- The decrement button in camera preference such as exposure, picture size. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_decrement">Decrease %1$s</string>
+    <!-- The increment button in camera preference such as exposure, picture size. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_increment">Increase %1$s</string>
+    <!-- The on/off switch in camera settings, such as store location. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_switch">%1$s switch</string>
+
+    <!-- TODO: remove the string as it is a work-around solution to bypass the default speak of the element type. -->
+    <string name="empty" translatable="false">" "</string>
 </resources>
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index cac446c..cd8a0b3 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -1675,7 +1675,6 @@
 
     private void closeCamera() {
         if (mCameraDevice != null) {
-            mCameraDevice.cancelAutoFocus(); // Reset the focus.
             CameraHolder.instance().release();
             mCameraDevice.setZoomChangeListener(null);
             mCameraDevice.setFaceDetectionListener(null);
@@ -1745,6 +1744,7 @@
     private void stopPreview() {
         if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
             Log.v(TAG, "stopPreview");
+            mCameraDevice.cancelAutoFocus(); // Reset the focus.
             mCameraDevice.stopPreview();
         }
         mCameraState = PREVIEW_STOPPED;
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index 61a55dd..768bf27 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -79,7 +79,7 @@
 
     private static boolean sIsTabletUI;
     private static float sPixelDensity = 1;
-    private static String sImageFileNameFormat;
+    private static ImageFileNamer sImageFileNamer;
 
     private Util() {
     }
@@ -92,8 +92,8 @@
                 context.getSystemService(Context.WINDOW_SERVICE);
         wm.getDefaultDisplay().getMetrics(metrics);
         sPixelDensity = metrics.density;
-
-        sImageFileNameFormat = context.getString(R.string.image_file_name_format);
+        sImageFileNamer = new ImageFileNamer(
+                context.getString(R.string.image_file_name_format));
     }
 
     public static boolean isTabletUI() {
@@ -517,9 +517,9 @@
     }
 
     public static String createJpegName(long dateTaken) {
-        Date date = new Date(dateTaken);
-        SimpleDateFormat dateFormat = new SimpleDateFormat(sImageFileNameFormat);
-        return dateFormat.format(date);
+        synchronized (sImageFileNamer) {
+            return sImageFileNamer.generateName(dateTaken);
+        }
     }
 
     public static void broadcastNewPicture(Context context, Uri uri) {
@@ -615,4 +615,35 @@
             win.setAttributes(winParams);
         }
     }
+
+    private static class ImageFileNamer {
+        private SimpleDateFormat mFormat;
+
+        // The date (in milliseconds) used to generate the last name.
+        private long mLastDate;
+
+        // Number of names generated for the same second.
+        private int mSameSecondCount;
+
+        public ImageFileNamer(String format) {
+            mFormat = new SimpleDateFormat(format);
+        }
+
+        public String generateName(long dateTaken) {
+            Date date = new Date(dateTaken);
+            String result = mFormat.format(date);
+
+            // If the last name was generated for the same second,
+            // we append _1, _2, etc to the name.
+            if (dateTaken / 1000 == mLastDate / 1000) {
+                mSameSecondCount++;
+                result += "_" + mSameSecondCount;
+            } else {
+                mLastDate = dateTaken;
+                mSameSecondCount = 0;
+            }
+
+            return result;
+        }
+    }
 }
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
old mode 100644
new mode 100755
index a880a01..77e163e
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -165,7 +165,8 @@
     private ModePicker mModePicker;
     private ShutterButton mShutterButton;
     private TextView mRecordingTimeView;
-    private TextView mBgLearningMessage;
+    private RotateLayout mBgLearningMessageRotater;
+    private View mBgLearningMessageFrame;
     private LinearLayout mLabelsLinearLayout;
 
     private boolean mIsVideoCaptureIntent;
@@ -418,7 +419,8 @@
         // R.id.labels_w1024. That is, mLabelsLinearLayout should be null in tablet layout.
         mLabelsLinearLayout = (LinearLayout) findViewById(R.id.labels);
 
-        mBgLearningMessage = (TextView) findViewById(R.id.bg_replace_message);
+        mBgLearningMessageRotater = (RotateLayout) findViewById(R.id.bg_replace_message);
+        mBgLearningMessageFrame = findViewById(R.id.bg_replace_message_frame);
 
         mLocationManager = new LocationManager(this, null);
 
@@ -540,6 +542,7 @@
         if (mThumbnailView != null) mThumbnailView.setDegree(degree);
         if (mModePicker != null) mModePicker.setDegree(degree);
         if (mSharePopup != null) mSharePopup.setOrientation(degree);
+        if (mBgLearningMessageRotater != null) mBgLearningMessageRotater.setOrientation(degree);
         if (mIndicatorControlContainer != null) mIndicatorControlContainer.setDegree(degree);
         if (mReviewDoneButton != null) mReviewDoneButton.setOrientation(degree);
         if (mReviewPlayButton != null) mReviewPlayButton.setOrientation(degree);
@@ -611,6 +614,10 @@
         }
     }
 
+    public void onProtectiveCurtainClick(View v) {
+        // Consume clicks
+    }
+
     public void onShutterButtonClick(ShutterButton button) {
         switch (button.getId()) {
             case R.id.shutter_button:
@@ -711,10 +718,7 @@
                 Log.w(TAG, "No URI from gallery, resetting to no effect");
                 mEffectType = EffectsRecorder.EFFECT_NONE;
                 mEffectParameter = null;
-                ComboPreferences.Editor editor = mPreferences.edit();
-                editor.putString(CameraSettings.KEY_VIDEO_EFFECT,
-                        getString(R.string.pref_video_effect_default));
-                editor.apply();
+                writeDefaultEffectToPrefs();
                 if (mIndicatorControlContainer != null) {
                     mIndicatorControlContainer.overrideSettings(
                         CameraSettings.KEY_VIDEO_QUALITY,
@@ -753,6 +757,13 @@
         getDesiredPreviewSize();
     }
 
+    private void writeDefaultEffectToPrefs()  {
+        ComboPreferences.Editor editor = mPreferences.edit();
+        editor.putString(CameraSettings.KEY_VIDEO_EFFECT,
+                getString(R.string.pref_video_effect_default));
+        editor.apply();
+    }
+
     private void getDesiredPreviewSize() {
         mParameters = mCameraDevice.getParameters();
         if (mParameters.getSupportedVideoSizes() == null || effectsActive()) {
@@ -1599,6 +1610,8 @@
         for (int id : pickIds) {
             Util.fadeIn(findViewById(id));
         }
+
+        showTimeLapseUI(false);
     }
 
     private void hideAlert() {
@@ -1902,21 +1915,32 @@
         if (effectMsg == EffectsRecorder.EFFECT_MSG_EFFECTS_STOPPED) {
             // Effects have shut down. Hide learning message if any,
             // and restart regular preview.
-            mBgLearningMessage.setVisibility(View.GONE);
+            mBgLearningMessageFrame.setVisibility(View.GONE);
             checkQualityAndStartPreview();
         } else if (effectId == EffectsRecorder.EFFECT_BACKDROPPER) {
             switch (effectMsg) {
                 case EffectsRecorder.EFFECT_MSG_STARTED_LEARNING:
-                    mBgLearningMessage.setVisibility(View.VISIBLE);
+                    mBgLearningMessageFrame.setVisibility(View.VISIBLE);
                     break;
                 case EffectsRecorder.EFFECT_MSG_DONE_LEARNING:
                 case EffectsRecorder.EFFECT_MSG_SWITCHING_EFFECT:
-                    mBgLearningMessage.setVisibility(View.GONE);
+                    mBgLearningMessageFrame.setVisibility(View.GONE);
                     break;
             }
         }
     }
 
+    public void onCancelBgTraining(View v) {
+        // Remove training message
+        mBgLearningMessageFrame.setVisibility(View.GONE);
+        // Write default effect out to shared prefs
+        writeDefaultEffectToPrefs();
+        // Tell the indicator controller to redraw based on new shared pref values
+        mIndicatorControlContainer.reloadPreferences();
+        // Tell VideoCamer to re-init based on new shared pref values.
+        onSharedPreferenceChanged();
+    }
+
     @Override
     public synchronized void onEffectsError(Exception exception, String fileName) {
         // TODO: Eventually we may want to show the user an error dialog, and then restart the
@@ -1998,6 +2022,7 @@
                 finish();
             } else {
                 readVideoPreferences();
+                showTimeLapseUI(mCaptureTimeLapse);
                 // We need to restart the preview if preview size is changed.
                 Size size = mParameters.getPreviewSize();
                 if (size.width != mDesiredPreviewWidth
@@ -2013,7 +2038,6 @@
                     setCameraParameters();
                 }
             }
-            showTimeLapseUI(mCaptureTimeLapse);
         }
     }
 
@@ -2060,6 +2084,7 @@
     // preview. If not, resets the surface holder and resizes the view.
     private void checkQualityAndStartPreview() {
         readVideoPreferences();
+        showTimeLapseUI(mCaptureTimeLapse);
         Size size = mParameters.getPreviewSize();
         if (size.width != mDesiredPreviewWidth
                 || size.height != mDesiredPreviewHeight) {
diff --git a/src/com/android/camera/ui/AbstractIndicatorButton.java b/src/com/android/camera/ui/AbstractIndicatorButton.java
index 037a273..a661586 100644
--- a/src/com/android/camera/ui/AbstractIndicatorButton.java
+++ b/src/com/android/camera/ui/AbstractIndicatorButton.java
@@ -50,6 +50,8 @@
         HIGHLIGHT_COLOR = context.getResources().getColor(R.color.review_control_pressed_color);
         setScaleType(ImageView.ScaleType.CENTER);
         PopupManager.getInstance(context).setOnOtherPopupShowedListener(this);
+        // Set the click listener to help the comprehension of the accessibility.
+        setClickable(true);
     }
 
     @Override
diff --git a/src/com/android/camera/ui/CameraPicker.java b/src/com/android/camera/ui/CameraPicker.java
index 78e2b27..ac8b8a8 100644
--- a/src/com/android/camera/ui/CameraPicker.java
+++ b/src/com/android/camera/ui/CameraPicker.java
@@ -38,6 +38,8 @@
     public CameraPicker(Context context) {
         super(context);
         setImageResource(mImageResource);
+        setContentDescription(getResources().getString(
+                R.string.accessibility_camera_picker));
     }
 
     public static void setImageResourceId(int imageResource) {
diff --git a/src/com/android/camera/ui/EffectSettingPopup.java b/src/com/android/camera/ui/EffectSettingPopup.java
index 6005c8d..606524b 100644
--- a/src/com/android/camera/ui/EffectSettingPopup.java
+++ b/src/com/android/camera/ui/EffectSettingPopup.java
@@ -133,8 +133,8 @@
     public void reloadPreference() {
         int index = mPreference.findIndexOfValue(mPreference.getValue());
         if (index >= 0) {
-            mBackgroundGrid.clearChoices();
-            mSillyFacesGrid.clearChoices();
+            mBackgroundGrid.setItemChecked(mBackgroundGrid.getCheckedItemPosition(), false);
+            mSillyFacesGrid.setItemChecked(mSillyFacesGrid.getCheckedItemPosition(), false);
             if (index >= 1 && index < EffectsRecorder.NUM_OF_GF_EFFECTS + 1) {
                 mSillyFacesGrid.setItemChecked(index - 1, true);
             } else if (index >= EffectsRecorder.NUM_OF_GF_EFFECTS + 1) {
diff --git a/src/com/android/camera/ui/InLineSettingItem.java b/src/com/android/camera/ui/InLineSettingItem.java
index 6f84e6f..bf6bdb2 100644
--- a/src/com/android/camera/ui/InLineSettingItem.java
+++ b/src/com/android/camera/ui/InLineSettingItem.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -70,6 +71,7 @@
             mListener.onSettingChanged();
         }
         updateView();
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
         return true;
     }
 
diff --git a/src/com/android/camera/ui/InLineSettingKnob.java b/src/com/android/camera/ui/InLineSettingKnob.java
index 9bb771c..99a3b66 100644
--- a/src/com/android/camera/ui/InLineSettingKnob.java
+++ b/src/com/android/camera/ui/InLineSettingKnob.java
@@ -16,6 +16,7 @@
 
 package com.android.camera.ui;
 
+import com.android.camera.ListPreference;
 import com.android.camera.R;
 
 import android.content.Context;
@@ -25,6 +26,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.TextView;
 
@@ -100,6 +102,16 @@
         mEntry = (TextView) findViewById(R.id.current_setting);
     }
 
+    @Override
+    public void initialize(ListPreference preference) {
+        super.initialize(preference);
+        // Add content descriptions for the increment and decrement buttons.
+        mNextButton.setContentDescription(getResources().getString(
+                R.string.accessibility_increment, mPreference.getTitle()));
+        mPrevButton.setContentDescription(getResources().getString(
+                R.string.accessibility_decrement, mPreference.getTitle()));
+    }
+
     protected void updateView() {
         if (mOverrideValue == null) {
             mEntry.setText(mPreference.getEntry());
@@ -120,4 +132,15 @@
         }
     }
 
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        onPopulateAccessibilityEvent(event);
+        return true;
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
+        event.getText().add(mPreference.getTitle() + mPreference.getEntry());
+    }
 }
diff --git a/src/com/android/camera/ui/InLineSettingSwitch.java b/src/com/android/camera/ui/InLineSettingSwitch.java
index 8663a05..8fc37da 100644
--- a/src/com/android/camera/ui/InLineSettingSwitch.java
+++ b/src/com/android/camera/ui/InLineSettingSwitch.java
@@ -16,11 +16,13 @@
 
 package com.android.camera.ui;
 
+import com.android.camera.ListPreference;
 import com.android.camera.R;
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
@@ -47,6 +49,14 @@
         mSwitch.setOnCheckedChangeListener(mCheckedChangeListener);
     }
 
+    @Override
+    public void initialize(ListPreference preference) {
+        super.initialize(preference);
+        // Add content descriptions for the increment and decrement buttons.
+        mSwitch.setContentDescription(getContext().getResources().getString(
+                R.string.accessibility_switch, mPreference.getTitle()));
+    }
+
     protected void updateView() {
         if (mOverrideValue == null) {
             mSwitch.setChecked(mIndex == 1);
@@ -55,4 +65,16 @@
             mSwitch.setChecked(index == 1);
         }
     }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        onPopulateAccessibilityEvent(event);
+        return true;
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
+        event.getText().add(mPreference.getTitle());
+    }
 }
diff --git a/src/com/android/camera/ui/IndicatorControl.java b/src/com/android/camera/ui/IndicatorControl.java
index 03003d8..86b0cc9 100644
--- a/src/com/android/camera/ui/IndicatorControl.java
+++ b/src/com/android/camera/ui/IndicatorControl.java
@@ -125,6 +125,7 @@
     public IndicatorButton addIndicator(Context context, IconListPreference pref) {
         IndicatorButton b = new IndicatorButton(context, pref);
         b.setSettingChangedListener(this);
+        b.setContentDescription(pref.getTitle());
         addView(b);
         mIndicators.add(b);
         return b;
@@ -135,6 +136,8 @@
         OtherSettingIndicatorButton b = new OtherSettingIndicatorButton(
                 context, resId, mPreferenceGroup, keys);
         b.setSettingChangedListener(this);
+        b.setContentDescription(getResources().getString(
+                R.string.pref_camera_settings_category));
         addView(b);
         mIndicators.add(b);
         return b;
diff --git a/src/com/android/camera/ui/IndicatorControlBar.java b/src/com/android/camera/ui/IndicatorControlBar.java
index 4297528..6c2151d 100644
--- a/src/com/android/camera/ui/IndicatorControlBar.java
+++ b/src/com/android/camera/ui/IndicatorControlBar.java
@@ -83,9 +83,7 @@
     @Override
     protected void onLayout(
             boolean changed, int left, int top, int right, int bottom) {
-        // Layout the static components.
         int padding = getPaddingTop();
-        super.onLayout(changed, left, top, right, bottom);
 
         int count = getChildCount();
         if (count == 0) return;
diff --git a/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java b/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java
index 8fce8a7..c9037d9 100644
--- a/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java
+++ b/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java
@@ -35,7 +35,7 @@
         View.OnClickListener, AbstractIndicatorButton.IndicatorChangeListener {
     private static final String TAG = "SecondLevelIndicatorControlBar";
     private static int ICON_SPACING = Util.dpToPixel(16);
-    private ImageView mCloseIcon;
+    private View mCloseIcon;
     private View mDivider; // the divider line
     private View mIndicatorHighlight; // the side highlight bar
     private View mPopupedIndicator;
@@ -54,16 +54,13 @@
     protected void onFinishInflate() {
         mDivider = findViewById(R.id.divider);
         mIndicatorHighlight = findViewById(R.id.indicator_highlight);
+        mCloseIcon = findViewById(R.id.back_to_first_level);
+        mCloseIcon.setOnClickListener(this);
     }
 
     public void initialize(Context context, PreferenceGroup group,
             String[] keys, String[] otherSettingKeys) {
-        if (mCloseIcon == null) {
-            mCloseIcon = new ColorFilterImageView(context);
-            mCloseIcon.setImageResource(R.drawable.btn_close_settings);
-            mCloseIcon.setOnClickListener(this);
-            addView(mCloseIcon);
-        }
+
         setPreferenceGroup(group);
         mNonIndicatorButtonCount = getChildCount();
         addControls(keys, otherSettingKeys);
diff --git a/src/com/android/camera/ui/ZoomControl.java b/src/com/android/camera/ui/ZoomControl.java
index 60964a4..1809d18 100644
--- a/src/com/android/camera/ui/ZoomControl.java
+++ b/src/com/android/camera/ui/ZoomControl.java
@@ -88,6 +88,13 @@
     protected ImageView addImageView(Context context, int iconResourceId) {
         ImageView image = new RotateImageView(context);
         image.setImageResource(iconResourceId);
+        if (iconResourceId == R.drawable.ic_zoom_slider) {
+            image.setContentDescription(getResources().getString(
+                    R.string.accessibility_zoom_control));
+        } else {
+            image.setContentDescription(getResources().getString(
+                    R.string.empty));
+        }
         addView(image);
         return image;
     }
diff --git a/src/com/android/camera/ui/ZoomControlBar.java b/src/com/android/camera/ui/ZoomControlBar.java
index 0784b3f..08042d4 100644
--- a/src/com/android/camera/ui/ZoomControlBar.java
+++ b/src/com/android/camera/ui/ZoomControlBar.java
@@ -36,6 +36,9 @@
     private View mBar;
     private boolean mStartChanging;
     private int mSliderLength;
+    private int mHeight;
+    private int mIconHeight;
+    private int mTotalIconHeight;
 
     public ZoomControlBar(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -55,16 +58,11 @@
         // For left-hand users, as the device is rotated for 180 degree for
         // landscape mode, the zoom-in bottom should be on the top, so the
         // position should be reversed.
-        int totalIconHeight = mZoomIn.getHeight() + ICON_SPACING;
-        int height = getHeight();
         int pos; // the relative position in the zoom slider bar
         if (mDegree == 180) {
-            pos = y - totalIconHeight;
+            pos = y - mTotalIconHeight;
         } else {
-            pos = height - totalIconHeight - y;
-        }
-        if (mSliderLength == 0) {
-            mSliderLength = height - (2 * totalIconHeight);
+            pos = mHeight - mTotalIconHeight - y;
         }
         if (pos < 0) pos = 0;
         if (pos > mSliderLength) pos = mSliderLength;
@@ -72,11 +70,17 @@
     }
 
     @Override
-    public boolean dispatchTouchEvent(MotionEvent event) {
-        if (!onFilterTouchEventForSecurity(event)) return false;
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        mHeight = h;
+        mIconHeight = mZoomIn.getMeasuredHeight();
+        mTotalIconHeight = mIconHeight + ICON_SPACING;
+        mSliderLength = mHeight - (2 * mTotalIconHeight);
+    }
 
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent event) {
+        if (!isEnabled() || (mHeight == 0)) return false;
         int action = event.getAction();
-        if (!isEnabled() || (getHeight() == 0)) return false;
 
         switch (action) {
             case MotionEvent.ACTION_OUTSIDE:
@@ -90,12 +94,15 @@
                 setActivated(true);
                 mStartChanging = false;
             case MotionEvent.ACTION_MOVE:
-                // Make sure the movement is large enough before we start
-                // changing the zoom.
                 int pos = getSliderPosition((int) event.getY());
-                if (!mStartChanging && (Math.abs(mSliderPosition - pos)
-                        > THRESHOLD_FIRST_MOVE)) {
-                    mStartChanging = true;
+                if (!mStartChanging) {
+                    // Make sure the movement is large enough before we start
+                    // changing the zoom.
+                    int delta = mSliderPosition - pos;
+                    if ((delta > THRESHOLD_FIRST_MOVE) ||
+                            (delta < -THRESHOLD_FIRST_MOVE)) {
+                        mStartChanging = true;
+                    }
                 }
                 if (mStartChanging) {
                     performZoom(1.0d * pos / mSliderLength);
@@ -118,10 +125,7 @@
             boolean changed, int left, int top, int right, int bottom) {
         if (mZoomMax == 0) return;
         int width = right - left;
-        int height = bottom - top;
-        int iconHeight = mZoomIn.getMeasuredHeight();
-        mBar.layout(0, iconHeight + ICON_SPACING,
-                width, height - iconHeight - ICON_SPACING);
+        mBar.layout(0, mTotalIconHeight, width, mHeight - mTotalIconHeight);
         // For left-hand users, as the device is rotated for 180 degree,
         // the zoom-in button should be on the top.
         int pos; // slider position
@@ -132,12 +136,12 @@
             sliderPosition = (int) ((double) mSliderLength * mZoomIndex / mZoomMax);
         }
         if (mDegree == 180) {
-            mZoomOut.layout(0, 0, width, iconHeight);
-            mZoomIn.layout(0, height - iconHeight, width, height);
+            mZoomOut.layout(0, 0, width, mIconHeight);
+            mZoomIn.layout(0, mHeight - mIconHeight, width, mHeight);
             pos = mBar.getTop() + sliderPosition;
         } else {
-            mZoomIn.layout(0, 0, width, iconHeight);
-            mZoomOut.layout(0, height - iconHeight, width, height);
+            mZoomIn.layout(0, 0, width, mIconHeight);
+            mZoomOut.layout(0, mHeight - mIconHeight, width, mHeight);
             pos = mBar.getBottom() - sliderPosition;
         }
         int sliderHeight = mZoomSlider.getMeasuredHeight();