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

Commit e0ac4f06 authored by Vinit Nayak's avatar Vinit Nayak Committed by Automerger Merge Worker
Browse files

Merge "Draw a fake home handle during QuickSwitch" into rvc-dev am: 673533f6

Change-Id: Ia64faccca4362339593df9512b6b4b9ebbb5c0a7
parents df0e6db4 673533f6
Loading
Loading
Loading
Loading
+185 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;

import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
@@ -56,6 +57,8 @@ import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
@@ -71,6 +74,7 @@ import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -104,6 +108,7 @@ import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
@@ -133,7 +138,7 @@ import dagger.Lazy;
 * on clicks and view states of the nav bar.
 */
public class NavigationBarFragment extends LifecycleFragment implements Callbacks,
        NavigationModeController.ModeChangedListener {
        NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener {

    public static final String TAG = "NavigationBar";
    private static final boolean DEBUG = false;
@@ -141,6 +146,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
    private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
    private static final String EXTRA_APPEARANCE = "appearance";
    private static final String EXTRA_TRANSIENT_STATE = "transient_state";
    private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";


    /** Allow some time inbetween the long press for back and recents. */
    private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
@@ -199,6 +206,23 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
    private boolean mIsOnDefaultDisplay;
    public boolean mHomeBlockedThisTouch;

    /**
     * When user is QuickSwitching between apps of different orientations, we'll draw a fake
     * home handle on the orientation they originally touched down to start their swipe
     * gesture to indicate to them that they can continue in that orientation without having to
     * rotate the phone
     * The secondary handle will show when we get
     * {@link OverviewProxyListener#onQuickSwitchToNewTask(int)} callback with the
     * original handle hidden and we'll flip the visibilities once the
     * {@link #mTasksFrozenListener} fires
     */
    private NavigationHandle mOrientationHandle;
    private WindowManager.LayoutParams mOrientationParams;
    private boolean mFrozenTasks;
    private int mStartingQuickSwitchRotation;
    private int mCurrentRotation;
    private boolean mFixedRotationEnabled;

    /** Only for default display */
    @Nullable
    private AssistHandleViewController mAssistHandlerViewController;
@@ -248,6 +272,12 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
            mShadeController.collapsePanel(true /* animate */);
        }

        @Override
        public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
            mStartingQuickSwitchRotation = rotation;
            orientSecondaryHomeHandle();
        }

        @Override
        public void startAssistant(Bundle bundle) {
            mAssistManager.startAssist(bundle);
@@ -271,6 +301,22 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        }
    };

    private TaskStackChangeListener mTasksFrozenListener = new TaskStackChangeListener() {
        @Override
        public void onRecentTaskListFrozenChanged(boolean frozen) {
            mFrozenTasks = frozen;
            orientSecondaryHomeHandle();
        }
    };

    private NavigationBarTransitions.DarkIntensityListener mOrientationHandleIntensityListener =
            new NavigationBarTransitions.DarkIntensityListener() {
                @Override
                public void onDarkIntensity(float darkIntensity) {
                    mOrientationHandle.setDarkIntensity(darkIntensity);
                }
            };

    private final ContextButtonListener mRotationButtonListener = (button, visible) -> {
        if (visible) {
            // If the button will actually become visible and the navbar is about to hide,
@@ -294,6 +340,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        }
    };

    private final ContentObserver mFixedRotationObserver = new ContentObserver(
            new Handler(Looper.getMainLooper())) {
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            updatedFixedRotation();
        }
    };

    private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
            new DeviceConfig.OnPropertiesChangedListener() {
        @Override
@@ -351,6 +405,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
                Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
                false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);

        mContentResolver.registerContentObserver(
                Settings.Global.getUriFor(FIXED_ROTATION_TRANSFORM_SETTING_NAME),
                false /* notifyForDescendants */, mFixedRotationObserver, UserHandle.USER_ALL);

        if (savedInstanceState != null) {
            mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
            mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
@@ -376,6 +434,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        mNavigationModeController.removeListener(this);
        mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
        mContentResolver.unregisterContentObserver(mAssistContentObserver);
        mContentResolver.unregisterContentObserver(mFixedRotationObserver);

        DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
    }
@@ -406,6 +465,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        }
        mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
        mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
        updatedFixedRotation();

        prepareNavigationBarView();
        checkNavBarModes();
@@ -442,6 +502,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
                new AssistHandleViewController(mHandler, mNavigationBarView);
            getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController);
        }

        initSecondaryHomeHandleForRotation();
        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTasksFrozenListener);
    }

    @Override
@@ -458,6 +521,13 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        }
        mOverviewProxyService.removeCallback(mOverviewProxyListener);
        mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTasksFrozenListener);
        if (mOrientationHandle != null) {
            resetSecondaryHandle();
            getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this);
            getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
            mWindowManager.removeView(mOrientationHandle);
        }
    }

    @Override
