Loading packages/SystemUI/res/values/config.xml +9 −0 Original line number Diff line number Diff line Loading @@ -977,4 +977,13 @@ Width in pixels of the Side FPS sensor. --> <integer name="config_sfpsSensorWidth">200</integer> <!-- They are service names that, if enabled, will cause the magnification settings button to never hide after timeout. --> <string-array name="services_always_show_magnification_settings" translatable="false"> <item>com.android.switchaccess.SwitchAccessService</item> <item>com.google.android.apps.accessibility.voiceaccess.JustSpeakService</item> </string-array> </resources> packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +41 −1 Original line number Diff line number Diff line Loading @@ -20,12 +20,14 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.annotation.UiContext; import android.content.ComponentCallbacks; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; Loading @@ -49,6 +51,8 @@ import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.res.R; import java.util.Collections; import java.util.Optional; import java.util.Set; /** * Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of Loading Loading @@ -315,11 +319,47 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS | AccessibilityManager.FLAG_CONTENT_CONTROLS); if (shouldAlwaysShowSettings()) { mUiTimeout = -1; } } // Refresh the time slot of the fade-out task whenever this method is called. stopFadeOutAnimation(); if (mUiTimeout >= 0) { mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mUiTimeout); } } private boolean shouldAlwaysShowSettings() { try { var serviceNamesArray = mContext.getResources().getStringArray( R.array.services_always_show_magnification_settings); if (serviceNamesArray.length == 0) { return false; } Set serviceNamesSet = Set.of(serviceNamesArray); var serviceInfoList = mAccessibilityManager .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); for (var serviceInfo : serviceInfoList) { var serviceName = Optional.ofNullable(serviceInfo) .map(AccessibilityServiceInfo::getResolveInfo) .map(resolveInfo -> resolveInfo.serviceInfo) .map(resolvedServiceInfo -> resolvedServiceInfo.name) .orElse(null); if (serviceName == null) { continue; } if (serviceNamesSet.contains(serviceName)) { return true; } } } catch (Resources.NotFoundException nfe) { // No-op. Do not crash for not finding resources. } return false; } private void stopFadeOutAnimation() { mImageView.removeCallbacks(mFadeOutAnimationTask); Loading packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +85 −1 Original line number Diff line number Diff line Loading @@ -49,8 +49,11 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.graphics.Insets; import android.graphics.Rect; import android.os.Handler; Loading @@ -71,8 +74,8 @@ import android.widget.ImageView; import androidx.test.filters.SmallTest; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.res.R; import org.junit.After; import org.junit.Before; Loading Loading @@ -185,6 +188,87 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout)); } @Test public void showMagnificationButton_noA11yServicesRunning_postDelayedAnimationsWithTimeout() { final int a11yTimeout = 12345; when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn( a11yTimeout); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of()); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mAccessibilityManager).getRecommendedTimeoutMillis( DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS | AccessibilityManager.FLAG_CONTENT_CONTROLS); verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout)); } @Test public void showMagnificationButton_voiceAccessRunning_noTimeout() { var serviceInfo = createServiceInfoWithName( "com.google.android.apps.accessibility.voiceaccess.JustSpeakService"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(serviceInfo)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong()); } @Test public void showMagnificationButton_switchAccessRunning_noTimeout() { var serviceInfo = createServiceInfoWithName( "com.android.switchaccess.SwitchAccessService"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(serviceInfo)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong()); } @Test public void showMagnificationButton_switchAccessAndVoiceAccessBothRunning_noTimeout() { var switchAccessServiceInfo = createServiceInfoWithName( "com.android.switchaccess.SwitchAccessService"); var voiceAccessServiceInfo = createServiceInfoWithName( "com.google.android.apps.accessibility.voiceaccess.JustSpeakService"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(switchAccessServiceInfo, voiceAccessServiceInfo)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong()); } @Test public void showMagnificationButton_someOtherServiceRunning_postDelayedAnimationsWithTimeout() { final int a11yTimeout = 12345; when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn( a11yTimeout); var serviceInfo1 = createServiceInfoWithName("com.test.someService1"); var serviceInfo2 = createServiceInfoWithName("com.test.someService2"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(serviceInfo1, serviceInfo2)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mAccessibilityManager).getRecommendedTimeoutMillis( DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS | AccessibilityManager.FLAG_CONTENT_CONTROLS); verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout)); } private AccessibilityServiceInfo createServiceInfoWithName(String name) { var resolveInfo = new ResolveInfo(); resolveInfo.serviceInfo = new ServiceInfo(); resolveInfo.serviceInfo.name = name; var serviceInfo = new AccessibilityServiceInfo(); serviceInfo.setResolveInfo(resolveInfo); return serviceInfo; } @Test public void showMagnificationButton_windowModeAndFadingOut_verifyAnimationEndAction() { mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); Loading Loading
packages/SystemUI/res/values/config.xml +9 −0 Original line number Diff line number Diff line Loading @@ -977,4 +977,13 @@ Width in pixels of the Side FPS sensor. --> <integer name="config_sfpsSensorWidth">200</integer> <!-- They are service names that, if enabled, will cause the magnification settings button to never hide after timeout. --> <string-array name="services_always_show_magnification_settings" translatable="false"> <item>com.android.switchaccess.SwitchAccessService</item> <item>com.google.android.apps.accessibility.voiceaccess.JustSpeakService</item> </string-array> </resources>
packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +41 −1 Original line number Diff line number Diff line Loading @@ -20,12 +20,14 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.annotation.UiContext; import android.content.ComponentCallbacks; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; Loading @@ -49,6 +51,8 @@ import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.res.R; import java.util.Collections; import java.util.Optional; import java.util.Set; /** * Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of Loading Loading @@ -315,11 +319,47 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS | AccessibilityManager.FLAG_CONTENT_CONTROLS); if (shouldAlwaysShowSettings()) { mUiTimeout = -1; } } // Refresh the time slot of the fade-out task whenever this method is called. stopFadeOutAnimation(); if (mUiTimeout >= 0) { mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mUiTimeout); } } private boolean shouldAlwaysShowSettings() { try { var serviceNamesArray = mContext.getResources().getStringArray( R.array.services_always_show_magnification_settings); if (serviceNamesArray.length == 0) { return false; } Set serviceNamesSet = Set.of(serviceNamesArray); var serviceInfoList = mAccessibilityManager .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); for (var serviceInfo : serviceInfoList) { var serviceName = Optional.ofNullable(serviceInfo) .map(AccessibilityServiceInfo::getResolveInfo) .map(resolveInfo -> resolveInfo.serviceInfo) .map(resolvedServiceInfo -> resolvedServiceInfo.name) .orElse(null); if (serviceName == null) { continue; } if (serviceNamesSet.contains(serviceName)) { return true; } } } catch (Resources.NotFoundException nfe) { // No-op. Do not crash for not finding resources. } return false; } private void stopFadeOutAnimation() { mImageView.removeCallbacks(mFadeOutAnimationTask); Loading
packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +85 −1 Original line number Diff line number Diff line Loading @@ -49,8 +49,11 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.graphics.Insets; import android.graphics.Rect; import android.os.Handler; Loading @@ -71,8 +74,8 @@ import android.widget.ImageView; import androidx.test.filters.SmallTest; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.res.R; import org.junit.After; import org.junit.Before; Loading Loading @@ -185,6 +188,87 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout)); } @Test public void showMagnificationButton_noA11yServicesRunning_postDelayedAnimationsWithTimeout() { final int a11yTimeout = 12345; when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn( a11yTimeout); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of()); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mAccessibilityManager).getRecommendedTimeoutMillis( DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS | AccessibilityManager.FLAG_CONTENT_CONTROLS); verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout)); } @Test public void showMagnificationButton_voiceAccessRunning_noTimeout() { var serviceInfo = createServiceInfoWithName( "com.google.android.apps.accessibility.voiceaccess.JustSpeakService"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(serviceInfo)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong()); } @Test public void showMagnificationButton_switchAccessRunning_noTimeout() { var serviceInfo = createServiceInfoWithName( "com.android.switchaccess.SwitchAccessService"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(serviceInfo)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong()); } @Test public void showMagnificationButton_switchAccessAndVoiceAccessBothRunning_noTimeout() { var switchAccessServiceInfo = createServiceInfoWithName( "com.android.switchaccess.SwitchAccessService"); var voiceAccessServiceInfo = createServiceInfoWithName( "com.google.android.apps.accessibility.voiceaccess.JustSpeakService"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(switchAccessServiceInfo, voiceAccessServiceInfo)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong()); } @Test public void showMagnificationButton_someOtherServiceRunning_postDelayedAnimationsWithTimeout() { final int a11yTimeout = 12345; when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn( a11yTimeout); var serviceInfo1 = createServiceInfoWithName("com.test.someService1"); var serviceInfo2 = createServiceInfoWithName("com.test.someService2"); when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt())) .thenReturn(List.of(serviceInfo1, serviceInfo2)); mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); verify(mAccessibilityManager).getRecommendedTimeoutMillis( DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS | AccessibilityManager.FLAG_CONTENT_CONTROLS); verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout)); } private AccessibilityServiceInfo createServiceInfoWithName(String name) { var resolveInfo = new ResolveInfo(); resolveInfo.serviceInfo = new ServiceInfo(); resolveInfo.serviceInfo.name = name; var serviceInfo = new AccessibilityServiceInfo(); serviceInfo.setResolveInfo(resolveInfo); return serviceInfo; } @Test public void showMagnificationButton_windowModeAndFadingOut_verifyAnimationEndAction() { mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); Loading