Commit 34c4aa94 authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Commit Bot

Android: Factor out accessibility handling out of ChromeActivity

This CL factors accessibility-related methods/interfaces out of
ChromeActivity into its own class ChromeAccessibility.
|updateAccessibiilityVisibility| in TabImpl was also moved to
the new class, reducing the ChromeActivity's dependency
on TabImpl.

Bug: 995903
Change-Id: I2296aa25cbcee3e09f1fa48a5ba43ccb9eec92ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2015919
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740464}
parent 2fe094a1
...@@ -28,9 +28,6 @@ import android.view.View; ...@@ -28,9 +28,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewStub; import android.view.ViewStub;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
...@@ -92,7 +89,6 @@ import org.chromium.chrome.browser.gsa.GSAAccountChangeListener; ...@@ -92,7 +89,6 @@ import org.chromium.chrome.browser.gsa.GSAAccountChangeListener;
import org.chromium.chrome.browser.gsa.GSAState; import org.chromium.chrome.browser.gsa.GSAState;
import org.chromium.chrome.browser.help.HelpAndFeedback; import org.chromium.chrome.browser.help.HelpAndFeedback;
import org.chromium.chrome.browser.history.HistoryManagerUtils; import org.chromium.chrome.browser.history.HistoryManagerUtils;
import org.chromium.chrome.browser.infobar.InfoBarContainer;
import org.chromium.chrome.browser.init.AsyncInitializationActivity; import org.chromium.chrome.browser.init.AsyncInitializationActivity;
import org.chromium.chrome.browser.init.ProcessInitializationHandler; import org.chromium.chrome.browser.init.ProcessInitializationHandler;
import org.chromium.chrome.browser.init.StartupTabPreloader; import org.chromium.chrome.browser.init.StartupTabPreloader;
...@@ -125,6 +121,7 @@ import org.chromium.chrome.browser.share.ShareDelegate; ...@@ -125,6 +121,7 @@ import org.chromium.chrome.browser.share.ShareDelegate;
import org.chromium.chrome.browser.share.ShareDelegateImpl; import org.chromium.chrome.browser.share.ShareDelegateImpl;
import org.chromium.chrome.browser.sync.ProfileSyncService; import org.chromium.chrome.browser.sync.ProfileSyncService;
import org.chromium.chrome.browser.sync.SyncController; import org.chromium.chrome.browser.sync.SyncController;
import org.chromium.chrome.browser.tab.AccessibilityVisibilityHandler;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabDelegateFactory;
import org.chromium.chrome.browser.tab.TabHidingType; import org.chromium.chrome.browser.tab.TabHidingType;
...@@ -152,7 +149,6 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate; ...@@ -152,7 +149,6 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarManageable; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarManageable;
import org.chromium.chrome.browser.ui.system.StatusBarColorController; import org.chromium.chrome.browser.ui.system.StatusBarColorController;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.chrome.browser.vr.ArDelegate; import org.chromium.chrome.browser.vr.ArDelegate;
import org.chromium.chrome.browser.vr.ArDelegateProvider; import org.chromium.chrome.browser.vr.ArDelegateProvider;
import org.chromium.chrome.browser.vr.VrModuleProvider; import org.chromium.chrome.browser.vr.VrModuleProvider;
...@@ -201,8 +197,8 @@ import java.util.function.Consumer; ...@@ -201,8 +197,8 @@ import java.util.function.Consumer;
*/ */
public abstract class ChromeActivity<C extends ChromeActivityComponent> public abstract class ChromeActivity<C extends ChromeActivityComponent>
extends AsyncInitializationActivity extends AsyncInitializationActivity
implements TabCreatorManager, AccessibilityStateChangeListener, PolicyChangeListener, implements TabCreatorManager, PolicyChangeListener, ContextualSearchTabPromotionDelegate,
ContextualSearchTabPromotionDelegate, SnackbarManageable, SceneChangeObserver, SnackbarManageable, SceneChangeObserver,
StatusBarColorController.StatusBarColorProvider, AppMenuDelegate, AppMenuBlocker, StatusBarColorController.StatusBarColorProvider, AppMenuDelegate, AppMenuBlocker,
MenuOrKeyboardActionController { MenuOrKeyboardActionController {
/** /**
...@@ -245,12 +241,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -245,12 +241,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
private boolean mTabModelsInitialized; private boolean mTabModelsInitialized;
private boolean mNativeInitialized; private boolean mNativeInitialized;
private boolean mRemoveWindowBackgroundDone; private boolean mRemoveWindowBackgroundDone;
protected AccessibilityVisibilityHandler mAccessibilityVisibilityHandler;
// The class cannot implement TouchExplorationStateChangeListener,
// because it is only available for Build.VERSION_CODES.KITKAT and later.
// We have to instantiate the TouchExplorationStateChangeListner object in the code.
@SuppressLint("NewApi")
private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
// Observes when sync becomes ready to create the mContextReporter. // Observes when sync becomes ready to create the mContextReporter.
private ProfileSyncService.SyncStateChangedListener mSyncStateChangedListener; private ProfileSyncService.SyncStateChangedListener mSyncStateChangedListener;
...@@ -422,15 +413,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -422,15 +413,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
mAssistStatusHandler.updateAssistState(); mAssistStatusHandler.updateAssistState();
} }
AccessibilityManager manager = (AccessibilityManager) getBaseContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
manager.addAccessibilityStateChangeListener(this);
mTouchExplorationStateChangeListener = enabled -> {
AccessibilityUtil.resetAccessibilityEnabled();
checkAccessibility();
};
manager.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
// Make the activity listen to policy change events // Make the activity listen to policy change events
CombinedPolicyProvider.get().addPolicyChangeListener(this); CombinedPolicyProvider.get().addPolicyChangeListener(this);
mDidAddPolicyChangeListener = true; mDidAddPolicyChangeListener = true;
...@@ -1128,11 +1110,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -1128,11 +1110,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
} }
if (mCompositorViewHolder != null) mCompositorViewHolder.onStart(); if (mCompositorViewHolder != null) mCompositorViewHolder.onStart();
// Explicitly call checkAccessibility() so things are initialized correctly when Chrome has
// been re-started after closing due to the last tab being closed when homepage is enabled.
// See crbug.com/541546.
checkAccessibility();
Configuration config = getResources().getConfiguration(); Configuration config = getResources().getConfiguration();
mUiMode = config.uiMode; mUiMode = config.uiMode;
mDensityDpi = config.densityDpi; mDensityDpi = config.densityDpi;
...@@ -1267,11 +1244,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -1267,11 +1244,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
UpdateMenuItemHelper.getInstance().unregisterObserver(mUpdateStateChangedListener); UpdateMenuItemHelper.getInstance().unregisterObserver(mUpdateStateChangedListener);
AccessibilityManager manager = (AccessibilityManager)
getBaseContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
manager.removeAccessibilityStateChangeListener(this);
manager.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
mActivityTabProvider.destroy(); mActivityTabProvider.destroy();
mComponent = null; mComponent = null;
...@@ -1407,23 +1379,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -1407,23 +1379,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
return mNativeInitialized; return mNativeInitialized;
} }
/**
* Called when the accessibility status of this device changes. This might be triggered by
* touch exploration or general accessibility status updates. It is an aggregate of two other
* accessibility update methods.
*
* @see #onAccessibilityStateChanged
* @see #mTouchExplorationStateChangeListener
* @param enabled Whether or not accessibility and touch exploration are currently enabled.
*/
protected void onAccessibilityModeChanged(boolean enabled) {
InfoBarContainer.setIsAllowedToAutoHide(!enabled);
if (getToolbarManager() != null) getToolbarManager().onAccessibilityStatusChanged(enabled);
if (mContextualSearchManager != null) {
mContextualSearchManager.onAccessibilityModeChanged(enabled);
}
}
@Override @Override
public boolean onOptionsItemSelected(int itemId, @Nullable Bundle menuItemData) { public boolean onOptionsItemSelected(int itemId, @Nullable Bundle menuItemData) {
if (mManualFillingComponent != null) mManualFillingComponent.dismiss(); if (mManualFillingComponent != null) mManualFillingComponent.dismiss();
...@@ -1480,16 +1435,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -1480,16 +1435,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
}; };
} }
@Override
public final void onAccessibilityStateChanged(boolean enabled) {
AccessibilityUtil.resetAccessibilityEnabled();
checkAccessibility();
}
private void checkAccessibility() {
onAccessibilityModeChanged(AccessibilityUtil.isAccessibilityEnabled());
}
/** /**
* @return A casted version of {@link #getApplication()}. * @return A casted version of {@link #getApplication()}.
*/ */
......
...@@ -170,7 +170,7 @@ import java.util.Locale; ...@@ -170,7 +170,7 @@ import java.util.Locale;
* This is the main activity for ChromeMobile when not running in document mode. All the tabs * This is the main activity for ChromeMobile when not running in document mode. All the tabs
* are accessible via a chrome specific tab switching UI. * are accessible via a chrome specific tab switching UI.
*/ */
public class ChromeTabbedActivity extends ChromeActivity { public class ChromeTabbedActivity extends ChromeActivity implements AccessibilityUtil.Observer {
private static final String TAG = "ChromeTabbedActivity"; private static final String TAG = "ChromeTabbedActivity";
private static final String HELP_URL_PREFIX = "https://support.google.com/chrome/"; private static final String HELP_URL_PREFIX = "https://support.google.com/chrome/";
...@@ -826,6 +826,7 @@ public class ChromeTabbedActivity extends ChromeActivity { ...@@ -826,6 +826,7 @@ public class ChromeTabbedActivity extends ChromeActivity {
this::maybeGetFeedAppLifecycleAndMaybeCreatePageViewObserver); this::maybeGetFeedAppLifecycleAndMaybeCreatePageViewObserver);
PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::addOverviewModeObserver); PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::addOverviewModeObserver);
PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::finishNativeInitialization); PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::finishNativeInitialization);
AccessibilityUtil.addObserver(this);
} }
} }
...@@ -838,6 +839,9 @@ public class ChromeTabbedActivity extends ChromeActivity { ...@@ -838,6 +839,9 @@ public class ChromeTabbedActivity extends ChromeActivity {
mOverviewListLayout = (OverviewListLayout) mLayoutManager.getOverviewListLayout(); mOverviewListLayout = (OverviewListLayout) mLayoutManager.getOverviewListLayout();
getTabObscuringHandler().addObserver(mCompositorViewHolder); getTabObscuringHandler().addObserver(mCompositorViewHolder);
getTabObscuringHandler().addObserver(mOverviewListLayout); getTabObscuringHandler().addObserver(mOverviewListLayout);
AccessibilityUtil.addObserver(mLayoutManager);
if (isTablet()) AccessibilityUtil.addObserver(mCompositorViewHolder);
} }
@Override @Override
...@@ -1169,17 +1173,6 @@ public class ChromeTabbedActivity extends ChromeActivity { ...@@ -1169,17 +1173,6 @@ public class ChromeTabbedActivity extends ChromeActivity {
@Override @Override
public void onAccessibilityModeChanged(boolean enabled) { public void onAccessibilityModeChanged(boolean enabled) {
super.onAccessibilityModeChanged(enabled);
if (mLayoutManager != null) {
mLayoutManager.setEnableAnimations(DeviceClassManager.enableAnimations());
}
if (isTablet()) {
if (getCompositorViewHolder() != null) {
getCompositorViewHolder().onAccessibilityStatusChanged(enabled);
}
}
onAccessibilityTabSwitcherModeChanged(); onAccessibilityTabSwitcherModeChanged();
} }
...@@ -2024,6 +2017,10 @@ public class ChromeTabbedActivity extends ChromeActivity { ...@@ -2024,6 +2017,10 @@ public class ChromeTabbedActivity extends ChromeActivity {
getTabObscuringHandler().removeObserver(mOverviewListLayout); getTabObscuringHandler().removeObserver(mOverviewListLayout);
} }
if (isTablet()) AccessibilityUtil.removeObserver(mCompositorViewHolder);
AccessibilityUtil.removeObserver(this);
AccessibilityUtil.removeObserver(mLayoutManager);
super.onDestroyInternal(); super.onDestroyInternal();
} }
......
...@@ -59,6 +59,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector; ...@@ -59,6 +59,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.toolbar.ControlContainer; import org.chromium.chrome.browser.toolbar.ControlContainer;
import org.chromium.chrome.browser.toolbar.ToolbarColors; import org.chromium.chrome.browser.toolbar.ToolbarColors;
import org.chromium.chrome.browser.ui.TabObscuringHandler; import org.chromium.chrome.browser.ui.TabObscuringHandler;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.components.browser_ui.widget.InsetObserverView; import org.chromium.components.browser_ui.widget.InsetObserverView;
import org.chromium.components.content_capture.ContentCaptureConsumer; import org.chromium.components.content_capture.ContentCaptureConsumer;
import org.chromium.components.content_capture.ContentCaptureConsumerImpl; import org.chromium.components.content_capture.ContentCaptureConsumerImpl;
...@@ -86,7 +87,8 @@ import java.util.Set; ...@@ -86,7 +87,8 @@ import java.util.Set;
public class CompositorViewHolder extends FrameLayout public class CompositorViewHolder extends FrameLayout
implements ContentOffsetProvider, LayoutManagerHost, LayoutRenderHost, Invalidator.Host, implements ContentOffsetProvider, LayoutManagerHost, LayoutRenderHost, Invalidator.Host,
FullscreenListener, InsetObserverView.WindowInsetObserver, FullscreenListener, InsetObserverView.WindowInsetObserver,
CompositorViewResizer.Observer, TabObscuringHandler.Observer { CompositorViewResizer.Observer, AccessibilityUtil.Observer,
TabObscuringHandler.Observer {
private static final long SYSTEM_UI_VIEWPORT_UPDATE_DELAY_MS = 500; private static final long SYSTEM_UI_VIEWPORT_UPDATE_DELAY_MS = 500;
/** /**
...@@ -1300,14 +1302,14 @@ public class CompositorViewHolder extends FrameLayout ...@@ -1300,14 +1302,14 @@ public class CompositorViewHolder extends FrameLayout
} }
} }
/** // AccessibilityUtil.Observer
* Called when the accessibility enabled state changes.
* @param enabled Whether accessibility is enabled. @Override
*/ public void onAccessibilityModeChanged(boolean enabled) {
public void onAccessibilityStatusChanged(boolean enabled) {
// Instantiate and install the accessibility node provider on this view if necessary. // Instantiate and install the accessibility node provider on this view if necessary.
// This overrides any hover event listeners or accessibility delegates // This overrides any hover event listeners or accessibility delegates
// that may have been added elsewhere. // that may have been added elsewhere.
assert mLayoutManager != null;
if (enabled && (mNodeProvider == null)) { if (enabled && (mNodeProvider == null)) {
mAccessibilityView = new View(getContext()); mAccessibilityView = new View(getContext());
addView(mAccessibilityView); addView(mAccessibilityView);
......
...@@ -45,7 +45,8 @@ import java.util.List; ...@@ -45,7 +45,8 @@ import java.util.List;
* A {@link Layout} controller for the more complicated Chrome browser. This is currently a * A {@link Layout} controller for the more complicated Chrome browser. This is currently a
* superset of {@link LayoutManager}. * superset of {@link LayoutManager}.
*/ */
public class LayoutManagerChrome extends LayoutManager implements OverviewModeController { public class LayoutManagerChrome
extends LayoutManager implements OverviewModeController, AccessibilityUtil.Observer {
// Layouts // Layouts
/** An {@link Layout} that should be used as the accessibility tab switcher. */ /** An {@link Layout} that should be used as the accessibility tab switcher. */
protected OverviewListLayout mOverviewListLayout; protected OverviewListLayout mOverviewListLayout;
...@@ -414,6 +415,13 @@ public class LayoutManagerChrome extends LayoutManager implements OverviewModeCo ...@@ -414,6 +415,13 @@ public class LayoutManagerChrome extends LayoutManager implements OverviewModeCo
mOverviewModeObservers.removeObserver(listener); mOverviewModeObservers.removeObserver(listener);
} }
// AccessibilityUtil.Observer
@Override
public void onAccessibilityModeChanged(boolean enabled) {
setEnableAnimations(DeviceClassManager.enableAnimations());
}
/** /**
* A {@link EdgeSwipeHandler} meant to respond to edge events for the toolbar. * A {@link EdgeSwipeHandler} meant to respond to edge events for the toolbar.
*/ */
......
...@@ -53,6 +53,7 @@ import org.chromium.chrome.browser.tab.TabSelectionType; ...@@ -53,6 +53,7 @@ import org.chromium.chrome.browser.tab.TabSelectionType;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.EventConstants;
import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.components.feature_engagement.FeatureConstants;
import org.chromium.components.feature_engagement.Tracker; import org.chromium.components.feature_engagement.Tracker;
...@@ -77,9 +78,9 @@ import java.util.regex.Pattern; ...@@ -77,9 +78,9 @@ import java.util.regex.Pattern;
* Manager for the Contextual Search feature. This class keeps track of the status of Contextual * Manager for the Contextual Search feature. This class keeps track of the status of Contextual
* Search and coordinates the control with the layout. * Search and coordinates the control with the layout.
*/ */
public class ContextualSearchManager implements ContextualSearchManagementDelegate, public class ContextualSearchManager
ContextualSearchNetworkCommunicator, implements ContextualSearchManagementDelegate, ContextualSearchNetworkCommunicator,
ContextualSearchSelectionHandler { ContextualSearchSelectionHandler, AccessibilityUtil.Observer {
/** A delegate for reporting selected context to GSA for search quality. */ /** A delegate for reporting selected context to GSA for search quality. */
public interface ContextReporterDelegate { public interface ContextReporterDelegate {
/** /**
...@@ -287,6 +288,7 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega ...@@ -287,6 +288,7 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega
mInternalStateController.reset(StateChangeReason.UNKNOWN); mInternalStateController.reset(StateChangeReason.UNKNOWN);
listenForTabModelSelectorNotifications(); listenForTabModelSelectorNotifications();
AccessibilityUtil.addObserver(this);
} }
/** /**
...@@ -303,6 +305,7 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega ...@@ -303,6 +305,7 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega
stopListeningForHideNotifications(); stopListeningForHideNotifications();
mTabRedirectHandler.clear(); mTabRedirectHandler.clear();
mInternalStateController.enter(InternalState.UNDEFINED); mInternalStateController.enter(InternalState.UNDEFINED);
AccessibilityUtil.removeObserver(this);
} }
@Override @Override
...@@ -879,11 +882,7 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega ...@@ -879,11 +882,7 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega
} }
} }
/** @Override
* Notifies that the Accessibility Mode state has changed.
*
* @param enabled Whether the Accessibility Mode is enabled.
*/
public void onAccessibilityModeChanged(boolean enabled) { public void onAccessibilityModeChanged(boolean enabled) {
mIsAccessibilityModeEnabled = enabled; mIsAccessibilityModeEnabled = enabled;
if (enabled) hideContextualSearch(StateChangeReason.UNKNOWN); if (enabled) hideContextualSearch(StateChangeReason.UNKNOWN);
......
...@@ -22,6 +22,7 @@ import org.chromium.chrome.browser.tab.Tab; ...@@ -22,6 +22,7 @@ import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabImpl; import org.chromium.chrome.browser.tab.TabImpl;
import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver;
import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver; import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
...@@ -42,6 +43,13 @@ public class InfoBarContainer implements UserData, KeyboardVisibilityListener { ...@@ -42,6 +43,13 @@ public class InfoBarContainer implements UserData, KeyboardVisibilityListener {
private static final Class<InfoBarContainer> USER_DATA_KEY = InfoBarContainer.class; private static final Class<InfoBarContainer> USER_DATA_KEY = InfoBarContainer.class;
private static final AccessibilityUtil.Observer sAccessibilityObserver;
static {
sAccessibilityObserver = (enabled) -> setIsAllowedToAutoHide(!enabled);
AccessibilityUtil.addObserver(sAccessibilityObserver);
}
/** /**
* A listener for the InfoBar animations. * A listener for the InfoBar animations.
*/ */
...@@ -426,7 +434,7 @@ public class InfoBarContainer implements UserData, KeyboardVisibilityListener { ...@@ -426,7 +434,7 @@ public class InfoBarContainer implements UserData, KeyboardVisibilityListener {
* Expected to be called when Touch Exploration is enabled. * Expected to be called when Touch Exploration is enabled.
* @param isAllowed Whether auto-hiding is allowed. * @param isAllowed Whether auto-hiding is allowed.
*/ */
public static void setIsAllowedToAutoHide(boolean isAllowed) { private static void setIsAllowedToAutoHide(boolean isAllowed) {
InfoBarContainerView.setIsAllowedToAutoHide(isAllowed); InfoBarContainerView.setIsAllowedToAutoHide(isAllowed);
} }
......
...@@ -109,6 +109,7 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuObserver; ...@@ -109,6 +109,7 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuObserver;
import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate; import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
import org.chromium.chrome.browser.ui.appmenu.MenuButtonDelegate; import org.chromium.chrome.browser.ui.appmenu.MenuButtonDelegate;
import org.chromium.chrome.browser.ui.native_page.NativePage; import org.chromium.chrome.browser.ui.native_page.NativePage;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.chrome.browser.util.UrlConstants; import org.chromium.chrome.browser.util.UrlConstants;
import org.chromium.chrome.browser.widget.ScrimView; import org.chromium.chrome.browser.widget.ScrimView;
import org.chromium.chrome.browser.widget.ScrimView.ScrimObserver; import org.chromium.chrome.browser.widget.ScrimView.ScrimObserver;
...@@ -137,7 +138,8 @@ import java.util.List; ...@@ -137,7 +138,8 @@ import java.util.List;
* with the rest of the application to ensure the toolbar is always visually up to date. * with the rest of the application to ensure the toolbar is always visually up to date.
*/ */
public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlFocusChangeListener, public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlFocusChangeListener,
ThemeColorObserver, MenuButtonDelegate { ThemeColorObserver, MenuButtonDelegate,
AccessibilityUtil.Observer {
/** /**
* Handle UI updates of menu icons. Only applicable for phones. * Handle UI updates of menu icons. Only applicable for phones.
*/ */
...@@ -753,6 +755,8 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF ...@@ -753,6 +755,8 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
mToolbar.setIncognitoStateProvider(mIncognitoStateProvider); mToolbar.setIncognitoStateProvider(mIncognitoStateProvider);
mToolbar.setThemeColorProvider( mToolbar.setThemeColorProvider(
mActivity.isTablet() ? mAppThemeColorProvider : mTabThemeColorProvider); mActivity.isTablet() ? mAppThemeColorProvider : mTabThemeColorProvider);
AccessibilityUtil.addObserver(this);
} }
/** /**
...@@ -1214,6 +1218,7 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF ...@@ -1214,6 +1218,7 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
if (mAppThemeColorProvider != null) mAppThemeColorProvider.destroy(); if (mAppThemeColorProvider != null) mAppThemeColorProvider.destroy();
mActivity.unregisterComponentCallbacks(mComponentCallbacks); mActivity.unregisterComponentCallbacks(mComponentCallbacks);
mComponentCallbacks = null; mComponentCallbacks = null;
AccessibilityUtil.removeObserver(this);
} }
/** /**
...@@ -1245,11 +1250,8 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF ...@@ -1245,11 +1250,8 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
} }
} }
/** @Override
* Called when the accessibility enabled state changes. public void onAccessibilityModeChanged(boolean enabled) {
* @param enabled Whether accessibility is enabled.
*/
public void onAccessibilityStatusChanged(boolean enabled) {
mToolbar.onAccessibilityStatusChanged(enabled); mToolbar.onAccessibilityStatusChanged(enabled);
} }
......
...@@ -10,6 +10,8 @@ import android.content.Context; ...@@ -10,6 +10,8 @@ import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Build; import android.os.Build;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
...@@ -18,6 +20,7 @@ import org.chromium.base.ActivityState; ...@@ -18,6 +20,7 @@ import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus; import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatus.ActivityStateListener; import org.chromium.base.ApplicationStatus.ActivityStateListener;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.ObserverList;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import java.util.List; import java.util.List;
...@@ -26,8 +29,41 @@ import java.util.List; ...@@ -26,8 +29,41 @@ import java.util.List;
* Exposes information about the current accessibility state * Exposes information about the current accessibility state
*/ */
public class AccessibilityUtil { public class AccessibilityUtil {
/**
* An observer to be notified of accessibility status changes.
*/
public interface Observer {
/**
* @param enabled Whether a touch exploration or an accessibility service that performs can
* perform gestures is enabled. Indicates that the UI must be fully navigable using
* the accessibility view tree.
*/
void onAccessibilityModeChanged(boolean enabled);
}
private static Boolean sIsAccessibilityEnabled; private static Boolean sIsAccessibilityEnabled;
private static ActivityStateListener sActivityStateListener; private static ActivityStateListener sActivityStateListener;
private static ObserverList<Observer> sObservers;
private static class ModeChangeHandler
implements AccessibilityStateChangeListener, TouchExplorationStateChangeListener {
// AccessibilityStateChangeListener
@Override
public final void onAccessibilityStateChanged(boolean enabled) {
resetAccessibilityEnabled();
notifyModeChange();
}
// TouchExplorationStateChangeListener
@Override
public void onTouchExplorationStateChanged(boolean enabled) {
resetAccessibilityEnabled();
notifyModeChange();
}
}
private static ModeChangeHandler sModeChangeHandler;
private AccessibilityUtil() {} private AccessibilityUtil() {}
...@@ -36,13 +72,12 @@ public class AccessibilityUtil { ...@@ -36,13 +72,12 @@ public class AccessibilityUtil {
* @return Whether or not accessibility and touch exploration are enabled. * @return Whether or not accessibility and touch exploration are enabled.
*/ */
public static boolean isAccessibilityEnabled() { public static boolean isAccessibilityEnabled() {
if (sModeChangeHandler == null) registerModeChangeListeners();
if (sIsAccessibilityEnabled != null) return sIsAccessibilityEnabled; if (sIsAccessibilityEnabled != null) return sIsAccessibilityEnabled;
TraceEvent.begin("AccessibilityManager::isAccessibilityEnabled"); TraceEvent.begin("AccessibilityManager::isAccessibilityEnabled");
AccessibilityManager manager = AccessibilityManager manager = getAccessibilityManager();
(AccessibilityManager) ContextUtils.getApplicationContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
boolean accessibilityEnabled = boolean accessibilityEnabled =
manager != null && manager.isEnabled() && manager.isTouchExplorationEnabled(); manager != null && manager.isEnabled() && manager.isTouchExplorationEnabled();
...@@ -72,6 +107,7 @@ public class AccessibilityUtil { ...@@ -72,6 +107,7 @@ public class AccessibilityUtil {
|| ApplicationStatus.isEveryActivityDestroyed()) { || ApplicationStatus.isEveryActivityDestroyed()) {
resetAccessibilityEnabled(); resetAccessibilityEnabled();
} }
if (ApplicationStatus.isEveryActivityDestroyed()) cleanUp();
} }
}; };
ApplicationStatus.registerStateListenerForAllActivities(sActivityStateListener); ApplicationStatus.registerStateListenerForAllActivities(sActivityStateListener);
...@@ -80,23 +116,78 @@ public class AccessibilityUtil { ...@@ -80,23 +116,78 @@ public class AccessibilityUtil {
return sIsAccessibilityEnabled; return sIsAccessibilityEnabled;
} }
/**
* Add {@link Observer} object. The observer will be notified of the current accessibility
* mode immediately.
* @param observer Observer object monitoring a11y mode change.
*/
public static void addObserver(Observer observer) {
getObservers().addObserver(observer);
// Notify mode change to a new observer so things are initialized correctly when Chrome
// has been re-started after closing due to the last tab being closed when homepage is
// enabled. See crbug.com/541546.
observer.onAccessibilityModeChanged(isAccessibilityEnabled());
}
/**
* Remove {@link Observer} object.
* @param observer Observer object monitoring a11y mode change.
*/
public static void removeObserver(Observer observer) {
getObservers().removeObserver(observer);
}
/**
* @return True if a hardware keyboard is detected.
*/
public static boolean isHardwareKeyboardAttached(Configuration c) {
return c.keyboard != Configuration.KEYBOARD_NOKEYS;
}
private static AccessibilityManager getAccessibilityManager() {
return (AccessibilityManager) ContextUtils.getApplicationContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
}
private static void registerModeChangeListeners() {
assert sModeChangeHandler == null;
sModeChangeHandler = new ModeChangeHandler();
AccessibilityManager manager = getAccessibilityManager();
manager.addAccessibilityStateChangeListener(sModeChangeHandler);
manager.addTouchExplorationStateChangeListener(sModeChangeHandler);
}
private static void cleanUp() {
if (sObservers != null) sObservers.clear();
if (sModeChangeHandler == null) return;
AccessibilityManager manager = getAccessibilityManager();
manager.removeAccessibilityStateChangeListener(sModeChangeHandler);
manager.removeTouchExplorationStateChangeListener(sModeChangeHandler);
}
/** /**
* Reset the static used to determine whether accessibility is enabled. * Reset the static used to determine whether accessibility is enabled.
* TODO(twellington): Make this private and have classes that care about accessibility state
* observe this class rather than observing the AccessibilityManager
* directly.
*/ */
public static void resetAccessibilityEnabled() { private static void resetAccessibilityEnabled() {
ApplicationStatus.unregisterActivityStateListener(sActivityStateListener); ApplicationStatus.unregisterActivityStateListener(sActivityStateListener);
sActivityStateListener = null; sActivityStateListener = null;
sIsAccessibilityEnabled = null; sIsAccessibilityEnabled = null;
} }
private static ObserverList<Observer> getObservers() {
if (sObservers == null) sObservers = new ObserverList<>();
return sObservers;
}
/** /**
* @return True if a hardware keyboard is detected. * Notify all the observers of the mode change.
*/ */
public static boolean isHardwareKeyboardAttached(Configuration c) { private static void notifyModeChange() {
return c.keyboard != Configuration.KEYBOARD_NOKEYS; boolean enabled = isAccessibilityEnabled();
for (Observer observer : getObservers()) {
observer.onAccessibilityModeChanged(enabled);
}
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment