OSDN Git Service

Quicksettings accessibility.
authorJulia Reynolds <juliacr@google.com>
Wed, 4 May 2016 20:44:08 +0000 (16:44 -0400)
committerJulia Reynolds <juliacr@google.com>
Fri, 6 May 2016 14:24:38 +0000 (10:24 -0400)
Bug: 15696340
Change-Id: I6887e2dad4822911d3a1642aaec5703174b57330

27 files changed:
packages/SystemUI/res/layout/qs_paged_tile_layout.xml
packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
packages/SystemUI/src/com/android/systemui/qs/QSTile.java
packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java

index 68129ce..ee55ec2 100644 (file)
@@ -47,7 +47,8 @@
             android:textAppearance="@style/TextAppearance.QS.DetailButton"
             android:textColor="#64FFFFFF"
             android:focusable="true"
-            android:text="@string/qs_edit" />
+            android:text="@string/qs_edit"
+            android:contentDescription="@string/accessibility_quick_settings_edit"/>
 
     </FrameLayout>
 
index a4f9df3..8611942 100644 (file)
@@ -26,6 +26,7 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:baselineAligned="false"
+    android:clickable="false"
     >
 
     <LinearLayout
@@ -64,7 +65,7 @@
                 android:layout_height="match_parent"
                 android:background="@drawable/ripple_drawable"
                 android:src="@drawable/ic_settings"
-                android:contentDescription="@string/accessibility_desc_settings" />
+                android:contentDescription="@string/accessibility_quick_settings_settings" />
             <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
         android:text="@*android:string/emergency_calls_only"
         android:singleLine="true"
-        android:gravity="center_vertical" />
+        android:gravity="center_vertical"
+        android:focusable="true" />
 
     <LinearLayout
         android:id="@+id/date_time_alarm_group"
             android:id="@+id/date_time_group"
             android:layout_width="wrap_content"
             android:layout_height="19dp"
-            android:orientation="horizontal">
+            android:orientation="horizontal"
+            android:focusable="true" >
 
             <include layout="@layout/split_clock_view"
                 android:layout_width="wrap_content"
         android:layout_marginEnd="12dp"
         android:layout_alignParentEnd="true"
         android:clipChildren="false"
-        android:clipToPadding="false" />
+        android:clipToPadding="false"
+        android:importantForAccessibility="yes"
+        android:focusable="true"
+        android:accessibilityTraversalAfter="@id/date_time_group"
+        android:accessibilityTraversalBefore="@id/expand_indicator" />
 
     <com.android.systemui.statusbar.AlphaOptimizedImageView
         android:id="@+id/qs_detail_header_progress"
index 6081248..f07e8fc 100644 (file)
@@ -203,6 +203,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
         public TilePage(Context context, AttributeSet attrs) {
             super(context, attrs);
             updateResources();
+            setContentDescription(mContext.getString(R.string.accessibility_desc_quick_settings));
         }
 
         @Override
index 413bc01..0e8d76a 100644 (file)
@@ -272,12 +272,16 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
     }
 
     public void setTiles(Collection<QSTile<?>> tiles) {
+        setTiles(tiles, false);
+    }
+
+    public void setTiles(Collection<QSTile<?>> tiles, boolean collapsedView) {
         for (TileRecord record : mRecords) {
             mTileLayout.removeTile(record);
         }
         mRecords.clear();
         for (QSTile<?> tile : tiles) {
-            addTile(tile);
+            addTile(tile, collapsedView);
         }
     }
 
@@ -285,14 +289,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
         r.tileView.onStateChanged(state);
     }
 
-    protected QSTileBaseView createTileView(QSTile<?> tile) {
-        return new QSTileView(mContext, tile.createTileView(mContext));
+    protected QSTileBaseView createTileView(QSTile<?> tile, boolean collapsedView) {
+        return new QSTileView(mContext, tile.createTileView(mContext), collapsedView);
     }
 
-    protected void addTile(final QSTile<?> tile) {
+    protected void addTile(final QSTile<?> tile, boolean collapsedView) {
         final TileRecord r = new TileRecord();
         r.tile = tile;
-        r.tileView = createTileView(tile);
+        r.tileView = createTileView(tile, collapsedView);
         final QSTile.Callback callback = new QSTile.Callback() {
             @Override
             public void onStateChanged(QSTile.State state) {
index 7692598..0cc30a8 100644 (file)
@@ -513,9 +513,12 @@ public abstract class QSTile<TState extends State> implements Listenable {
         public CharSequence label;
         public CharSequence contentDescription;
         public CharSequence dualLabelContentDescription;
+        public CharSequence minimalContentDescription;
         public boolean autoMirrorDrawable = true;
         public boolean disabledByPolicy;
         public EnforcedAdmin enforcedAdmin;
+        public String minimalAccessibilityClassName;
+        public String expandedAccessibilityClassName;
 
         public boolean copyTo(State other) {
             if (other == null) throw new IllegalArgumentException();
@@ -526,12 +529,21 @@ public abstract class QSTile<TState extends State> implements Listenable {
                     || !Objects.equals(other.autoMirrorDrawable, autoMirrorDrawable)
                     || !Objects.equals(other.dualLabelContentDescription,
                     dualLabelContentDescription)
+                    || !Objects.equals(other.minimalContentDescription,
+                    minimalContentDescription)
+                    || !Objects.equals(other.minimalAccessibilityClassName,
+                    minimalAccessibilityClassName)
+                    || !Objects.equals(other.expandedAccessibilityClassName,
+                    expandedAccessibilityClassName)
                     || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
                     || !Objects.equals(other.enforcedAdmin, enforcedAdmin);
             other.icon = icon;
             other.label = label;
             other.contentDescription = contentDescription;
             other.dualLabelContentDescription = dualLabelContentDescription;
+            other.minimalContentDescription = minimalContentDescription;
+            other.minimalAccessibilityClassName = minimalAccessibilityClassName;
+            other.expandedAccessibilityClassName = expandedAccessibilityClassName;
             other.autoMirrorDrawable = autoMirrorDrawable;
             other.disabledByPolicy = disabledByPolicy;
             if (enforcedAdmin == null) {
@@ -555,6 +567,9 @@ public abstract class QSTile<TState extends State> implements Listenable {
             sb.append(",label=").append(label);
             sb.append(",contentDescription=").append(contentDescription);
             sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
+            sb.append(",minimalContentDescription=").append(minimalContentDescription);
+            sb.append(",minimalAccessibilityClassName=").append(minimalAccessibilityClassName);
+            sb.append(",expandedAccessibilityClassName=").append(expandedAccessibilityClassName);
             sb.append(",autoMirrorDrawable=").append(autoMirrorDrawable);
             sb.append(",disabledByPolicy=").append(disabledByPolicy);
             sb.append(",enforcedAdmin=").append(enforcedAdmin);
@@ -581,8 +596,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
         }
     }
 
-    public static final class SignalState extends State {
-        public boolean enabled;
+    public static final class SignalState extends BooleanState {
         public boolean connected;
         public boolean activityIn;
         public boolean activityOut;
@@ -593,12 +607,10 @@ public abstract class QSTile<TState extends State> implements Listenable {
         @Override
         public boolean copyTo(State other) {
             final SignalState o = (SignalState) other;
-            final boolean changed = o.enabled != enabled
-                    || o.connected != connected || o.activityIn != activityIn
+            final boolean changed = o.connected != connected || o.activityIn != activityIn
                     || o.activityOut != activityOut
                     || o.overlayIconId != overlayIconId
                     || o.isOverlayIconWide != isOverlayIconWide;
-            o.enabled = enabled;
             o.connected = connected;
             o.activityIn = activityIn;
             o.activityOut = activityOut;
@@ -611,7 +623,6 @@ public abstract class QSTile<TState extends State> implements Listenable {
         @Override
         protected StringBuilder toStringBuilder() {
             final StringBuilder rt = super.toStringBuilder();
-            rt.insert(rt.length() - 1, ",enabled=" + enabled);
             rt.insert(rt.length() - 1, ",connected=" + connected);
             rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
             rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
index 44b38f1..f05aa3c 100644 (file)
@@ -22,8 +22,12 @@ import android.graphics.drawable.RippleDrawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.text.TextUtils;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.LinearLayout;
+import android.widget.Switch;
 
 import com.android.systemui.R;
 
@@ -33,8 +37,15 @@ public class QSTileBaseView extends LinearLayout {
     private QSIconView mIcon;
     private RippleDrawable mRipple;
     private Drawable mTileBackground;
+    private String mAccessibilityClass;
+    private boolean mTileState;
+    private boolean mCollapsedView;
 
     public QSTileBaseView(Context context, QSIconView icon) {
+        this(context, icon, false);
+    }
+
+    public QSTileBaseView(Context context, QSIconView icon, boolean collapsedView) {
         super(context);
         mIcon = icon;
         addView(mIcon);
@@ -51,6 +62,7 @@ public class QSTileBaseView extends LinearLayout {
         setPadding(0, padding, 0, padding);
         setClipChildren(false);
         setClipToPadding(false);
+        mCollapsedView = collapsedView;
     }
 
     private Drawable newTileBackground() {
@@ -116,13 +128,54 @@ public class QSTileBaseView extends LinearLayout {
 
     protected void handleStateChanged(QSTile.State state) {
         mIcon.setIcon(state);
-        setContentDescription(state.contentDescription);
+        if (mCollapsedView && !TextUtils.isEmpty(state.minimalContentDescription)) {
+            setContentDescription(state.minimalContentDescription);
+        } else {
+            setContentDescription(state.contentDescription);
+        }
+        if (mCollapsedView) {
+            mAccessibilityClass = state.minimalAccessibilityClassName;
+        } else {
+            mAccessibilityClass = state.expandedAccessibilityClassName;
+        }
+        if (state instanceof QSTile.BooleanState) {
+            mTileState = ((QSTile.BooleanState) state).value;
+        }
     }
 
     public QSIconView getIcon() {
         return mIcon;
     }
 
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        if (!TextUtils.isEmpty(mAccessibilityClass)) {
+            event.setClassName(mAccessibilityClass);
+            if (Switch.class.getName().equals(mAccessibilityClass)) {
+                String label = getResources()
+                        .getString(mTileState ? R.string.switch_bar_on : R.string.switch_bar_off);
+                event.setContentDescription(label);
+                event.setChecked(mTileState);
+            }
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        if (!TextUtils.isEmpty(mAccessibilityClass)) {
+            info.setClassName(mAccessibilityClass);
+            if (Switch.class.getName().equals(mAccessibilityClass)) {
+                String label = getResources()
+                        .getString(mTileState ? R.string.switch_bar_on : R.string.switch_bar_off);
+                info.setText(label);
+                info.setChecked(mTileState);
+                info.setCheckable(true);
+            }
+        }
+    }
+
     private class H extends Handler {
         private static final int STATE_CHANGED = 1;
         public H() {
index c3766e8..9247794 100644 (file)
@@ -40,7 +40,11 @@ public class QSTileView extends QSTileBaseView {
     private ImageView mPadLock;
 
     public QSTileView(Context context, QSIconView icon) {
-        super(context, icon);
+        this(context, icon, false);
+    }
+
+    public QSTileView(Context context, QSIconView icon, boolean collapsedView) {
+        super(context, icon, collapsedView);
 
         mContext = context;
         final Resources res = context.getResources();
index 2ef3672..a11a6e5 100644 (file)
@@ -23,6 +23,7 @@ import android.view.Gravity;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.Space;
+
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile.SignalState;
 import com.android.systemui.qs.QSTile.State;
@@ -93,8 +94,8 @@ public class QuickQSPanel extends QSPanel {
     }
 
     @Override
-    protected QSTileBaseView createTileView(QSTile<?> tile) {
-        return new QSTileBaseView(mContext, tile.createTileView(mContext));
+    protected QSTileBaseView createTileView(QSTile<?> tile, boolean collapsedView) {
+        return new QSTileBaseView(mContext, tile.createTileView(mContext), collapsedView);
     }
 
     @Override
@@ -133,7 +134,7 @@ public class QuickQSPanel extends QSPanel {
                 break;
             }
         }
-        super.setTiles(quickTiles);
+        super.setTiles(quickTiles, true);
     }
 
     private final Tunable mNumTiles = new Tunable() {
@@ -150,6 +151,7 @@ public class QuickQSPanel extends QSPanel {
     private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
 
         private final Space mEndSpacer;
+        protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
 
         public HeaderTileLayout(Context context) {
             super(context);
@@ -185,6 +187,7 @@ public class QuickQSPanel extends QSPanel {
             // Add a spacer.
             addView(new Space(mContext), getChildCount() - 1 /* Leave icon at end */,
                     generateSpaceParams());
+            mRecords.add(tile);
         }
 
         private LayoutParams generateSpaceParams() {
@@ -209,6 +212,7 @@ public class QuickQSPanel extends QSPanel {
             removeViewAt(childIndex);
             // Remove its spacer as well.
             removeViewAt(childIndex);
+            mRecords.remove(tile);
         }
 
         private int getChildIndex(QSTileBaseView tileView) {
@@ -236,5 +240,21 @@ public class QuickQSPanel extends QSPanel {
         public boolean hasOverlappingRendering() {
             return false;
         }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            if (mRecords != null && mRecords.size() > 0) {
+                View previousView = this;
+                for (TileRecord record : mRecords) {
+                    if (record.tileView.getVisibility() == GONE) continue;
+                    previousView = record.tileView.updateAccessibilityOrder(previousView);
+                }
+                mRecords.get(0).tileView.setAccessibilityTraversalAfter(
+                        R.id.alarm_status_collapsed);
+                mRecords.get(mRecords.size() - 1).tileView.setAccessibilityTraversalBefore(
+                        R.id.expand_indicator);
+            }
+        }
     }
 }
index 1e3c458..a578e6c 100644 (file)
@@ -32,6 +32,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
 
     public TileLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setFocusableInTouchMode(true);
         updateResources();
     }
 
index 5f5a87e..a980a7f 100644 (file)
@@ -23,6 +23,7 @@ import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -88,13 +89,12 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
         state.label = mContext.getString(R.string.airplane_mode);
         if (airplaneMode) {
             state.icon = mEnable;
-            state.contentDescription =  mContext.getString(
-                    R.string.accessibility_quick_settings_airplane_on);
         } else {
             state.icon = mDisable;
-            state.contentDescription =  mContext.getString(
-                    R.string.accessibility_quick_settings_airplane_off);
         }
+        state.contentDescription = state.label;
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
     }
 
     @Override
index 77eaa3b..985bc9f 100644 (file)
@@ -31,6 +31,7 @@ import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.widget.Button;
 import android.widget.Checkable;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -131,7 +132,13 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
         };
         state.label = percentage;
         state.contentDescription = mContext.getString(R.string.accessibility_quick_settings_battery,
-                percentage);
+                percentage) + "," +
+                (mPowerSave ? mContext.getString(R.string.battery_saver_notification_title)
+                        : mCharging ? mContext.getString(R.string.expanded_header_battery_charging)
+                                : "")
+                + "," + mContext.getString(R.string.accessibility_battery_details);
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Button.class.getName();
     }
 
     @Override
index 63c85db..7a23910 100644 (file)
@@ -24,6 +24,8 @@ import android.provider.Settings;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -107,22 +109,31 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState>  {
         final boolean connecting = mController.isBluetoothConnecting();
         state.value = enabled;
         state.autoMirrorDrawable = false;
+        state.minimalContentDescription =
+                mContext.getString(R.string.accessibility_quick_settings_bluetooth);
         if (enabled) {
             state.label = null;
             if (connected) {
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
-                state.contentDescription = mContext.getString(
-                        R.string.accessibility_quick_settings_bluetooth_connected);
                 state.label = mController.getLastDeviceName();
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_bluetooth_name, state.label);
+                state.minimalContentDescription = state.minimalContentDescription + ","
+                        + state.contentDescription;
             } else if (connecting) {
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connecting);
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_bluetooth_connecting);
                 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
+                state.minimalContentDescription = state.minimalContentDescription + ","
+                        + state.contentDescription;
             } else {
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
                 state.contentDescription = mContext.getString(
-                        R.string.accessibility_quick_settings_bluetooth_on);
+                        R.string.accessibility_quick_settings_bluetooth_on) + ","
+                        + mContext.getString(R.string.accessibility_not_connected);
+                state.minimalContentDescription = state.minimalContentDescription + ","
+                        + mContext.getString(R.string.accessibility_not_connected);
             }
             if (TextUtils.isEmpty(state.label)) {
                 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
@@ -140,6 +151,10 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState>  {
                     R.string.accessibility_bluetooth_name, state.label);
         }
         state.dualLabelContentDescription = bluetoothName;
+        state.contentDescription = state.contentDescription + "," + mContext.getString(
+                R.string.accessibility_quick_settings_open_settings, getTileLabel());
+        state.expandedAccessibilityClassName = Button.class.getName();
+        state.minimalAccessibilityClassName = Switch.class.getName();
     }
 
     @Override
index bea1e15..c3e9b6e 100644 (file)
@@ -23,6 +23,7 @@ import android.util.Log;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
+import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -115,6 +116,7 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mContext.getString(R.string.quick_settings_cast_title);
+        state.contentDescription = state.label;
         state.value = false;
         state.autoMirrorDrawable = false;
         final Set<CastDevice> devices = mController.getCastDevices();
@@ -123,6 +125,8 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
             if (device.state == CastDevice.STATE_CONNECTED) {
                 state.value = true;
                 state.label = getDeviceName(device);
+                state.contentDescription = state.contentDescription + "," +
+                        mContext.getString(R.string.accessibility_cast_name, state.label);
             } else if (device.state == CastDevice.STATE_CONNECTING) {
                 connecting = true;
             }
@@ -133,6 +137,10 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
                 : R.drawable.ic_qs_cast_off);
         mDetailAdapter.updateItems(devices);
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName =
+                Button.class.getName();
+        state.contentDescription = state.contentDescription + ","
+                + mContext.getString(R.string.accessibility_quick_settings_open_details);
     }
 
     @Override
index 55b00b5..18191cf 100644 (file)
@@ -23,6 +23,8 @@ import android.content.res.Resources;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -132,13 +134,28 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
         final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0)
                 ? cb.signalContentDescription
                 : r.getString(R.string.accessibility_no_signal);
-        final String dataContentDesc = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
-                ? cb.dataContentDescription
-                : r.getString(R.string.accessibility_no_data);
-        state.contentDescription = r.getString(
-                R.string.accessibility_quick_settings_mobile,
-                signalContentDesc, dataContentDesc,
-                state.label);
+
+        if (cb.noSim) {
+            state.contentDescription = state.label;
+        } else {
+            String enabledDesc = cb.enabled ? r.getString(R.string.accessibility_cell_data_on)
+                    : r.getString(R.string.accessibility_cell_data_off);
+
+            state.contentDescription = r.getString(
+                    R.string.accessibility_quick_settings_mobile,
+                    enabledDesc, signalContentDesc,
+                    state.label);
+            state.minimalContentDescription = r.getString(
+                    R.string.accessibility_quick_settings_mobile,
+                    r.getString(R.string.accessibility_cell_data), signalContentDesc,
+                    state.label);
+        }
+        state.contentDescription = state.contentDescription + "," + r.getString(
+                R.string.accessibility_quick_settings_open_settings, getTileLabel());
+        state.expandedAccessibilityClassName = Button.class.getName();
+        state.minimalAccessibilityClassName = Switch.class.getName();
+        state.value = mDataController.isMobileDataSupported()
+                && mDataController.isMobileDataEnabled();
     }
 
     @Override
index 416132e..5ae7a76 100644 (file)
@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles;
 import android.content.Intent;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
+import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -96,6 +97,9 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
         state.value = enabled;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
         state.icon = enabled ? mEnable : mDisable;
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
+        state.contentDescription = state.label;
     }
 
     @Override
index b22e1ec..aabafe1 100644 (file)
@@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles;
 
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -96,10 +97,11 @@ public class DataSaverTile extends QSTile<QSTile.BooleanState> implements
         state.value = arg instanceof Boolean ? (Boolean) arg
                 : mDataSaverController.isDataSaverEnabled();
         state.label = mContext.getString(R.string.data_saver);
-        state.contentDescription = mContext.getString(state.value
-                ? R.string.accessibility_data_saver_on : R.string.accessibility_data_saver_off);
+        state.contentDescription = state.label;
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_data_saver
                 : R.drawable.ic_data_saver_off);
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
     }
 
     @Override
index 11efd56..04cb553 100644 (file)
@@ -29,6 +29,7 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
+import android.widget.Switch;
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
@@ -162,7 +163,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
                 state.icon = TOTAL_SILENCE.equals(state.icon) ? mDisableTotalSilence : mDisable;
                 state.label = mContext.getString(R.string.quick_settings_dnd_label);
                 state.contentDescription =  mContext.getString(
-                        R.string.accessibility_quick_settings_dnd_off);
+                        R.string.accessibility_quick_settings_dnd);
                 break;
         }
         if (mShowingDetail && !state.value) {
@@ -171,6 +172,8 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
         if (valueChanged) {
             fireToggleStateChanged(state.value);
         }
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
     }
 
     @Override
index 69e71bc..5ff0bd0 100644 (file)
@@ -22,6 +22,8 @@ import android.graphics.drawable.Drawable;
 import android.provider.MediaStore;
 import android.text.SpannableStringBuilder;
 import android.text.style.ForegroundColorSpan;
+import android.widget.Switch;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -122,10 +124,9 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
         }
         final AnimationIcon icon = state.value ? mEnable : mDisable;
         state.icon = icon;
-        int onOrOffId = state.value
-                ? R.string.accessibility_quick_settings_flashlight_on
-                : R.string.accessibility_quick_settings_flashlight_off;
-        state.contentDescription = mContext.getString(onOrOffId);
+        state.contentDescription = mContext.getString(R.string.quick_settings_flashlight_label);
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
     }
 
     @Override
index 25a3eff..3587262 100644 (file)
@@ -20,6 +20,8 @@ import android.content.Intent;
 import android.os.UserManager;
 
 import android.provider.Settings;
+import android.widget.Switch;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -94,6 +96,9 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
             state.value = mController.isHotspotEnabled();
         }
         state.icon = state.value ? mEnable : mDisable;
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
+        state.contentDescription = state.label;
     }
 
     @Override
index 6286f5e..5b5ecae 100644 (file)
@@ -20,6 +20,8 @@ import android.content.Intent;
 import android.os.UserManager;
 
 import android.provider.Settings;
+import android.widget.Switch;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -113,6 +115,8 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location_off);
         }
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
     }
 
     @Override
