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

Commit 3c7ecee1 authored by Miranda Kephart's avatar Miranda Kephart
Browse files

Fix screenshot swipe dismiss logs

Currently we log a "swipe dismiss" event whenever we animate to the
side, even if it wasn't caused by a swipe -- e.g. if the UI times
out, we log both a "timeout" and a "swipe dismiss" event. This
change fixes the logging logic so that we only log swipe dismiss
if it was caused by a swipe/fling, as well as adding a couple
of missing dismissal logs in edge cases.

Bug: 252823661
Test: atest DraggableConstraintLayoutTest

Change-Id: I437de637e606f4d2fe806ca6dd6a397b4ca372c6
parent 354ad8b4
Loading
Loading
Loading
Loading
+21 −13
Original line number Original line Diff line number Diff line
@@ -49,7 +49,6 @@ public class DraggableConstraintLayout extends ConstraintLayout
    private final SwipeDismissHandler mSwipeDismissHandler;
    private final SwipeDismissHandler mSwipeDismissHandler;
    private final GestureDetector mSwipeDetector;
    private final GestureDetector mSwipeDetector;
    private View mActionsContainer;
    private View mActionsContainer;
    private View mActionsContainerBackground;
    private SwipeDismissCallbacks mCallbacks;
    private SwipeDismissCallbacks mCallbacks;
    private final DisplayMetrics mDisplayMetrics;
    private final DisplayMetrics mDisplayMetrics;


