Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.

Commit f5679ec

Browse files
authored
feat(focus-mvp-android-device): silence focus events after a recent orientation change (#93)
* feat(focus-mvp-android-device): silence focus events after a recent orientation change * use dateProvider
1 parent 3fa7f59 commit f5679ec

File tree

4 files changed

+63
-14
lines changed

4 files changed

+63
-14
lines changed

AccessibilityInsightsForAndroidService/app/src/main/java/com/microsoft/accessibilityinsightsforandroidservice/AccessibilityInsightsForAndroidService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ protected void onServiceConnected() {
116116
LayoutParamGenerator layoutParamGenerator = new LayoutParamGenerator(this::getRealDisplayMetrics);
117117
focusVisualizationCanvas = new FocusVisualizationCanvas(this);
118118
focusVisualizer = new FocusVisualizer(new FocusVisualizerStyles(), focusVisualizationCanvas);
119-
focusVisualizerController = new FocusVisualizerController(focusVisualizer, focusVisualizationStateManager, new UIThreadRunner(), windowManager, layoutParamGenerator, focusVisualizationCanvas);
119+
focusVisualizerController = new FocusVisualizerController(focusVisualizer, focusVisualizationStateManager, new UIThreadRunner(), windowManager, layoutParamGenerator, focusVisualizationCanvas, new DateProvider());
120120
accessibilityEventDispatcher = new AccessibilityEventDispatcher();
121121
deviceOrientationHandler = new DeviceOrientationHandler(getResources().getConfiguration().orientation);
122122

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
package com.microsoft.accessibilityinsightsforandroidservice;
5+
6+
import java.util.Date;
7+
8+
public class DateProvider {
9+
public Date get() {
10+
return new Date();
11+
}
12+
}

AccessibilityInsightsForAndroidService/app/src/main/java/com/microsoft/accessibilityinsightsforandroidservice/FocusVisualizerController.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import android.view.WindowManager;
77
import android.view.accessibility.AccessibilityEvent;
88
import android.view.accessibility.AccessibilityNodeInfo;
9+
import java.util.Date;
910

1011
public class FocusVisualizerController {
1112
private FocusVisualizer focusVisualizer;
@@ -15,27 +16,33 @@ public class FocusVisualizerController {
1516
private LayoutParamGenerator layoutParamGenerator;
1617
private FocusVisualizationCanvas focusVisualizationCanvas;
1718
private AccessibilityNodeInfo lastEventSource;
19+
private DateProvider dateProvider;
20+
private Date lastOrientationChange;
21+
private long maximumOrientationChangeDelay = 1000;
1822

1923
public FocusVisualizerController(
2024
FocusVisualizer focusVisualizer,
2125
FocusVisualizationStateManager focusVisualizationStateManager,
2226
UIThreadRunner uiThreadRunner,
2327
WindowManager windowManager,
2428
LayoutParamGenerator layoutParamGenerator,
25-
FocusVisualizationCanvas focusVisualizationCanvas) {
29+
FocusVisualizationCanvas focusVisualizationCanvas,
30+
DateProvider dateProvider) {
2631
this.focusVisualizer = focusVisualizer;
2732
this.focusVisualizationStateManager = focusVisualizationStateManager;
2833
this.uiThreadRunner = uiThreadRunner;
2934
this.windowManager = windowManager;
3035
this.layoutParamGenerator = layoutParamGenerator;
3136
this.focusVisualizationCanvas = focusVisualizationCanvas;
37+
this.dateProvider = dateProvider;
3238
this.focusVisualizationStateManager.subscribe(this::onFocusVisualizationStateChange);
39+
this.lastOrientationChange = dateProvider.get();
3340
}
3441

3542
public void onFocusEvent(AccessibilityEvent event) {
3643
lastEventSource = event.getSource();
37-
38-
if (focusVisualizationStateManager.getState() == false) {
44+
if (focusVisualizationStateManager.getState() == false
45+
|| ignoreFocusEventDueToRecentOrientationChange()) {
3946
return;
4047
}
4148

@@ -62,7 +69,7 @@ public void onOrientationChanged(Integer orientation) {
6269
if (focusVisualizationStateManager.getState() == false) {
6370
return;
6471
}
65-
72+
lastOrientationChange = dateProvider.get();
6673
windowManager.updateViewLayout(focusVisualizationCanvas, layoutParamGenerator.get());
6774
focusVisualizer.resetVisualizations();
6875
}
@@ -86,4 +93,12 @@ private void removeFocusVisualizationToScreen() {
8693
focusVisualizer.resetVisualizations();
8794
windowManager.removeView(focusVisualizationCanvas);
8895
}
96+
97+
private boolean ignoreFocusEventDueToRecentOrientationChange() {
98+
Date currentTime = dateProvider.get();
99+
long cur = currentTime.getTime();
100+
long last = lastOrientationChange.getTime();
101+
long timeSinceLastOrientationChange = cur - last;
102+
return timeSinceLastOrientationChange < maximumOrientationChangeDelay;
103+
}
89104
}

AccessibilityInsightsForAndroidService/app/src/test/java/com/microsoft/accessibilityinsightsforandroidservice/FocusVisualizerControllerTest.java

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package com.microsoft.accessibilityinsightsforandroidservice;
55

66
import static org.mockito.ArgumentMatchers.any;
7+
import static org.mockito.Mockito.reset;
78
import static org.mockito.Mockito.times;
89
import static org.mockito.Mockito.verify;
910
import static org.mockito.Mockito.when;
@@ -12,8 +13,7 @@
1213
import android.view.WindowManager;
1314
import android.view.accessibility.AccessibilityEvent;
1415
import android.view.accessibility.AccessibilityNodeInfo;
15-
import java.util.concurrent.Executors;
16-
import java.util.concurrent.ScheduledExecutorService;
16+
import java.util.Date;
1717
import java.util.function.Consumer;
1818
import org.junit.Assert;
1919
import org.junit.Before;
@@ -25,8 +25,6 @@
2525
@RunWith(PowerMockRunner.class)
2626
public class FocusVisualizerControllerTest {
2727

28-
private static final ScheduledExecutorService mainThread =
29-
Executors.newSingleThreadScheduledExecutor();
3028
@Mock FocusVisualizer focusVisualizerMock;
3129
@Mock FocusVisualizationStateManager focusVisualizationStateManagerMock;
3230
@Mock AccessibilityEvent accessibilityEventMock;
@@ -36,6 +34,9 @@ public class FocusVisualizerControllerTest {
3634
@Mock FocusVisualizationCanvas focusVisualizationCanvas;
3735
@Mock WindowManager.LayoutParams layoutParams;
3836
@Mock AccessibilityNodeInfo accessibilityNodeInfo;
37+
@Mock DateProvider dateProvider;
38+
@Mock Date oldDateMock;
39+
@Mock Date newDateMock;
3940

4041
Consumer<Boolean> listener;
4142
FocusVisualizerController testSubject;
@@ -44,14 +45,16 @@ public class FocusVisualizerControllerTest {
4445
public void prepare() {
4546
when(layoutParamGenerator.get()).thenReturn(layoutParams);
4647
listener = null;
48+
when(dateProvider.get()).thenReturn(oldDateMock);
4749
testSubject =
4850
new FocusVisualizerController(
4951
focusVisualizerMock,
5052
focusVisualizationStateManagerMock,
5153
uiThreadRunner,
5254
windowManager,
5355
layoutParamGenerator,
54-
focusVisualizationCanvas);
56+
focusVisualizationCanvas,
57+
dateProvider);
5558
}
5659

5760
@Test
@@ -67,9 +70,25 @@ public void onFocusEventDoesNotCallVisualizerIfStateIsFalse() {
6770
}
6871

6972
@Test
70-
public void onFocusEventCallsVisualizerIfStateIsTrue() {
73+
public void onFocusEventDoesNotCallVisualizerIfOrientationChangedRecently() {
74+
reset(dateProvider);
75+
when(dateProvider.get()).thenReturn(newDateMock);
76+
when(focusVisualizationStateManagerMock.getState()).thenReturn(true);
77+
when(oldDateMock.getTime()).thenReturn((long) 500);
78+
when(newDateMock.getTime()).thenReturn((long) 501);
79+
testSubject.onFocusEvent(accessibilityEventMock);
80+
verify(focusVisualizerMock, times(0)).addNewFocusedElement(accessibilityNodeInfo);
81+
}
82+
83+
@Test
84+
public void onFocusEventCallsVisualizerIfStateIsTrueAndOrientationHasNotChangedRecently()
85+
throws Exception {
86+
reset(dateProvider);
87+
when(dateProvider.get()).thenReturn(newDateMock);
7188
when(focusVisualizationStateManagerMock.getState()).thenReturn(true);
7289
when(accessibilityEventMock.getSource()).thenReturn(accessibilityNodeInfo);
90+
when(oldDateMock.getTime()).thenReturn((long) 500);
91+
when(newDateMock.getTime()).thenReturn((long) 10000);
7392
testSubject.onFocusEvent(accessibilityEventMock);
7493
verify(focusVisualizerMock, times(1)).addNewFocusedElement(accessibilityNodeInfo);
7594
}
@@ -145,7 +164,8 @@ public void onFocusVisualizationStateChangeToEnabledAddsVisualization() {
145164
uiThreadRunner,
146165
windowManager,
147166
layoutParamGenerator,
148-
focusVisualizationCanvas);
167+
focusVisualizationCanvas,
168+
dateProvider);
149169

150170
verify(windowManager).addView(focusVisualizationCanvas, layoutParams);
151171
}
@@ -178,7 +198,8 @@ public void onFocusVisualizationStateChangeToEnabledAddsVisualizationWithLastEve
178198
uiThreadRunner,
179199
windowManager,
180200
layoutParamGenerator,
181-
focusVisualizationCanvas);
201+
focusVisualizationCanvas,
202+
dateProvider);
182203

183204
testSubject.onFocusEvent(accessibilityEventMock);
184205
listener.accept(true);
@@ -214,7 +235,8 @@ public void onFocusVisualizationStateChangToDisabledRemovesVisualizations() {
214235
uiThreadRunner,
215236
windowManager,
216237
layoutParamGenerator,
217-
focusVisualizationCanvas);
238+
focusVisualizationCanvas,
239+
dateProvider);
218240

219241
verify(focusVisualizerMock).resetVisualizations();
220242
}

0 commit comments

Comments
 (0)