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

Commit d4bb3bc9 authored by Jens Doll's avatar Jens Doll Committed by Danny Baumann
Browse files

Pie controls: A new way of activation

Based on "Pie controls: Introducing a pie delivery service" this
commit binds the pie controls to the newly created pie service.

Patch Set #2:
* Fixed glitch when displaying the search panel at the lock
  screen.

Patch Set #5:
* Switch Position to com.android.internal.util.pie.Position
* Removed legacy and unused code

Patch Set #6:
* Fixed lock screen glitch, finally!

Patch Set #7:
* Rebase

Patch Set #9:
* Moved almost all of the pie logic to PieController

Patch Set #10:
* Remove window completely from WindowManager when not shown

Patch Set #13:
* Fixed Taichi's bug
* Removed observers in PieView

Patch Set #14 & #15:
* Rebase

Change-Id: I352f198068807694d95699618597d0927da3f324
parent 9f11bd11
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -218,10 +218,6 @@
    <dimen name="status_bar_battery_cluster_text_margin">-1dip</dimen>

    <!-- ==================== pie controls ==================== -->
    <!-- Actual width/height of the trigger views placed on the UI -->
    <dimen name="pie_trigger_height">3dp</dimen>
    <!-- The distance a touch event must travel on the surface to trigger the pie control -->
    <dimen name="pie_trigger_distance">8dp</dimen>
    <!-- Padding between the pie controls and the screen border -->
    <dimen name="pie_padding">16dp</dimen>

+18 −291
Original line number Diff line number Diff line
@@ -28,10 +28,8 @@ import com.android.systemui.SystemUI;
import com.android.systemui.recent.RecentTasksLoader;
import com.android.systemui.recent.RecentsActivity;
import com.android.systemui.recent.TaskDescription;
import com.android.systemui.statusbar.pie.PieLayout;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
import com.android.systemui.statusbar.policy.PieController;
import com.android.systemui.statusbar.policy.PieController.Position;
import com.android.systemui.statusbar.tablet.StatusBarPanel;

