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

Commit c5f8397f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Implement screen edge swipe for prototype"

parents b031e8e7 b831fb4f
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -23,8 +23,9 @@
    <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
    <!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
    <dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
    <!-- The distance from a side of device of the navigation bar to start an edge swipe -->
    <dimen name="navigation_bar_edge_swipe_threshold">48dp</dimen>
    <!-- The default distance from a side of the device to start an edge swipe from -->
    <dimen name="navigation_bar_default_edge_width">48dp</dimen>
    <dimen name="navigation_bar_default_edge_height">500dp</dimen>

    <!-- thickness (height) of the dead zone at the top of the navigation bar,
         reducing false presses on navbar buttons; approx 2mm -->
+3 −0
Original line number Diff line number Diff line
@@ -1829,6 +1829,9 @@
    <!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
    <string name="nav_bar">Navigation bar</string>

    <!-- Label for navigation edge panel for gestures [CHAR LIMIT=60] -->
    <string name="nav_bar_edge_panel" translatable="false">Navigation bar Edge Panel</string>

    <!-- SysUI Tuner: Button that controls layout of navigation bar [CHAR LIMIT=60] -->
    <string name="nav_bar_layout">Layout</string>

+78 −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.annotation.NonNull;
import android.content.Context;
import android.graphics.PixelFormat;
import android.view.View;
import android.view.WindowManager;

import com.android.systemui.R;

public class NavigationBarEdgePanel extends View {
    private static final String TAG = "NavigationBarEdgePanel";

    public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height,
            int gravity) {
        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                PixelFormat.TRANSLUCENT);
        lp.gravity = gravity;
        lp.setTitle(TAG + context.getDisplayId());
        lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel);
        lp.windowAnimations = 0;
        NavigationBarEdgePanel panel = new NavigationBarEdgePanel(context);
        panel.setLayoutParams(lp);
        return panel;
    }

    private NavigationBarEdgePanel(Context context) {
        super(context);
    }

    public void setWindowFlag(int flags, boolean enable) {
        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
        if (lp == null || enable == ((lp.flags & flags) != 0)) {
            return;
        }
        if (enable) {
            lp.flags |= flags;
        } else {
            lp.flags &= ~flags;
        }
        updateLayout(lp);
    }

    public void setDimensions(int width, int height) {
        final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
        if (lp.width != width || lp.height != height) {
            lp.width = width;
            lp.height = height;
            updateLayout(lp);
        }
    }

    private void updateLayout(WindowManager.LayoutParams lp) {
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        wm.updateViewLayout(this, lp);
    }
}
+104 −14
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.phone;

import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;

import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
@@ -35,6 +37,8 @@ import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.SuppressLint;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -51,6 +55,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
@@ -87,12 +92,21 @@ import com.android.systemui.statusbar.policy.KeyButtonDrawable;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;

public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
    final static boolean DEBUG = false;
    final static String TAG = "StatusBar/NavBarView";

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({WINDOW_TARGET_BOTTOM, WINDOW_TARGET_LEFT, WINDOW_TARGET_RIGHT})
    public @interface WindowTarget{}
    public static final int WINDOW_TARGET_BOTTOM = 0;
    public static final int WINDOW_TARGET_LEFT = 1;
    public static final int WINDOW_TARGET_RIGHT = 2;

    // slippery nav bar when everything is disabled, e.g. during setup
    final static boolean SLIPPERY_WHEN_DISABLED = true;

@@ -109,6 +123,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
    int mNavigationIconHints = 0;

    private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
    private @WindowTarget int mWindowHitTarget = WINDOW_TARGET_BOTTOM;
    private Rect mHomeButtonBounds = new Rect();
    private Rect mBackButtonBounds = new Rect();
    private Rect mRecentsButtonBounds = new Rect();
