Adding accessibility support to the Status Bar.

1. Added content description to pretty much all animals
   in the zoo including buttons in the navigation bar,
   notifications and status icons for battery, signal,
   data, etc.

2. Rectored to avoid ovelaying views since they block
   touch exploratino. In general overlaying views
   cause trouble for touch exploration and accessibility
   in general.

3. Avoid sending accessibility events in case the user is
   touching outside of the StatauBAr panels to avoid
   confusion.

4. Added records to accessibility events in the places where
   this would help the presentation. So the event comes from
   a given "leaf" view and its predecessor is adding a record
   to the event for itself to provide more cotext. It is up
   to the accessiiblity service to choose how to present that.

bug:4686943

Change-Id: I1c1bd123d828fb10911bca92130e9a05c1f020b3
diff --git a/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml b/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml
index d29e495..a354336 100644
--- a/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml
+++ b/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml
@@ -43,6 +43,7 @@
         android:layout_height="wrap_content"
         android:layout_centerInParent="true"
         android:src="@drawable/compat_mode_help_diagram"
+        android:contentDescription="@string/accessibility_compatibility_zoom_example"
         />
     <RelativeLayout
         android:orientation="horizontal"
@@ -61,6 +62,7 @@
             android:layout_alignParentRight="true"
             android:layout_centerVertical="true"
             android:src="@drawable/compat_mode_help_icon"
+            android:contentDescription="@string/accessibility_compatibility_zoom_button"
             />
         <TextView
             android:id="@+id/explanation"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar.xml b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
index d9f3f23..a2a6473 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
@@ -49,6 +49,7 @@
                 android:src="@drawable/ic_sysbar_back"
                 android:layout_alignParentLeft="true"
                 systemui:keyCode="4"
+                android:contentDescription="@string/accessibility_back"
                 />
             <LinearLayout
                 android:id="@+id/navigationArea"
@@ -62,11 +63,13 @@
                     android:layout_height="match_parent"
                     android:src="@drawable/ic_sysbar_home"
                     systemui:keyCode="3"
+                    android:contentDescription="@string/accessibility_home"
                     />
                 <ImageView android:id="@+id/recent_apps"
                     android:layout_width="80dip"
                     android:layout_height="match_parent"
                     android:src="@drawable/ic_sysbar_recent"
+                    android:contentDescription="@string/accessibility_menu"
                     />
                 <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
                     android:layout_width="80dip"
@@ -74,6 +77,7 @@
                     android:src="@drawable/ic_sysbar_menu"
                     systemui:keyCode="82"
                     android:visibility="invisible"
+                    android:contentDescription="@string/accessibility_menu"
                     />
             </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml
index 3fef7e0..41a20fb 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_input_methods_item.xml
@@ -53,7 +53,8 @@
                 android:id="@+id/item_icon"
                 android:layout_width="@android:dimen/app_icon_size"
                 android:layout_height="wrap_content"
-                android:scaleType="fitCenter" />
+                android:scaleType="fitCenter"
+                android:contentDescription="@null" />
             <LinearLayout
                 android:orientation="vertical"
                 android:layout_width="0px"
@@ -94,7 +95,8 @@
             android:visibility="visible"
             android:clickable="true"
             android:focusable="true"
-            android:background="?android:attr/selectableItemBackground" />
+            android:background="?android:attr/selectableItemBackground"
+            android:contentDescription="@string/accessibility_settings_button" />
     </LinearLayout>
     <View
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
index fecfe7f..1e3099d 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_area.xml
@@ -16,7 +16,7 @@
 -->
 
 <!-- notification icons & panel access -->
-<LinearLayout
+<com.android.systemui.statusbar.tablet.NotificationArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/notificationArea"
@@ -40,6 +40,7 @@
             android:layout_marginLeft="8dip"
             android:src="@drawable/ic_sysbar_ime_default"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_ime_switch_button"
             />
 
         <com.android.systemui.statusbar.policy.CompatModeButton
@@ -49,6 +50,7 @@
             android:layout_marginLeft="8dip"
             android:src="@drawable/ic_sysbar_zoom"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_compatibility_zoom_button"
             />
 
         <com.android.systemui.statusbar.tablet.NotificationIconArea
@@ -152,4 +154,4 @@
                 />
         </LinearLayout>
     </LinearLayout>
-</LinearLayout>
+</com.android.systemui.statusbar.tablet.NotificationArea>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
index 543f4ed..bbb2bc6 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
@@ -14,15 +14,17 @@
   limitations under the License.
 -->
 
-<RelativeLayout
+<com.android.systemui.statusbar.tablet.NotificationPanelTitle
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/title_area"
-    android:layout_width="0dp"
-    android:layout_height="0dp"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:clickable="true"
     android:orientation="vertical"
     android:background="@drawable/notify_panel_clock_bg"
     >
+
     <LinearLayout
         android:id="@+id/icons"
         android:layout_width="wrap_content"
@@ -34,6 +36,7 @@
         android:layout_marginTop="16dp"
         android:layout_marginBottom="16dp"
         >
+
         <ImageView
             android:id="@+id/bluetooth"
             android:layout_height="32dp"
@@ -41,6 +44,7 @@
             android:scaleType="centerInside"
             android:baseline="22dp"
             android:visibility="gone"
+            android:contentDescription="@null"
             />
 
         <FrameLayout
@@ -49,21 +53,28 @@
             android:layout_width="32dp"
             android:layout_marginRight="4dp"
             >
+
             <ImageView
                 android:id="@+id/network_signal"
                 android:layout_height="match_parent"
                 android:layout_width="match_parent"
+                android:contentDescription="@null"
                 />
+
             <ImageView
                 android:id="@+id/network_type"
                 android:layout_height="match_parent"
                 android:layout_width="match_parent"
+                android:contentDescription="@null"
                 />
+
             <ImageView
                 android:id="@+id/network_direction"
                 android:layout_height="match_parent"
                 android:layout_width="match_parent"
+                android:contentDescription="@null"
                 />
+
         </FrameLayout>
             
         <TextView
@@ -86,6 +97,7 @@
             android:layout_toRightOf="@id/network_text"
             android:layout_alignBaseline="@id/network_signal"
             android:baseline="22dp"
+            android:contentDescription="@null"
             />
 
         <TextView
@@ -110,6 +122,7 @@
         android:paddingRight="16dp"
         android:src="@drawable/ic_sysbar_quicksettings"
         android:baseline="21dp"
+        android:contentDescription="@string/accessibility_settings_button"
         />
 
     <ImageView
@@ -122,6 +135,7 @@
         android:src="@drawable/ic_notification_open"
         android:baseline="21dp"
         android:visibility="invisible"
+        android:contentDescription="@string/accessibility_notifications_button"
         />
 
     <View