@@ -111,6 +110,9 @@ public class DraggableConstraintLayout extends ConstraintLayout
                    }
                    }
                });
                });
        mSwipeDetector.setIsLongpressEnabled(false);
        mSwipeDetector.setIsLongpressEnabled(false);

        mCallbacks = new SwipeDismissCallbacks() {
        }; // default to unimplemented callbacks
    }
    }


    public void setCallbacks(SwipeDismissCallbacks callbacks) {
    public void setCallbacks(SwipeDismissCallbacks callbacks) {
@@ -119,16 +121,13 @@ public class DraggableConstraintLayout extends ConstraintLayout


    @Override
    @Override
    public boolean onInterceptHoverEvent(MotionEvent event) {
    public boolean onInterceptHoverEvent(MotionEvent event) {
        if (mCallbacks != null) {
        mCallbacks.onInteraction();
        mCallbacks.onInteraction();
        }
        return super.onInterceptHoverEvent(event);
        return super.onInterceptHoverEvent(event);
    }
    }


    @Override // View
    @Override // View
    protected void onFinishInflate() {
    protected void onFinishInflate() {
        mActionsContainer = findViewById(R.id.actions_container);
        mActionsContainer = findViewById(R.id.actions_container);
        mActionsContainerBackground = findViewById(R.id.actions_container_background);
    }
    }


    @Override
    @Override
@@ -186,6 +185,13 @@ public class DraggableConstraintLayout extends ConstraintLayout
        inoutInfo.touchableRegion.set(r);
        inoutInfo.touchableRegion.set(r);
    }
    }


    private int getBackgroundRight() {
        // background expected to be null in testing.
        // animation may have unexpected behavior if view is not present
        View background = findViewById(R.id.actions_container_background);
        return background == null ? 0 : background.getRight();
    }

    /**
    /**
     * Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not
     * Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not
     * met
     * met
@@ -213,8 +219,6 @@ public class DraggableConstraintLayout extends ConstraintLayout
            mGestureDetector = new GestureDetector(context, gestureListener);
            mGestureDetector = new GestureDetector(context, gestureListener);
            mDisplayMetrics = new DisplayMetrics();
            mDisplayMetrics = new DisplayMetrics();
            context.getDisplay().getRealMetrics(mDisplayMetrics);
            context.getDisplay().getRealMetrics(mDisplayMetrics);
            mCallbacks = new SwipeDismissCallbacks() {
            }; // default to unimplemented callbacks
        }
        }


        @Override
        @Override
@@ -230,7 +234,9 @@ public class DraggableConstraintLayout extends ConstraintLayout
                    return true;
                    return true;
                }
                }
                if (isPastDismissThreshold()) {
                if (isPastDismissThreshold()) {
                    dismiss();
                    ValueAnimator anim = createSwipeDismissAnimation();
                    mCallbacks.onSwipeDismissInitiated(anim);
                    dismiss(anim);
                } else {
                } else {
                    // if we've moved, but not past the threshold, start the return animation
                    // if we've moved, but not past the threshold, start the return animation
                    if (DEBUG_DISMISS) {
                    if (DEBUG_DISMISS) {
@@ -295,10 +301,7 @@ public class DraggableConstraintLayout extends ConstraintLayout
        }
        }


        void dismiss() {
        void dismiss() {
            float velocityPxPerMs = FloatingWindowUtil.dpToPx(mDisplayMetrics, VELOCITY_DP_PER_MS);
            dismiss(createSwipeDismissAnimation());
            ValueAnimator anim = createSwipeDismissAnimation(velocityPxPerMs);
            mCallbacks.onSwipeDismissInitiated(anim);
            dismiss(anim);
        }
        }


        private void dismiss(ValueAnimator animator) {
        private void dismiss(ValueAnimator animator) {
@@ -323,6 +326,11 @@ public class DraggableConstraintLayout extends ConstraintLayout
            mDismissAnimation.start();
            mDismissAnimation.start();
        }
        }


        private ValueAnimator createSwipeDismissAnimation() {
            float velocityPxPerMs = FloatingWindowUtil.dpToPx(mDisplayMetrics, VELOCITY_DP_PER_MS);
            return createSwipeDismissAnimation(velocityPxPerMs);
        }

        private ValueAnimator createSwipeDismissAnimation(float velocity) {
        private ValueAnimator createSwipeDismissAnimation(float velocity) {
            // velocity is measured in pixels per millisecond
            // velocity is measured in pixels per millisecond
            velocity = Math.min(3, Math.max(1, velocity));
            velocity = Math.min(3, Math.max(1, velocity));
@@ -337,7 +345,7 @@ public class DraggableConstraintLayout extends ConstraintLayout
            if (startX > 0 || (startX == 0 && layoutDir == LAYOUT_DIRECTION_RTL)) {
            if (startX > 0 || (startX == 0 && layoutDir == LAYOUT_DIRECTION_RTL)) {
                finalX = mDisplayMetrics.widthPixels;
                finalX = mDisplayMetrics.widthPixels;
            } else {
            } else {
                finalX = -1 * mActionsContainerBackground.getRight();
                finalX = -1 * getBackgroundRight();
            }
            }
            float distance = Math.abs(finalX - startX);
            float distance = Math.abs(finalX - startX);


+9 −15
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import static com.android.systemui.screenshot.LogConfig.DEBUG_UI;
import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
import static com.android.systemui.screenshot.LogConfig.logTag;
import static com.android.systemui.screenshot.LogConfig.logTag;
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER;
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER;
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT;


import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNull;


@@ -322,9 +323,7 @@ public class ScreenshotController {
            if (DEBUG_UI) {
            if (DEBUG_UI) {
                Log.d(TAG, "Corner timeout hit");
                Log.d(TAG, "Corner timeout hit");
            }
            }
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT, 0,
            dismissScreenshot(SCREENSHOT_INTERACTION_TIMEOUT);
                    mPackageName);
            ScreenshotController.this.dismissScreenshot(false);
        });
        });


        mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
        mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
@@ -351,8 +350,7 @@ public class ScreenshotController {
            @Override
            @Override
            public void onReceive(Context context, Intent intent) {
            public void onReceive(Context context, Intent intent) {
                if (ClipboardOverlayController.COPY_OVERLAY_ACTION.equals(intent.getAction())) {
                if (ClipboardOverlayController.COPY_OVERLAY_ACTION.equals(intent.getAction())) {
                    mUiEventLogger.log(SCREENSHOT_DISMISSED_OTHER);
                    dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
                    dismissScreenshot(false);
                }
                }
            }
            }
        };
        };
@@ -419,25 +417,21 @@ public class ScreenshotController {
    /**
    /**
     * Clears current screenshot
     * Clears current screenshot
     */
     */
    void dismissScreenshot(boolean immediate) {
    void dismissScreenshot(ScreenshotEvent event) {
        if (DEBUG_DISMISS) {
        if (DEBUG_DISMISS) {
            Log.d(TAG, "dismissScreenshot(immediate=" + immediate + ")");
            Log.d(TAG, "dismissScreenshot");
        }
        }
        // If we're already animating out, don't restart the animation
        // If we're already animating out, don't restart the animation
        // (but do obey an immediate dismissal)
        if (mScreenshotView.isDismissing()) {
        if (!immediate && mScreenshotView.isDismissing()) {
            if (DEBUG_DISMISS) {
            if (DEBUG_DISMISS) {
                Log.v(TAG, "Already dismissing, ignoring duplicate command");
                Log.v(TAG, "Already dismissing, ignoring duplicate command");
            }
            }
            return;
            return;
        }
        }
        mUiEventLogger.log(event, 0, mPackageName);
        mScreenshotHandler.cancelTimeout();
        mScreenshotHandler.cancelTimeout();
        if (immediate) {
            finishDismiss();
        } else {
        mScreenshotView.animateDismissal();
        mScreenshotView.animateDismissal();
    }
    }
    }


    boolean isPendingSharedTransition() {
    boolean isPendingSharedTransition() {
        return mScreenshotView.isPendingSharedTransition();
        return mScreenshotView.isPendingSharedTransition();
@@ -509,7 +503,7 @@ public class ScreenshotController {
                if (DEBUG_INPUT) {
                if (DEBUG_INPUT) {
                    Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK");
                    Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK");
                }
                }
                dismissScreenshot(false);
                dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
                return true;
                return true;
            }
            }
            return false;
            return false;
+1 −2
Original line number Original line Diff line number Diff line
@@ -89,8 +89,7 @@ public class TakeScreenshotService extends Service {
                    Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
                    Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
                }
                }
                if (!mScreenshot.isPendingSharedTransition()) {
                if (!mScreenshot.isPendingSharedTransition()) {
                    mUiEventLogger.log(SCREENSHOT_DISMISSED_OTHER);
                    mScreenshot.dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
                    mScreenshot.dismissScreenshot(false);
                }
                }
            }
            }
        }
        }
+81 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 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.screenshot;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class DraggableConstraintLayoutTest extends SysuiTestCase {

    @Mock
    DraggableConstraintLayout.SwipeDismissCallbacks mCallbacks;

    private DraggableConstraintLayout mDraggableConstraintLayout;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mDraggableConstraintLayout = new DraggableConstraintLayout(mContext, null, 0);
    }

    @Test
    public void test_dismissDoesNotCallSwipeInitiated() {
        mDraggableConstraintLayout.setCallbacks(mCallbacks);

        mDraggableConstraintLayout.dismiss();

        verify(mCallbacks, never()).onSwipeDismissInitiated(any());
    }

    @Test
    public void test_onTouchCallsOnInteraction() {
        mDraggableConstraintLayout.setCallbacks(mCallbacks);

        mDraggableConstraintLayout.onInterceptTouchEvent(
                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));

        verify(mCallbacks).onInteraction();
    }

    @Test
    public void test_callbacksNotSet() {
        // just test that it doesn't throw an NPE
        mDraggableConstraintLayout.onInterceptTouchEvent(
                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
        mDraggableConstraintLayout.onInterceptHoverEvent(
                MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0));
        mDraggableConstraintLayout.dismiss();
    }
}