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

Commit 21538ffb authored by Jason Chang's avatar Jason Chang Committed by Android (Google) Code Review
Browse files

Merge "Fix after turning the Dark theme on, users can not clearly identify the...

Merge "Fix after turning the Dark theme on, users can not clearly identify the screen has entered one handed mode"
parents 76b6d14f 7e8e7441
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -91,6 +91,14 @@ public class DisplayAreaOrganizer extends WindowOrganizer {
     */
    public static final int FEATURE_IME_PLACEHOLDER = FEATURE_SYSTEM_FIRST + 7;

    /**
     * Display area for one handed background layer, which preventing when user
     * turning the Dark theme on, they can not clearly identify the screen has entered
     * one handed mode.
     * @hide
     */
    public static final int FEATURE_ONE_HANDED_BACKGROUND_PANEL = FEATURE_SYSTEM_FIRST + 8;

    /**
     * The last boundary of display area for system features
     */
+6 −0
Original line number Diff line number Diff line
@@ -42,4 +42,10 @@
    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
     when the PIP menu is shown in center. -->
    <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>

    <!-- one handed background panel default color RGB -->
    <item name="config_one_handed_background_rgb" format="float" type="dimen">0.5</item>

    <!-- one handed background panel default alpha -->
    <item name="config_one_handed_background_alpha" format="float" type="dimen">0.5</item>
</resources>
+1 −1
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ public class OneHandedAnimationController {
            mSurfaceTransactionHelper = helper;
        }

        OneHandedTransitionAnimator<T> setOneHandedAnimationCallbacks(
        OneHandedTransitionAnimator<T> addOneHandedAnimationCallback(
                OneHandedAnimationCallback callback) {
            mOneHandedAnimationCallbacks.add(callback);
            return this;
+201 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 static android.view.Display.DEFAULT_DISPLAY;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.android.internal.annotations.GuardedBy;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;

import java.util.List;
import java.util.concurrent.Executor;

/**
 * Manages OneHanded color background layer areas.
 * To avoid when turning the Dark theme on, users can not clearly identify
 * the screen has entered one handed mode.
 */
public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
        implements OneHandedTransitionCallback {
    private static final String TAG = "OneHandedBackgroundPanelOrganizer";

    private final Object mLock = new Object();
    private final SurfaceSession mSurfaceSession = new SurfaceSession();
    private final float[] mColor;
    private final float mAlpha;
    private final Rect mRect;
    private final Handler mHandler;
    private final Point mDisplaySize = new Point();
    private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
            mSurfaceControlTransactionFactory;

    @VisibleForTesting
    @GuardedBy("mLock")
    boolean mIsShowing;
    @Nullable
    @GuardedBy("mLock")
    private SurfaceControl mBackgroundSurface;
    @Nullable
    @GuardedBy("mLock")
    private SurfaceControl mParentLeash;

    private final OneHandedAnimationCallback mOneHandedAnimationCallback =
            new OneHandedAnimationCallback() {
                @Override
                public void onOneHandedAnimationStart(
                        OneHandedAnimationController.OneHandedTransitionAnimator animator) {
                    mHandler.post(() -> showBackgroundPanelLayer());
                }
            };

    @Override
    public void onStopFinished(Rect bounds) {
        mHandler.post(() -> removeBackgroundPanelLayer());
    }

    public OneHandedBackgroundPanelOrganizer(Context context, DisplayController displayController,
            Executor executor) {
        super(executor);
        displayController.getDisplay(DEFAULT_DISPLAY).getRealSize(mDisplaySize);
        final Resources res = context.getResources();
        final float defaultRGB = res.getFloat(R.dimen.config_one_handed_background_rgb);
        mColor = new float[]{defaultRGB, defaultRGB, defaultRGB};
        mAlpha = res.getFloat(R.dimen.config_one_handed_background_alpha);
        mRect = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
        mHandler = new Handler();
        mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
    }

    @Override
    public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
            @NonNull SurfaceControl leash) {
        synchronized (mLock) {
            if (mParentLeash == null) {
                mParentLeash = leash;
            } else {
                throw new RuntimeException("There should be only one DisplayArea for "
                        + "the one-handed mode background panel");
            }
        }
    }

    OneHandedAnimationCallback getOneHandedAnimationCallback() {
        return mOneHandedAnimationCallback;
    }

    @Override
    public List<DisplayAreaAppearedInfo> registerOrganizer(int displayAreaFeature) {
        synchronized (mLock) {
            final List<DisplayAreaAppearedInfo> displayAreaInfos;
            displayAreaInfos = super.registerOrganizer(displayAreaFeature);
            for (int i = 0; i < displayAreaInfos.size(); i++) {
                final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
                onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
            }
            return displayAreaInfos;
        }
    }

    @Override
    public void unregisterOrganizer() {
        synchronized (mLock) {
            super.unregisterOrganizer();
            mParentLeash = null;
        }
    }

    @Nullable
    @VisibleForTesting
    SurfaceControl getBackgroundSurface() {
        synchronized (mLock) {
            if (mParentLeash == null) {
                return null;
            }

            if (mBackgroundSurface == null) {
                mBackgroundSurface = new SurfaceControl.Builder(mSurfaceSession)
                        .setParent(mParentLeash)
                        .setColorLayer()
                        .setFormat(PixelFormat.RGBA_8888)
                        .setOpaque(false)
                        .setName("one-handed-background-panel")
                        .setCallsite("OneHandedBackgroundPanelOrganizer")
                        .build();
            }
            return mBackgroundSurface;
        }
    }

    @VisibleForTesting
    void showBackgroundPanelLayer() {
        synchronized (mLock) {
            if (mIsShowing) {
                return;
            }

            if (getBackgroundSurface() == null) {
                Log.w(TAG, "mBackgroundSurface is null !");
                return;
            }

            SurfaceControl.Transaction transaction =
                    mSurfaceControlTransactionFactory.getTransaction();
            transaction.setLayer(mBackgroundSurface, -1 /* at bottom-most layer */)
                    .setColor(mBackgroundSurface, mColor)
                    .setAlpha(mBackgroundSurface, mAlpha)
                    .show(mBackgroundSurface)
                    .apply();
            transaction.close();
            mIsShowing = true;
        }
    }

    @VisibleForTesting
    void removeBackgroundPanelLayer() {
        synchronized (mLock) {
            if (mBackgroundSurface == null) {
                return;
            }

            SurfaceControl.Transaction transaction =
                    mSurfaceControlTransactionFactory.getTransaction();
            transaction.remove(mBackgroundSurface);
            transaction.apply();
            transaction.close();
            mBackgroundSurface = null;
            mIsShowing = false;
        }
    }
}
+14 −3
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ public class OneHandedController implements OneHanded {

    private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
    private final AccessibilityManager mAccessibilityManager;
    private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;

    /**
     * Handle rotation based on OnDisplayChangingListener callback
@@ -204,17 +205,22 @@ public class OneHandedController implements OneHanded {
        OneHandedTouchHandler touchHandler = new OneHandedTouchHandler();
        OneHandedGestureHandler gestureHandler = new OneHandedGestureHandler(
                context, displayController);
        OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer =
                new OneHandedBackgroundPanelOrganizer(context, displayController, executor);
        OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
                context, displayController, animationController, tutorialHandler, executor);
                context, displayController, animationController, tutorialHandler, executor,
                oneHandedBackgroundPanelOrganizer);
        IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
                ServiceManager.getService(Context.OVERLAY_SERVICE));
        return new OneHandedController(context, displayController, organizer, touchHandler,
                tutorialHandler, gestureHandler, overlayManager, taskStackListener);
        return new OneHandedController(context, displayController,
                oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
                gestureHandler, overlayManager, taskStackListener);
    }

    @VisibleForTesting
    OneHandedController(Context context,
            DisplayController displayController,
            OneHandedBackgroundPanelOrganizer backgroundPanelOrganizer,
            OneHandedDisplayAreaOrganizer displayAreaOrganizer,
            OneHandedTouchHandler touchHandler,
            OneHandedTutorialHandler tutorialHandler,
@@ -222,6 +228,7 @@ public class OneHandedController implements OneHanded {
            IOverlayManager overlayManager,
            TaskStackListenerImpl taskStackListener) {
        mContext = context;
        mBackgroundPanelOrganizer = backgroundPanelOrganizer;
        mDisplayAreaOrganizer = displayAreaOrganizer;
        mDisplayController = displayController;
        mTouchHandler = touchHandler;
@@ -355,6 +362,7 @@ public class OneHandedController implements OneHanded {
        mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler);
        mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler);
        mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
        mDisplayAreaOrganizer.registerTransitionCallback(mBackgroundPanelOrganizer);
    }

    private void setupSettingObservers() {
@@ -405,9 +413,12 @@ public class OneHandedController implements OneHanded {
        }
        // TODO Be aware to unregisterOrganizer() after animation finished
        mDisplayAreaOrganizer.unregisterOrganizer();
        mBackgroundPanelOrganizer.unregisterOrganizer();
        if (mIsOneHandedEnabled) {
            mDisplayAreaOrganizer.registerOrganizer(
                    OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED);
            mBackgroundPanelOrganizer.registerOrganizer(
                    OneHandedBackgroundPanelOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL);
        }
        mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);
        mGestureHandler.onOneHandedEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled);
Loading