From 97946e4b3bccac4e0f95a37650f9929859df7e2d Mon Sep 17 00:00:00 2001 From: Longbo Wei Date: Fri, 28 Feb 2025 21:36:00 +0000 Subject: a11y: Add ScrollPanel Develop a skeleton scroll panel to manage the autoclick scroll feature. This panel will appear when the autoclick type is set to 'scroll' and a pending click is finished. It will be hidden when the autoclick type is changed from 'scroll' to another type. Note that this is a temporary UI, Our focus is on getting the scroll feature working, and we will update the UI to the final design(screen/W6iBBZJMWWJmmhp) later. video: http://shortn/_4H94pLSb2s Design doc: http://b/397391986#comment2 Bug: b/388845721 Test: AutoclickControllerTest Flag: com.android.server.accessibility.enable_autoclick_indicator Change-Id: I57b3b375b55872484da12962e0111bf7a8e07fb9 --- .../autoclick/AutoclickController.java | 25 +++++ .../autoclick/AutoclickScrollPanel.java | 105 +++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java (limited to 'services/accessibility') diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java index 0f6f86b39458..739ea0df87ab 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java @@ -25,6 +25,7 @@ import static android.view.accessibility.AccessibilityManager.AUTOCLICK_IGNORE_M import static com.android.server.accessibility.autoclick.AutoclickIndicatorView.SHOW_INDICATOR_DELAY_TIME; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_RIGHT_CLICK; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AutoclickType; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.ClickPanelControllerInterface; @@ -87,6 +88,7 @@ public class AutoclickController extends BaseEventStreamTransformation { @VisibleForTesting AutoclickIndicatorScheduler mAutoclickIndicatorScheduler; @VisibleForTesting AutoclickIndicatorView mAutoclickIndicatorView; @VisibleForTesting AutoclickTypePanel mAutoclickTypePanel; + @VisibleForTesting AutoclickScrollPanel mAutoclickScrollPanel; private WindowManager mWindowManager; // Default click type is left-click. @@ -98,6 +100,11 @@ public class AutoclickController extends BaseEventStreamTransformation { @Override public void handleAutoclickTypeChange(@AutoclickType int clickType) { mActiveClickType = clickType; + + // Hide scroll panel when type is not scroll. + if (clickType != AUTOCLICK_TYPE_SCROLL && mAutoclickScrollPanel != null) { + mAutoclickScrollPanel.hide(); + } } @Override @@ -161,6 +168,7 @@ public class AutoclickController extends BaseEventStreamTransformation { mWindowManager = mContext.getSystemService(WindowManager.class); mAutoclickTypePanel = new AutoclickTypePanel(mContext, mWindowManager, mUserId, clickPanelController); + mAutoclickScrollPanel = new AutoclickScrollPanel(mContext, mWindowManager); mAutoclickTypePanel.show(); mWindowManager.addView(mAutoclickIndicatorView, mAutoclickIndicatorView.getLayoutParams()); @@ -189,6 +197,10 @@ public class AutoclickController extends BaseEventStreamTransformation { mClickScheduler.cancel(); } + if (mAutoclickScrollPanel != null) { + mAutoclickScrollPanel.hide(); + } + super.clearEvents(inputSource); } @@ -209,6 +221,11 @@ public class AutoclickController extends BaseEventStreamTransformation { mWindowManager.removeView(mAutoclickIndicatorView); mAutoclickTypePanel.hide(); } + + if (mAutoclickScrollPanel != null) { + mAutoclickScrollPanel.hide(); + mAutoclickScrollPanel = null; + } } private void handleMouseMotion(MotionEvent event, int policyFlags) { @@ -687,6 +704,14 @@ public class AutoclickController extends BaseEventStreamTransformation { return; } + // Handle scroll type specially, show scroll panel instead of sending click events. + if (mActiveClickType == AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL) { + if (mAutoclickScrollPanel != null) { + mAutoclickScrollPanel.show(); + } + return; + } + final int pointerIndex = mLastMotionEvent.getActionIndex(); if (mTempPointerProperties == null) { diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java new file mode 100644 index 000000000000..86f79a83ea28 --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java @@ -0,0 +1,105 @@ +/* + * Copyright 2025 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.server.accessibility.autoclick; + +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import com.android.internal.R; + +public class AutoclickScrollPanel { + private final Context mContext; + private final View mContentView; + private final WindowManager mWindowManager; + private boolean mInScrollMode = false; + + public AutoclickScrollPanel(Context context, WindowManager windowManager) { + mContext = context; + mWindowManager = windowManager; + mContentView = LayoutInflater.from(context).inflate( + R.layout.accessibility_autoclick_scroll_panel, null); + } + + /** + * Shows the autoclick scroll panel. + */ + public void show() { + if (mInScrollMode) { + return; + } + mWindowManager.addView(mContentView, getLayoutParams()); + mInScrollMode = true; + } + + /** + * Hides the autoclick scroll panel. + */ + public void hide() { + if (!mInScrollMode) { + return; + } + mWindowManager.removeView(mContentView); + mInScrollMode = false; + } + + /** + * Retrieves the layout params for AutoclickScrollPanel, used when it's added to the Window + * Manager. + */ + @NonNull + private WindowManager.LayoutParams getLayoutParams() { + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); + layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + layoutParams.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + layoutParams.setFitInsetsTypes(WindowInsets.Type.statusBars()); + layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + layoutParams.format = PixelFormat.TRANSLUCENT; + layoutParams.setTitle(AutoclickScrollPanel.class.getSimpleName()); + layoutParams.accessibilityTitle = + mContext.getString(R.string.accessibility_autoclick_scroll_panel_title); + layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; + layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + layoutParams.gravity = Gravity.CENTER; + return layoutParams; + } + + @VisibleForTesting + public boolean isVisible() { + return mInScrollMode; + } + + @VisibleForTesting + public View getContentViewForTesting() { + return mContentView; + } + + @VisibleForTesting + public WindowManager.LayoutParams getLayoutParamsForTesting() { + return getLayoutParams(); + } +} -- cgit v1.2.3-59-g8ed1b