Prevent NPE in NavigationBar

When the view detaches, we were left in a state where the view
was null but the a11y callbacks were still using it.

Test: atest SystemUITests
Fixes: 196285098
Change-Id: Ie53ac9d73c22be204d905079773f3f021010fd1d
This commit is contained in:
Dave Mankoff
2021-09-22 10:21:17 -04:00
parent a47b439b06
commit eec420a375
2 changed files with 24 additions and 5 deletions

View File

@@ -712,6 +712,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mHandler.removeCallbacks(mAutoDim);
mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
mHandler.removeCallbacks(mEnableLayoutTransitions);
mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
mFrame = null;
mNavigationBarView = null;
mOrientationHandle = null;
@@ -1391,10 +1392,11 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
void updateAccessibilityServicesState() {
int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
if (mNavigationBarView != null) {
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
}
updateSystemUiStateFlags(a11yFlags);
}

View File

@@ -56,6 +56,7 @@ import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityManager;
@@ -122,6 +123,8 @@ public class NavigationBarTest extends SysuiTestCase {
EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
@Mock
EdgeBackGestureHandler mEdgeBackGestureHandler;
@Mock
NavigationBarA11yHelper mNavigationBarA11yHelper;
@Rule
public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -256,6 +259,20 @@ public class NavigationBarTest extends SysuiTestCase {
assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
}
@Test
public void testA11yEventAfterDetach() {
View v = mNavigationBar.createView(null);
mNavigationBar.onViewAttachedToWindow(v);
verify(mNavigationBarA11yHelper).registerA11yEventListener(any(
NavigationBarA11yHelper.NavA11yEventListener.class));
mNavigationBar.onViewDetachedFromWindow(v);
verify(mNavigationBarA11yHelper).removeA11yEventListener(any(
NavigationBarA11yHelper.NavA11yEventListener.class));
// Should be safe even though the internal view is now null.
mNavigationBar.updateAccessibilityServicesState();
}
private NavigationBar createNavBar(Context context) {
DeviceProvisionedController deviceProvisionedController =
mock(DeviceProvisionedController.class);
@@ -287,7 +304,7 @@ public class NavigationBarTest extends SysuiTestCase {
mHandler,
mock(NavigationBarOverlayController.class),
mUiEventLogger,
mock(NavigationBarA11yHelper.class),
mNavigationBarA11yHelper,
mock(UserTracker.class)));
}