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

Commit 4ed6fd0c authored by Danny Baumann's avatar Danny Baumann Committed by Gerrit Code Review
Browse files

Merge "Pie controls: Catching activation corner cases" into cm-10.1

parents d7b4e94d 4e88ae90
Loading
Loading
Loading
Loading
+58 −42
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
    private Context mContext;
    private PieManager mPieManager;
    private PieView mPieContainer;
    private boolean mIsDetaching = false;
    /**
     * This is only needed for #toggleRecentApps() and #showSearchPanel()
     */
@@ -143,12 +144,12 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
                // restore listener state immediately (after the bookkeeping), and since the
                // search panel is a single gesture we will not trigger again
                mHandler.obtainMessage(MSG_PIE_RESTORE_LISTENER_STATE).sendToTarget();
            } else if (mPieContainer != null) {
                // set the snap points depending on current trigger and mask
                mPieContainer.setSnapPoints(mPieTriggerMask & ~mPieTriggerSlots);
                activateFromListener(touchX, touchY, position);
            } else if (mPieContainer != null && activateFromListener(touchX, touchY, position)) {
                // give the main thread some time to do the bookkeeping
                mHandler.obtainMessage(MSG_PIE_GAIN_FOCUS).sendToTarget();
            } else {
                // if anything goes wrong, just quit the ongoing activation
                mPieActivationListener.restoreListenerState();
            }
        }
    };
@@ -166,9 +167,13 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
                            InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
                    break;
                case MSG_PIE_GAIN_FOCUS:
                    if (mPieContainer != null) {
                        if (!mPieActivationListener.gainTouchFocus(mPieContainer.getWindowToken())) {
                            mPieContainer.exit();
                        }
                    } else {
                        mPieActivationListener.restoreListenerState();
                    }
                    break;
                case MSG_PIE_RESTORE_LISTENER_STATE:
                    mPieActivationListener.restoreListenerState();
@@ -235,8 +240,11 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
                setupContainer();
                setupNavigationItems();
                setupListener();
            } else {
            } else if (!isShowing()) {
                detachContainer();
            } else {
                // delay detach to #onExit()
                mIsDetaching = true;
            }
        }
    }
@@ -292,23 +300,6 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
        mSettingsObserver.onChange(true);
    }

    private void detachContainer() {
        if (mPieContainer == null) {
            return;
        }

        mPieManager.updatePieActivationListener(mPieActivationListener, 0);

        if (mTelephonyManager != null) {
            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
        }

        mContext.unregisterReceiver(mBroadcastReceiver);

        mPieContainer.clearSlices();
        mPieContainer = null;
    }

    public void attachStatusBar(BaseStatusBar statusBar) {
        mStatusBar = statusBar;
    }
@@ -349,6 +340,33 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
        mPieContainer.addSlice(mSysInfo);
    }

    @Override
    public void onExit() {
        mWindowManager.removeView(mPieContainer);
        mPieActivationListener.restoreListenerState();
        if (mIsDetaching) {
            detachContainer();
            mIsDetaching = false;
        }
    }

    private void detachContainer() {
        if (mPieContainer == null) {
            return;
        }

        mPieManager.updatePieActivationListener(mPieActivationListener, 0);

        if (mTelephonyManager != null) {
            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
        }

        mContext.unregisterReceiver(mBroadcastReceiver);

        mPieContainer.clearSlices();
        mPieContainer = null;
    }

    private void setupListener() {
        ContentResolver resolver = mContext.getContentResolver();

@@ -424,7 +442,6 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
                return item;
            }
        }

        return null;
    }

