Loading quickstep/recents_ui_overrides/res/layout/proactive_hints_container.xmldeleted 100644 → 0 +0 −7 Original line number Diff line number Diff line <com.android.quickstep.hints.ProactiveHintsContainer xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|bottom" android:gravity="center_horizontal"> </com.android.quickstep.hints.ProactiveHintsContainer> No newline at end of file quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +6 −9 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.KeyguardManager; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading Loading @@ -234,7 +233,6 @@ public class TouchInteractionService extends Service implements private final InputConsumer mResetGestureInputConsumer = new ResetGestureInputConsumer(mSwipeSharedState); private KeyguardManager mKM; private ActivityManagerWrapper mAM; private RecentsModel mRecentsModel; private ISystemUiProxy mISystemUiProxy; Loading Loading @@ -280,7 +278,6 @@ public class TouchInteractionService extends Service implements // Initialize anything here that is needed in direct boot mode. // Everything else should be initialized in initWhenUserUnlocked() below. mKM = getSystemService(KeyguardManager.class); mMainChoreographer = Choreographer.getInstance(); mAM = ActivityManagerWrapper.getInstance(); Loading Loading @@ -547,6 +544,10 @@ public class TouchInteractionService extends Service implements (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base, mInputMonitorCompat, mSwipeTouchRegion); } } else { if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) { base = mResetGestureInputConsumer; } } return base; } Loading @@ -556,11 +557,8 @@ public class TouchInteractionService extends Service implements if (!useSharedState) { mSwipeSharedState.clearAllState(); } if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0 || mKM.isDeviceLocked()) { // This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched // while device is locked after exiting direct boot mode (e.g. camera), or if the // app is showing over the lockscreen (even if not locked) if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) { // This handles apps showing over the lockscreen (e.g. camera) return createDeviceLockedInputConsumer(runningTaskInfo); } Loading Loading @@ -665,7 +663,6 @@ public class TouchInteractionService extends Service implements pw.println(" systemUiFlags=" + mSystemUiStateFlags); pw.println(" systemUiFlagsDesc=" + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags)); pw.println(" isDeviceLocked=" + mKM.isDeviceLocked()); pw.println(" assistantAvailable=" + mAssistantAvailable); pw.println(" assistantDisabled=" + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)); Loading quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +31 −27 Original line number Diff line number Diff line Loading @@ -22,10 +22,9 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.INVALID_POINTER_ID; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_LANDSCAPE; import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE; import static com.android.launcher3.util.RaceConditionTracker.ENTER; import static com.android.launcher3.util.RaceConditionTracker.EXIT; import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; Loading @@ -45,10 +44,7 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; import androidx.annotation.UiThread; import com.android.launcher3.R; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.TraceHelper; Loading @@ -68,10 +64,11 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.BackgroundExecutor; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; import java.util.function.Consumer; import androidx.annotation.UiThread; /** * Input consumer for handling events originating from an activity other than Launcher */ Loading @@ -81,6 +78,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public static final String DOWN_EVT = "OtherActivityInputConsumer.DOWN"; private static final String UP_EVT = "OtherActivityInputConsumer.UP"; // TODO: Move to quickstep contract private static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final RunningTaskInfo mRunningTask; private final RecentsModel mRecentsModel; Loading @@ -107,14 +107,16 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private final PointF mLastPos = new PointF(); private int mActivePointerId = INVALID_POINTER_ID; private final float mDragSlop; // Distance after which we start dragging the window. private final float mTouchSlop; private final float mSquaredTouchSlop; private final boolean mDisableHorizontalSwipe; // Slop used to check when we start moving window. private boolean mPassedDragSlop; private boolean mPaddedWindowMoveSlop; // Slop used to determine when we say that the gesture has started. private boolean mPassedTouchSlop; private boolean mPassedPilferInputSlop; // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar. private float mStartDisplacement; Loading Loading @@ -156,12 +158,13 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mSwipeSharedState = swipeSharedState; mNavBarPosition = new NavBarPosition(base); mDragSlop = QuickStepContract.getQuickStepDragSlopPx(); float slop = QuickStepContract.getQuickStepTouchSlopPx(); mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop(); float slop = QUICKSTEP_TOUCH_SLOP_RATIO * mTouchSlop; mSquaredTouchSlop = slop * slop; mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture; mDisableHorizontalSwipe = !mPassedTouchSlop && disableHorizontalSwipe; mPassedPilferInputSlop = mPaddedWindowMoveSlop = continuingPreviousGesture; mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe; } @Override Loading @@ -183,7 +186,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } // Proxy events to recents view if (mPassedDragSlop && mInteractionHandler != null if (mPaddedWindowMoveSlop && mInteractionHandler != null && !mRecentsViewDispatcher.hasConsumer()) { mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher( mNavBarPosition.getRotationMode())); Loading Loading @@ -217,7 +220,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC break; } case ACTION_POINTER_DOWN: { if (!mPassedTouchSlop) { if (!mPassedPilferInputSlop) { // Cancel interaction in case of multi-touch interaction int ptrIdx = ev.getActionIndex(); if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) { Loading Loading @@ -248,18 +251,18 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC float displacement = getDisplacement(ev); float displacementX = mLastPos.x - mDownPos.x; if (!mPassedDragSlop) { if (!mPaddedWindowMoveSlop) { if (!mIsDeferredDownTarget) { // Normal gesture, ensure we pass the drag slop before we start tracking // the gesture if (Math.abs(displacement) > mDragSlop) { mPassedDragSlop = true; mStartDisplacement = displacement; if (Math.abs(displacement) > mTouchSlop) { mPaddedWindowMoveSlop = true; mStartDisplacement = Math.min(displacement, -mTouchSlop); } } } if (!mPassedTouchSlop) { if (!mPassedPilferInputSlop) { float displacementY = mLastPos.y - mDownPos.y; if (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop) { if (mDisableHorizontalSwipe Loading @@ -269,23 +272,24 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC break; } mPassedTouchSlop = true; mPassedPilferInputSlop = true; if (mIsDeferredDownTarget) { // Deferred gesture, start the animation and gesture tracking once // we pass the actual touch slop startTouchTrackingForWindowAnimation(ev.getEventTime()); } if (!mPassedDragSlop) { mPassedDragSlop = true; mStartDisplacement = displacement; if (!mPaddedWindowMoveSlop) { mPaddedWindowMoveSlop = true; mStartDisplacement = Math.min(displacement, -mTouchSlop); } notifyGestureStarted(); } } if (mInteractionHandler != null) { if (mPassedDragSlop) { if (mPaddedWindowMoveSlop) { // Move mInteractionHandler.updateDisplacement(displacement - mStartDisplacement); } Loading Loading @@ -362,7 +366,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC RaceConditionTracker.onEvent(UP_EVT, ENTER); TraceHelper.endSection("TouchInt"); if (mPassedDragSlop && mInteractionHandler != null) { if (mPaddedWindowMoveSlop && mInteractionHandler != null) { if (ev.getActionMasked() == ACTION_CANCEL) { mInteractionHandler.onGestureCancelled(); } else { Loading Loading @@ -448,6 +452,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC @Override public boolean allowInterceptByParent() { return !mPassedTouchSlop; return !mPassedPilferInputSlop; } } quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java +65 −40 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.quickstep.views; import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS; import static com.android.launcher3.Utilities.prefixTextWithIcon; import android.annotation.TargetApi; import android.app.ActivityOptions; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.AppUsageLimit; Loading @@ -28,16 +30,16 @@ import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; import android.icu.util.MeasureUnit; import android.os.Build; import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.StringRes; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.userevent.nano.LauncherLogProto; Loading @@ -46,45 +48,72 @@ import com.android.systemui.shared.recents.model.Task; import java.time.Duration; import java.util.Locale; public final class DigitalWellBeingToast extends LinearLayout { @TargetApi(Build.VERSION_CODES.Q) public final class DigitalWellBeingToast { static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS); static final int MINUTE_MS = 60000; private final LauncherApps mLauncherApps; public interface InitializeCallback { void call(String contentDescription); } private static final String TAG = DigitalWellBeingToast.class.getSimpleName(); private final BaseDraggingActivity mActivity; private final TaskView mTaskView; private final LauncherApps mLauncherApps; private Task mTask; private TextView mText; private boolean mHasLimit; private long mAppRemainingTimeMs; public DigitalWellBeingToast(Context context, AttributeSet attrs) { super(context, attrs); setLayoutDirection(Utilities.isRtl(getResources()) ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); setOnClickListener((view) -> openAppUsageSettings()); mLauncherApps = context.getSystemService(LauncherApps.class); public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) { mActivity = activity; mTaskView = taskView; mLauncherApps = activity.getSystemService(LauncherApps.class); } public TextView getTextView() { return mText; private void setTaskFooter(View view) { View oldFooter = mTaskView.setFooter(TaskView.INDEX_DIGITAL_WELLBEING_TOAST, view); if (oldFooter != null) { oldFooter.setOnClickListener(null); mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, oldFooter); } } @Override protected void onFinishInflate() { super.onFinishInflate(); private void setNoLimit() { mHasLimit = false; mTaskView.setContentDescription(mTask.titleDescription); setTaskFooter(null); mAppRemainingTimeMs = 0; } mText = findViewById(R.id.digital_well_being_remaining_time); private void setLimit(long appUsageLimitTimeMs, long appRemainingTimeMs) { mAppRemainingTimeMs = appRemainingTimeMs; mHasLimit = true; TextView toast = mActivity.getViewCache().getView(R.layout.digital_wellbeing_toast, mActivity, mTaskView); toast.setText(prefixTextWithIcon(mActivity, R.drawable.ic_hourglass_top, getText())); toast.setOnClickListener(this::openAppUsageSettings); setTaskFooter(toast); mTaskView.setContentDescription( getContentDescriptionForTask(mTask, appUsageLimitTimeMs, appRemainingTimeMs)); RecentsView rv = mTaskView.getRecentsView(); if (rv != null) { rv.onDigitalWellbeingToastShown(); } } public String getText() { return getText(mAppRemainingTimeMs); } public void initialize(Task task, InitializeCallback callback) { public boolean hasLimit() { return mHasLimit; } public void initialize(Task task) { mTask = task; if (task.key.userId != UserHandle.myUserId()) { setVisibility(GONE); callback.call(task.titleDescription); setNoLimit(); return; } Loading @@ -98,16 +127,12 @@ public final class DigitalWellBeingToast extends LinearLayout { final long appRemainingTimeMs = usageLimit != null ? usageLimit.getUsageRemaining() : -1; post(() -> { mTaskView.post(() -> { if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) { setVisibility(GONE); setNoLimit(); } else { setVisibility(VISIBLE); mText.setText(getText(appRemainingTimeMs)); setLimit(appUsageLimitTimeMs, appRemainingTimeMs); } callback.call(getContentDescriptionForTask( task, appUsageLimitTimeMs, appRemainingTimeMs)); }); }); } Loading Loading @@ -146,7 +171,7 @@ public final class DigitalWellBeingToast extends LinearLayout { // Use a specific string for usage less than one minute but non-zero. if (duration.compareTo(Duration.ZERO) > 0) { return getResources().getString(durationLessThanOneMinuteStringId); return mActivity.getString(durationLessThanOneMinuteStringId); } // Otherwise, return 0-minute string. Loading Loading @@ -176,24 +201,24 @@ public final class DigitalWellBeingToast extends LinearLayout { } private String getText(long remainingTime) { return getResources().getString( return mActivity.getString( R.string.time_left_for_app, getRoundedUpToMinuteReadableDuration(remainingTime)); } public void openAppUsageSettings() { public void openAppUsageSettings(View view) { final Intent intent = new Intent(OPEN_APP_USAGE_SETTINGS_TEMPLATE) .putExtra(Intent.EXTRA_PACKAGE_NAME, mTask.getTopComponent().getPackageName()).addFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); try { final BaseActivity activity = BaseActivity.fromContext(getContext()); final BaseActivity activity = BaseActivity.fromContext(view.getContext()); final ActivityOptions options = ActivityOptions.makeScaleUpAnimation( this, 0, 0, getWidth(), getHeight()); view, 0, 0, view.getWidth(), view.getHeight()); activity.startActivity(intent, options.toBundle()); activity.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP, LauncherLogProto.ControlType.APP_USAGE_SETTINGS, this); LauncherLogProto.ControlType.APP_USAGE_SETTINGS, view); } catch (ActivityNotFoundException e) { Log.e(TAG, "Failed to open app usage settings for task " + mTask.getTopComponent().getPackageName(), e); Loading @@ -203,7 +228,7 @@ public final class DigitalWellBeingToast extends LinearLayout { private String getContentDescriptionForTask( Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) { return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ? getResources().getString( mActivity.getString( R.string.task_contents_description_with_remaining_time, task.titleDescription, getText(appRemainingTimeMs)) : Loading quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +3 −0 Original line number Diff line number Diff line Loading @@ -351,6 +351,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding); setWillNotDraw(false); updateEmptyMessage(); // Initialize quickstep specific cache params here, as this is constructed only once mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5); } public OverScroller getScroller() { Loading Loading
quickstep/recents_ui_overrides/res/layout/proactive_hints_container.xmldeleted 100644 → 0 +0 −7 Original line number Diff line number Diff line <com.android.quickstep.hints.ProactiveHintsContainer xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|bottom" android:gravity="center_horizontal"> </com.android.quickstep.hints.ProactiveHintsContainer> No newline at end of file
quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +6 −9 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.KeyguardManager; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading Loading @@ -234,7 +233,6 @@ public class TouchInteractionService extends Service implements private final InputConsumer mResetGestureInputConsumer = new ResetGestureInputConsumer(mSwipeSharedState); private KeyguardManager mKM; private ActivityManagerWrapper mAM; private RecentsModel mRecentsModel; private ISystemUiProxy mISystemUiProxy; Loading Loading @@ -280,7 +278,6 @@ public class TouchInteractionService extends Service implements // Initialize anything here that is needed in direct boot mode. // Everything else should be initialized in initWhenUserUnlocked() below. mKM = getSystemService(KeyguardManager.class); mMainChoreographer = Choreographer.getInstance(); mAM = ActivityManagerWrapper.getInstance(); Loading Loading @@ -547,6 +544,10 @@ public class TouchInteractionService extends Service implements (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base, mInputMonitorCompat, mSwipeTouchRegion); } } else { if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) { base = mResetGestureInputConsumer; } } return base; } Loading @@ -556,11 +557,8 @@ public class TouchInteractionService extends Service implements if (!useSharedState) { mSwipeSharedState.clearAllState(); } if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0 || mKM.isDeviceLocked()) { // This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched // while device is locked after exiting direct boot mode (e.g. camera), or if the // app is showing over the lockscreen (even if not locked) if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) { // This handles apps showing over the lockscreen (e.g. camera) return createDeviceLockedInputConsumer(runningTaskInfo); } Loading Loading @@ -665,7 +663,6 @@ public class TouchInteractionService extends Service implements pw.println(" systemUiFlags=" + mSystemUiStateFlags); pw.println(" systemUiFlagsDesc=" + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags)); pw.println(" isDeviceLocked=" + mKM.isDeviceLocked()); pw.println(" assistantAvailable=" + mAssistantAvailable); pw.println(" assistantDisabled=" + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)); Loading
quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +31 −27 Original line number Diff line number Diff line Loading @@ -22,10 +22,9 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.INVALID_POINTER_ID; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_LANDSCAPE; import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE; import static com.android.launcher3.util.RaceConditionTracker.ENTER; import static com.android.launcher3.util.RaceConditionTracker.EXIT; import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; Loading @@ -45,10 +44,7 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; import androidx.annotation.UiThread; import com.android.launcher3.R; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.TraceHelper; Loading @@ -68,10 +64,11 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.BackgroundExecutor; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; import java.util.function.Consumer; import androidx.annotation.UiThread; /** * Input consumer for handling events originating from an activity other than Launcher */ Loading @@ -81,6 +78,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public static final String DOWN_EVT = "OtherActivityInputConsumer.DOWN"; private static final String UP_EVT = "OtherActivityInputConsumer.UP"; // TODO: Move to quickstep contract private static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final RunningTaskInfo mRunningTask; private final RecentsModel mRecentsModel; Loading @@ -107,14 +107,16 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private final PointF mLastPos = new PointF(); private int mActivePointerId = INVALID_POINTER_ID; private final float mDragSlop; // Distance after which we start dragging the window. private final float mTouchSlop; private final float mSquaredTouchSlop; private final boolean mDisableHorizontalSwipe; // Slop used to check when we start moving window. private boolean mPassedDragSlop; private boolean mPaddedWindowMoveSlop; // Slop used to determine when we say that the gesture has started. private boolean mPassedTouchSlop; private boolean mPassedPilferInputSlop; // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar. private float mStartDisplacement; Loading Loading @@ -156,12 +158,13 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mSwipeSharedState = swipeSharedState; mNavBarPosition = new NavBarPosition(base); mDragSlop = QuickStepContract.getQuickStepDragSlopPx(); float slop = QuickStepContract.getQuickStepTouchSlopPx(); mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop(); float slop = QUICKSTEP_TOUCH_SLOP_RATIO * mTouchSlop; mSquaredTouchSlop = slop * slop; mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture; mDisableHorizontalSwipe = !mPassedTouchSlop && disableHorizontalSwipe; mPassedPilferInputSlop = mPaddedWindowMoveSlop = continuingPreviousGesture; mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe; } @Override Loading @@ -183,7 +186,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } // Proxy events to recents view if (mPassedDragSlop && mInteractionHandler != null if (mPaddedWindowMoveSlop && mInteractionHandler != null && !mRecentsViewDispatcher.hasConsumer()) { mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher( mNavBarPosition.getRotationMode())); Loading Loading @@ -217,7 +220,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC break; } case ACTION_POINTER_DOWN: { if (!mPassedTouchSlop) { if (!mPassedPilferInputSlop) { // Cancel interaction in case of multi-touch interaction int ptrIdx = ev.getActionIndex(); if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) { Loading Loading @@ -248,18 +251,18 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC float displacement = getDisplacement(ev); float displacementX = mLastPos.x - mDownPos.x; if (!mPassedDragSlop) { if (!mPaddedWindowMoveSlop) { if (!mIsDeferredDownTarget) { // Normal gesture, ensure we pass the drag slop before we start tracking // the gesture if (Math.abs(displacement) > mDragSlop) { mPassedDragSlop = true; mStartDisplacement = displacement; if (Math.abs(displacement) > mTouchSlop) { mPaddedWindowMoveSlop = true; mStartDisplacement = Math.min(displacement, -mTouchSlop); } } } if (!mPassedTouchSlop) { if (!mPassedPilferInputSlop) { float displacementY = mLastPos.y - mDownPos.y; if (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop) { if (mDisableHorizontalSwipe Loading @@ -269,23 +272,24 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC break; } mPassedTouchSlop = true; mPassedPilferInputSlop = true; if (mIsDeferredDownTarget) { // Deferred gesture, start the animation and gesture tracking once // we pass the actual touch slop startTouchTrackingForWindowAnimation(ev.getEventTime()); } if (!mPassedDragSlop) { mPassedDragSlop = true; mStartDisplacement = displacement; if (!mPaddedWindowMoveSlop) { mPaddedWindowMoveSlop = true; mStartDisplacement = Math.min(displacement, -mTouchSlop); } notifyGestureStarted(); } } if (mInteractionHandler != null) { if (mPassedDragSlop) { if (mPaddedWindowMoveSlop) { // Move mInteractionHandler.updateDisplacement(displacement - mStartDisplacement); } Loading Loading @@ -362,7 +366,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC RaceConditionTracker.onEvent(UP_EVT, ENTER); TraceHelper.endSection("TouchInt"); if (mPassedDragSlop && mInteractionHandler != null) { if (mPaddedWindowMoveSlop && mInteractionHandler != null) { if (ev.getActionMasked() == ACTION_CANCEL) { mInteractionHandler.onGestureCancelled(); } else { Loading Loading @@ -448,6 +452,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC @Override public boolean allowInterceptByParent() { return !mPassedTouchSlop; return !mPassedPilferInputSlop; } }
quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java +65 −40 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.quickstep.views; import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS; import static com.android.launcher3.Utilities.prefixTextWithIcon; import android.annotation.TargetApi; import android.app.ActivityOptions; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.AppUsageLimit; Loading @@ -28,16 +30,16 @@ import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; import android.icu.util.MeasureUnit; import android.os.Build; import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.StringRes; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.userevent.nano.LauncherLogProto; Loading @@ -46,45 +48,72 @@ import com.android.systemui.shared.recents.model.Task; import java.time.Duration; import java.util.Locale; public final class DigitalWellBeingToast extends LinearLayout { @TargetApi(Build.VERSION_CODES.Q) public final class DigitalWellBeingToast { static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS); static final int MINUTE_MS = 60000; private final LauncherApps mLauncherApps; public interface InitializeCallback { void call(String contentDescription); } private static final String TAG = DigitalWellBeingToast.class.getSimpleName(); private final BaseDraggingActivity mActivity; private final TaskView mTaskView; private final LauncherApps mLauncherApps; private Task mTask; private TextView mText; private boolean mHasLimit; private long mAppRemainingTimeMs; public DigitalWellBeingToast(Context context, AttributeSet attrs) { super(context, attrs); setLayoutDirection(Utilities.isRtl(getResources()) ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); setOnClickListener((view) -> openAppUsageSettings()); mLauncherApps = context.getSystemService(LauncherApps.class); public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) { mActivity = activity; mTaskView = taskView; mLauncherApps = activity.getSystemService(LauncherApps.class); } public TextView getTextView() { return mText; private void setTaskFooter(View view) { View oldFooter = mTaskView.setFooter(TaskView.INDEX_DIGITAL_WELLBEING_TOAST, view); if (oldFooter != null) { oldFooter.setOnClickListener(null); mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, oldFooter); } } @Override protected void onFinishInflate() { super.onFinishInflate(); private void setNoLimit() { mHasLimit = false; mTaskView.setContentDescription(mTask.titleDescription); setTaskFooter(null); mAppRemainingTimeMs = 0; } mText = findViewById(R.id.digital_well_being_remaining_time); private void setLimit(long appUsageLimitTimeMs, long appRemainingTimeMs) { mAppRemainingTimeMs = appRemainingTimeMs; mHasLimit = true; TextView toast = mActivity.getViewCache().getView(R.layout.digital_wellbeing_toast, mActivity, mTaskView); toast.setText(prefixTextWithIcon(mActivity, R.drawable.ic_hourglass_top, getText())); toast.setOnClickListener(this::openAppUsageSettings); setTaskFooter(toast); mTaskView.setContentDescription( getContentDescriptionForTask(mTask, appUsageLimitTimeMs, appRemainingTimeMs)); RecentsView rv = mTaskView.getRecentsView(); if (rv != null) { rv.onDigitalWellbeingToastShown(); } } public String getText() { return getText(mAppRemainingTimeMs); } public void initialize(Task task, InitializeCallback callback) { public boolean hasLimit() { return mHasLimit; } public void initialize(Task task) { mTask = task; if (task.key.userId != UserHandle.myUserId()) { setVisibility(GONE); callback.call(task.titleDescription); setNoLimit(); return; } Loading @@ -98,16 +127,12 @@ public final class DigitalWellBeingToast extends LinearLayout { final long appRemainingTimeMs = usageLimit != null ? usageLimit.getUsageRemaining() : -1; post(() -> { mTaskView.post(() -> { if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) { setVisibility(GONE); setNoLimit(); } else { setVisibility(VISIBLE); mText.setText(getText(appRemainingTimeMs)); setLimit(appUsageLimitTimeMs, appRemainingTimeMs); } callback.call(getContentDescriptionForTask( task, appUsageLimitTimeMs, appRemainingTimeMs)); }); }); } Loading Loading @@ -146,7 +171,7 @@ public final class DigitalWellBeingToast extends LinearLayout { // Use a specific string for usage less than one minute but non-zero. if (duration.compareTo(Duration.ZERO) > 0) { return getResources().getString(durationLessThanOneMinuteStringId); return mActivity.getString(durationLessThanOneMinuteStringId); } // Otherwise, return 0-minute string. Loading Loading @@ -176,24 +201,24 @@ public final class DigitalWellBeingToast extends LinearLayout { } private String getText(long remainingTime) { return getResources().getString( return mActivity.getString( R.string.time_left_for_app, getRoundedUpToMinuteReadableDuration(remainingTime)); } public void openAppUsageSettings() { public void openAppUsageSettings(View view) { final Intent intent = new Intent(OPEN_APP_USAGE_SETTINGS_TEMPLATE) .putExtra(Intent.EXTRA_PACKAGE_NAME, mTask.getTopComponent().getPackageName()).addFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); try { final BaseActivity activity = BaseActivity.fromContext(getContext()); final BaseActivity activity = BaseActivity.fromContext(view.getContext()); final ActivityOptions options = ActivityOptions.makeScaleUpAnimation( this, 0, 0, getWidth(), getHeight()); view, 0, 0, view.getWidth(), view.getHeight()); activity.startActivity(intent, options.toBundle()); activity.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP, LauncherLogProto.ControlType.APP_USAGE_SETTINGS, this); LauncherLogProto.ControlType.APP_USAGE_SETTINGS, view); } catch (ActivityNotFoundException e) { Log.e(TAG, "Failed to open app usage settings for task " + mTask.getTopComponent().getPackageName(), e); Loading @@ -203,7 +228,7 @@ public final class DigitalWellBeingToast extends LinearLayout { private String getContentDescriptionForTask( Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) { return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ? getResources().getString( mActivity.getString( R.string.task_contents_description_with_remaining_time, task.titleDescription, getText(appRemainingTimeMs)) : Loading
quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +3 −0 Original line number Diff line number Diff line Loading @@ -351,6 +351,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding); setWillNotDraw(false); updateEmptyMessage(); // Initialize quickstep specific cache params here, as this is constructed only once mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5); } public OverScroller getScroller() { Loading