@@ -138,7 +152,7 @@
     <com.android.systemui.statusbar.tablet.HoloClock
         android:id="@+id/clock"
         android:layout_height="wrap_content"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_alignParentRight="true"
         android:layout_above="@id/title_divider"
         android:layout_marginRight="6dip"
@@ -164,19 +178,11 @@
         android:id="@+id/date"
         style="@style/StatusBarNotificationText"
         android:layout_height="wrap_content"
-        android:layout_width="120dp"
+        android:layout_width="wrap_content"
         android:layout_alignBottom="@id/clock"
         android:layout_alignParentLeft="true"
         android:gravity="left"
         android:layout_marginLeft="32dp"
         />
 
-    <view
-        class="com.android.systemui.statusbar.tablet.NotificationPanel$ModeToggle"
-        android:id="@+id/mode_toggle"
-        android:background="@null"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clickable="true"
-        />
-</RelativeLayout>
+</com.android.systemui.statusbar.tablet.NotificationPanelTitle>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 51e7d97..5d7e8de 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -54,6 +54,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:layout_weight="1"
+                android:contentDescription="@string/accessibility_back"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
                 android:layout_width="80dp"
@@ -66,6 +67,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:layout_weight="1"
+                android:contentDescription="@string/accessibility_home"
                 />
             <ImageView android:id="@+id/recent_apps"
                 android:layout_width="80dp"
@@ -80,6 +82,7 @@
                 systemui:keyCode="82"
                 android:layout_weight="0"
                 android:visibility="invisible"
+                android:contentDescription="@string/accessibility_menu"
                 />
         </LinearLayout>
 
@@ -124,6 +127,7 @@
                 android:layout_height="match_parent"
                 android:layout_width="match_parent"
                 android:layout_weight="1"
+                android:contentDescription="@string/accessibility_menu"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
                 android:layout_height="80dp"
@@ -131,11 +135,13 @@
                 android:src="@drawable/ic_sysbar_home_default_land"
                 systemui:keyCode="3"
                 android:layout_weight="0"
+                android:contentDescription="@string/accessibility_home"
                 />
             <View 
                 android:layout_height="match_parent"
                 android:layout_width="match_parent"
                 android:layout_weight="1"
+                android:contentDescription="@string/accessibility_back"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                 android:layout_height="80dp"
@@ -148,6 +154,7 @@
                 android:layout_height="40dp"
                 android:layout_width="match_parent"
                 android:layout_weight="0"
+                android:contentDescription="@string/accessibility_menu"
                 />
         </LinearLayout>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 01cf2dc..082dab3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -169,4 +169,135 @@
     <string name="screenshot_saving_toast">Screenshot saved to Gallery</string>
     <!-- toast message displayed when we fail to take a screenshot. -->
     <string name="screenshot_failed_toast">Could not save screenshot</string>
+
+    <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
+    <string name="usb_preference_title">USB file transfer options</string>
+    <!-- Label for the MTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="use_mtp_button_title">Mount as a media player (MTP)</string>
+    <!-- Label for the PTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="use_ptp_button_title">Mount as a camera (PTP)</string>
+    <!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="installer_cd_button_title">Install Android File Transfer application for Mac</string>
+
+    <!-- Content description of the back button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_back">Back</string>
+    <!-- Content description of the home button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_home">Home</string>
+    <!-- Content description of the menu button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_menu">Menu</string>
+
+    <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ime_switch_button">Switch input method button.</string>
+    <!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string>
+
+    <!-- Content description of picture of the compatibility zoom example for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_compatibility_zoom_example">Zoom smaller to larger screen.</string>
+
+    <!-- Content description of the bluetooth icon when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_bluetooth_connected">Bluetooth connected.</string>
+    <!-- Content description of the bluetooth icon when connecting for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_bluetooth_disconnected">Bluetooth disconnected.</string>
+
+    <!-- Content description of the battery when no battery for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_no_battery">No battery.</string>
+    <!-- Content description of the battery when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_one_bar">Battery one bar.</string>
+    <!-- Content description of the battery when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_two_bars">Battery two bars.</string>
+     <!-- Content description of the battery when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_three_bars">Battery three bars.</string>
+    <!-- Content description of the battery when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_full">Battery full.</string>
+
+    <!-- Content description of the phone signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_no_phone">No phone.</string>
+    <!-- Content description of the phone signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_phone_one_bar">Phone one bar.</string>
+    <!-- Content description of the phone signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_phone_two_bars">Phone two bars.</string>
+    <!-- Content description of the phone signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_phone_three_bars">Phone three bars.</string>
+    <!-- Content description of the phone signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_phone_signal_full">Phone signal full.</string>
+
+    <!-- Content description of the data signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_no_data">No data.</string>
+    <!-- Content description of the data signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_one_bar">Data one bar.</string>
+    <!-- Content description of the data signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_two_bars">Data two bars.</string>
+    <!-- Content description of the data signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_three_bars">Data three bars.</string>
+    <!-- Content description of the data signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_signal_full">Data signal full.</string>
+
+    <!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_no_wifi">No WiFi.</string>
+    <!-- Content description of the WIFI signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_one_bar">WiFi one bar.</string>
+    <!-- Content description of the WIFI signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_two_bars">WiFi two bars.</string>
+    <!-- Content description of the WIFI signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_three_bars">WiFi three bars.</string>
+    <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_signal_full">WiFi signal full.</string>
+
+    <!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_connection_gprs">GPRS</string>
+
+    <!-- Content description of the data connection type 3G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_connection_3g">3G</string>
+
+    <!-- Content description of the data connection type 3.5G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_connection_3.5g">3.5G</string>
+
+    <!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_connection_4g">4G</string>
+
+    <!-- Content description of the data connection type CDMA for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_connection_cdma">CDMA</string>
+
+    <!-- Content description of the data connection type Edge for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_connection_edge">Edge</string>
+
+    <!-- Content description of the data connection type WiFi for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_connection_wifi">WiFi</string>
+
+    <!-- Content description of the data connection with no SIM for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_no_sim">No SIM.</string>
+
+    <!-- Content description of the bluetooth tethering icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_bluetooth_tether">Bluetooth tethering.</string>
+
+    <!-- Content description of the airplane mode icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_airplane_mode">Airplane mode.</string>
+
+    <!-- Content description of the battery level icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_level">Battery <xliff:g id="number">%d</xliff:g> percent.</string>
+
+    <!-- Content description of the button for showing a settings panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_settings_button">Settings button.</string>
+
+    <!-- Content description of the button for showing a notifications panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_notifications_button">Notifications button.</string>
+
+    <!-- Content description of the button for removing a notification in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_remove_notification">Remove notification.</string>
+
+    <!-- Content description of the enabled GPS icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_gps_enabled">GPS enabled.</string>
+
+    <!-- Content description of the acquiring GPS icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_gps_acquiring">GPS acquiring.</string>
+
+    <!-- Content description of the TeleTypewriter(TTY) enabled icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_tty_enabled">TeleTypewriter enabled.</string>
+
+    <!-- Content description of the ringer vibrate icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ringer_vibrate">Ringer vibrate.</string>
+
+    <!-- Content description of the ringer silent icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ringer_silent">Ringer silent.</string>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index bc0a508..cca7947 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -22,7 +22,6 @@
 import android.animation.Animator;
 import android.animation.LayoutTransition;
 import android.app.ActivityManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -48,6 +47,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