@@ -435,15 +452,20 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
        }
    }

    public void activateFromListener(int touchX, int touchY, PiePosition position) {
        if (!isShowing()) {
    public boolean activateFromListener(int touchX, int touchY, PiePosition position) {
        if (isShowing()) {
            return false;
        }

        doHapticTriggerFeedback();

        mPosition = position;
        Point center = new Point(touchX, touchY);
        mPieContainer.setSnapPoints(mPieTriggerMask & ~mPieTriggerSlots);
        mPieContainer.activate(center, position);
        mWindowManager.addView(mPieContainer, generateLayoutParam());
        }

        return true;
    }

    private WindowManager.LayoutParams generateLayoutParam() {
@@ -464,18 +486,12 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
        return lp;
    }

    @Override
    public void onExit() {
        mWindowManager.removeView(mPieContainer);
        mPieActivationListener.restoreListenerState();
    }

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

        // first we check, if it would make a change
        if ((mPieTriggerSlots & mPieTriggerMask) != oldState) {
        // check if we are active and if it would make a change at all
        if (mPieContainer != null && ((mPieTriggerSlots & mPieTriggerMask) != oldState)) {
            setupListener();
        }
    }
@@ -669,7 +685,7 @@ public class PieController implements BaseStatusBar.NavigationBarCallback, PieVi
    }

    public boolean isShowing() {
        return mPieContainer.isShowing();
        return mPieContainer != null && mPieContainer.isShowing();
    }

    public boolean isSearchLightEnabled() {
+12 −11
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ import java.io.PrintWriter;
 * 5) POSTSYNTHESIZE:
 *    mSyntheticDownTime != -1
 *    All following events will have the down time set to the synthesized ACTION_DOWN event time
 *    until an ACTION_UP is encountered and the state is reset to LISTEN.
 *    until an ACTION_UP or ACTION_CANCEL is encountered and the state is reset to LISTEN.
 * <p>
 * If you are reading this within Java Doc, you are doing something wrong ;)
 */