import android.app.ActivityManager;
@@ -46,7 +44,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
@@ -54,7 +51,6 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@@ -65,6 +61,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.pie.PieManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -92,7 +89,6 @@ public abstract class BaseStatusBar extends SystemUI implements
        CommandQueue.Callbacks {
    public static final String TAG = "StatusBar";
    public static final boolean DEBUG = false;
    public static final boolean DEBUG_INPUT = false;
    public static final boolean MULTIUSER_DEBUG = false;

    protected static final int MSG_TOGGLE_RECENTS_PANEL = 1020;
@@ -134,7 +130,6 @@ public abstract class BaseStatusBar extends SystemUI implements

    protected FrameLayout mStatusBarContainer;


    /**
     * An interface for navigation key bars to allow status bars to signal which keys are
     * currently of interest to the user.<br>
@@ -162,95 +157,7 @@ public abstract class BaseStatusBar extends SystemUI implements
            new ArrayList<NavigationBarCallback>();

    // Pie Control
    protected int mExpandedDesktopState;
    protected PieController mPieController;
    protected PieLayout mPieContainer;
    private int mPieTriggerSlots;
    private int mPieTriggerMask = Position.LEFT.FLAG
            | Position.BOTTOM.FLAG
            | Position.RIGHT.FLAG
            | Position.TOP.FLAG;
    private View[] mPieTrigger = new View[Position.values().length];
    private PieSettingsObserver mSettingsObserver;

    private View.OnTouchListener mPieTriggerOnTouchHandler = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            final int action = event.getAction();
            final PieController.Tracker tracker = (PieController.Tracker)v.getTag();

            if (tracker == null) {
                if (DEBUG_INPUT) {
                    Slog.v(TAG, "Pie trigger onTouch: action: " + action + ", ("
                            + event.getAxisValue(MotionEvent.AXIS_X) + ","
                            + event.getAxisValue(MotionEvent.AXIS_Y) + ") position: NULL returning: false");
                }
                return false;
            }

            if (!mPieController.isShowing()) {
                if (event.getPointerCount() > 1) {
                    if (DEBUG_INPUT) {
                        Slog.v(TAG, "Pie trigger onTouch: action: " + action
                                + ", (to many pointers) position: " + tracker.position.name()
                                + " returning: false");
                    }
                    return false;
                }

                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        tracker.start(event);
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (tracker.move(event)) {
                            if (DEBUG) {
                                Slog.v(TAG, "Pie control activated on: ("
                                        + event.getAxisValue(MotionEvent.AXIS_X) + ","
                                        + event.getAxisValue(MotionEvent.AXIS_Y) + ") with position: "
                                        + tracker.position.name());
                            }
                            if (tracker.position == Position.BOTTOM
                                    && mPieController.isSearchLightEnabled()) {
                                // if we are at the bottom and nothing else is there, use a
                                // search light!
                                showSearchPanel();
                            } else {
                                // set the snap points depending on current trigger and mask
                                mPieContainer.setSnapPoints(mPieTriggerMask & ~mPieTriggerSlots);
                                // send the activation to the controller
                                mPieController.activateFromTrigger(v, event, tracker.position);
                                // forward a spoofed ACTION_DOWN event
                                MotionEvent echo = event.copy();
                                echo.setAction(MotionEvent.ACTION_DOWN);
                                return mPieContainer.onTouch(v, echo);
                            }
                        }
                        break;
                    default:
                        // whatever it was, we are giving up on this one
                        tracker.active = false;
                        break;
                }
            } else {
                if (DEBUG_INPUT) {
                    Slog.v(TAG, "Pie trigger onTouch: action: " + action + ", ("
                            + event.getAxisValue(MotionEvent.AXIS_X) + ","
                            + event.getAxisValue(MotionEvent.AXIS_Y)
                            + ") position: " + tracker.position.name() + " delegating");
                }
                return mPieContainer.onTouch(v, event);
            }
            if (DEBUG_INPUT) {
                Slog.v(TAG, "Pie trigger onTouch: action: " + action + ", ("
                        + event.getAxisValue(MotionEvent.AXIS_X) + ","
                        + event.getAxisValue(MotionEvent.AXIS_Y) + ") position: "
                        + tracker.position.name() + " returning: " + tracker.active);
            }
            return tracker.active;
        }

    };

    // UI-specific methods

@@ -411,11 +318,11 @@ public abstract class BaseStatusBar extends SystemUI implements
            }
        }, filter);

        mSettingsObserver = new PieSettingsObserver(new Handler());

        // this calls attachPie() implicitly
        mSettingsObserver.onChange(true);
        mSettingsObserver.observe();
        if (PieManager.getInstance().isPresent()) {
            mPieController = new PieController(mContext);
            mPieController.attachStatusBar(this);
            addNavigationBarCallback(mPieController);
        }
    }

    public void userSwitched(int newUserId) {
@@ -803,30 +710,12 @@ public abstract class BaseStatusBar extends SystemUI implements
                 if (DEBUG) Slog.d(TAG, "opening search panel");
                 if (mSearchPanelView != null) {
                     mSearchPanelView.show(true, true);

                     View bottom = mPieTrigger[Position.BOTTOM.INDEX];
                     if (bottom != null) {
                         WindowManager.LayoutParams lp =
                                 (android.view.WindowManager.LayoutParams) bottom.getLayoutParams();
                         lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
                         lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
                         mWindowManager.updateViewLayout(bottom, lp);
                     }
                 }
                 break;
             case MSG_CLOSE_SEARCH_PANEL:
                 if (DEBUG) Slog.d(TAG, "closing search panel");
                 if (mSearchPanelView != null && mSearchPanelView.isShowing()) {
                     mSearchPanelView.show(false, true);

                     View bottom = mPieTrigger[Position.BOTTOM.INDEX];
                     if (bottom != null) {
                         WindowManager.LayoutParams lp =
                                 (android.view.WindowManager.LayoutParams) bottom.getLayoutParams();
                         lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
                         lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
                         mWindowManager.updateViewLayout(bottom, lp);
                     }
                 }
                 break;
            }
@@ -1304,6 +1193,16 @@ public abstract class BaseStatusBar extends SystemUI implements
        return km.inKeyguardRestrictedInputMode();
    }

    public int getExpandedDesktopMode() {
        ContentResolver resolver = mContext.getContentResolver();
        boolean expanded = Settings.System.getInt(resolver,
                Settings.System.EXPANDED_DESKTOP_STATE, 0) == 1;
        if (expanded) {
            return Settings.System.getInt(resolver, Settings.System.EXPANDED_DESKTOP_STYLE, 0);
        }
        return 0;
    }

    public void addNavigationBarCallback(NavigationBarCallback callback) {
        mNavigationCallbacks.add(callback);
    }
@@ -1328,181 +1227,9 @@ public abstract class BaseStatusBar extends SystemUI implements

    // Pie Controls

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        if (DEBUG) Slog.d(TAG, "Configuration changed! Update pie triggers");

        attachPie();
    }

    private final class PieSettingsObserver extends ContentObserver {
        PieSettingsObserver(Handler handler) {
            super(handler);
        }

        void observe() {
            ContentResolver resolver = mContext.getContentResolver();
            resolver.registerContentObserver(Settings.System.getUriFor(
                    Settings.System.PIE_CONTROLS), false, this);
            resolver.registerContentObserver(Settings.System.getUriFor(
                    Settings.System.PIE_POSITIONS), false, this);
            resolver.registerContentObserver(Settings.System.getUriFor(
                    Settings.System.EXPANDED_DESKTOP_STATE), false, this);
            resolver.registerContentObserver(Settings.System.getUriFor(
                    Settings.System.EXPANDED_DESKTOP_STYLE), false, this);
        }

        @Override
        public void onChange(boolean selfChange) {
            ContentResolver resolver = mContext.getContentResolver();

            mPieTriggerSlots = Settings.System.getInt(resolver,
                    Settings.System.PIE_POSITIONS, Position.BOTTOM.FLAG);

            boolean expanded = Settings.System.getInt(resolver,
                    Settings.System.EXPANDED_DESKTOP_STATE, 0) == 1;
            if (expanded) {
                mExpandedDesktopState = Settings.System.getInt(resolver,
                        Settings.System.EXPANDED_DESKTOP_STYLE, 0);
            } else {
                mExpandedDesktopState = 0;
            }

            attachPie();
        }
    }

    private boolean isPieEnabled() {
        int pie = Settings.System.getInt(mContext.getContentResolver(),
                Settings.System.PIE_CONTROLS, 0);

        return (pie == 1 && mExpandedDesktopState != 0) || pie == 2;
    }

    private void attachPie() {
        if (isPieEnabled()) {

            // Create our container, if it does not exist already
            if (mPieContainer == null) {
                mPieContainer = new PieLayout(mContext);
                WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
                        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                        PixelFormat.TRANSLUCENT);
                // This title is for debugging only. See: dumpsys window
                lp.setTitle("PieControlPanel");
                lp.windowAnimations = android.R.style.Animation;
                lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;

                mWindowManager.addView(mPieContainer, lp);
                // once we need a pie controller, we create one and keep it forever ...
                if (mPieController == null) {
                    mPieController = new PieController(mContext);
                    mPieController.attachStatusBar(this);
                    addNavigationBarCallback(mPieController);
                }
                mPieController.attachContainer(mPieContainer);
            }

            // add or update pie triggers
            if (DEBUG) {
                Slog.d(TAG, "AttachPie with trigger position flags: "
                        + mPieTriggerSlots + " masked: " + (mPieTriggerSlots & mPieTriggerMask));
            }

            refreshPieTriggers();

        } else {
            for (int i = 0; i < mPieTrigger.length; i++) {
                if (mPieTrigger[i] != null) {
                    mWindowManager.removeView(mPieTrigger[i]);
                    mPieTrigger[i] = null;
                }
            }
            // detach from the pie container and unregister observers and receivers
            if (mPieController != null) {
                mPieController.detachContainer();
                mPieContainer = null;
            }
        }
    }

    public void updatePieTriggerMask(int newMask) {
        int oldState = mPieTriggerSlots & mPieTriggerMask;
        mPieTriggerMask = newMask;

        // first we check, if it would make a change
        if ((mPieTriggerSlots & mPieTriggerMask) != oldState) {
            if (isPieEnabled()) {
                refreshPieTriggers();
            }
        }
    }

    // This should only be called, when is is clear that the pie controls are active
    private void refreshPieTriggers() {
        for (Position g : Position.values()) {
            View trigger = mPieTrigger[g.INDEX];
            if (trigger == null && (mPieTriggerSlots & mPieTriggerMask & g.FLAG) != 0) {
                trigger = new View(mContext);
                trigger.setClickable(false);
                trigger.setLongClickable(false);
                trigger.setTag(mPieController.buildTracker(g));
                trigger.setOnTouchListener(mPieTriggerOnTouchHandler);

                if (DEBUG) {
                    trigger.setVisibility(View.VISIBLE);
                    trigger.setBackgroundColor(0x77ff0000);
                    Slog.d(TAG, "addPieTrigger on " + g.INDEX
                            + " with position: " + g + " : " + trigger.toString());
                }
                mWindowManager.addView(trigger, getPieTriggerLayoutParams(g));
                mPieTrigger[g.INDEX] = trigger;
            } else if (trigger != null && (mPieTriggerSlots & mPieTriggerMask & g.FLAG) == 0) {
                mWindowManager.removeView(trigger);
                mPieTrigger[g.INDEX] = null;
            } else if (trigger != null) {
                mWindowManager.updateViewLayout(trigger, getPieTriggerLayoutParams(g));
            }
        }
    }

    private WindowManager.LayoutParams getPieTriggerLayoutParams(Position position) {
        final Resources res = mContext.getResources();

        int width = (int) (res.getDisplayMetrics().widthPixels * 0.8f);
        int height = (int) (res.getDisplayMetrics().heightPixels * 0.8f);
        int triggerThickness = (int) (res.getDimensionPixelSize(R.dimen.pie_trigger_height));
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                (position == Position.TOP || position == Position.BOTTOM
                        ? width : triggerThickness),
                (position == Position.LEFT || position == Position.RIGHT
                        ? height : triggerThickness),
                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        /* | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM */,
                PixelFormat.TRANSLUCENT);
        // This title is for debugging only. See: dumpsys window
        lp.setTitle("PieTrigger" + position.name());
        if (position == Position.LEFT || position == Position.RIGHT) {
            lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
                    | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
        } else {
            lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
                    | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
        if (mPieController != null) {
            mPieController.updatePieTriggerMask(newMask);
        }
        lp.gravity = position.ANDROID_GRAVITY;
        return lp;
    }

}
+9 −9
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import android.widget.TextView;

