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

Commit dd211bab authored by Bill Lin's avatar Bill Lin Committed by Automerger Merge Worker
Browse files

Merge "Allow one-handed mode shortcut expand notification" into sc-dev am: 789f014c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14957128

Change-Id: Ifce69988d9f86294ad0b91c94606dedce3a15f08
parents 61f6e5bc 789f014c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@
    <integer name="long_press_dock_anim_duration">250</integer>

    <!-- Animation duration for translating of one handed when trigger / dismiss. -->
    <integer name="config_one_handed_translate_animation_duration">800</integer>
    <integer name="config_one_handed_translate_animation_duration">600</integer>

    <!-- One handed mode default offset % of display size -->
    <fraction name="config_one_handed_offset">40%</fraction>
+5 −0
Original line number Diff line number Diff line
@@ -67,6 +67,11 @@ public interface OneHanded {
     */
    void setLockedDisabled(boolean locked, boolean enabled);

    /**
     * Registers callback to notify WMShell when user tap shortcut to expand notification.
     */
    void registerEventCallback(OneHandedEventCallback callback);

    /**
     * Registers callback to be notified after {@link OneHandedDisplayAreaOrganizer}
     * transition start or finish
+68 −10
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.util.Slog;
import android.view.Surface;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -72,6 +73,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
    private static final String ONE_HANDED_MODE_GESTURAL_OVERLAY =
            "com.android.internal.systemui.onehanded.gestural";
    private static final int OVERLAY_ENABLED_DELAY_MS = 250;
    private static final int DISPLAY_AREA_READY_RETRY_MS = 10;

    static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";

@@ -99,6 +101,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
    private final Handler mMainHandler;
    private final OneHandedImpl mImpl = new OneHandedImpl();

    private OneHandedEventCallback mEventCallback;
    private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
    private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;

@@ -288,7 +291,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        mTimeoutObserver = getObserver(this::onTimeoutSettingChanged);
        mTaskChangeExitObserver = getObserver(this::onTaskChangeExitSettingChanged);
        mSwipeToNotificationEnabledObserver =
                getObserver(this::onSwipeToNotificationEnabledSettingChanged);
                getObserver(this::onSwipeToNotificationEnabledChanged);

        mDisplayController.addDisplayChangingController(mRotationController);
        setupCallback();
@@ -358,14 +361,23 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
            Slog.d(TAG, "Temporary lock disabled");
            return;
        }

        if (!mDisplayAreaOrganizer.isReady()) {
            // Must wait until DisplayAreaOrganizer is ready for transitioning.
            mMainExecutor.executeDelayed(this::startOneHanded, DISPLAY_AREA_READY_RETRY_MS);
            return;
        }

        if (mState.isTransitioning() || mState.isInOneHanded()) {
            return;
        }

        final int currentRotation = mDisplayAreaOrganizer.getDisplayLayout().rotation();
        if (currentRotation != Surface.ROTATION_0 && currentRotation != Surface.ROTATION_180) {
            Slog.w(TAG, "One handed mode only support portrait mode");
            return;
        }

        mState.setState(STATE_ENTERING);
        final int yOffSet = Math.round(
                mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);
@@ -394,6 +406,10 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        mOneHandedUiEventLogger.writeEvent(uiEvent);
    }

    void registerEventCallback(OneHandedEventCallback callback) {
        mEventCallback = callback;
    }

    @VisibleForTesting
    void registerTransitionCallback(OneHandedTransitionCallback callback) {
        mDisplayAreaOrganizer.registerTransitionCallback(callback);
@@ -463,9 +479,30 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        };
    }

    @VisibleForTesting
    void notifyExpandNotification() {
        mMainExecutor.execute(() -> mEventCallback.notifyExpandNotification());
    }

    @VisibleForTesting
    void notifyUserConfigChanged(boolean success) {
        if (!success) {
            return;
        }
        // TODO Check UX if popup Toast to notify user when auto-enabled one-handed is good option.
        Toast.makeText(mContext, R.string.one_handed_tutorial_title, Toast.LENGTH_LONG).show();
    }

    @VisibleForTesting
    void onActivatedActionChanged() {
        if (mState.isTransitioning() || !isOneHandedEnabled()) {
        if (!isOneHandedEnabled()) {
            final boolean success = mOneHandedSettingsUtil.setOneHandedModeEnabled(
                    mContext.getContentResolver(), 1 /* Enabled for shortcut */, mUserId);
            notifyUserConfigChanged(success);
        }

        if (isSwipeToNotificationEnabled()) {
            notifyExpandNotification();
            return;
        }