@@ -112,7 +112,7 @@
             position = _pos;
             packageName = _packageName;
         }
-    };
+    }
 
     private final class OnLongClickDelegate implements View.OnLongClickListener {
         View mOtherView;
@@ -252,6 +252,19 @@
         mChoreo.setPanelHeight(mRecentsContainer.getHeight());
     }
 
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Ignore hover events outside of this panel bounds since such events
+        // generate spurious accessibility events with the panel content when
+        // tapping outside of it, thus confusing the user.
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
+            return super.dispatchHoverEvent(event);
+        }
+        return true;
+    }
+
     /**
      * Whether the panel is showing, or, if it's animating, whether it will be
      * when the animation is done.
@@ -316,7 +329,6 @@
 
 
         mRecentsGlowView = findViewById(R.id.recents_glow);
-        mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
         mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, this);
         mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
         mRecentsDismissButton.setOnClickListener(new OnClickListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
index 64ec063..6419777 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
@@ -18,8 +18,8 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
 public class LatestItemView extends FrameLayout {
@@ -27,7 +27,22 @@
         super(context, attrs);
     }
 
+    @Override
     public void setOnClickListener(OnClickListener l) {
         super.setOnClickListener(l);
     }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEvent(child, event)) {
+            // Add a record for the entire layout since its content is somehow small.
+            // The event comes from a leaf view that is interacted with.
+            AccessibilityEvent record = AccessibilityEvent.obtain();
+            onInitializeAccessibilityEvent(record);
+            dispatchPopulateAccessibilityEvent(record);
+            event.appendRecord(record);
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index d9d9c06..be4b395 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import android.app.Notification;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -23,11 +24,11 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.Log;
-import android.view.View;
 import android.view.ViewDebug;
-import android.widget.FrameLayout;
+import android.view.accessibility.AccessibilityEvent;
 
 import java.text.NumberFormat;
 
@@ -45,8 +46,9 @@
     private int mNumberX;
     private int mNumberY;
     private String mNumberText;
+    private Notification mNotification;
 
-    public StatusBarIconView(Context context, String slot) {
+    public StatusBarIconView(Context context, String slot, Notification notification) {
         super(context);
         final Resources res = context.getResources();
         mSlot = slot;
@@ -54,6 +56,8 @@
         mNumberPain.setTextAlign(Paint.Align.CENTER);
         mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color));
         mNumberPain.setAntiAlias(true);
+        mNotification = notification;
+        setContentDescription(notification);
     }
 
     private static boolean streq(String a, String b) {
@@ -83,6 +87,7 @@
         final boolean numberEquals = mIcon != null
                 && mIcon.number == icon.number;
         mIcon = icon.clone();
+        setContentDescription(icon.contentDescription);
         if (!iconEquals) {
             Drawable drawable = getIcon(icon);
             if (drawable == null) {
@@ -159,6 +164,15 @@
         return mIcon;
     }
 
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        if (mNotification != null) {
+            event.setParcelableData(mNotification);
+        }
+    }
+
+    @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
         if (mNumberBackground != null) {
@@ -166,6 +180,7 @@
         }
     }
 
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
@@ -175,6 +190,7 @@
         }
     }
 
+    @Override
     protected void debug(int depth) {
         super.debug(depth);
         Log.d("View", debugIndent(depth) + "slot=" + mSlot);
@@ -213,4 +229,13 @@
         mNumberY = h-r.bottom-((dh-r.top-th-r.bottom)/2);
         mNumberBackground.setBounds(w-dw, h-dh, w, h);
     }
+
+    private void setContentDescription(Notification notification) {
+        if (notification != null) {
+            CharSequence tickerText = notification.tickerText;
+            if (!TextUtils.isEmpty(tickerText)) {
+                setContentDescription(tickerText);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
index e1d17a8..f6aa159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
@@ -33,7 +33,8 @@
 
     private int mIconSize;
     private StatusBarIconView mMoreView;
-    private StatusBarIcon mMoreIcon = new StatusBarIcon(null, R.drawable.stat_notify_more, 0);
+    private StatusBarIcon mMoreIcon = new StatusBarIcon(null, R.drawable.stat_notify_more, 0, 0,
+            null);
 
     public IconMerger(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -41,7 +42,7 @@
         mIconSize = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_icon_size);
 
-        mMoreView = new StatusBarIconView(context, "more");
+        mMoreView = new StatusBarIconView(context, "more", null);
         mMoreView.set(mMoreIcon);
         addView(mMoreView, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f4c4bbc..b93ad68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -472,7 +472,7 @@
     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
         if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
                 + " icon=" + icon);
-        StatusBarIconView view = new StatusBarIconView(mContext, slot);
+        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
         view.set(icon);
         mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
     }
@@ -607,7 +607,7 @@
                 // Update the icon.
                 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
                         notification.notification.icon, notification.notification.iconLevel,
-                        notification.notification.number);
+                        notification.notification.number, notification.notification.tickerText);
                 if (!oldEntry.icon.set(ic)) {
                     handleNotificationError(key, notification, "Couldn't update icon: " + ic);
                     return;
@@ -765,9 +765,11 @@
         final View expanded = views[2];
         // Construct the icon.
         final StatusBarIconView iconView = new StatusBarIconView(mContext,
-                notification.pkg + "/0x" + Integer.toHexString(notification.id));
+                notification.pkg + "/0x" + Integer.toHexString(notification.id),
+                notification.notification);
         final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
-                    notification.notification.iconLevel, notification.notification.number);
+                    notification.notification.iconLevel, notification.notification.number,
+                    notification.notification.tickerText);
         if (!iconView.set(ic)) {
             handleNotificationError(key, notification, "Coulding create icon: " + ic);
             return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index af5c72d..7b50985 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -18,25 +18,17 @@
 
 import android.app.StatusBarManager;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothPbap;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.TypedArray;
-import android.graphics.PixelFormat;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
 import android.location.LocationManager;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
-import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Handler;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
@@ -44,18 +36,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
-import android.text.format.DateFormat;
-import android.text.style.CharacterStyle;
-import android.text.style.RelativeSizeSpan;
-import android.text.style.ForegroundColorSpan;
-import android.text.style.StyleSpan;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
 import android.util.Slog;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.telephony.IccCard;
@@ -63,7 +44,6 @@
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.internal.telephony.cdma.TtyIntent;
 import com.android.server.am.BatteryStatsService;
-
 import com.android.systemui.R;
 
 /**
@@ -447,6 +427,32 @@
               R.drawable.stat_sys_data_fully_inandout_1x }
             };
 
+    // Accessibility;
+
+    private static final int[] sPhoneSignalStrength = {
+        R.string.accessibility_no_phone,
+        R.string.accessibility_phone_one_bar,
+        R.string.accessibility_phone_two_bars,
+        R.string.accessibility_phone_three_bars,
+        R.string.accessibility_phone_signal_full
+    };
+
+    private static final int[] sDataConnectionStrength = {
+        R.string.accessibility_no_data,
+        R.string.accessibility_data_one_bar,
+        R.string.accessibility_data_two_bars,
+        R.string.accessibility_data_three_bars,
+        R.string.accessibility_data_signal_full
+    };
+
+    private static final int[] sWifiConnectionStrength = {
+        R.string.accessibility_no_wifi,
+        R.string.accessibility_wifi_one_bar,
+        R.string.accessibility_wifi_two_bars,
+        R.string.accessibility_wifi_three_bars,
+        R.string.accessibility_wifi_signal_full
+    };
+
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
     IccCard.State mSimState = IccCard.State.READY;
@@ -546,12 +552,13 @@
                 new com.android.systemui.usb.StorageNotification(context));
 
         // battery
-        mService.setIcon("battery", com.android.internal.R.drawable.stat_sys_battery_unknown, 0);
+        mService.setIcon("battery", com.android.internal.R.drawable.stat_sys_battery_unknown, 0,
+                null);
 
         // phone_signal
         mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
         mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
-        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0, null);
 
         // register for phone state notifications.
         ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
@@ -563,24 +570,24 @@
                         | PhoneStateListener.LISTEN_DATA_ACTIVITY);
 
         // data_connection
-        mService.setIcon("data_connection", R.drawable.stat_sys_data_connected_g, 0);
+        mService.setIcon("data_connection", R.drawable.stat_sys_data_connected_g, 0, null);
         mService.setIconVisibility("data_connection", false);
 
         // wifi
-        mService.setIcon("wifi", sWifiSignalImages[0][0], 0);
+        mService.setIcon("wifi", sWifiSignalImages[0][0], 0, null);
         mService.setIconVisibility("wifi", false);
         // wifi will get updated by the sticky intents
 
         // TTY status
-        mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0);
+        mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0, null);
         mService.setIconVisibility("tty", false);
 
         // Cdma Roaming Indicator, ERI
-        mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0);
+        mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0, null);
         mService.setIconVisibility("cdma_eri", false);
 
         // bluetooth status
-        mService.setIcon("bluetooth", R.drawable.stat_sys_data_bluetooth, 0);
+        mService.setIcon("bluetooth", R.drawable.stat_sys_data_bluetooth, 0, null);
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         if (adapter != null) {
             mBluetoothEnabled = adapter.isEnabled();
@@ -590,21 +597,23 @@
         mService.setIconVisibility("bluetooth", mBluetoothEnabled);
 
         // Gps status
-        mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0);
+        mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0, null);
         mService.setIconVisibility("gps", false);
 
         // Alarm clock
-        mService.setIcon("alarm_clock", R.drawable.stat_notify_alarm, 0);
+        mService.setIcon("alarm_clock", R.drawable.stat_notify_alarm, 0, null);
         mService.setIconVisibility("alarm_clock", false);
 
         // Sync state
-        mService.setIcon("sync_active", com.android.internal.R.drawable.stat_notify_sync_anim0, 0);
-        mService.setIcon("sync_failing", com.android.internal.R.drawable.stat_notify_sync_error, 0);
+        mService.setIcon("sync_active", com.android.internal.R.drawable.stat_notify_sync_anim0,
+                0, null);
+        mService.setIcon("sync_failing", com.android.internal.R.drawable.stat_notify_sync_error,
+                0, null);
         mService.setIconVisibility("sync_active", false);
         mService.setIconVisibility("sync_failing", false);
 
         // volume
-        mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0);
+        mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null);
         mService.setIconVisibility("volume", false);
         updateVolume();
 
@@ -655,7 +664,8 @@
     private final void updateBattery(Intent intent) {
         final int id = intent.getIntExtra("icon-small", 0);
         int level = intent.getIntExtra("level", 0);
-        mService.setIcon("battery", id, level);
+        String contentDescription = mContext.getString(R.string.accessibility_battery_level, level);
+        mService.setIcon("battery", id, level, contentDescription);
     }
 
     private void updateConnectivity(Intent intent) {
@@ -677,12 +687,16 @@
             if (info.isConnected()) {
                 mIsWifiConnected = true;
                 int iconId;
+                String contentDescription = null;
                 if (mLastWifiSignalLevel == -1) {
                     iconId = sWifiSignalImages[mInetCondition][0];
+                    contentDescription = mContext.getString(sWifiConnectionStrength[0]);
                 } else {
                     iconId = sWifiSignalImages[mInetCondition][mLastWifiSignalLevel];
-                }
-                mService.setIcon("wifi", iconId, 0);
+                    contentDescription = mContext.getString(
+                            sWifiConnectionStrength[mLastWifiSignalLevel]);
+                } 
+                mService.setIcon("wifi", iconId, 0, contentDescription);
                 // Show the icon since wi-fi is connected
                 mService.setIconVisibility("wifi", true);
             } else {
@@ -690,7 +704,8 @@
                 mIsWifiConnected = false;
                 int iconId = sWifiSignalImages[0][0];
 
-                mService.setIcon("wifi", iconId, 0);
+                String contentDescription = mContext.getString(R.string.accessibility_no_wifi);
+                mService.setIcon("wifi", iconId, 0, contentDescription);
                 // Hide the icon since we're not connected
                 mService.setIconVisibility("wifi", false);
             }
@@ -781,6 +796,7 @@
 
     private final void updateSignalStrength() {
         int[] iconList;
+        String contentDescription = null;
 
         // Display signal strength while in "emergency calls only" mode
         if (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly())) {
@@ -788,10 +804,12 @@
             if (Settings.System.getInt(mContext.getContentResolver(),
                     Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
                 mPhoneSignalIconId = R.drawable.stat_sys_signal_flightmode;
+                contentDescription = mContext.getString(R.string.accessibility_airplane_mode);
             } else {
                 mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+                contentDescription = mContext.getString(R.string.accessibility_no_phone);
             }
-            mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+            mService.setIcon("phone_signal", mPhoneSignalIconId, 0, contentDescription);
             return;
         }
 
@@ -805,8 +823,11 @@
         } else {
             iconList = sSignalImages[mInetCondition];
         }
-        mPhoneSignalIconId = iconList[mSignalStrength.getLevel()];
-        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+
+        final int signalLevel = mSignalStrength.getLevel();
+        mPhoneSignalIconId = iconList[signalLevel];
+        contentDescription = mContext.getString(sPhoneSignalStrength[signalLevel]);
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0, contentDescription);
     }
 
     private final void updateDataNetType(int net) {
@@ -850,6 +871,7 @@
 
     private final void updateDataIcon() {
         int iconId;
+        String contentDescription = null;
         boolean visible = true;
 
         if (!isCdma()) {
@@ -870,13 +892,15 @@
                             iconId = mDataIconList[0];
                             break;
                     }
-                    mService.setIcon("data_connection", iconId, 0);
+                    contentDescription = mContext.getString(sDataConnectionStrength[mDataActivity]);
+                    mService.setIcon("data_connection", iconId, 0, contentDescription);
                 } else {
                     visible = false;
                 }
             } else {
                 iconId = R.drawable.stat_sys_no_sim;
-                mService.setIcon("data_connection", iconId, 0);
+                contentDescription = mContext.getString(R.string.accessibility_no_sim);
+                mService.setIcon("data_connection", iconId, 0, contentDescription);
             }
         } else {
             // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
@@ -896,7 +920,7 @@
                         iconId = mDataIconList[0];
                         break;
                 }
-                mService.setIcon("data_connection", iconId, 0);
+                mService.setIcon("data_connection", iconId, 0, null);
             } else {
                 visible = false;
             }
@@ -921,12 +945,19 @@
         final int ringerMode = audioManager.getRingerMode();
         final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
                 ringerMode == AudioManager.RINGER_MODE_VIBRATE;
-        final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
-                ? R.drawable.stat_sys_ringer_vibrate
-                : R.drawable.stat_sys_ringer_silent;
+
+        final int iconId;
+        String contentDescription = null;
+        if (audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
+            iconId = R.drawable.stat_sys_ringer_vibrate;
+            contentDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
+        } else {
+            iconId =  R.drawable.stat_sys_ringer_silent;
+            contentDescription = mContext.getString(R.string.accessibility_ringer_silent);
+        }
 
         if (visible) {
-            mService.setIcon("volume", iconId, 0);
+            mService.setIcon("volume", iconId, 0, contentDescription);
         }
         if (visible != mVolumeVisible) {
             mService.setIconVisibility("volume", visible);
@@ -936,6 +967,7 @@
 
     private final void updateBluetooth(Intent intent) {
         int iconId = R.drawable.stat_sys_data_bluetooth;
+        String contentDescription = null;
         String action = intent.getAction();
         if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
             int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
@@ -945,12 +977,16 @@
                 BluetoothAdapter.STATE_DISCONNECTED);
             if (state == BluetoothAdapter.STATE_CONNECTED) {
                 iconId = R.drawable.stat_sys_data_bluetooth_connected;
+                contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
+            } else {
+                contentDescription = mContext.getString(
+                        R.string.accessibility_bluetooth_disconnected);
             }
         } else {
             return;
         }
 
-        mService.setIcon("bluetooth", iconId, 0);
+        mService.setIcon("bluetooth", iconId, 0, contentDescription);
         mService.setIconVisibility("bluetooth", mBluetoothEnabled);
     }
 
@@ -974,6 +1010,7 @@
             }
         } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
             int iconId;
+            String contentDescription = null;
             final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
                                                                   sWifiSignalImages[0].length);
@@ -981,10 +1018,13 @@
                 mLastWifiSignalLevel = newSignalLevel;
                 if (mIsWifiConnected) {
                     iconId = sWifiSignalImages[mInetCondition][newSignalLevel];
+                    contentDescription = mContext.getString(
+                            sWifiConnectionStrength[newSignalLevel]);
                 } else {
                     iconId = sWifiTemporarilyNotConnectedImage;
+                    contentDescription = mContext.getString(R.string.accessibility_no_wifi);
                 }
-                mService.setIcon("wifi", iconId, 0);
+                mService.setIcon("wifi", iconId, 0, contentDescription);
             }
         }
     }
@@ -995,14 +1035,16 @@
 
         if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
             // GPS is getting fixes
-            mService.setIcon("gps", com.android.internal.R.drawable.stat_sys_gps_on, 0);
+            mService.setIcon("gps", com.android.internal.R.drawable.stat_sys_gps_on, 0,
+                    mContext.getString(R.string.accessibility_gps_enabled));
             mService.setIconVisibility("gps", true);
         } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
             // GPS is off
             mService.setIconVisibility("gps", false);
         } else {
             // GPS is on, but not receiving fixes
-            mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0);
+            mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0,
+                    mContext.getString(R.string.accessibility_gps_acquiring));
             mService.setIconVisibility("gps", true);
         }
     }
@@ -1016,7 +1058,8 @@
         if (enabled) {
             // TTY is on
             if (false) Slog.v(TAG, "updateTTY: set TTY on");
-            mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0);
+            mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0,
+                    mContext.getString(R.string.accessibility_tty_enabled));
             mService.setIconVisibility("tty", true);
         } else {
             // TTY is off
@@ -1058,15 +1101,15 @@
 
         switch (iconMode) {
             case EriInfo.ROAMING_ICON_MODE_NORMAL:
-                mService.setIcon("cdma_eri", iconList[iconIndex], 0);
+                mService.setIcon("cdma_eri", iconList[iconIndex], 0, null);
                 mService.setIconVisibility("cdma_eri", true);
                 break;
             case EriInfo.ROAMING_ICON_MODE_FLASH:
-                mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_flash, 0);
+                mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_flash, 0, null);
                 mService.setIconVisibility("cdma_eri", true);
                 break;
 
         }
-        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0, null);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 84c524a..c2390e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -26,6 +26,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
@@ -203,5 +204,19 @@
         return mService.interceptTouchEvent(event)
                 ? true : super.onInterceptTouchEvent(event);
     }
-}
 
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEvent(child, event)) {
+            // The status bar is very small so augment the view that the user is touching
+            // with the content of the status bar a whole. This way an accessibility service
+            // may announce the current item as well as the entire content if appropriate.
+            AccessibilityEvent record = AccessibilityEvent.obtain();
+            onInitializeAccessibilityEvent(record);
+            dispatchPopulateAccessibilityEvent(record);
+            event.appendRecord(record);
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
index 8ee12de..e76fe51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
@@ -183,7 +183,8 @@
         }
 
         final Drawable icon = StatusBarIconView.getIcon(mContext,
-                new StatusBarIcon(n.pkg, n.notification.icon, n.notification.iconLevel, 0));
+                new StatusBarIcon(n.pkg, n.notification.icon, n.notification.iconLevel, 0,
+                        n.notification.tickerText));
         final Segment newSegment = new Segment(n, icon, n.notification.tickerText);
 
         // If there's already a notification schedule for this package and id, remove it.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
new file mode 100644
index 0000000..13fb03e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
@@ -0,0 +1,37 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.R;
+
+/**
+ * Content descriptions for accessibility support.
+ */
+public class AccessibilityContentDescriptions {
+
+    private AccessibilityContentDescriptions() {}
+    
+    static final int[] PHONE_SIGNAL_STRENGTH = {
+        R.string.accessibility_no_phone,
+        R.string.accessibility_phone_one_bar,
+        R.string.accessibility_phone_two_bars,
+        R.string.accessibility_phone_three_bars,
+        R.string.accessibility_phone_signal_full
+    };
+
+    static final int[] DATA_CONNECTION_STRENGTH = {
+        R.string.accessibility_no_data,
+        R.string.accessibility_data_one_bar,
+        R.string.accessibility_data_two_bars,
+        R.string.accessibility_data_three_bars,
+        R.string.accessibility_data_signal_full
+    };
+
+    static final int[] WIFI_CONNECTION_STRENGTH = {
+        R.string.accessibility_no_wifi,
+        R.string.accessibility_wifi_one_bar,
+        R.string.accessibility_wifi_two_bars,
+        R.string.accessibility_wifi_three_bars,
+        R.string.accessibility_wifi_signal_full
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index ae2b6b2..3957c1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -62,12 +62,15 @@
                 ImageView v = mIconViews.get(i);
                 v.setImageResource(icon);
                 v.setImageLevel(level);
+                v.setContentDescription(mContext.getString(R.string.accessibility_battery_level,
+                        level));
             }
             N = mLabelViews.size();
             for (int i=0; i<N; i++) {
                 //final boolean plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
                 TextView v = mLabelViews.get(i);
-                v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format, level));
+                v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format,
+                        level));
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 0525054..c6f416f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -19,12 +19,10 @@
 import java.util.ArrayList;
 
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.util.Slog;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -54,26 +52,24 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
-            mEnabled = state == BluetoothAdapter.STATE_ON;
-        } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
-            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
+        int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
                 BluetoothAdapter.STATE_DISCONNECTED);