index 38b3706..521df37 100644 (file)
@@ -21,6 +21,8 @@ import android.content.Intent;
 import android.content.res.Configuration;
 
 import android.provider.Settings;
+import android.widget.Switch;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -106,10 +108,9 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
             state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
             state.icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
         }
-        state.contentDescription = getAccessibilityString(rotationLocked,
-                R.string.accessibility_rotation_lock_on_portrait,
-                R.string.accessibility_rotation_lock_on_landscape,
-                R.string.accessibility_rotation_lock_off);
+        state.contentDescription = getAccessibilityString(rotationLocked);
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
     }
 
     public static boolean isCurrentOrientationLockPortrait(RotationLockController controller,
@@ -133,29 +134,25 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
      * Get the correct accessibility string based on the state
      *
      * @param locked Whether or not rotation is locked.
-     * @param idWhenPortrait The id which should be used when locked in portrait.
-     * @param idWhenLandscape The id which should be used when locked in landscape.
-     * @param idWhenOff The id which should be used when the rotation lock is off.
-     * @return
      */
-    private String getAccessibilityString(boolean locked, int idWhenPortrait, int idWhenLandscape,
-            int idWhenOff) {
-        int stringID;
+    private String getAccessibilityString(boolean locked) {
         if (locked) {
-            stringID = isCurrentOrientationLockPortrait(mController, mContext) ? idWhenPortrait
-                    : idWhenLandscape;
+            return mContext.getString(R.string.accessibility_quick_settings_rotation) + ","
+                    + mContext.getString(R.string.accessibility_quick_settings_rotation_value,
+                    isCurrentOrientationLockPortrait(mController, mContext)
+                            ? mContext.getString(
+                                    R.string.quick_settings_rotation_locked_portrait_label)
+                            : mContext.getString(
+                                    R.string.quick_settings_rotation_locked_landscape_label));
+
         } else {
-            stringID = idWhenOff;
+            return mContext.getString(R.string.accessibility_quick_settings_rotation);
         }
-        return mContext.getString(stringID);
     }
 
     @Override
     protected String composeChangeAnnouncement() {
-        return getAccessibilityString(mState.value,
-                R.string.accessibility_rotation_lock_on_portrait_changed,
-                R.string.accessibility_rotation_lock_on_landscape_changed,
-                R.string.accessibility_rotation_lock_off_changed);
+        return getAccessibilityString(mState.value);
     }
 
     private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
index c72bbf3..661212c 100644 (file)
@@ -24,6 +24,8 @@ import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -101,8 +103,8 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
     protected void handleSecondaryClick() {
         // Secondary clicks are header clicks, just toggle.
         mState.copyTo(mStateBeforeClick);
-        MetricsLogger.action(mContext, getMetricsCategory(), !mState.enabled);
-        mController.setWifiEnabled(!mState.enabled);
+        MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
+        mController.setWifiEnabled(!mState.value);
     }
 
     @Override
@@ -111,9 +113,9 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
             mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS));
             return;
         }