@@ -490,6 +560,88 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        repositionNavigationBar();
    }

    private void initSecondaryHomeHandleForRotation() {
        if (!canShowSecondaryHandle()) {
            return;
        }

        getContext().getSystemService(DisplayManager.class)
                .registerDisplayListener(this, new Handler(Looper.getMainLooper()));

        mOrientationHandle = new VerticalNavigationHandle(getContext());

        getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener);
        mOrientationParams = new WindowManager.LayoutParams(0, 0,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
                PixelFormat.TRANSLUCENT);
        mWindowManager.addView(mOrientationHandle, mOrientationParams);
        mOrientationHandle.setVisibility(View.GONE);
    }

    private void orientSecondaryHomeHandle() {
        if (!canShowSecondaryHandle()) {
            return;
        }

        if (!mFrozenTasks) {
            resetSecondaryHandle();
        } else {
            int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation);
            int height = 0;
            int width = 0;
            Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
            switch (deltaRotation) {
                case Surface.ROTATION_90:
                case Surface.ROTATION_270:
                    height = dispSize.height();
                    width = getResources()
                            .getDimensionPixelSize(R.dimen.navigation_bar_height);
                    break;
                case Surface.ROTATION_180:
                case Surface.ROTATION_0:
                    // TODO(b/152683657): Need to determine best UX for this
                    resetSecondaryHandle();
                    return;
            }

            mOrientationParams.gravity =
                    deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT;
            mOrientationParams.height = height;
            mOrientationParams.width = width;
            mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
            mNavigationBarView.setVisibility(View.GONE);
            mOrientationHandle.setVisibility(View.VISIBLE);
        }
    }

    private void resetSecondaryHandle() {
        if (mOrientationHandle != null) {
            // Case where nav mode is changed w/o ever invoking a quickstep
            // mOrientedHandle is initialized lazily
            mOrientationHandle.setVisibility(View.GONE);
        }
        mNavigationBarView.setVisibility(View.VISIBLE);
    }

    private int deltaRotation(int oldRotation, int newRotation) {
        int delta = newRotation - oldRotation;
        if (delta < 0) delta += 4;
        return delta;
    }

    private void updatedFixedRotation() {
        mFixedRotationEnabled = Settings.Global.getInt(getContext().getContentResolver(),
                FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
        if (!canShowSecondaryHandle()) {
            resetSecondaryHandle();
        }
    }

    @Override
    public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
        if (mNavigationBarView != null) {
@@ -1112,6 +1264,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        mNavBarMode = mode;
        updateScreenPinningGestures();

        if (!canShowSecondaryHandle()) {
            resetSecondaryHandle();
        }

        // Workaround for b/132825155, for secondary users, we currently don't receive configuration
        // changes on overlay package change since SystemUI runs for the system user. In this case,
        // trigger a new configuration change to ensure that the nav bar is updated in the same way.
@@ -1156,6 +1312,34 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
    private final AccessibilityServicesStateChangeListener mAccessibilityListener =
            this::updateAccessibilityServicesState;

    @Override
    public void onDisplayAdded(int displayId) {

    }

    @Override
    public void onDisplayRemoved(int displayId) {

    }

    @Override
    public void onDisplayChanged(int displayId) {
        if (!canShowSecondaryHandle()) {
            return;
        }

        int rotation = getContext().getResources().getConfiguration()
                .windowConfiguration.getRotation();
        if (rotation != mCurrentRotation) {
            mCurrentRotation = rotation;
            orientSecondaryHomeHandle();
        }
    }

    private boolean canShowSecondaryHandle() {
        return mFixedRotationEnabled && mNavBarMode == NAV_BAR_MODE_GESTURAL;
    }

    private final Consumer<Integer> mRotationWatcher = rotation -> {
        if (mNavigationBarView != null
                && mNavigationBarView.needsReorient(rotation)) {
+3 −3
Original line number Diff line number Diff line
@@ -32,11 +32,11 @@ import com.android.systemui.R;

public class NavigationHandle extends View implements ButtonInterface {

    private final Paint mPaint = new Paint();
    protected final Paint mPaint = new Paint();
    private @ColorInt final int mLightColor;
    private @ColorInt final int mDarkColor;
    private final int mRadius;
    private final int mBottom;
    protected final int mRadius;
    protected final int mBottom;
    private boolean mRequiresInvalidate;

    public NavigationHandle(Context context) {
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.systemui.statusbar.phone;

import android.content.Context;
import android.graphics.Canvas;

import com.android.systemui.R;

/** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
public class VerticalNavigationHandle extends NavigationHandle {
    private final int mWidth;

    public VerticalNavigationHandle(Context context) {
        super(context);
        mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int left;
        int top;
        int bottom;
        int right;

        int radiusOffset = mRadius * 2;
        right = getWidth() - mBottom;
        top = getHeight() / 2 - (mWidth / 2); /* (height of screen / 2) - (height of bar / 2) */
        left = getWidth() - mBottom - radiusOffset;
        bottom = getHeight() / 2 + (mWidth / 2);
        canvas.drawRoundRect(left, top, right, bottom, mRadius, mRadius, mPaint);
    }
}