-            if (state == BluetoothAdapter.STATE_CONNECTED) {
-                mIconId = R.drawable.stat_sys_data_bluetooth_connected;
-            } else {
-                mIconId = R.drawable.stat_sys_data_bluetooth;
-            }
-        }
+        int contentDescriptionResId = 0;
 
+        if (state == BluetoothAdapter.STATE_CONNECTED) {
+            mIconId = R.drawable.stat_sys_data_bluetooth_connected;
+            contentDescriptionResId = R.string.accessibility_bluetooth_connected;
+        } else {
+            mIconId = R.drawable.stat_sys_data_bluetooth;
+            contentDescriptionResId = R.string.accessibility_bluetooth_disconnected;
+        }
 
         int N = mIconViews.size();
         for (int i=0; i<N; i++) {
             ImageView v = mIconViews.get(i);
             v.setImageResource(mIconId);
             v.setVisibility(mEnabled ? View.VISIBLE : View.GONE);
+            v.setContentDescription(mContext.getString(contentDescriptionResId));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 3175a99..829855b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -28,14 +28,11 @@
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
-import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
@@ -87,6 +84,11 @@
     int mDataTypeIconId;
     boolean mDataActive;
 
+    String mContentDescriptionPhoneSignal;
+    String mContentDescriptionWifi;
+    String mContentDescriptionCombinedSignal;
+    String mContentDescriptionDataType;
+
     // wifi
     final WifiManager mWifiManager;
     AsyncChannel mWifiChannel;
@@ -366,6 +368,8 @@
             if (mSignalStrength == null) {
                 mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
                 mDataSignalIconId = R.drawable.stat_sys_signal_0; // note we use 0 instead of null
+                mContentDescriptionPhoneSignal = mContext.getString(
+                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
             } else {
                 int iconLevel;
                 int[] iconList;
@@ -385,6 +389,9 @@
                     }
                 }
                 mPhoneSignalIconId = iconList[iconLevel];
+                mContentDescriptionPhoneSignal = mContext.getString(
+                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
+
                 mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
             }
         }