-        if (!mState.enabled) {
+        if (!mState.value) {
             mController.setWifiEnabled(true);
-            mState.enabled = true;
+            mState.value = true;
         }
         showDetail(true);
     }
@@ -133,43 +135,58 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
 
         boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
         boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
-        boolean enabledChanging = state.enabled != cb.enabled;
+        boolean enabledChanging = state.value != cb.enabled;
         if (enabledChanging) {
             mDetailAdapter.setItemsVisible(cb.enabled);
             fireToggleStateChanged(cb.enabled);
         }
-        state.enabled = cb.enabled;
+        state.value = cb.enabled;
         state.connected = wifiConnected;
         state.activityIn = cb.enabled && cb.activityIn;
         state.activityOut = cb.enabled && cb.activityOut;
         state.filter = true;
-        final String signalContentDescription;
+        final StringBuffer minimalContentDescription = new StringBuffer();
+        final StringBuffer expandedContentDescription = new StringBuffer();
         final Resources r = mContext.getResources();
-        if (!state.enabled) {
+        if (!state.value) {
             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled);
             state.label = r.getString(R.string.quick_settings_wifi_label);
-            signalContentDescription = r.getString(R.string.accessibility_wifi_off);
         } else if (wifiConnected) {
             state.icon = ResourceIcon.get(cb.wifiSignalIconId);
             state.label = removeDoubleQuotes(cb.enabledDesc);
-            signalContentDescription = cb.wifiSignalContentDescription;
         } else if (wifiNotConnected) {
             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
             state.label = r.getString(R.string.quick_settings_wifi_label);
-            signalContentDescription = r.getString(R.string.accessibility_no_wifi);
         } else {
             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_no_network);
             state.label = r.getString(R.string.quick_settings_wifi_label);