@@ -81,7 +81,7 @@ public class PieInputFilter implements IInputFilter {
    private static final boolean DEBUG = false;
    private static final boolean DEBUG_INPUT = false;
    // TODO: Should be turned off in final commit
    private static final boolean SYSTRACE = true;
    private static final boolean SYSTRACE = false;

    private final Handler mHandler;

@@ -174,6 +174,7 @@ public class PieInputFilter implements IInputFilter {
                res.getDimensionPixelSize(R.dimen.pie_perpendicular_distance));
        mTracker.setOnActivationListener(new OnActivationListener() {
            public void onActivation(MotionEvent event, int touchX, int touchY, PiePosition position) {
                // mLock is held by #processMotionEvent
                mHandler.obtainMessage(PieService.MSG_PIE_ACTIVATION,
                        touchX, touchY, position).sendToTarget();
                mState = State.LOCKED;
@@ -307,7 +308,7 @@ public class PieInputFilter implements IInputFilter {
                case SYNTHESIZE:
                    if (action == MotionEvent.ACTION_MOVE) {
                        clearDelayedMotionEventsLocked();
                        sendSynthesizedMotionEvent(motionEvent, policyFlags);
                        sendSynthesizedMotionEventLocked(motionEvent, policyFlags);
                        mState = State.POSTSYNTHESIZE;
                    } else {
                        // This is the case where a race condition caught us: We already
@@ -319,7 +320,7 @@ public class PieInputFilter implements IInputFilter {
                    break;
                case POSTSYNTHESIZE:
                    motionEvent.setDownTime(mSyntheticDownTime);
                    if (action == MotionEvent.ACTION_UP) {
                    if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                        mState = State.LISTEN;
                        mSyntheticDownTime = -1;
                    }
@@ -396,7 +397,7 @@ public class PieInputFilter implements IInputFilter {
                if (info.event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                    mSyntheticDownTime = info.event.getDownTime() + offset;
                }
                sendMotionEventWithOffset(info.event, info.policyFlags, mSyntheticDownTime, offset);
                sendMotionEventWithOffsetLocked(info.event, info.policyFlags, mSyntheticDownTime, offset);
                if (info.event.getActionMasked() == MotionEvent.ACTION_UP) {
                    mSyntheticDownTime = -1;
                }
@@ -421,11 +422,11 @@ public class PieInputFilter implements IInputFilter {
        }
    }

    private void sendMotionEventWithOffset(MotionEvent event, int policyFlags,
    private void sendMotionEventWithOffsetLocked(MotionEvent event, int policyFlags,
            long downTime, long offset) {
        final int pointerCount = event.getPointerCount();
        PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
        PointerProperties[] properties = getTempPointerPropertiesWithMinSize(pointerCount);
        PointerCoords[] coords = getTempPointerCoordsWithMinSizeLocked(pointerCount);
        PointerProperties[] properties = getTempPointerPropertiesWithMinSizeLocked(pointerCount);
        for (int i = 0; i < pointerCount; i++) {
            event.getPointerCoords(i, coords[i]);
            event.getPointerProperties(i, properties[i]);
@@ -437,7 +438,7 @@ public class PieInputFilter implements IInputFilter {
                policyFlags);
    }

    private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
    private PointerCoords[] getTempPointerCoordsWithMinSizeLocked(int size) {
        final int oldSize = mTempPointerCoords.length;
        if (oldSize < size) {
            PointerCoords[] oldTempPointerCoords = mTempPointerCoords;
@@ -450,7 +451,7 @@ public class PieInputFilter implements IInputFilter {
        return mTempPointerCoords;
    }

    private PointerProperties[] getTempPointerPropertiesWithMinSize(int size) {
    private PointerProperties[] getTempPointerPropertiesWithMinSizeLocked(int size) {
        final int oldSize = mTempPointerProperties.length;
        if (oldSize < size) {
            PointerProperties[] oldTempPointerProperties = mTempPointerProperties;
@@ -463,7 +464,7 @@ public class PieInputFilter implements IInputFilter {
        return mTempPointerProperties;
    }

    private void sendSynthesizedMotionEvent(MotionEvent event, int policyFlags) {
    private void sendSynthesizedMotionEventLocked(MotionEvent event, int policyFlags) {
        if (event.getPointerCount() == 1) {
            event.getPointerCoords(0, mTempPointerCoords[0]);
            event.getPointerProperties(0, mTempPointerProperties[0]);
+93 −103
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@ import android.service.pie.IPieService;
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.View;
import android.view.WindowManager;

import com.android.internal.util.pie.PiePosition;
@@ -69,18 +68,16 @@ public class PieService extends IPieService.Stub {

    private final Context mContext;
    private final InputManagerService mInputManager;
    private final WindowManagerService mWindowManager;

    private HandlerThread mHandlerThread = new HandlerThread("Pie");
    private final HandlerThread mHandlerThread = new HandlerThread("Pie");
    private Handler mHandler;

    // Lock for thread, handler, mInputFilter, activations and listener related variables
    // Lock for mInputFilter, activations and listener related variables
    private final Object mLock = new Object();
    private Handler mHandler;
    private PieInputFilter mInputFilter;

    private int mGlobalPositions = 0;
    private int mGlobalSensitivity = 3;
    private boolean mIsMonitoring = false;

    private final class PieActivationListenerRecord extends IPieHostCallback.Stub implements DeathRecipient {
        private boolean mActive;
@@ -94,16 +91,16 @@ public class PieService extends IPieService.Stub {
            removeListenerRecord(this);
        }

        public void updateFlags(int flags) {
        private void updateFlags(int flags) {
            this.positions = flags & POSITION_MASK;
            this.sensitivity = (flags & SENSITIVITY_MASK) >> SENSITIVITY_SHIFT;
        }

        public boolean eligibleForActivation(int positionFlag) {
        private boolean eligibleForActivation(int positionFlag) {
            return (positions & positionFlag) != 0;
        }

        public boolean notifyPieActivation(int touchX, int touchY, PiePosition position) {
        private boolean notifyPieActivation(int touchX, int touchY, PiePosition position) {
            if ((positions & position.FLAG) != 0) {
                try {
                    listener.onPieActivation(touchX, touchY, position.INDEX, 0);
@@ -167,7 +164,6 @@ public class PieService extends IPieService.Stub {
    public PieService(Context context, WindowManagerService windowManager, InputManagerService inputManager) {
        mContext = context;
        mInputManager = inputManager;
        mWindowManager = windowManager;
    }

    // called by system server
@@ -186,19 +182,41 @@ public class PieService extends IPieService.Stub {
        });
        mDisplayObserver = new DisplayObserver(mContext, mHandler);
        // check if anyone registered during startup
        updateMonitoring();
        mHandler.obtainMessage(MSG_UPDATE_SERVICE,
                mGlobalPositions, mGlobalSensitivity).sendToTarget();
        updateMonitoring();
    }


    private void updateMonitoring() {
        synchronized(mLock) {
            mGlobalPositions = 0;
            mGlobalSensitivity = SENSITIVITY_NONE;
            for (PieActivationListenerRecord temp : mPieActivationListener) {
                mGlobalPositions |= temp.positions;
                if (temp.sensitivity != SENSITIVITY_NONE) {
                    mGlobalSensitivity = Math.max(mGlobalSensitivity, temp.sensitivity);
                }
            }
            // if no special sensitivity is requested, we settle on DEFAULT
            if (mGlobalSensitivity == SENSITIVITY_NONE) {
                mGlobalSensitivity = SENSITIVITY_DEFAULT;
            }

            if (mInputFilter == null && mGlobalPositions != 0) {
                enforceMonitoringLocked();
            } else if (mInputFilter != null && mGlobalPositions == 0) {
                shutdownMonitoringLocked();
            }
        }
    }

    private void enforceMonitoringLocked() {
        if (DEBUG) {
            Slog.d(TAG, "Attempting to start monitoring input events ...");
        }
        if (mInputFilter == null) {
        mInputFilter = new PieInputFilter(mContext, mHandler);
        mInputManager.registerSecondaryInputFilter(mInputFilter);
        }
        mDisplayObserver.observe();
    }

@@ -207,22 +225,9 @@ public class PieService extends IPieService.Stub {
            Slog.d(TAG, "Shutting down monitoring input events ...");
        }
        mDisplayObserver.unobserve();
        if (mInputFilter != null) {
        mInputManager.unregisterSecondaryInputFilter(mInputFilter);
        mInputFilter = null;
    }
    }

    private void updateMonitoring() {
        synchronized(mLock) {
            if (!mIsMonitoring && mGlobalPositions != 0) {
                enforceMonitoringLocked();
            } else if (mIsMonitoring && mGlobalPositions == 0) {
                shutdownMonitoringLocked();
            }
            mIsMonitoring = mGlobalPositions != 0;
        }
    }

    // called through Binder
    public IPieHostCallback registerPieActivationListener(IPieActivationListener listener) {
@@ -242,6 +247,12 @@ public class PieService extends IPieService.Stub {
            record = findListenerRecordLocked(listener.asBinder());
            if (record == null) {
                record = new PieActivationListenerRecord(listener);
                try {
                    listener.asBinder().linkToDeath(record, 0);
                } catch (RemoteException e) {
                    Slog.w(TAG, "Recipient died during registration pid=" + Binder.getCallingPid());
                    return null;
                }
                mPieActivationListener.add(record);
            }
        }
@@ -260,14 +271,13 @@ public class PieService extends IPieService.Stub {
                throw new IllegalStateException("listener not registered");
            }
            record.updateFlags(positionFlags);
            updatePositionsLocked();
            updateSensitivityLocked();
            updateMonitoring();
            // update input filter only when not being active and #systemReady() was called
            if (mActiveRecord == null && mHandler != null) {
                mHandler.obtainMessage(MSG_UPDATE_SERVICE,
                        mGlobalPositions, mGlobalSensitivity).sendToTarget();
            }
        }
        updateMonitoring();
    }

    private PieActivationListenerRecord findListenerRecordLocked(IBinder listener) {
@@ -279,38 +289,18 @@ public class PieService extends IPieService.Stub {
        return null;
    }

    private void updatePositionsLocked() {
        mGlobalPositions = 0;
        for (PieActivationListenerRecord temp : mPieActivationListener) {
            mGlobalPositions |= temp.positions;
        }
    }

    private void updateSensitivityLocked() {
        mGlobalSensitivity = SENSITIVITY_NONE;
        for (PieActivationListenerRecord temp : mPieActivationListener) {
            if (temp.sensitivity != SENSITIVITY_NONE) {
                mGlobalSensitivity = Math.max(mGlobalSensitivity, temp.sensitivity);
            }
        }
        // if no special sensitivity is requested, we settle on DEFAULT
        if (mGlobalSensitivity == SENSITIVITY_NONE) {
            mGlobalSensitivity = SENSITIVITY_DEFAULT;
        }
    }

    private void removeListenerRecord(PieActivationListenerRecord record) {
        synchronized(mLock) {
            mPieActivationListener.remove(record);
            updatePositionsLocked();
            updateMonitoring();
            // check if the record was the active one
            if (record == mActiveRecord) {
                // restore input filter state by updating
                mHandler.obtainMessage(MSG_UPDATE_SERVICE,
                        mGlobalPositions, mGlobalSensitivity).sendToTarget();
                mActiveRecord = null;
            }
        }
        updateMonitoring();
    }

    // called by handler thread
@@ -333,55 +323,8 @@ public class PieService extends IPieService.Stub {
            if (target != null && target.notifyPieActivation(touchX, touchY, position)) {
                mActiveRecord = target;
            }
        }
            return mActiveRecord != null;
        }

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        try {
            return super.onTransact(code, data, reply, flags);
        } catch (RuntimeException e) {
            // let's log all exceptions we do not know about.
            if (!(e instanceof IllegalArgumentException || e instanceof IllegalStateException)) {
                Slog.e(TAG, "PieService crashed: ", e);
            }
            throw e;
        }
    }

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
            pw.println("Permission Denial: can't dump PieService from from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid());
            return;
        }

        pw.println("PIE SERVICE (dumpsys pieservice)\n");
        synchronized(mLock) {
            pw.println("  mIsMonitoring=" + mIsMonitoring);
            pw.println("  mInputFilter=" + mInputFilter);
            if (mInputFilter != null) {
                mInputFilter.dump(pw, "    ");
            }
            pw.println("  mGlobalPositions=0x" + Integer.toHexString(mGlobalPositions));
            int i = 0;
            for (PieActivationListenerRecord record : mPieActivationListener) {
                if (record == mActiveRecord) break;
                i++;
            }
            pw.println("  mActiveRecord=" + (mActiveRecord != null ? ("#" + i) : "null"));
            i = 0;
            for (PieActivationListenerRecord record : mPieActivationListener) {
                pw.println("  Listener #" + i + ":");
                record.dump(pw, "    ");
                i++;
            }
        }
    }

    private final class H extends Handler {
@@ -481,4 +424,51 @@ public class PieService extends IPieService.Stub {
            updateDisplayInfo();
        }
    }

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        try {
            return super.onTransact(code, data, reply, flags);
        } catch (RuntimeException e) {
            // let's log all exceptions we do not know about.
            if (!(e instanceof IllegalArgumentException || e instanceof IllegalStateException)) {
                Slog.e(TAG, "PieService crashed: ", e);
            }
            throw e;
        }
    }

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
            pw.println("Permission Denial: can't dump PieService from from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid());
            return;
        }

        pw.println("PIE SERVICE (dumpsys pieservice)\n");
        synchronized(mLock) {
            pw.println("  mInputFilter=" + mInputFilter);
            if (mInputFilter != null) {
                mInputFilter.dump(pw, "    ");
            }
            pw.println("  mGlobalPositions=0x" + Integer.toHexString(mGlobalPositions));
            pw.println("  mGlobalSensitivity=" + mGlobalSensitivity);
            int i = 0;
            for (PieActivationListenerRecord record : mPieActivationListener) {
                if (record == mActiveRecord) break;
                i++;
            }
            pw.println("  mActiveRecord=" + (mActiveRecord != null ? ("#" + i) : "null"));
            i = 0;
            for (PieActivationListenerRecord record : mPieActivationListener) {
                pw.println("  Listener #" + i + ":");
                record.dump(pw, "    ");
                i++;
            }
        }
    }
}