Merge "Add content description to volume button"

This commit is contained in:
Julia Reynolds
2018-01-30 20:13:12 +00:00
committed by Android (Google) Code Review
6 changed files with 156 additions and 7 deletions

View File

@@ -61,6 +61,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:background="?android:selectableItemBackgroundBorderless"
android:contentDescription="@string/accessibility_output_chooser"
style="@style/VolumeButtons"
android:layout_centerVertical="true"
android:src="@drawable/ic_swap"

View File

@@ -1272,6 +1272,9 @@
<!-- Content description for accessibility (not shown on the screen): volume dialog collapse button. [CHAR LIMIT=NONE] -->
<string name="accessibility_volume_collapse">Collapse</string>
<!-- content description for audio output chooser [CHAR LIMIT=NONE]-->
<string name="accessibility_output_chooser">Switch output device</string>
<!-- Screen pinning dialog title. -->
<string name="screen_pinning_title">Screen is pinned</string>
<!-- Screen pinning dialog description. -->

View File

@@ -14,10 +14,14 @@
package com.android.systemui.statusbar.policy;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
import java.util.List;
/**
* For mocking because AccessibilityManager is final for some reason...
*/
@@ -39,4 +43,27 @@ public class AccessibilityManagerWrapper implements
public void removeCallback(AccessibilityServicesStateChangeListener listener) {
mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener);
}
public void addAccessibilityStateChangeListener(
AccessibilityManager.AccessibilityStateChangeListener listener) {
mAccessibilityManager.addAccessibilityStateChangeListener(listener);
}
public void removeAccessibilityStateChangeListener(
AccessibilityManager.AccessibilityStateChangeListener listener) {
mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
}
public boolean isEnabled() {
return mAccessibilityManager.isEnabled();
}
public void sendAccessibilityEvent(AccessibilityEvent event) {
mAccessibilityManager.sendAccessibilityEvent(event);
}
public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(
int feedbackTypeFlags) {
return mAccessibilityManager.getEnabledAccessibilityServiceList(feedbackTypeFlags);
}
}

View File

@@ -76,7 +76,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private static final int DYNAMIC_STREAM_START_INDEX = 100;
private static final int VIBRATE_HINT_DURATION = 50;
private static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
static final ArrayMap<Integer, Integer> STREAMS = new ArrayMap<>();
static {
STREAMS.put(AudioSystem.STREAM_ALARM, R.string.stream_alarm);
STREAMS.put(AudioSystem.STREAM_BLUETOOTH_SCO, R.string.stream_bluetooth_sco);

View File

@@ -63,7 +63,6 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageButton;
@@ -79,6 +78,7 @@ import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.VolumeDialogController.State;
import com.android.systemui.plugins.VolumeDialogController.StreamState;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -111,7 +111,7 @@ public class VolumeDialogImpl implements VolumeDialog {
private ConfigurableTexts mConfigurableTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
private final KeyguardManager mKeyguard;
private final AccessibilityManager mAccessibilityMgr;
private final AccessibilityManagerWrapper mAccessibilityMgr;
private final Object mSafetyWarningLock = new Object();
private final Object mOutputChooserLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
@@ -134,8 +134,7 @@ public class VolumeDialogImpl implements VolumeDialog {
mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
mController = Dependency.get(VolumeDialogController.class);
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mAccessibilityMgr =
(AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
}
@@ -231,6 +230,10 @@ public class VolumeDialogImpl implements VolumeDialog {
initRingerH();
}
protected ViewGroup getDialogView() {
return mDialogView;
}
private ColorStateList loadColorStateList(int colorResId) {
return ColorStateList.valueOf(mContext.getColor(colorResId));
}
@@ -258,6 +261,7 @@ public class VolumeDialogImpl implements VolumeDialog {
private void addRow(int stream, int iconRes, int iconMuteRes, boolean important,
boolean defaultStream, boolean dynamic) {
if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream);
VolumeRow row = new VolumeRow();
initRow(row, stream, iconRes, iconMuteRes, important, defaultStream);
int rowSize;
@@ -621,7 +625,7 @@ public class VolumeDialogImpl implements VolumeDialog {
}
}
private void onStateChangedH(State state) {
protected void onStateChangedH(State state) {
mState = state;
mDynamic.clear();
// add any new dynamic rows
@@ -894,7 +898,7 @@ public class VolumeDialogImpl implements VolumeDialog {
return ss.remoteLabel;
}
try {
return mContext.getString(ss.name);
return mContext.getResources().getString(ss.name);
} catch (Resources.NotFoundException e) {
Slog.e(TAG, "Can't find translation for stream " + ss);
return "";

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2018 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.volume;
import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN;
import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN;
import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
import static junit.framework.Assert.assertTrue;
import android.app.KeyguardManager;
import android.media.AudioManager;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.function.Predicate;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class VolumeDialogImplTest extends SysuiTestCase {
VolumeDialogImpl mDialog;
@Mock
VolumeDialogController mController;
@Mock
KeyguardManager mKeyguard;
@Mock
AccessibilityManagerWrapper mAccessibilityMgr;
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mController = mDependency.injectMockDependency(VolumeDialogController.class);
mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
getContext().addMockSystemService(KeyguardManager.class, mKeyguard);
mDialog = new VolumeDialogImpl(getContext());
mDialog.init(0, null);
VolumeDialogController.State state = new VolumeDialogController.State();
for (int i = AudioManager.STREAM_VOICE_CALL; i <= AudioManager.STREAM_ACCESSIBILITY; i++) {
VolumeDialogController.StreamState ss = new VolumeDialogController.StreamState();
ss.name = STREAMS.get(i);
state.states.append(i, ss);
}
mDialog.onStateChangedH(state);
}
private void navigateViews(View view, Predicate<View> condition) {
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
navigateViews(viewGroup.getChildAt(i), condition);
}
} else {
String resourceName = null;
try {
resourceName = getContext().getResources().getResourceName(view.getId());
} catch (Exception e) {}
assertTrue("View " + resourceName != null ? resourceName : view.getId()
+ " failed test", condition.test(view));
}
}
@Test
public void testContentDescriptions() {
mDialog.show(SHOW_REASON_UNKNOWN);
ViewGroup dialog = mDialog.getDialogView();
navigateViews(dialog, view -> {
if (view instanceof ImageView) {
return !TextUtils.isEmpty(view.getContentDescription());
} else {
return true;
}
});
mDialog.dismiss(DISMISS_REASON_UNKNOWN);
}
}