diff options
| author | 2024-02-23 17:30:40 +0000 | |
|---|---|---|
| committer | 2024-02-26 15:29:46 +0000 | |
| commit | d636009b72ac01f309bb653b604c8f02c416b29c (patch) | |
| tree | f425c730c66368e3369c820f4e5015944af3d068 | |
| parent | 05c4854f1fff2be8d3ce1358cdbd698cb08eece8 (diff) | |
Move pointer icon caching logic into a new class: PointerIconCache
This is a refactor without any behavior changes to consolidate all
pointer icon loading and caching logic in a separate class for
maintainability.
Bug: 321324470
Bug: 325133368
Test: manual
Change-Id: Idfe692846381eb08d12ee04ceeb502a1a317439b
| -rw-r--r-- | services/core/java/com/android/server/input/InputManagerService.java | 140 | ||||
| -rw-r--r-- | services/core/java/com/android/server/input/PointerIconCache.java | 207 |
2 files changed, 215 insertions, 132 deletions
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index dbef427e23a7..a79e7715f064 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -38,7 +38,6 @@ import android.graphics.PointF; import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager.Sensors; import android.hardware.SensorPrivacyManagerInternal; -import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayViewport; import android.hardware.input.HostUsiVersion; @@ -86,9 +85,7 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.util.SparseIntArray; import android.view.Display; -import android.view.DisplayInfo; import android.view.IInputFilter; import android.view.IInputFilterHost; import android.view.IInputMonitorHost; @@ -117,7 +114,6 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.DisplayThread; import com.android.server.LocalServices; -import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.input.InputManagerInternal.LidSwitchCallback; import com.android.server.input.debug.FocusEventDebugView; @@ -325,6 +321,9 @@ public class InputManagerService extends IInputManager.Stub // Manages Keyboard modifier keys remapping private final KeyRemapper mKeyRemapper; + // Manages loading PointerIcons + private final PointerIconCache mPointerIconCache; + // Maximum number of milliseconds to wait for input event injection. private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; @@ -411,74 +410,6 @@ public class InputManagerService extends IInputManager.Stub private boolean mShowKeyPresses = false; private boolean mShowRotaryInput = false; - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType = - new SparseArray<>(); - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - boolean mUseLargePointerIcons = false; - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - final SparseArray<Context> mDisplayContexts = new SparseArray<>(); - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - final SparseIntArray mDisplayDensities = new SparseIntArray(); - - final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { - @Override - public void onDisplayAdded(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - updateDisplayDensity(displayId); - } - } - - @Override - public void onDisplayRemoved(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - mLoadedPointerIconsByDisplayAndType.remove(displayId); - mDisplayContexts.remove(displayId); - mDisplayDensities.delete(displayId); - } - } - - @Override - public void onDisplayChanged(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - if (!updateDisplayDensity(displayId)) { - return; - } - // The display density changed, so force all cached pointer icons to be - // reloaded for the display. - Slog.i(TAG, - "Reloading pointer icons due to density change on display: " + displayId); - var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId); - if (iconsByType == null) { - return; - } - iconsByType.clear(); - mDisplayContexts.remove(displayId); - } - mNative.reloadPointerIcons(); - } - - // Updates the cached display density for the given displayId, and returns true if - // the cached density changed. - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - private boolean updateDisplayDensity(int displayId) { - final DisplayManager displayManager = Objects.requireNonNull( - mContext.getSystemService(DisplayManager.class)); - final Display display = displayManager.getDisplay(displayId); - if (display == null) { - return false; - } - DisplayInfo info = new DisplayInfo(); - display.getDisplayInfo(info); - final int oldDensity = mDisplayDensities.get(displayId, 0 /* default */); - if (oldDensity == info.logicalDensityDpi) { - return false; - } - mDisplayDensities.put(displayId, info.logicalDensityDpi); - return true; - } - }; - /** Point of injection for test dependencies. */ @VisibleForTesting static class Injector { @@ -537,6 +468,7 @@ public class InputManagerService extends IInputManager.Stub : new KeyboardBacklightControllerInterface() {}; mStickyModifierStateController = new StickyModifierStateController(); mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper()); + mPointerIconCache = new PointerIconCache(mContext, mNative); mUseDevInputEventForAudioJack = mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); @@ -646,18 +578,11 @@ public class InputManagerService extends IInputManager.Stub mWiredAccessoryCallbacks.systemReady(); } - final DisplayManager displayManager = Objects.requireNonNull( - mContext.getSystemService(DisplayManager.class)); - displayManager.registerDisplayListener(mDisplayListener, UiThread.getHandler()); - final Display[] displays = displayManager.getDisplays(); - for (int i = 0; i < displays.length; i++) { - mDisplayListener.onDisplayAdded(displays[i].getDisplayId()); - } - mKeyboardLayoutManager.systemRunning(); mBatteryController.systemRunning(); mKeyboardBacklightController.systemRunning(); mKeyRemapper.systemRunning(); + mPointerIconCache.systemRunning(); } private void reloadDeviceAliases() { @@ -2411,8 +2336,8 @@ public class InputManagerService extends IInputManager.Stub synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ } synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ } synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ } - synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by pointer lock */} mBatteryController.monitor(); + mPointerIconCache.monitor(); mNative.monitor(); } @@ -2806,21 +2731,7 @@ public class InputManagerService extends IInputManager.Stub // Native callback. @SuppressWarnings("unused") private @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get( - displayId); - if (iconsByType == null) { - iconsByType = new SparseArray<>(); - mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType); - } - PointerIcon icon = iconsByType.get(type); - if (icon == null) { - icon = PointerIcon.getLoadedSystemIcon(getContextForDisplay(displayId), type, - mUseLargePointerIcons); - iconsByType.put(type, icon); - } - return Objects.requireNonNull(icon); - } + return mPointerIconCache.getLoadedPointerIcon(displayId, type); } // Native callback. @@ -2833,33 +2744,6 @@ public class InputManagerService extends IInputManager.Stub return sc.mNativeObject; } - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - @NonNull - private Context getContextForDisplay(int displayId) { - if (displayId == Display.INVALID_DISPLAY) { - // Fallback to using the default context. - return mContext; - } - if (displayId == mContext.getDisplay().getDisplayId()) { - return mContext; - } - - Context displayContext = mDisplayContexts.get(displayId); - if (displayContext == null) { - final DisplayManager displayManager = Objects.requireNonNull( - mContext.getSystemService(DisplayManager.class)); - final Display display = displayManager.getDisplay(displayId); - if (display == null) { - // Fallback to using the default context. - return mContext; - } - - displayContext = mContext.createDisplayContext(display); - mDisplayContexts.put(displayId, displayContext); - } - return displayContext; - } - // Native callback. @SuppressWarnings("unused") private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier, String languageTag, @@ -3665,15 +3549,7 @@ public class InputManagerService extends IInputManager.Stub } void setUseLargePointerIcons(boolean useLargeIcons) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - if (mUseLargePointerIcons == useLargeIcons) { - return; - } - mUseLargePointerIcons = useLargeIcons; - // Clear all cached icons on all displays. - mLoadedPointerIconsByDisplayAndType.clear(); - } - UiThread.getHandler().post(mNative::reloadPointerIcons); + mPointerIconCache.setUseLargePointerIcons(useLargeIcons); } interface KeyboardBacklightControllerInterface { diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java new file mode 100644 index 000000000000..233b865c69a6 --- /dev/null +++ b/services/core/java/com/android/server/input/PointerIconCache.java @@ -0,0 +1,207 @@ +/* + * Copyright 2024 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.input; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.display.DisplayManager; +import android.os.Handler; +import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.PointerIcon; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.UiThread; + +import java.util.Objects; + +/** + * A thread-safe component of {@link InputManagerService} responsible for caching loaded + * {@link PointerIcon}s and triggering reloading of the icons. + */ +final class PointerIconCache { + private static final String TAG = PointerIconCache.class.getSimpleName(); + + private final Context mContext; + + // Do not hold the lock when calling into native code. + private final NativeInputManagerService mNative; + + // We use the UI thread for loading pointer icons. + private final Handler mUiThreadHandler = UiThread.getHandler(); + + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType = + new SparseArray<>(); + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private boolean mUseLargePointerIcons = false; + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private final SparseArray<Context> mDisplayContexts = new SparseArray<>(); + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private final SparseIntArray mDisplayDensities = new SparseIntArray(); + + private final DisplayManager.DisplayListener mDisplayListener = + new DisplayManager.DisplayListener() { + @Override + public void onDisplayAdded(int displayId) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + updateDisplayDensityLocked(displayId); + } + } + + @Override + public void onDisplayRemoved(int displayId) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + mLoadedPointerIconsByDisplayAndType.remove(displayId); + mDisplayContexts.remove(displayId); + mDisplayDensities.delete(displayId); + } + } + + @Override + public void onDisplayChanged(int displayId) { + handleDisplayChanged(displayId); + } + }; + + /* package */ PointerIconCache(Context context, NativeInputManagerService nativeService) { + mContext = context; + mNative = nativeService; + } + + public void systemRunning() { + final DisplayManager displayManager = Objects.requireNonNull( + mContext.getSystemService(DisplayManager.class)); + displayManager.registerDisplayListener(mDisplayListener, mUiThreadHandler); + final Display[] displays = displayManager.getDisplays(); + for (int i = 0; i < displays.length; i++) { + mDisplayListener.onDisplayAdded(displays[i].getDisplayId()); + } + } + + public void monitor() { + synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by lock */} + } + + /** Set whether the large pointer icons should be used for accessibility. */ + public void setUseLargePointerIcons(boolean useLargeIcons) { + mUiThreadHandler.post(() -> handleSetUseLargePointerIcons(useLargeIcons)); + } + + /** + * Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if + * it isn't already cached. + */ + public @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get( + displayId); + if (iconsByType == null) { + iconsByType = new SparseArray<>(); + mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType); + } + PointerIcon icon = iconsByType.get(type); + if (icon == null) { + icon = PointerIcon.getLoadedSystemIcon(getContextForDisplayLocked(displayId), type, + mUseLargePointerIcons); + iconsByType.put(type, icon); + } + return Objects.requireNonNull(icon); + } + } + + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private @NonNull Context getContextForDisplayLocked(int displayId) { + if (displayId == Display.INVALID_DISPLAY) { + // Fallback to using the default context. + return mContext; + } + if (displayId == mContext.getDisplay().getDisplayId()) { + return mContext; + } + + Context displayContext = mDisplayContexts.get(displayId); + if (displayContext == null) { + final DisplayManager displayManager = Objects.requireNonNull( + mContext.getSystemService(DisplayManager.class)); + final Display display = displayManager.getDisplay(displayId); + if (display == null) { + // Fallback to using the default context. + return mContext; + } + + displayContext = mContext.createDisplayContext(display); + mDisplayContexts.put(displayId, displayContext); + } + return displayContext; + } + + @android.annotation.UiThread + private void handleDisplayChanged(int displayId) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + if (!updateDisplayDensityLocked(displayId)) { + return; + } + // The display density changed, so force all cached pointer icons to be + // reloaded for the display. + Slog.i(TAG, "Reloading pointer icons due to density change on display: " + displayId); + var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId); + if (iconsByType == null) { + return; + } + iconsByType.clear(); + mDisplayContexts.remove(displayId); + } + mNative.reloadPointerIcons(); + } + + @android.annotation.UiThread + private void handleSetUseLargePointerIcons(boolean useLargeIcons) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + if (mUseLargePointerIcons == useLargeIcons) { + return; + } + mUseLargePointerIcons = useLargeIcons; + // Clear all cached icons on all displays. + mLoadedPointerIconsByDisplayAndType.clear(); + } + mNative.reloadPointerIcons(); + } + + // Updates the cached display density for the given displayId, and returns true if + // the cached density changed. + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private boolean updateDisplayDensityLocked(int displayId) { + final DisplayManager displayManager = Objects.requireNonNull( + mContext.getSystemService(DisplayManager.class)); + final Display display = displayManager.getDisplay(displayId); + if (display == null) { + return false; + } + DisplayInfo info = new DisplayInfo(); + display.getDisplayInfo(info); + final int oldDensity = mDisplayDensities.get(displayId, 0 /* default */); + if (oldDensity == info.logicalDensityDpi) { + return false; + } + mDisplayDensities.put(displayId, info.logicalDensityDpi); + return true; + } +} |