@@ -395,14 +402,20 @@
             case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                 mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
                 mDataTypeIconId = 0;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_gprs);
                 break;
             case TelephonyManager.NETWORK_TYPE_EDGE:
                 mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_edge;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_edge);
                 break;
             case TelephonyManager.NETWORK_TYPE_UMTS:
                 mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_3g;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_3g);
                 break;
             case TelephonyManager.NETWORK_TYPE_HSDPA:
             case TelephonyManager.NETWORK_TYPE_HSUPA:
@@ -410,19 +423,27 @@
                 if (mHspaDataDistinguishable) {
                     mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
                     mDataTypeIconId = R.drawable.stat_sys_signal_hsdpa;
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_3_5g);
                 } else {
                     mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
                     mDataTypeIconId = R.drawable.stat_sys_signal_3g;
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_3g);
                 }
                 break;
             case TelephonyManager.NETWORK_TYPE_CDMA:
                 // display 1xRTT for IS95A/B
                 mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_1x;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_cdma);
                 break;
             case TelephonyManager.NETWORK_TYPE_1xRTT:
                 mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_1x;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_cdma);
                 break;
             case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
             case TelephonyManager.NETWORK_TYPE_EVDO_A:
@@ -430,14 +451,20 @@
             case TelephonyManager.NETWORK_TYPE_EHRPD:
                 mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_3g;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_3g);
                 break;
             case TelephonyManager.NETWORK_TYPE_LTE:
                 mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_4g;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_4g);
                 break;
             default:
                 mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
                 mDataTypeIconId = R.drawable.stat_sys_signal_gprs;
+                mContentDescriptionDataType = mContext.getString(
+                        R.string.accessibility_data_connection_gprs);
                 break;
         }
         if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
@@ -618,8 +645,11 @@
     private void updateWifiIcons() {
         if (mWifiConnected) {
             mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+            mContentDescriptionWifi = mContext.getString(
+                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
         } else {
             mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[0][0];
+            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
         }
     }
 
@@ -704,6 +734,7 @@
                 }
             }
             combinedSignalIconId = mWifiIconId;
+            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
             dataTypeIconId = 0;
         } else if (mDataConnected) {
             label = mNetworkName;
@@ -723,22 +754,29 @@
                     break;
             }
             combinedSignalIconId = mDataSignalIconId;
+            mContentDescriptionCombinedSignal = mContentDescriptionDataType;
             dataTypeIconId = mDataTypeIconId;
         } else if (mBluetoothTethered) {
             label = mContext.getString(R.string.bluetooth_tethered);
             combinedSignalIconId = mBluetoothTetherIconId;
+            mContentDescriptionCombinedSignal = mContext.getString(
+                    R.string.accessibility_bluetooth_tether);
             dataTypeIconId = 0;
         } else if (mAirplaneMode &&
                 (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
             // Only display the flight-mode icon if not in "emergency calls only" mode.
             label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
             combinedSignalIconId = R.drawable.stat_sys_signal_flightmode;
+            mContentDescriptionCombinedSignal = mContext.getString(
+                    R.string.accessibility_airplane_mode);
             dataTypeIconId = 0;
         } else {
             label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
             // On devices without mobile radios, we want to show the wifi icon
             combinedSignalIconId =
                 hasMobileDataFeature() ? mDataSignalIconId : mWifiIconId;
+            mContentDescriptionCombinedSignal = hasMobileDataFeature()
+                ? mContentDescriptionDataType : mContentDescriptionWifi;
             dataTypeIconId = 0;
         }
 
@@ -764,6 +802,7 @@
             for (int i=0; i<N; i++) {
                 final ImageView v = mPhoneSignalIconViews.get(i);
                 v.setImageResource(mPhoneSignalIconId);
+                v.setContentDescription(mContentDescriptionPhoneSignal);
             }
         }
 
