diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2011-07-21 13:11:44 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-07-21 13:11:44 -0700 |
commit | d24cd90486821535fb058531fac54aa5b9360693 (patch) | |
tree | 99534099e922f23dc9ae698c7b780da0e372785c | |
parent | 374d387203e86cc798cb6c689dbe4eb647dd9bb9 (diff) | |
parent | 6179ea3196e9306d3f14361fe9ef14191b1edba6 (diff) | |
download | frameworks_base-d24cd90486821535fb058531fac54aa5b9360693.zip frameworks_base-d24cd90486821535fb058531fac54aa5b9360693.tar.gz frameworks_base-d24cd90486821535fb058531fac54aa5b9360693.tar.bz2 |
Merge "Adding accessibility support to the Status Bar."
38 files changed, 732 insertions, 230 deletions
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 1af0983..ca64c88 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -97,9 +97,10 @@ public class StatusBarManager { } } - public void setIcon(String slot, int iconId, int iconLevel) { + public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) { try { - mService.setIcon(slot, mContext.getPackageName(), iconId, iconLevel); + mService.setIcon(slot, mContext.getPackageName(), iconId, iconLevel, + contentDescription); } catch (RemoteException ex) { // system process is dead anyway. throw new RuntimeException(ex); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 54fee3c..92a8ce7 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2148,9 +2148,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager onPopulateAccessibilityEvent(event); // Let our children have a shot in populating the event. for (int i = 0, count = getChildCount(); i < count; i++) { - boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event); - if (handled) { - return handled; + View child = getChildAt(i); + if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { + boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event); + if (handled) { + return handled; + } } } return false; diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 755d4e0..00c75a9 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -902,15 +902,16 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { @Override public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { - // Add a record for ourselves as well. - AccessibilityEvent record = AccessibilityEvent.obtain(); - record.setSource(this); - // Set the class since it is not populated in #dispatchPopulateAccessibilityEvent - record.setClassName(getClass().getName()); - child.onInitializeAccessibilityEvent(record); - child.dispatchPopulateAccessibilityEvent(record); - event.appendRecord(record); - return true; + if (super.onRequestSendAccessibilityEvent(child, event)) { + // Add a record for ourselves as well. + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + // Populate with the text of the requesting child. + child.dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; } @Override diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 161b404..299e1ff 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -30,14 +30,15 @@ import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.RemotableViewMethod; import android.view.View; import android.view.ViewDebug; +import android.view.accessibility.AccessibilityEvent; import android.widget.RemoteViews.RemoteView; - /** * Displays an arbitrary image, such as an icon. The ImageView class * can load images from various sources (such as resources or content @@ -208,7 +209,15 @@ public class ImageView extends View { } return false; } - + + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + CharSequence contentDescription = getContentDescription(); + if (!TextUtils.isEmpty(contentDescription)) { + event.getText().add(contentDescription); + } + } + /** * Set this to true if you want the ImageView to adjust its bounds * to preserve the aspect ratio of its drawable. diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index a9e5057..07430e7 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -27,7 +27,7 @@ interface IStatusBarService void expand(); void collapse(); void disable(int what, IBinder token, String pkg); - void setIcon(String slot, String iconPackage, int iconId, int iconLevel); + void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription); void setIconVisibility(String slot, boolean visible); void removeIcon(String slot); void topAppWindowChanged(boolean menuVisible); diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java index ae2cac2..3333c82 100644 --- a/core/java/com/android/internal/statusbar/StatusBarIcon.java +++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java @@ -19,42 +19,35 @@ package com.android.internal.statusbar; import android.os.Parcel; import android.os.Parcelable; -/** - * @hide - */ public class StatusBarIcon implements Parcelable { public String iconPackage; public int iconId; public int iconLevel; public boolean visible = true; public int number; + public CharSequence contentDescription; - private StatusBarIcon() { - } - - public StatusBarIcon(String iconPackage, int iconId, int iconLevel) { - this.iconPackage = iconPackage; - this.iconId = iconId; - this.iconLevel = iconLevel; - } - - public StatusBarIcon(String iconPackage, int iconId, int iconLevel, int number) { + public StatusBarIcon(String iconPackage, int iconId, int iconLevel, int number, + CharSequence contentDescription) { this.iconPackage = iconPackage; this.iconId = iconId; this.iconLevel = iconLevel; this.number = number; + this.contentDescription = contentDescription; } + @Override public String toString() { return "StatusBarIcon(pkg=" + this.iconPackage + " id=0x" + Integer.toHexString(this.iconId) + " level=" + this.iconLevel + " visible=" + visible + " num=" + this.number + " )"; } + @Override public StatusBarIcon clone() { - StatusBarIcon that = new StatusBarIcon(this.iconPackage, this.iconId, this.iconLevel); + StatusBarIcon that = new StatusBarIcon(this.iconPackage, this.iconId, this.iconLevel, + this.number, this.contentDescription); that.visible = this.visible; - that.number = this.number; return that; } @@ -71,6 +64,7 @@ public class StatusBarIcon implements Parcelable { this.iconLevel = in.readInt(); this.visible = in.readInt() != 0; this.number = in.readInt(); + this.contentDescription = in.readCharSequence(); } public void writeToParcel(Parcel out, int flags) { @@ -79,6 +73,7 @@ public class StatusBarIcon implements Parcelable { out.writeInt(this.iconLevel); out.writeInt(this.visible ? 1 : 0); out.writeInt(this.number); + out.writeCharSequence(this.contentDescription); } public int describeContents() { diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 2e870fe..509ee69 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3056,4 +3056,9 @@ <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] --> <string name="share_action_provider_share_with">Share with...</string> + <!-- Status Bar icon descriptions --> + + <!-- Description of for the status bar's icon that the device is locked for accessibility. [CHAR LIMIT=NONE] --> + <string name="status_bar_device_locked">Device locked.</string> + </resources> 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 java.util.List; 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.DisplayMetrics; 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 @@ public class RecentsPanelView extends RelativeLayout position = _pos; packageName = _packageName; } - }; + } private final class OnLongClickDelegate implements View.OnLongClickListener { View mOtherView; @@ -252,6 +252,19 @@ public class RecentsPanelView extends RelativeLayout 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 @@ public class RecentsPanelView extends RelativeLayout 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 @@ package com.android.systemui.statusbar; 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 @@ public class LatestItemView extends FrameLayout { 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.drawable.Drawable; 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 @@ public class StatusBarIconView extends AnimatedImageView { 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 @@ public class StatusBarIconView extends AnimatedImageView { 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 @@ public class StatusBarIconView extends AnimatedImageView { 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 @@ public class StatusBarIconView extends AnimatedImageView { 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 @@ public class StatusBarIconView extends AnimatedImageView { } } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -175,6 +190,7 @@ public class StatusBarIconView extends AnimatedImageView { } } + @Override protected void debug(int depth) { super.debug(depth); Log.d("View", debugIndent(depth) + "slot=" + mSlot); @@ -213,4 +229,13 @@ public class StatusBarIconView extends AnimatedImageView { 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 @@ public class IconMerger extends LinearLayout { 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 @@ public class IconMerger extends LinearLayout { 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 class PhoneStatusBar extends StatusBar { 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 @@ public class PhoneStatusBar extends StatusBar { // 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 @@ public class PhoneStatusBar extends StatusBar { 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 @@ package com.android.systemui.statusbar.phone; 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.PhoneStateListener; 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.TelephonyIntents; 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { | 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { } 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 @@ public class PhoneStatusBarPolicy { private final void updateDataIcon() { int iconId; + String contentDescription = null; boolean visible = true; if (!isCdma()) { @@ -870,13 +892,15 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { iconId = mDataIconList[0]; break; } - mService.setIcon("data_connection", iconId, 0); + mService.setIcon("data_connection", iconId, 0, null); } else { visible = false; } @@ -921,12 +945,19 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { } } 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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 @@ public class PhoneStatusBarPolicy { 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.MotionEvent; 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 @@ public class PhoneStatusBarView extends FrameLayout { 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 @@ public abstract class Ticker { } 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 @@ public class BatteryController extends BroadcastReceiver { 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 @@ package com.android.systemui.statusbar.policy; 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 @@ public class BluetoothController extends BroadcastReceiver { @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.IntentFilter; 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 @@ public class NetworkController extends BroadcastReceiver { int mDataTypeIconId; boolean mDataActive; + String mContentDescriptionPhoneSignal; + String mContentDescriptionWifi; + String mContentDescriptionCombinedSignal; + String mContentDescriptionDataType; + // wifi final WifiManager mWifiManager; AsyncChannel mWifiChannel; @@ -366,6 +368,8 @@ public class NetworkController extends BroadcastReceiver { 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 @@ public class NetworkController extends BroadcastReceiver { } } mPhoneSignalIconId = iconList[iconLevel]; + mContentDescriptionPhoneSignal = mContext.getString( + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]); + mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel]; } } @@ -395,14 +402,20 @@ public class NetworkController extends BroadcastReceiver { 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 @@ public class NetworkController extends BroadcastReceiver { 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 @@ public class NetworkController extends BroadcastReceiver { 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 @@ public class NetworkController extends BroadcastReceiver { 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 @@ public class NetworkController extends BroadcastReceiver { } } combinedSignalIconId = mWifiIconId; + mContentDescriptionCombinedSignal = mContentDescriptionWifi; dataTypeIconId = 0; } else if (mDataConnected) { label = mNetworkName; @@ -723,22 +754,29 @@ public class NetworkController extends BroadcastReceiver { 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 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mPhoneSignalIconViews.get(i); v.setImageResource(mPhoneSignalIconId); + v.setContentDescription(mContentDescriptionPhoneSignal); } } @@ -774,6 +813,7 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mDataDirectionIconViews.get(i); v.setImageResource(mDataDirectionIconId); + v.setContentDescription(mContentDescriptionDataType); } } @@ -784,6 +824,7 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mWifiIconViews.get(i); v.setImageResource(mWifiIconId); + v.setContentDescription(mContentDescriptionWifi); } } @@ -794,6 +835,7 @@ public class NetworkController extends BroadcastReceiver { for (int i=0; i<N; i++) { final ImageView v = mCombinedSignalIconViews.get(i); v.setImageResource(combinedSignalIconId); + v.setContentDescription(mContentDescriptionCombinedSignal); } } @@ -808,6 +850,7 @@ public class NetworkController extends BroadcastReceiver { } else { v.setVisibility(View.VISIBLE); v.setImageResource(dataTypeIconId); + v.setContentDescription(mContentDescriptionDataType); } } } @@ -826,6 +869,7 @@ public class NetworkController extends BroadcastReceiver { } 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.content.res.TypedArray; 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 @@ public class CompatModePanel extends FrameLayout implements StatusBarPanel, 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.text.TextUtils; 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 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, } } + @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 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, 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 class InputMethodsPanel extends LinearLayout implements StatusBarPanel, 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.Animator; 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 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, boolean mShowing; int mNotificationCount = 0; - View mTitleArea; - ModeToggle mModeToggle; + NotificationPanelTitle mTitleArea; View mSettingsButton; View mNotificationButton; View mNotificationScroller; @@ -68,48 +55,6 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, 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 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, 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 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, } } + @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 class NotificationPanel extends RelativeLayout implements StatusBarPanel, */ 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 @@ package com.android.systemui.statusbar.tablet; 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 @@ public class NotificationPeekPanel extends RelativeLayout implements StatusBarPa 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 @@ public class TabletStatusBar extends StatusBar implements // 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 @@ public class TabletStatusBar extends StatusBar implements 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 @@ public class TabletStatusBar extends StatusBar implements } // 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 @@ public class TabletStatusBar extends StatusBar implements // 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 @@ public class TabletStatusBar extends StatusBar implements .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 @@ public class TabletStatusBar extends StatusBar implements } 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 @@ public class TabletTicker } 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); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 935f4ad..47d34b3 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -35,7 +35,6 @@ import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Handler; -import android.os.IBinder; import android.os.LocalPowerManager; import android.os.Message; import android.os.PowerManager; @@ -43,7 +42,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; @@ -1117,8 +1115,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // Give feedback to user when secure keyguard is active and engaged if (mShowing && isSecure()) { if (!mShowingLockIcon) { + String contentDescription = mContext.getString( + com.android.internal.R.string.status_bar_device_locked); mStatusBarManager.setIcon("secure", - com.android.internal.R.drawable.stat_sys_secure, 0); + com.android.internal.R.drawable.stat_sys_secure, 0, + contentDescription); mShowingLockIcon = true; } } else { diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 2597978..7399679 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -50,6 +50,7 @@ import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Configuration; @@ -1046,7 +1047,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mStatusBar.setIconVisibility("ime", false); } else if (packageName != null) { if (DEBUG) Slog.d(TAG, "show a small icon for the input method"); - mStatusBar.setIcon("ime", packageName, iconId, 0); + CharSequence contentDescription = null; + try { + PackageManager packageManager = mContext.getPackageManager(); + contentDescription = packageManager.getApplicationLabel( + packageManager.getApplicationInfo(packageName, 0)); + } catch (NameNotFoundException nnfe) { + /* ignore */ + } + mStatusBar.setIcon("ime", packageName, iconId, 0, + contentDescription != null ? contentDescription.toString() : null); mStatusBar.setIconVisibility("ime", true); } } diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java index 286a937..4ced83c 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/java/com/android/server/StatusBarManagerService.java @@ -22,10 +22,10 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.os.IBinder; -import android.os.RemoteException; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; import android.util.Slog; import android.view.View; @@ -175,7 +175,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } - public void setIcon(String slot, String iconPackage, int iconId, int iconLevel) { + public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, + String contentDescription) { enforceStatusBar(); synchronized (mIcons) { @@ -184,7 +185,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub throw new SecurityException("invalid status bar icon slot: " + slot); } - StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel); + StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel, 0, + contentDescription); //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); mIcons.setIcon(index, icon); diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java index b212533..e75a079 100644 --- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java @@ -100,22 +100,22 @@ public class StatusBarTest extends TestActivity new Test("Double Remove") { public void run() { Log.d(TAG, "set 0"); - mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0, null); Log.d(TAG, "remove 1"); mStatusBarManager.removeIcon("tty"); SystemClock.sleep(1000); Log.d(TAG, "set 1"); - mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0, null); if (false) { Log.d(TAG, "set 2"); - mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0, null); } Log.d(TAG, "remove 2"); mStatusBarManager.removeIcon("tty"); Log.d(TAG, "set 3"); - mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0); + mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0, null); } }, new Test("Hide (FLAG_FULLSCREEN)") { |