-            signalContentDescription = r.getString(R.string.accessibility_wifi_off);
         }
-        state.contentDescription = mContext.getString(
-                R.string.accessibility_quick_settings_wifi,
-                signalContentDescription);
+        minimalContentDescription.append(
+                mContext.getString(R.string.quick_settings_wifi_label)).append(",");
+        if (state.value) {
+            expandedContentDescription.append(
+                    r.getString(R.string.quick_settings_wifi_on_label)).append(",");
+            if (wifiConnected) {
+                minimalContentDescription.append(cb.wifiSignalContentDescription).append(",");
+                minimalContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
+                expandedContentDescription.append(cb.wifiSignalContentDescription).append(",");
+                expandedContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
+            }
+        } else {
+            expandedContentDescription.append(
+                    r.getString(R.string.quick_settings_wifi_off_label));
+        }
+        state.minimalContentDescription =  minimalContentDescription;
+        expandedContentDescription.append(",").append(
+                r.getString(R.string.accessibility_quick_settings_open_settings, getTileLabel()));
+        state.contentDescription = expandedContentDescription;
         CharSequence wifiName = state.label;
         if (state.connected) {
             wifiName = r.getString(R.string.accessibility_wifi_name, state.label);
         }
         state.dualLabelContentDescription = wifiName;
+        state.expandedAccessibilityClassName = Button.class.getName();
+        state.minimalAccessibilityClassName = Switch.class.getName();
     }
 
     @Override
@@ -179,12 +196,12 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
 
     @Override
     protected boolean shouldAnnouncementBeDelayed() {
-        return mStateBeforeClick.enabled == mState.enabled;
+        return mStateBeforeClick.value == mState.value;
     }
 
     @Override
     protected String composeChangeAnnouncement() {
-        if (mState.enabled) {
+        if (mState.value) {
             return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_on);
         } else {
             return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_off);
@@ -263,7 +280,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
 
         @Override
         public Boolean getToggleState() {
-            return mState.enabled;
+            return mState.value;
         }
 
         @Override
@@ -291,7 +308,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
             mItems.setEmptyState(R.drawable.ic_qs_wifi_detail_empty,
                     R.string.quick_settings_wifi_detail_empty_text);
             updateItems();
-            setItemsVisible(mState.enabled);
+            setItemsVisible(mState.value);
             return mItems;
         }
 
index 2c5f7d5..459e8ec 100644 (file)
@@ -18,6 +18,8 @@ package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
 import android.provider.Settings;
+import android.widget.Switch;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
@@ -104,6 +106,8 @@ public class WorkModeTile extends QSTile<QSTile.BooleanState> implements
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_off);
         }
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
     }
 
     @Override