@@ -160,6 +175,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
    private NavigationAssistantAction mAssistantAction;
    private NavigationNotificationPanelAction mNotificationPanelAction;

    private NavigationBarEdgePanel mLeftEdgePanel;
    private NavigationBarEdgePanel mRightEdgePanel;

    /**
     * Helper that is responsible for showing the right toast when a disallowed activity operation
     * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
@@ -222,6 +240,18 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        }
    };

    private final OnTouchListener mEdgePanelTouchListener = new OnTouchListener() {
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getActionMasked() == ACTION_DOWN) {
                mWindowHitTarget = v == mLeftEdgePanel ? WINDOW_TARGET_LEFT : WINDOW_TARGET_RIGHT;
                mDownHitTarget = HIT_TARGET_NONE;
            }
            return mGestureHelper.onTouchEvent(event);
        }
    };

    private class H extends Handler {
        public void handleMessage(Message m) {
            switch (m.what) {
@@ -297,6 +327,16 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
                mColorAdaptionController.end();
            }
        }

        @Override
        public void onEdgeSensitivityChanged(int width, int height) {
            if (mLeftEdgePanel != null) {
                mLeftEdgePanel.setDimensions(width, height);
            }
            if (mRightEdgePanel != null) {
                mRightEdgePanel.setDimensions(width, height);
            }
        }
    };

    public NavigationBarView(Context context, AttributeSet attrs) {
@@ -433,6 +473,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
                int x = (int) event.getX();
                int y = (int) event.getY();
                mDownHitTarget = HIT_TARGET_NONE;
                mWindowHitTarget = WINDOW_TARGET_BOTTOM;
                if (deadZoneConsumed) {
                    mDownHitTarget = HIT_TARGET_DEAD_ZONE;
                } else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
@@ -483,6 +524,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        return mDownHitTarget;
    }

    public @WindowTarget int getWindowTarget() {
        return mWindowHitTarget;
    }

    public void abortCurrentGesture() {
        getHomeButton().abortCurrentGesture();
    }
@@ -837,25 +882,33 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
    }

    private void setSlippery(boolean slippery) {
        boolean changed = false;
        setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
    }

    public void setWindowTouchable(boolean flag) {
        setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
        if (mLeftEdgePanel != null) {
            mLeftEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
        }
        if (mRightEdgePanel != null) {
            mRightEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
        }
    }

    private void setWindowFlag(int flags, boolean enable) {
        final ViewGroup navbarView = ((ViewGroup) getParent());
        final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView
                .getLayoutParams();
        if (lp == null) {
        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView.getLayoutParams();
        if (lp == null || enable == ((lp.flags & flags) != 0)) {
            return;
        }
        if (slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) == 0) {
            lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
            changed = true;
        } else if (!slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0) {
            lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
            changed = true;
        if (enable) {
            lp.flags |= flags;
        } else {
            lp.flags &= ~flags;
        }
        if (changed) {
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        wm.updateViewLayout(navbarView, lp);
    }
    }

    public void setMenuVisibility(final boolean show) {
        mContextualButtonGroup.setButtonVisiblity(R.id.menu, show);
@@ -1016,6 +1069,17 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to get nav bar position.", e);
        }

        // For landscape, hide the panel that would interfere with navigation bar layout
        if (mLeftEdgePanel != null && mRightEdgePanel != null) {
            mLeftEdgePanel.setVisibility(VISIBLE);
            mRightEdgePanel.setVisibility(VISIBLE);
            if (navBarPos == NAV_BAR_LEFT) {
                mLeftEdgePanel.setVisibility(GONE);
            } else if (navBarPos == NAV_BAR_RIGHT) {
                mRightEdgePanel.setVisibility(GONE);
            }
        }
        mGestureHelper.setBarState(isRtl, navBarPos);
    }

@@ -1142,6 +1206,21 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
                NavGesture.class, false /* Only one */);
        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
        mColorAdaptionController.start();

        if (mPrototypeController.isEnabled()) {
            WindowManager wm = (WindowManager) getContext()
                    .getSystemService(Context.WINDOW_SERVICE);
            int width = mPrototypeController.getEdgeSensitivityWidth();
            int height = mPrototypeController.getEdgeSensitivityHeight();
            mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
                    Gravity.START | Gravity.BOTTOM);
            mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
                    Gravity.END | Gravity.BOTTOM);
            mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
            mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
            wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams());
            wm.addView(mRightEdgePanel, mRightEdgePanel.getLayoutParams());
        }
    }

    @Override
@@ -1157,6 +1236,17 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        for (int i = 0; i < mButtonDispatchers.size(); ++i) {
            mButtonDispatchers.valueAt(i).onDestroy();
        }

        if (mPrototypeController.isEnabled()) {
            WindowManager wm = (WindowManager) getContext()
                    .getSystemService(Context.WINDOW_SERVICE);
            if (mLeftEdgePanel != null) {
                wm.removeView(mLeftEdgePanel);
            }
            if (mRightEdgePanel != null) {
                wm.removeView(mRightEdgePanel);
            }
        }
    }

    private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
+33 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;

import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
@@ -34,7 +35,12 @@ import java.lang.annotation.RetentionPolicy;
public class NavigationPrototypeController extends ContentObserver {
    private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
    private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
    private static final String PROTOTYPE_ENABLED = "prototype_enabled";

    private static final String EDGE_SENSITIVITY_HEIGHT_SETTING =
            "quickstepcontroller_edge_height_sensitivity";
    public static final String EDGE_SENSITIVITY_WIDTH_SETTING =
            "quickstepcontroller_edge_width_sensitivity";
    private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
    public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";

@@ -79,6 +85,8 @@ public class NavigationPrototypeController extends ContentObserver {
        registerObserver(HIDE_HOME_BUTTON_SETTING);
        registerObserver(GESTURE_MATCH_SETTING);
        registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
        registerObserver(EDGE_SENSITIVITY_WIDTH_SETTING);
        registerObserver(EDGE_SENSITIVITY_HEIGHT_SETTING);
    }

    /**
@@ -106,10 +114,26 @@ public class NavigationPrototypeController extends ContentObserver {
            } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
                mListener.onColorAdaptChanged(
                        NavBarTintController.isEnabled(mContext));
            } else if (path.endsWith(EDGE_SENSITIVITY_WIDTH_SETTING)
                    || path.endsWith(EDGE_SENSITIVITY_HEIGHT_SETTING)) {
                mListener.onEdgeSensitivityChanged(getEdgeSensitivityWidth(),
                        getEdgeSensitivityHeight());
            }
        }
    }

    public int getEdgeSensitivityWidth() {
        return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_WIDTH_SETTING, 0));
    }

    public int getEdgeSensitivityHeight() {
        return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_HEIGHT_SETTING, 0));
    }

    public boolean isEnabled() {
        return getGlobalBool(PROTOTYPE_ENABLED, false);
    }

    /**
     * Retrieve the action map to apply to the quick step controller
     * @return an action map
@@ -144,15 +168,24 @@ public class NavigationPrototypeController extends ContentObserver {
        return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal ? 1 : 0) == 1;
    }

    private int getGlobalInt(String name, int defaultVal) {
        return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal);
    }

    private void registerObserver(String name) {
        mContext.getContentResolver()
                .registerContentObserver(Settings.Global.getUriFor(name), false, this);
    }

    private static int convertDpToPixel(float dp) {
        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
    }

    public interface OnPrototypeChangedListener {
        void onGestureRemap(@GestureAction int[] actions);
        void onBackButtonVisibilityChanged(boolean visible);
        void onHomeButtonVisibilityChanged(boolean visible);
        void onColorAdaptChanged(boolean enabled);
        void onEdgeSensitivityChanged(int width, int height);
    }
}
Loading