Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 327e463a authored by Jason Chang's avatar Jason Chang
Browse files

Fix Talk back announces "Exit one handed mode" on every orientation

change though one-handed mode is off

Add more condition check when Talk back announce one-handed mode
related.

Bug: 182475904
Test: manual
Test: atest WMShellUnitTests
Change-Id: I0644146eaa6d7d6701af94fe6caceee5e6c3be8b
parent befdba37
Loading
Loading
Loading
Loading
+91 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.wm.shell.onehanded;

import android.content.Context;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;

import androidx.annotation.NonNull;

import com.android.wm.shell.R;

import java.io.PrintWriter;

/**
 * The util for handling A11y events.
 */
public final class OneHandedAccessibilityUtil {
    private static final String TAG = "OneHandedAccessibilityUtil";

    private final AccessibilityManager mAccessibilityManager;
    private final String mStartOneHandedDescription;
    private final String mStopOneHandedDescription;
    private final String mPackageName;

    private String mDescription;

    public OneHandedAccessibilityUtil(Context context) {
        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mPackageName = context.getPackageName();
        mStartOneHandedDescription = context.getResources().getString(
                R.string.accessibility_action_start_one_handed);
        mStopOneHandedDescription = context.getResources().getString(
                R.string.accessibility_action_stop_one_handed);
    }

    /**
     * Gets One-Handed start description.
     * @return text of start description.
     */
    public String getOneHandedStartDescription() {
        return mStartOneHandedDescription;
    }

    /**
     * Gets One-Handed stop description.
     * @return text of stop description.
     */
    public String getOneHandedStopDescription() {
        return mStopOneHandedDescription;
    }

    /**
     * Announcement of A11y Events
     * @param description for accessibility announcement text
     */
    public void announcementForScreenReader(String description) {
        if (!mAccessibilityManager.isTouchExplorationEnabled()) {
            return;
        }
        mDescription = description;
        final AccessibilityEvent event = AccessibilityEvent.obtain();
        event.setPackageName(mPackageName);
        event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
        event.getText().add(mDescription);
        mAccessibilityManager.sendAccessibilityEvent(event);
    }

    public void dump(@NonNull PrintWriter pw) {
        final String innerPrefix = "  ";
        pw.println(TAG + "States: ");
        pw.print(innerPrefix + "mPackageName=");
        pw.println(mPackageName);
        pw.print(innerPrefix + "mDescription=");
        pw.println(mDescription);
    }
}
+19 −4
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
    private final AccessibilityManager mAccessibilityManager;
    private final DisplayController mDisplayController;
    private final OneHandedSettingsUtil mOneHandedSettingsUtil;
    private final OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
    private final OneHandedTimeoutHandler mTimeoutHandler;
    private final OneHandedTouchHandler mTouchHandler;
    private final OneHandedTutorialHandler mTutorialHandler;
@@ -193,6 +194,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
            return null;
        }

        OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil();
        OneHandedAccessibilityUtil accessibilityUtil = new OneHandedAccessibilityUtil(context);
        OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
        OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
                windowManager, mainExecutor);
@@ -205,16 +208,16 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer =
                new OneHandedBackgroundPanelOrganizer(context, displayLayout, mainExecutor);
        OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
                context, displayLayout, animationController, tutorialHandler,
                context, displayLayout, settingsUtil, animationController, tutorialHandler,
                oneHandedBackgroundPanelOrganizer, mainExecutor);
        OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil();
        OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
        IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
                ServiceManager.getService(Context.OVERLAY_SERVICE));
        return new OneHandedController(context, displayController,
                oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
                gestureHandler, settingsUtil, timeoutHandler, oneHandedUiEventsLogger,
                overlayManager, taskStackListener, mainExecutor, mainHandler);
                gestureHandler, settingsUtil, accessibilityUtil, timeoutHandler,
                oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor,
                mainHandler);
    }

    @VisibleForTesting
@@ -226,6 +229,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
            OneHandedTutorialHandler tutorialHandler,
            OneHandedGestureHandler gestureHandler,
            OneHandedSettingsUtil settingsUtil,
            OneHandedAccessibilityUtil oneHandedAccessibilityUtil,
            OneHandedTimeoutHandler timeoutHandler,
            OneHandedUiEventLogger uiEventsLogger,
            IOverlayManager overlayManager,
@@ -234,6 +238,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
            Handler mainHandler) {
        mContext = context;
        mOneHandedSettingsUtil = settingsUtil;
        mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil;
        mBackgroundPanelOrganizer = backgroundPanelOrganizer;
        mDisplayAreaOrganizer = displayAreaOrganizer;
        mDisplayController = displayController;
@@ -334,6 +339,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        if (!mDisplayAreaOrganizer.isInOneHanded()) {
            final int yOffSet = Math.round(
                    mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);
            mOneHandedAccessibilityUtil.announcementForScreenReader(
                    mOneHandedAccessibilityUtil.getOneHandedStartDescription());
            mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
            mTimeoutHandler.resetTimer();

@@ -345,6 +352,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
    @VisibleForTesting
    void stopOneHanded() {
        if (mDisplayAreaOrganizer.isInOneHanded()) {
            mOneHandedAccessibilityUtil.announcementForScreenReader(
                    mOneHandedAccessibilityUtil.getOneHandedStopDescription());
            mDisplayAreaOrganizer.scheduleOffset(0, 0);
            mTimeoutHandler.removeTimer();
        }
@@ -352,6 +361,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>

    private void stopOneHanded(int uiEvent) {
        if (mDisplayAreaOrganizer.isInOneHanded()) {
            mOneHandedAccessibilityUtil.announcementForScreenReader(
                    mOneHandedAccessibilityUtil.getOneHandedStopDescription());
            mDisplayAreaOrganizer.scheduleOffset(0, 0);
            mTimeoutHandler.removeTimer();
            mOneHandedUiEventLogger.writeEvent(uiEvent);
@@ -629,6 +640,10 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
            mTutorialHandler.dump(pw);
        }

        if (mOneHandedAccessibilityUtil != null) {
            mOneHandedAccessibilityUtil.dump(pw);
        }

        mOneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver(), mUserId);

        if (mOverlayManager != null) {
+10 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.wm.shell.onehanded;

import static android.os.UserHandle.myUserId;

import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT;
import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER;

@@ -61,6 +63,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {

    private final Rect mLastVisualDisplayBounds = new Rect();
    private final Rect mDefaultDisplayBounds = new Rect();
    private final OneHandedSettingsUtil mOneHandedSettingsUtil;

    private boolean mIsInOneHanded;
    private int mEnterExitAnimationDurationMs;
@@ -109,12 +112,14 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
     */
    public OneHandedDisplayAreaOrganizer(Context context,
            DisplayLayout displayLayout,
            OneHandedSettingsUtil oneHandedSettingsUtil,
            OneHandedAnimationController animationController,
            OneHandedTutorialHandler tutorialHandler,
            OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer,
            ShellExecutor mainExecutor) {
        super(mainExecutor);
        mDisplayLayout.set(displayLayout);
        mOneHandedSettingsUtil = oneHandedSettingsUtil;
        updateDisplayBounds();
        mAnimationController = animationController;
        final int animationDurationConfig = context.getResources().getInteger(
@@ -168,6 +173,11 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
        if (mDisplayLayout.rotation() == toRotation) {
            return;
        }

        if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(context.getContentResolver(),
                myUserId())) {
            return;
        }
        mDisplayLayout.rotateTo(context.getResources(), toRotation);
        resetWindowsOffset(wct);
        updateDisplayBounds();
+0 −23
Original line number Diff line number Diff line
@@ -28,8 +28,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
@@ -51,7 +49,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
            "persist.debug.one_handed_offset_percentage";
    private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
    private final WindowManager mWindowManager;
    private final AccessibilityManager mAccessibilityManager;
    private final String mPackageName;
    private final Rect mDisplaySize;

@@ -59,8 +56,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
    private View mTutorialView;
    private ContentResolver mContentResolver;
    private boolean mCanShowTutorial;
    private String mStartOneHandedDescription;
    private String mStopOneHandedDescription;
    private boolean mIsOneHandedMode;

    private enum ONE_HANDED_TRIGGER_STATE {
@@ -106,11 +101,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
        mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds();
        mPackageName = context.getPackageName();
        mContentResolver = context.getContentResolver();
        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mStartOneHandedDescription = context.getResources().getString(
                R.string.accessibility_action_start_one_handed);
        mStopOneHandedDescription = context.getResources().getString(
                R.string.accessibility_action_stop_one_handed);
        mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
                Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
                ? false : true;
@@ -131,14 +121,12 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
    public void onStartFinished(Rect bounds) {
        updateFinished(View.VISIBLE, 0f);
        updateTutorialCount();
        announcementForScreenReader(true);
        mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
    }

    @Override
    public void onStopFinished(Rect bounds) {
        updateFinished(View.INVISIBLE, -mTargetViewContainer.getHeight());
        announcementForScreenReader(false);
        removeTutorialFromWindowManager();
        mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
    }
@@ -170,17 +158,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
                Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount);
    }

    private void announcementForScreenReader(boolean isStartOneHanded) {
        if (mAccessibilityManager.isTouchExplorationEnabled()) {
            final AccessibilityEvent event = AccessibilityEvent.obtain();
            event.setPackageName(mPackageName);
            event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
            event.getText().add(isStartOneHanded
                    ? mStartOneHandedDescription : mStopOneHandedDescription);
            mAccessibilityManager.sendAccessibilityEvent(event);
        }
    }

    /**
     * Adds the tutorial target view to the WindowManager and update its layout, so it's ready
     * to be animated in.
+5 −2
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {

    Display mDisplay;
    DisplayLayout mDisplayLayout;
    OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
    OneHandedController mSpiedOneHandedController;
    OneHandedTimeoutHandler mSpiedTimeoutHandler;

@@ -116,6 +117,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
                new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()));
        when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mDisplayLayout);

        mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext);
        mSpiedOneHandedController = spy(new OneHandedController(
                mContext,
                mMockDisplayController,
@@ -125,6 +127,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
                mMockTutorialHandler,
                mMockGestureHandler,
                mMockSettingsUitl,
                mOneHandedAccessibilityUtil,
                mSpiedTimeoutHandler,
                mMockUiEventLogger,
                mMockOverlayManager,
@@ -139,8 +142,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
        final OneHandedAnimationController animationController = new OneHandedAnimationController(
                mContext);
        OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
                mContext, mDisplayLayout, animationController, mMockTutorialHandler,
                mMockBackgroundOrganizer, mMockShellMainExecutor);
                mContext, mDisplayLayout, mMockSettingsUitl, animationController,
                mMockTutorialHandler, mMockBackgroundOrganizer, mMockShellMainExecutor);

        assertThat(displayAreaOrganizer.isInOneHanded()).isFalse();
    }
Loading