@@ -494,11 +531,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        setOneHandedEnabled(enabled);

        // Also checks swipe to notification settings since they all need gesture overlay.
        // Enabled overlay package may affect the current animation(e.g:Settings switch),
        // so we delay 250ms to enabled overlay after switch animation finish
        mMainExecutor.executeDelayed(() -> setEnabledGesturalOverlay(
        setEnabledGesturalOverlay(
                enabled || mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
                        mContext.getContentResolver(), mUserId)), OVERLAY_ENABLED_DELAY_MS);
                        mContext.getContentResolver(), mUserId), true /* DelayExecute */);
    }

    @VisibleForTesting
@@ -542,7 +577,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
    }

    @VisibleForTesting
    void onSwipeToNotificationEnabledSettingChanged() {
    void onSwipeToNotificationEnabledChanged() {
        final boolean enabled =
                mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
                        mContext.getContentResolver(), mUserId);
@@ -551,7 +586,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        // Also checks one handed mode settings since they all need gesture overlay.
        setEnabledGesturalOverlay(
                enabled || mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
                        mContext.getContentResolver(), mUserId));
                        mContext.getContentResolver(), mUserId), true /* DelayExecute */);
    }

    private void setupTimeoutListener() {
@@ -569,11 +604,19 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        return mIsOneHandedEnabled;
    }

    @VisibleForTesting
    boolean isSwipeToNotificationEnabled() {
        return mIsSwipeToNotificationEnabled;
    }

    private void updateOneHandedEnabled() {
        if (mState.getState() == STATE_ENTERING || mState.getState() == STATE_ACTIVE) {
            mMainExecutor.execute(() -> stopOneHanded());
        }

        // Reset and align shortcut one_handed_mode_activated status with current mState
        notifyShortcutState(mState.getState());

        mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);

        if (!mIsOneHandedEnabled) {
@@ -608,12 +651,19 @@ public class OneHandedController implements RemoteCallable<OneHandedController>

        if (info != null && !info.isEnabled()) {
            // Enable the default gestural one handed overlay.
            setEnabledGesturalOverlay(true);
            setEnabledGesturalOverlay(true /* enabled */, false /* delayExecute */);
        }
    }

    @VisibleForTesting
    private void setEnabledGesturalOverlay(boolean enabled) {
    private void setEnabledGesturalOverlay(boolean enabled, boolean delayExecute) {
        if (mState.isTransitioning() || delayExecute) {
            // Enabled overlay package may affect the current animation(e.g:Settings switch),
            // so we delay 250ms to enabled overlay after switch animation finish, only delay once.
            mMainExecutor.executeDelayed(() -> setEnabledGesturalOverlay(enabled, false),
                    OVERLAY_ENABLED_DELAY_MS);
            return;
        }
        try {
            mOverlayManager.setEnabled(ONE_HANDED_MODE_GESTURAL_OVERLAY, enabled, USER_CURRENT);
        } catch (RemoteException e) {
@@ -628,6 +678,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
        if (enabled == isFeatureEnabled) {
            return;
        }

        mLockedDisabled = locked && !enabled;
    }

@@ -760,6 +811,13 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
            });
        }

        @Override
        public void registerEventCallback(OneHandedEventCallback callback) {
            mMainExecutor.execute(() -> {
                OneHandedController.this.registerEventCallback(callback);
            });
        }

        @Override
        public void registerTransitionCallback(OneHandedTransitionCallback callback) {
            mMainExecutor.execute(() -> {
+10 −1
Original line number Diff line number Diff line
@@ -61,11 +61,12 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {

    private DisplayLayout mDisplayLayout = new DisplayLayout();

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

    private boolean mIsReady;
    private float mLastVisualOffset = 0;
    private int mEnterExitAnimationDurationMs;

    private ArrayMap<WindowContainerToken, SurfaceControl> mDisplayAreaTokenMap = new ArrayMap();
@@ -157,6 +158,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
            final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
            onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
        }
        mIsReady = true;
        updateDisplayBounds();
        return displayAreaInfos;
    }
@@ -164,9 +166,14 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
    @Override
    public void unregisterOrganizer() {
        super.unregisterOrganizer();
        mIsReady = false;
        resetWindowsOffset();
    }

    boolean isReady() {
        return mIsReady;
    }

    /**
     * Handler for display rotation changes by {@link DisplayLayout}
     *
@@ -312,6 +319,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
        pw.println(mDisplayAreaTokenMap);
        pw.print(innerPrefix + "mDefaultDisplayBounds=");
        pw.println(mDefaultDisplayBounds);
        pw.print(innerPrefix + "mIsReady=");
        pw.println(mIsReady);
        pw.print(innerPrefix + "mLastVisualDisplayBounds=");
        pw.println(mLastVisualDisplayBounds);
        pw.print(innerPrefix + "mLastVisualOffset=");
+28 −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;

/**
 * Additional callback interface for OneHanded events.
 */
public interface OneHandedEventCallback {
    /**
     * Called to notify expand notification shade.
     */
    default void notifyExpandNotification() {
    }
}
Loading