index 3fdc35c..a295cfa 100644 (file)
@@ -34,6 +34,7 @@ public class ExpandableIndicator extends ImageView {
         super.onFinishInflate();
         final int res = getDrawableResourceId(mExpanded);
         setImageResource(res);
+        setContentDescription(getContentDescription(mExpanded));
     }
 
     public void setExpanded(boolean expanded) {
@@ -46,6 +47,7 @@ public class ExpandableIndicator extends ImageView {
         setImageDrawable(avd);
         avd.forceAnimationOnUI();
         avd.start();
+        setContentDescription(getContentDescription(expanded));
     }
 
     /** Whether the icons are using the default direction or the opposite */
@@ -62,4 +64,9 @@ public class ExpandableIndicator extends ImageView {
                     : R.drawable.ic_volume_collapse_animation;
         }
     }
+
+    private String getContentDescription(boolean expanded) {
+        return expanded ? mContext.getString(R.string.accessibility_quick_settings_collapse)
+                : mContext.getString(R.string.accessibility_quick_settings_expand);
+    }
 }
index 6698d13..0186d34 100644 (file)
@@ -25,6 +25,9 @@ import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
@@ -150,24 +153,11 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
         }
 
         String text = null;
-        if (isClickable()) {
-            if (mUserManager.isUserSwitcherEnabled()) {
-                if (TextUtils.isEmpty(currentUser)) {
-                    text = mContext.getString(R.string.accessibility_multi_user_switch_switcher);
-                } else {
-                    text = mContext.getString(
-                            R.string.accessibility_multi_user_switch_switcher_with_current,
-                            currentUser);
-                }
-            } else {
-                text = mContext.getString(R.string.accessibility_multi_user_switch_quick_contact);
-            }
-        } else {
-            if (!TextUtils.isEmpty(currentUser)) {
-                text = mContext.getString(
-                        R.string.accessibility_multi_user_switch_inactive,
-                        currentUser);
-            }
+
+        if (!TextUtils.isEmpty(currentUser)) {
+            text = mContext.getString(
+                    R.string.accessibility_quick_settings_user,
+                    currentUser);
         }
 
         if (!TextUtils.equals(getContentDescription(), text)) {
@@ -176,6 +166,18 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
     }
 
     @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setClassName(Button.class.getName());
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setClassName(Button.class.getName());
+    }
+
+    @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
index 4a8d27f..e32d51a 100644 (file)
@@ -224,7 +224,12 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
     public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
         mNextAlarm = nextAlarm;
         if (nextAlarm != null) {
-            mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
+            String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm);
+            mAlarmStatus.setText(alarmString);
+            mAlarmStatus.setContentDescription(mContext.getString(
+                    R.string.accessibility_quick_settings_alarm, alarmString));
+            mAlarmStatusCollapsed.setContentDescription(mContext.getString(
+                    R.string.accessibility_quick_settings_alarm, alarmString));
         }
         if (mAlarmShowing != (nextAlarm != null)) {
             mAlarmShowing = nextAlarm != null;
@@ -281,6 +286,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
     public void updateEverything() {
         updateDateTimePosition();
         updateVisibilities();
+        setClickable(false);
     }
 
     protected void updateVisibilities() {
index a6ed04f..b890a30 100644 (file)
@@ -30,6 +30,8 @@ import com.android.settingslib.wifi.WifiStatusTracker;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
+import com.android.systemui.R;
+
 import java.util.Objects;
 
 
@@ -80,6 +82,10 @@ public class WifiSignalController extends
         String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
         boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
         String contentDescription = getStringIfExists(getContentDescription());
+        if (mCurrentState.inetCondition == 0) {
+            contentDescription +=
+                    ("," + mContext.getString(R.string.accessibility_quick_settings_no_internet));
+        }
 
         IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
         IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),