import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.internal.util.pie.PiePosition;
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
@@ -106,7 +107,6 @@ import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
import com.android.systemui.statusbar.policy.OnSizeChangedListener;
import com.android.systemui.statusbar.policy.Prefs;
import com.android.systemui.statusbar.policy.PieController.Position;
import com.android.systemui.statusbar.powerwidget.PowerWidget;

public class PhoneStatusBar extends BaseStatusBar {
@@ -1598,7 +1598,7 @@ public class PhoneStatusBar extends BaseStatusBar {
        }
        // don't allow expanding via e.g. service call while status bar is hidden
        // due to expanded desktop
        if (mExpandedDesktopState == 2) {
        if (getExpandedDesktopMode() == 2) {
            return;
        }

@@ -1670,7 +1670,7 @@ public class PhoneStatusBar extends BaseStatusBar {
        }
        // don't allow expanding via e.g. service call while status bar is hidden
        // due to expanded desktop
        if (mExpandedDesktopState == 2) {
        if (getExpandedDesktopMode() == 2) {
            return;
        }

@@ -2238,13 +2238,13 @@ public class PhoneStatusBar extends BaseStatusBar {
        // hide pie triggers when keyguard is visible
        try {
            if (mWindowManagerService.isKeyguardLocked()) {
                updatePieTriggerMask(Position.BOTTOM.FLAG
                        | Position.TOP.FLAG);
                updatePieTriggerMask(PiePosition.BOTTOM.FLAG
                        | PiePosition.TOP.FLAG);
            } else {
                updatePieTriggerMask(Position.LEFT.FLAG
                        | Position.BOTTOM.FLAG
                        | Position.RIGHT.FLAG
                        | Position.TOP.FLAG);
                updatePieTriggerMask(PiePosition.LEFT.FLAG
                        | PiePosition.BOTTOM.FLAG
                        | PiePosition.RIGHT.FLAG
                        | PiePosition.TOP.FLAG);
            }
        } catch (RemoteException e) {
            // nothing else to do ...
+9 −8
Original line number Diff line number Diff line
@@ -26,8 +26,9 @@ import android.util.Slog;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;

import com.android.internal.util.pie.PiePosition;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.PieController.Position;

public class PhoneStatusBarView extends PanelBar {
    private static final String TAG = "PhoneStatusBarView";
@@ -167,10 +168,10 @@ public class PhoneStatusBarView extends PanelBar {
        mLastFullyOpenedPanel = null;

        // show up you pie controls
        mBar.updatePieTriggerMask(Position.LEFT.FLAG
                | Position.TOP.FLAG
                | Position.RIGHT.FLAG
                | Position.TOP.FLAG);
        mBar.updatePieTriggerMask(PiePosition.LEFT.FLAG
                | PiePosition.TOP.FLAG
                | PiePosition.RIGHT.FLAG
                | PiePosition.TOP.FLAG);
    }

    @Override
@@ -182,9 +183,9 @@ public class PhoneStatusBarView extends PanelBar {

        // back off you pie controls!
        if (mShouldFade) {
            mBar.updatePieTriggerMask(Position.LEFT.FLAG
                    | Position.RIGHT.FLAG
                    | Position.TOP.FLAG);
            mBar.updatePieTriggerMask(PiePosition.LEFT.FLAG
                    | PiePosition.RIGHT.FLAG
                    | PiePosition.TOP.FLAG);
        }

        mFadingPanel = openPanel;
+10 −10
Original line number Diff line number Diff line
@@ -28,9 +28,9 @@ import android.graphics.PorterDuff.Mode;
import android.view.View;
import android.widget.ImageView;

import com.android.internal.util.pie.PiePosition;
import com.android.systemui.R;
import com.android.systemui.statusbar.pie.PieLayout.PieDrawable;
import com.android.systemui.statusbar.policy.PieController.Position;
import com.android.systemui.statusbar.pie.PieView.PieDrawable;

/**
 * A clickable pie menu item.
@@ -38,9 +38,9 @@ import com.android.systemui.statusbar.policy.PieController.Position;
 * This is the actual end point for user interaction.<br>
 * ( == This is what a user clicks on.)
 */
public class PieItem extends PieLayout.PieDrawable {
public class PieItem extends PieView.PieDrawable {

    private PieLayout mPieLayout;
    private PieView mPieLayout;

    private Paint mBackgroundPaint = new Paint();
    private Paint mSelectedPaint = new Paint();
@@ -87,7 +87,7 @@ public class PieItem extends PieLayout.PieDrawable {
     */
    public final static int CAN_LONG_PRESS = 0x400;

    public PieItem(Context context, PieLayout parent, int flags, int width, Object tag, View view) {
    public PieItem(Context context, PieView parent, int flags, int width, Object tag, View view) {
        mView = view;
        mPieLayout = parent;
        this.tag = tag;
@@ -129,9 +129,9 @@ public class PieItem extends PieLayout.PieDrawable {

    public void show(boolean show) {
        if (show) {
            flags |= PieLayout.PieDrawable.VISIBLE;
            flags |= PieView.PieDrawable.VISIBLE;
        } else {
            flags &= ~PieLayout.PieDrawable.VISIBLE;
            flags &= ~PieView.PieDrawable.VISIBLE;
        }
    }

@@ -168,7 +168,7 @@ public class PieItem extends PieLayout.PieDrawable {
    }

    @Override
    public void prepare(Position position, float scale) {
    public void prepare(PiePosition position, float scale) {
        mPath = getOutline(scale);
        if (mView != null) {
            mView.measure(mView.getLayoutParams().width, mView.getLayoutParams().height);
@@ -188,7 +188,7 @@ public class PieItem extends PieLayout.PieDrawable {
    }

    @Override
    public void draw(Canvas canvas, Position position) {
    public void draw(Canvas canvas, PiePosition position) {
        if ((flags & SELECTED) != 0) {
            Paint paint = (flags & LONG_PRESSED) == 0
                    ? mSelectedPaint : mLongPressPaint;
@@ -202,7 +202,7 @@ public class PieItem extends PieLayout.PieDrawable {
            int state = canvas.save();
            canvas.translate(mView.getLeft(), mView.getTop());
            // keep icons "upright" if we get displayed on TOP position
            if (position != Position.TOP) {
            if (position != PiePosition.TOP) {
                canvas.rotate(mStart + mSweep / 2 - 270);
            } else {
                canvas.rotate(mStart + mSweep / 2 - 90);
Loading