@@ -774,6 +813,7 @@
             for (int i=0; i<N; i++) {
                 final ImageView v = mDataDirectionIconViews.get(i);
                 v.setImageResource(mDataDirectionIconId);
+                v.setContentDescription(mContentDescriptionDataType);
             }
         }
 
@@ -784,6 +824,7 @@
             for (int i=0; i<N; i++) {
                 final ImageView v = mWifiIconViews.get(i);
                 v.setImageResource(mWifiIconId);
+                v.setContentDescription(mContentDescriptionWifi);
             }
         }
 
@@ -794,6 +835,7 @@
             for (int i=0; i<N; i++) {
                 final ImageView v = mCombinedSignalIconViews.get(i);
                 v.setImageResource(combinedSignalIconId);
+                v.setContentDescription(mContentDescriptionCombinedSignal);
             }
         }
 
@@ -808,6 +850,7 @@
                 } else {
                     v.setVisibility(View.VISIBLE);
                     v.setImageResource(dataTypeIconId);
+                    v.setContentDescription(mContentDescriptionDataType);
                 }
             }
         }
@@ -826,6 +869,7 @@
                 } else {
                     v.setVisibility(View.VISIBLE);
                     v.setImageResource(dataDirectionOverlayIconId);
+                    v.setContentDescription(mContentDescriptionDataType);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
index c62c4ad..8c4ae19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
@@ -22,6 +22,7 @@
 import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.Slog;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -90,6 +91,19 @@
         return false;
     }
 
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Ignore hover events outside of this panel bounds since such events
+        // generate spurious accessibility events with the panel content when
+        // tapping outside of it, thus confusing the user.
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
+            return super.dispatchHoverEvent(event);
+        }
+        return true;
+    }
+
     public void setTrigger(View v) {
         mTrigger = v;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index 339e3f3..1e417ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -30,6 +30,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -160,6 +161,19 @@
         }
     }
 
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Ignore hover events outside of this panel bounds since such events
+        // generate spurious accessibility events with the panel content when
+        // tapping outside of it, thus confusing the user.
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
+            return super.dispatchHoverEvent(event);
+        }
+        return true;
+    }
+
     private void updateHardKeyboardEnabled() {
         if (mHardKeyboardAvailable) {
             final boolean checked = mHardKeyboardSwitch.isChecked();
@@ -222,6 +236,7 @@
             itemSubtitle.setText(imiName);
         }
         subtypeIcon.setImageDrawable(icon);
+        subtypeIcon.setContentDescription(itemTitle.getText());
         final String settingsActivity = imi.getSettingsActivity();
         if (!TextUtils.isEmpty(settingsActivity)) {
             settingsIcon.setOnClickListener(new View.OnClickListener() {
@@ -463,4 +478,5 @@
     public interface OnHardKeyboardEnabledChangeListener {
         public void onHardKeyboardEnabledChange(boolean enabled);
     }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java
new file mode 100644
index 0000000..42bdf3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationArea.java
@@ -0,0 +1,45 @@
+/*
+ * 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.systemui.statusbar.tablet;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.LinearLayout;
+
+public class NotificationArea extends LinearLayout {
+
+    public NotificationArea(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEvent(child, event)) {
+            // The event is coming from a descendant like battery but append
+            // the content of the entire notification area so accessibility
+            // services can choose how to present the content to the user.
+            AccessibilityEvent record = AccessibilityEvent.obtain();
+            onInitializeAccessibilityEvent(record);
+            dispatchPopulateAccessibilityEvent(record);
+            event.appendRecord(record);
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 64a4f16..a316e4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -20,27 +20,15 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Slog;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
-import android.widget.TextView;
 
 import com.android.systemui.R;
 
@@ -53,8 +41,7 @@
 
     boolean mShowing;
     int mNotificationCount = 0;
-    View mTitleArea;
-    ModeToggle mModeToggle;
+    NotificationPanelTitle mTitleArea;
     View mSettingsButton;
     View mNotificationButton;
     View mNotificationScroller;
@@ -68,48 +55,6 @@
 
     Choreographer mChoreo = new Choreographer();
 
-    static class ModeToggle extends View {
-        NotificationPanel mPanel;
-        View mTitle;
-        public ModeToggle(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-        public void setPanel(NotificationPanel p) {
-            mPanel = p;
-        }
-        public void setTitleArea(View v) {
-            mTitle = v;
-        }
-        @Override
-        public boolean onTouchEvent(MotionEvent e) {
-            final int x = (int)e.getX();
-            final int y = (int)e.getY();
-            switch (e.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    mTitle.setPressed(true);
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    mTitle.setPressed(x >= 0
-                            && x < getWidth()
-                            && y >= 0
-                            && y < getHeight());
-                    break;
-                case MotionEvent.ACTION_CANCEL:
-                    mTitle.setPressed(false);
-                    break;
-                case MotionEvent.ACTION_UP:
-                    if (mTitle.isPressed()) {
-                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
-                        playSoundEffect(SoundEffectConstants.CLICK);
-                        mPanel.swapPanels();
-                        mTitle.setPressed(false);
-                    }
-                    break;
-            }
-            return true;
-        }
-    }
-
     public NotificationPanel(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -126,14 +71,11 @@
 
         mContentParent = (ViewGroup)findViewById(R.id.content_parent);
         mContentParent.bringToFront();
-        mTitleArea = findViewById(R.id.title_area);
-        mModeToggle = (ModeToggle) findViewById(R.id.mode_toggle);
-        mModeToggle.setOnClickListener(this);
-        mModeToggle.setPanel(this);
-        mModeToggle.setTitleArea(mTitleArea);
+        mTitleArea = (NotificationPanelTitle) findViewById(R.id.title_area);
+        mTitleArea.setPanel(this);
 
-        mSettingsButton = (ImageView)findViewById(R.id.settings_button);
-        mNotificationButton = (ImageView)findViewById(R.id.notification_button);
+        mSettingsButton = findViewById(R.id.settings_button);
+        mNotificationButton = findViewById(R.id.notification_button);
 
         mNotificationScroller = findViewById(R.id.notification_scroller);
         mContentFrame = (ViewGroup)findViewById(R.id.content_frame);
@@ -185,6 +127,19 @@
         }
     }
 
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Ignore hover events outside of this panel bounds since such events
+        // generate spurious accessibility events with the panel content when
+        // tapping outside of it, thus confusing the user.
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
+            return super.dispatchHoverEvent(event);
+        }
+        return true;
+    }
+
     /*
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
@@ -205,7 +160,7 @@
     */
 
     public void onClick(View v) {
-        if (v == mModeToggle) {
+        if (v == mTitleArea) {
             swapPanels();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java
new file mode 100644
index 0000000..689bc36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanelTitle.java
@@ -0,0 +1,82 @@
+/*
+ * 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.systemui.statusbar.tablet;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.RelativeLayout;
+
+public class NotificationPanelTitle extends RelativeLayout implements View.OnClickListener {
+    private NotificationPanel mPanel;
+
+    public NotificationPanelTitle(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setOnClickListener(this);
+    }
+
+    public void setPanel(NotificationPanel p) {
+        mPanel = p;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent e) {
+        switch (e.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                setPressed(true);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                final int x = (int) e.getX();
+                final int y = (int) e.getY();
+                setPressed(x > 0 && x < getWidth() && y > 0 && y < getHeight());
+                break;
+            case MotionEvent.ACTION_UP:
+                if (isPressed()) {
+                    playSoundEffect(SoundEffectConstants.CLICK);
+                    mPanel.swapPanels();
+                    setPressed(false);
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                setPressed(false);
+                break;
+        }
+        return true;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == this) {
+            mPanel.swapPanels();
+        }
+    }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEvent(child, event)) {
+            AccessibilityEvent record = AccessibilityEvent.obtain();
+            onInitializeAccessibilityEvent(record);
+            dispatchPopulateAccessibilityEvent(record);
+            event.appendRecord(record);
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
index 8b68240..ba28306 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
@@ -18,12 +18,9 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.Slog;
 import android.view.MotionEvent;
 import android.widget.RelativeLayout;
 
-import com.android.systemui.R;
-
 public class NotificationPeekPanel extends RelativeLayout implements StatusBarPanel {
     TabletStatusBar mBar;
 
@@ -54,5 +51,17 @@
         mBar.resetNotificationPeekFadeTimer();
         return false;
     }
-}
 
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Ignore hover events outside of this panel bounds since such events
+        // generate spurious accessibility events with the panel content when
+        // tapping outside of it, thus confusing the user.
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
+            return super.dispatchHoverEvent(event);
+        }
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index df09f84..13846ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -808,7 +808,8 @@
                 // Update the icon.
                 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
                         notification.notification.icon, notification.notification.iconLevel,
-                        notification.notification.number);
+                        notification.notification.number,
+                        notification.notification.tickerText);
                 if (!oldEntry.icon.set(ic)) {
                     handleNotificationError(key, notification, "Couldn't update icon: " + ic);
                     return;
@@ -1012,10 +1013,7 @@
 
         mCompatModeButton.refresh();
         if (mCompatModeButton.getVisibility() == View.VISIBLE) {
-            if (DEBUG_COMPAT_HELP
-                    || ! Prefs.read(mContext).getBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, false)) {
                 showCompatibilityHelp();
-            }
         } else {
             hideCompatibilityHelp();
             mCompatModePanel.closePanel();
@@ -1451,13 +1449,15 @@
         }
         // Construct the icon.
         final StatusBarIconView iconView = new StatusBarIconView(mContext,
-                notification.pkg + "/0x" + Integer.toHexString(notification.id));
+                notification.pkg + "/0x" + Integer.toHexString(notification.id),
+                notification.notification);
         iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
 
         final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
                     notification.notification.icon,
                     notification.notification.iconLevel,
-                    notification.notification.number);
+                    notification.notification.number,
+                    notification.notification.tickerText);
         if (!iconView.set(ic)) {
             handleNotificationError(key, notification, "Couldn't attach StatusBarIcon: " + ic);
             return null;
@@ -1501,11 +1501,6 @@
         // alternate behavior in DND mode
         if (mNotificationDNDMode) {
             if (mIconLayout.getChildCount() == 0) {
-                final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd");
-                iconView.setImageResource(R.drawable.ic_notification_dnd);
-                iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-                iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
-
                 final Notification dndNotification = new Notification.Builder(mContext)
                     .setContentTitle(mContext.getText(R.string.notifications_off_title))
                     .setContentText(mContext.getText(R.string.notifications_off_text))
@@ -1513,6 +1508,12 @@
                     .setOngoing(true)
                     .getNotification();
 
+                final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd",
+                        dndNotification);
+                iconView.setImageResource(R.drawable.ic_notification_dnd);
+                iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+                iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
+
                 mNotificationDNDDummyEntry = new NotificationData.Entry(
                         null,
                         new StatusBarNotification("", 0, "", 0, 0, dndNotification),
@@ -1634,19 +1635,24 @@
         } else {
             if ((sbn.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
                 vetoButton.setVisibility(View.INVISIBLE);
+                vetoButton.setContentDescription("VETO");
             } else {
                 vetoButton.setVisibility(View.GONE);
             }
         }
+        vetoButton.setContentDescription(mContext.getString(
+                R.string.accessibility_remove_notification));
 
         // the large icon
         ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
         if (sbn.notification.largeIcon != null) {
             largeIcon.setImageBitmap(sbn.notification.largeIcon);
+            largeIcon.setContentDescription(sbn.notification.tickerText);
         } else {
             largeIcon.getLayoutParams().width = 0;
             largeIcon.setVisibility(View.INVISIBLE);
         }
+        largeIcon.setContentDescription(sbn.notification.tickerText);
 
         // bind the click event to the content area
         ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index a8f4262..6045e31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -284,7 +284,7 @@
         } else if (n.tickerText != null) {
             group = (ViewGroup)inflater.inflate(R.layout.status_bar_ticker_compat, mWindow, false);
             final Drawable icon = StatusBarIconView.getIcon(mContext,
-                    new StatusBarIcon(notification.pkg, n.icon, n.iconLevel, 0));
+                    new StatusBarIcon(notification.pkg, n.icon, n.iconLevel, 0, n.tickerText));
             ImageView iv = (ImageView)group.findViewById(iconId);
             iv.setImageDrawable(icon);
             iv.setVisibility(View.VISIBLE);